{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "quick-feedback",
  "type": "registry:component",
  "title": "Quick Feedback",
  "description": "A responsive feedback component built for instant user responses, using subtle micro-interactions and snappy visual cues to confirm actions in real time.",
  "dependencies": [
    "lucide-react",
    "motion",
    "react-icons",
    "react-use-measure"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "components/watermelon/quick-feedback.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport { type FC, useState } from 'react';\nimport {\n  motion,\n  AnimatePresence,\n  type Transition,\n  MotionConfig,\n  LayoutGroup,\n} from 'motion/react';\nimport { Undo2 } from 'lucide-react';\nimport { FaThumbsDown, FaThumbsUp } from 'react-icons/fa6';\nimport useMeasure from 'react-use-measure';\nimport { cn } from '@/lib/utils';\nimport type { IconType } from 'react-icons';\n\nexport type FeedbackStatus = 'idle' | 'up' | 'down';\n\nexport interface QuickFeedbackProps {\n  defaultStatus?: FeedbackStatus;\n  showThemeToggle?: boolean;\n  feedbackText?: string;\n  onFeedback?: (status: 'up' | 'down') => void;\n  onUndo?: () => void;\n}\n\nconst containerTransition: Transition = {\n  type: 'spring',\n  stiffness: 150,\n  damping: 15,\n  mass: 1,\n};\n\nexport const QuickFeedback: FC<QuickFeedbackProps> = ({\n  defaultStatus = 'idle',\n  feedbackText = 'Feedback Received!',\n  onFeedback,\n  onUndo,\n}) => {\n  const [status, setStatus] = useState<FeedbackStatus>(defaultStatus);\n\n  const handleFeedback = (value: 'up' | 'down') => {\n    setStatus(value);\n    onFeedback?.(value);\n  };\n\n  const handleUndo = () => {\n    setStatus('idle');\n    onUndo?.();\n  };\n\n  return (\n    <div className=\"relative flex w-full items-center justify-center gap-4 bg-transparent px-4 transition-colors duration-500\">\n      <MotionConfig transition={containerTransition}>\n        <LayoutGroup>\n          <div className=\"relative flex items-center justify-center gap-2\">\n            <AnimatePresence mode=\"sync\" initial={false}>\n              {(status === 'idle' || status === 'up') && (\n                <QuickFeedbackButton\n                  key=\"up-btn\"\n                  name=\"up\"\n                  handleFeedback={() => handleFeedback('up')}\n                  handleUndo={handleUndo}\n                  status={status}\n                  feedbackText={feedbackText}\n                  Icon={FaThumbsUp}\n                />\n              )}\n              {(status === 'idle' || status === 'down') && (\n                <QuickFeedbackButton\n                  key=\"down-btn\"\n                  name=\"down\"\n                  handleFeedback={() => handleFeedback('down')}\n                  handleUndo={handleUndo}\n                  status={status}\n                  feedbackText=\"Sorry about that\"\n                  Icon={FaThumbsDown}\n                />\n              )}\n            </AnimatePresence>\n          </div>\n        </LayoutGroup>\n      </MotionConfig>\n    </div>\n  );\n};\n\ninterface QuickFeedbackButtonProps {\n  name: 'up' | 'down';\n  handleFeedback: () => void;\n  handleUndo: () => void;\n  status: FeedbackStatus;\n  feedbackText: string;\n  Icon: IconType;\n}\n\nexport const QuickFeedbackButton: FC<QuickFeedbackButtonProps> = ({\n  name,\n  handleFeedback,\n  handleUndo,\n  status,\n  feedbackText,\n  Icon,\n}) => {\n  const [ref, bounds] = useMeasure({ offsetSize: true });\n  const isActive = name === status;\n\n  return (\n    <motion.div\n      layout=\"position\"\n      animate={{\n        opacity: 1,\n        width: bounds.width > 0 ? bounds.width : 'auto',\n        height: bounds.height > 0 ? bounds.height : 'auto',\n      }}\n      className=\"relative overflow-hidden rounded-full bg-[#F3EFE9] will-change-transform dark:border-neutral-800 dark:bg-neutral-900\"\n    >\n      <motion.div\n        ref={ref}\n        className={cn(\n          'flex w-fit items-center justify-center gap-1 px-12 py-3',\n          isActive && 'px-4.5 py-3.5',\n        )}\n      >\n        <motion.button\n          layout\n          onClick={handleFeedback}\n          className={cn(\n            'ml-1 flex shrink-0 items-center justify-center rounded-full',\n            isActive && 'pointer-events-none',\n          )}\n        >\n          <Icon className=\"size-8 text-[#020200de] dark:text-neutral-100\" />\n        </motion.button>\n\n        <AnimatePresence mode=\"popLayout\" initial={false}>\n          {isActive && (\n            <motion.div\n              initial={{ opacity: 0, x: 20 }}\n              animate={{ opacity: 1, x: 0 }}\n              exit={{ opacity: 0, x: 20 }}\n              className=\"flex shrink-0 items-center gap-2 whitespace-nowrap\"\n            >\n              <span className=\"ml-1 text-sm font-bold tracking-wide text-[#020200] sm:ml-2 sm:text-lg dark:text-neutral-100\">\n                {feedbackText}\n              </span>\n\n              <button\n                onClick={(e) => {\n                  e.stopPropagation();\n                  handleUndo();\n                }}\n                className=\"flex shrink-0 items-center gap-1 rounded-full bg-[#E0DCD4] px-3 py-2 text-xs font-bold text-[#020200] transition hover:bg-[#d6d2ca] active:scale-95 sm:text-base dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700\"\n              >\n                <Undo2 size={16} className=\"sm:h-5 sm:w-5\" strokeWidth={2.5} />\n                Undo\n              </button>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </motion.div>\n    </motion.div>\n  );\n};\n"
    }
  ]
}
