{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "Dock-JS-CSS",
	"title": "Dock",
	"description": "macOS style magnifying dock with proximity scaling of icons.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "Dock.css",
			"target": "@components/Dock.css",
			"content": ".dock-outer {\n  margin: 0 0.5rem;\n  display: flex;\n  max-width: 100%;\n  align-items: center;\n}\n\n.dock-panel {\n  position: absolute;\n  bottom: 0.5rem;\n  left: 50%;\n  transform: translateX(-50%);\n  display: flex;\n  align-items: flex-end;\n  width: fit-content;\n  gap: 1rem;\n  border-radius: 1rem;\n  background-color: #120F17;\n  border: 1px solid #222;\n  padding: 0 0.5rem 0.5rem;\n}\n\n.dock-item {\n  position: relative;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  border-radius: 10px;\n  background-color: #120F17;\n  border: 1px solid #222;\n  box-shadow:\n    0 4px 6px -1px rgba(0, 0, 0, 0.1),\n    0 2px 4px -1px rgba(0, 0, 0, 0.06);\n  cursor: pointer;\n  outline: none;\n}\n\n.dock-icon {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.dock-label {\n  position: absolute;\n  top: -1.5rem;\n  left: 50%;\n  width: fit-content;\n  white-space: pre;\n  border-radius: 0.375rem;\n  border: 1px solid #222;\n  background-color: #120F17;\n  padding: 0.125rem 0.5rem;\n  font-size: 0.75rem;\n  color: #fff;\n  transform: translateX(-50%);\n}\n"
		},
		{
			"type": "registry:component",
			"path": "Dock.jsx",
			"content": "'use client';\n\nimport { motion, useMotionValue, useSpring, useTransform, AnimatePresence } from 'motion/react';\nimport { Children, cloneElement, useEffect, useMemo, useRef, useState } from 'react';\n\nimport './Dock.css';\n\nfunction DockItem({ children, className = '', onClick, mouseX, spring, distance, magnification, baseItemSize, label }) {\n  const ref = useRef(null);\n  const isHovered = useMotionValue(0);\n\n  const mouseDistance = useTransform(mouseX, val => {\n    const rect = ref.current?.getBoundingClientRect() ?? {\n      x: 0,\n      width: baseItemSize\n    };\n    return val - rect.x - baseItemSize / 2;\n  });\n\n  const targetSize = useTransform(mouseDistance, [-distance, 0, distance], [baseItemSize, magnification, baseItemSize]);\n  const size = useSpring(targetSize, spring);\n\n  const handleKeyDown = e => {\n    if (e.key === 'Enter' || e.key === ' ') {\n      e.preventDefault();\n      onClick?.();\n    }\n  };\n\n  return (\n    <motion.div\n      ref={ref}\n      style={{\n        width: size,\n        height: size\n      }}\n      onHoverStart={() => isHovered.set(1)}\n      onHoverEnd={() => isHovered.set(0)}\n      onFocus={() => isHovered.set(1)}\n      onBlur={() => isHovered.set(0)}\n      onClick={onClick}\n      className={`dock-item ${className}`}\n      tabIndex={0}\n      role=\"button\"\n      aria-haspopup=\"true\"\n      aria-label={label}\n      onKeyDown={handleKeyDown}\n    >\n      {Children.map(children, child => cloneElement(child, { isHovered }))}\n    </motion.div>\n  );\n}\n\nfunction DockLabel({ children, className = '', ...rest }) {\n  const { isHovered } = rest;\n  const [isVisible, setIsVisible] = useState(false);\n\n  useEffect(() => {\n    const unsubscribe = isHovered.on('change', latest => {\n      setIsVisible(latest === 1);\n    });\n    return () => unsubscribe();\n  }, [isHovered]);\n\n  return (\n    <AnimatePresence>\n      {isVisible && (\n        <motion.div\n          initial={{ opacity: 0, y: 0 }}\n          animate={{ opacity: 1, y: -10 }}\n          exit={{ opacity: 0, y: 0 }}\n          transition={{ duration: 0.2 }}\n          className={`dock-label ${className}`}\n          role=\"tooltip\"\n          style={{ x: '-50%' }}\n        >\n          {children}\n        </motion.div>\n      )}\n    </AnimatePresence>\n  );\n}\n\nfunction DockIcon({ children, className = '' }) {\n  return <div className={`dock-icon ${className}`}>{children}</div>;\n}\n\nexport default function Dock({\n  items,\n  className = '',\n  spring = { mass: 0.1, stiffness: 150, damping: 12 },\n  magnification = 70,\n  distance = 200,\n  panelHeight = 68,\n  dockHeight = 256,\n  baseItemSize = 50\n}) {\n  const mouseX = useMotionValue(Infinity);\n  const isHovered = useMotionValue(0);\n\n  const maxHeight = useMemo(\n    () => Math.max(dockHeight, magnification + magnification / 2 + 4),\n    [magnification, dockHeight]\n  );\n  const heightRow = useTransform(isHovered, [0, 1], [panelHeight, maxHeight]);\n  const height = useSpring(heightRow, spring);\n\n  return (\n    <motion.div style={{ height, scrollbarWidth: 'none' }} className=\"dock-outer\">\n      <motion.div\n        onMouseMove={({ pageX }) => {\n          isHovered.set(1);\n          mouseX.set(pageX);\n        }}\n        onMouseLeave={() => {\n          isHovered.set(0);\n          mouseX.set(Infinity);\n        }}\n        className={`dock-panel ${className}`}\n        style={{ height: panelHeight }}\n        role=\"toolbar\"\n        aria-label=\"Application dock\"\n      >\n        {items.map((item, index) => (\n          <DockItem\n            key={index}\n            onClick={item.onClick}\n            className={item.className}\n            mouseX={mouseX}\n            spring={spring}\n            distance={distance}\n            magnification={magnification}\n            baseItemSize={baseItemSize}\n            label={item.label}\n          >\n            <DockIcon>{item.icon}</DockIcon>\n            <DockLabel>{item.label}</DockLabel>\n          </DockItem>\n        ))}\n      </motion.div>\n    </motion.div>\n  );\n}\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"motion@^12.23.12"
	]
}