{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dock",
  "type": "registry:component",
  "title": "Dock",
  "description": "A macOS style dock for React: icons magnify under the pointer with spring physics and show a label. Real buttons or links, keyboard reachable and labelled.",
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/premium/dock.tsx",
      "type": "registry:ui",
      "target": "components/ui/dock.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { motion, useMotionValue, useReducedMotion, useSpring, useTransform, type MotionValue } from \"motion/react\"\nimport { CalendarIcon, FolderIcon, HomeIcon, MailIcon, MessageCircleIcon, SettingsIcon, type LucideIcon } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\n\n/**\n * A macOS style dock: icons swell as the pointer passes over them and ease\n * back when it leaves, with a label above the one under the pointer.\n * Every item is a real button or link, reachable and labelled for keyboard\n * and screen reader users; magnification is pointer only.\n */\ntype DockItem = { label: string; icon: LucideIcon; href?: string; onClick?: () => void; active?: boolean }\n\ntype DockProps = {\n  items?: DockItem[]\n  /** Resting icon size in pixels. */\n  size?: number\n  /** Size under the pointer. */\n  magnify?: number\n  /** How far the swell reaches, in pixels. */\n  distance?: number\n  className?: string\n}\n\nconst DEFAULT: DockItem[] = [\n  { label: \"Home\", icon: HomeIcon, active: true },\n  { label: \"Projects\", icon: FolderIcon },\n  { label: \"Messages\", icon: MessageCircleIcon },\n  { label: \"Mail\", icon: MailIcon },\n  { label: \"Calendar\", icon: CalendarIcon },\n  { label: \"Settings\", icon: SettingsIcon },\n]\n\nfunction DockIcon({ item, mouseX, size, magnify, distance }: { item: DockItem; mouseX: MotionValue<number>; size: number; magnify: number; distance: number }) {\n  const ref = React.useRef<HTMLAnchorElement & HTMLButtonElement>(null)\n  const [hover, setHover] = React.useState(false)\n  const d = useTransform(mouseX, (x) => {\n    const b = ref.current?.getBoundingClientRect()\n    return b ? x - (b.left + b.width / 2) : Infinity\n  })\n  const target = useTransform(d, [-distance, 0, distance], [size, magnify, size])\n  const s = useSpring(target, { mass: 0.1, stiffness: 180, damping: 14 })\n  const Icon = item.icon\n  const cls = \"relative grid aspect-square place-items-center rounded-[28%] border border-border bg-raised text-fg shadow-raised outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n  const inner = (\n    <>\n      <Icon className=\"size-[45%]\" strokeWidth={1.75} />\n      {item.active ? <span aria-hidden className=\"absolute -bottom-2 size-1 rounded-full bg-fg\" /> : null}\n      <motion.span\n        aria-hidden\n        initial={false}\n        animate={{ opacity: hover ? 1 : 0, y: hover ? 0 : 4 }}\n        className=\"pointer-events-none absolute -top-9 rounded-md border border-border bg-raised px-2 py-0.5 text-xs whitespace-nowrap text-fg shadow-overlay\"\n      >\n        {item.label}\n      </motion.span>\n    </>\n  )\n  const common = { ref, \"aria-label\": item.label, onPointerEnter: () => setHover(true), onPointerLeave: () => setHover(false), onFocus: () => setHover(true), onBlur: () => setHover(false), className: cls, style: { width: s, height: s } }\n  return item.href ? (\n    <motion.a href={item.href} {...common}>{inner}</motion.a>\n  ) : (\n    <motion.button type=\"button\" onClick={item.onClick} {...common}>{inner}</motion.button>\n  )\n}\n\nfunction Dock({ items = DEFAULT, size = 44, magnify = 68, distance = 130, className }: DockProps) {\n  const reduce = useReducedMotion()\n  const mouseX = useMotionValue(Infinity)\n  return (\n    <nav aria-label=\"Dock\" data-slot=\"dock\" className={cn(\"flex h-[88px] items-end\", className)}>\n      <div\n        onPointerMove={(e) => !reduce && mouseX.set(e.clientX)}\n        onPointerLeave={() => mouseX.set(Infinity)}\n        className=\"flex items-end gap-2.5 rounded-[22px] border border-border bg-surface/80 px-3 pb-2.5 pt-2.5 shadow-overlay backdrop-blur-md\"\n      >\n        {items.map((it) => (\n          <DockIcon key={it.label} item={it} mouseX={mouseX} size={size} magnify={reduce ? size : magnify} distance={distance} />\n        ))}\n      </div>\n    </nav>\n  )\n}\n\nexport { Dock }\nexport type { DockProps, DockItem }\n"
    }
  ]
}
