{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"hover-shelf","type":"registry:ui","title":"Hover Shelf","description":"macOS-style toolbar where icons magnify as the cursor passes.","dependencies":[],"registryDependencies":[],"files":[{"path":"registry/ui/hover-shelf.tsx","type":"registry:ui","content":"\"use client\";\n\nimport { useRef, type PointerEvent, type ReactNode } from \"react\";\n\nexport interface HoverShelfItem {\n  label: string;\n  icon: ReactNode;\n  onClick?: () => void;\n}\n\nexport interface HoverShelfProps {\n  items: HoverShelfItem[];\n  /** Resting icon size in px. */\n  baseSize?: number;\n  /** Icon size right under the cursor, in px. */\n  magnification?: number;\n  /** Px from the cursor where magnification fades out. */\n  distance?: number;\n  className?: string;\n}\n\nexport function HoverShelf({ items, baseSize = 48, magnification = 80, distance = 140, className }: HoverShelfProps) {\n  const refs = useRef<(HTMLButtonElement | null)[]>([]);\n\n  const onMove = (e: PointerEvent<HTMLDivElement>) => {\n    for (const el of refs.current) {\n      if (!el) continue;\n      const r = el.getBoundingClientRect();\n      const d = Math.abs(e.clientX - (r.left + r.width / 2));\n      // Cosine falloff: smooth peak under the cursor, zero at `distance`.\n      const k = d < distance ? (Math.cos((d / distance) * Math.PI) + 1) / 2 : 0;\n      const size = baseSize + (magnification - baseSize) * k;\n      el.style.width = el.style.height = `${size}px`;\n    }\n  };\n\n  const onLeave = () => {\n    for (const el of refs.current) if (el) el.style.width = el.style.height = `${baseSize}px`;\n  };\n\n  return (\n    <div\n      onPointerMove={onMove}\n      onPointerLeave={onLeave}\n      role=\"toolbar\"\n      className={`flex items-end gap-3 rounded-2xl border border-border bg-card/70 px-3 pb-2 pt-2 backdrop-blur ${className ?? \"\"}`}\n      style={{ height: baseSize + 16 }}\n    >\n      {items.map((item, i) => (\n        <button\n          key={item.label}\n          ref={(el) => {\n            refs.current[i] = el;\n          }}\n          type=\"button\"\n          aria-label={item.label}\n          onClick={item.onClick}\n          className=\"group relative grid shrink-0 place-items-center rounded-xl border border-border bg-muted text-foreground transition-[width,height] duration-100 ease-out focus-visible:outline-2 focus-visible:outline-offset-2\"\n          style={{ width: baseSize, height: baseSize }}\n        >\n          <span className=\"pointer-events-none absolute -top-9 whitespace-nowrap rounded-md border border-border bg-card px-2 py-1 text-xs opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100\">\n            {item.label}\n          </span>\n          <span className=\"grid size-1/2 place-items-center [&>svg]:size-full\">{item.icon}</span>\n        </button>\n      ))}\n    </div>\n  );\n}\n"}]}