{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "specials-reaction-dock",
  "type": "registry:component",
  "title": "Reaction Dock",
  "description": "A smooth, scaling dock of reaction emojis with magnification effect",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/new-york/animations/specials/reaction-dock.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n    motion,\n    useMotionValue,\n    useSpring,\n    useTransform,\n    MotionValue,\n    AnimatePresence,\n} from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface ReactionDockProps {\n    items: {\n        icon: React.ReactNode;\n        label: string;\n        onClick?: () => void;\n    }[];\n    className?: string;\n}\n\nexport function ReactionDock({ items, className }: ReactionDockProps) {\n    const mouseX = useMotionValue(Infinity);\n\n    return (\n        <motion.div\n            onMouseMove={(e) => mouseX.set(e.pageX)}\n            onMouseLeave={() => mouseX.set(Infinity)}\n            className={cn(\n                \"mx-auto flex h-16 items-end gap-4 rounded-2xl px-4 pb-3\",\n                \"bg-white/10 dark:bg-black/10 backdrop-blur-md border border-white/20 dark:border-white/10 shadow-2xl\",\n                className\n            )}\n        >\n            {items.map((item, i) => (\n                <DockItem key={i} mouseX={mouseX} onClick={item.onClick} label={item.label}>\n                    {item.icon}\n                </DockItem>\n            ))}\n        </motion.div>\n    );\n}\n\nfunction DockItem({\n    mouseX,\n    children,\n    onClick,\n    label,\n}: {\n    mouseX: MotionValue;\n    children: React.ReactNode;\n    onClick?: () => void;\n    label: string;\n}) {\n    const ref = React.useRef<HTMLDivElement>(null);\n\n    const distance = useTransform(mouseX, (val) => {\n        const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };\n        return val - bounds.x - bounds.width / 2;\n    });\n\n    const widthSync = useTransform(distance, [-150, 0, 150], [40, 90, 40]);\n    const width = useSpring(widthSync, {\n        mass: 0.1,\n        stiffness: 150,\n        damping: 12,\n    });\n\n    const [isHovered, setHovered] = React.useState(false);\n    const [hasReacted, setHasReacted] = React.useState(false);\n\n    const handleClick = () => {\n        setHasReacted(!hasReacted);\n        if (onClick) onClick();\n    };\n\n    return (\n        <div className=\"relative flex flex-col items-center\">\n            <AnimatePresence>\n                {isHovered && (\n                    <motion.div\n                        initial={{ opacity: 0, y: 10, x: \"-50%\" }}\n                        animate={{ opacity: 1, y: 0, x: \"-50%\" }}\n                        exit={{ opacity: 0, y: 2, x: \"-50%\" }}\n                        className=\"absolute -top-10 left-1/2 w-fit whitespace-nowrap rounded-full border border-zinc-200 bg-white px-2 py-0.5 text-xs text-zinc-900 shadow-md dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100\"\n                    >\n                        {label}\n                    </motion.div>\n                )}\n            </AnimatePresence>\n            <motion.div\n                ref={ref}\n                style={{ width }}\n                onClick={handleClick}\n                onMouseEnter={() => setHovered(true)}\n                onMouseLeave={() => setHovered(false)}\n                className=\"aspect-square cursor-pointer rounded-full bg-white/50 dark:bg-black/50 border border-white/40 dark:border-white/10 shadow-sm backdrop-blur-sm flex items-center justify-center hover:bg-white/80 dark:hover:bg-black/80 transition-colors relative overflow-hidden\"\n            >\n                <AnimatePresence>\n                    {hasReacted && (\n                        <motion.div\n                            initial={{ scale: 0, opacity: 0 }}\n                            animate={{ scale: 1.2, opacity: 1 }}\n                            exit={{ scale: 0, opacity: 0 }}\n                            transition={{ duration: 0.2 }}\n                            className=\"absolute inset-0 bg-zinc-100 dark:bg-zinc-800 rounded-full z-0\"\n                        />\n                    )}\n                </AnimatePresence>\n                <motion.div\n                    className={cn(\n                        \"w-full h-full flex items-center justify-center relative z-20 transition-colors duration-200\",\n                    )}\n                    whileTap={{ scale: 0.8 }}\n                >\n                    {React.isValidElement(children)\n                        ? React.cloneElement(children as React.ReactElement<any>, {\n                            fill: hasReacted ? \"currentColor\" : \"none\",\n                            stroke: hasReacted ? \"white\" : \"currentColor\",\n                            strokeWidth: hasReacted ? 1.5 : 2,\n                            className: cn((children as React.ReactElement<any>).props.className, \"transition-all duration-300\")\n                        })\n                        : children}\n                </motion.div>\n            </motion.div>\n        </div>\n    );\n}\n",
      "type": "registry:component"
    }
  ]
}