{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "dock",
  "title": "Dock",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-vue/components/dock/Dock.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref, type Component, type HTMLAttributes } from 'vue'\nimport { cn } from '@/lib/utils'\n\nexport interface DockItem {\n  /** Unique id for the item. */\n  id: string\n  /** Lucide icon component to render. */\n  icon: Component\n  /** Label shown in the tooltip on hover. */\n  label: string\n  /** Click handler. */\n  handler?: () => void\n  /** Whether this item is the active one. */\n  active?: boolean\n}\n\ninterface Props {\n  /** Dock items. */\n  items: DockItem[]\n  /** Base icon size in pixels. Default 48. */\n  baseSize?: number\n  /** Peak magnification scale as the cursor hovers directly over an item. Default 1.6. */\n  magnification?: number\n  /** Pixel radius within which items magnify. Default 120. */\n  distance?: number\n  /** Orientation. Only 'horizontal' (bottom dock) is supported. */\n  orientation?: 'horizontal'\n  /** Show the tooltip label on hover. Default true. */\n  showTooltips?: boolean\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  baseSize: 48,\n  magnification: 1.6,\n  distance: 120,\n  orientation: 'horizontal',\n  showTooltips: true,\n})\n\nconst mouseX = ref<number | null>(null)\nconst hoveredId = ref<string | null>(null)\n\nfunction onMove(e: MouseEvent) {\n  mouseX.value = e.clientX\n}\n\nfunction onLeave() {\n  mouseX.value = null\n  hoveredId.value = null\n}\n\nfunction sizeFor(item: DockItem, index: number): number {\n  if (mouseX.value === null) return props.baseSize\n  const el = itemRefs.value[index]\n  if (!el) return props.baseSize\n  const rect = el.getBoundingClientRect()\n  const center = rect.left + rect.width / 2\n  const dist = Math.abs(mouseX.value - center)\n  if (dist > props.distance) return props.baseSize\n  // Cosine bell curve so magnification falls off smoothly.\n  const t = 1 - dist / props.distance\n  const scale = 1 + (props.magnification - 1) * t\n  return props.baseSize * scale\n}\n\nconst itemRefs = ref<HTMLElement[]>([])\n\nfunction setRef(el: any, index: number) {\n  if (el) itemRefs.value[index] = el as HTMLElement\n}\n\nconst sizes = computed(() => props.items.map((_, i) => sizeFor(props.items[i]!, i)))\n</script>\n\n<template>\n  <div\n    data-uipkge\n    data-slot=\"dock\"\n    :data-orientation=\"orientation\"\n    :class=\"\n      cn(\n        'border-border/60 bg-background/60 flex items-end justify-center gap-3 rounded-2xl border px-3 py-2 backdrop-blur-md',\n        props.class,\n      )\n    \"\n    @mousemove=\"onMove\"\n    @mouseleave=\"onLeave\"\n  >\n    <div\n      v-for=\"(item, index) in items\"\n      :key=\"item.id\"\n      :ref=\"(el) => setRef(el, index)\"\n      data-slot=\"dock-item\"\n      :data-active=\"item.active ? '' : undefined\"\n      role=\"button\"\n      tabindex=\"0\"\n      :aria-label=\"item.label\"\n      :aria-current=\"item.active ? 'true' : undefined\"\n      class=\"group focus-visible:ring-ring/50 relative flex shrink-0 cursor-pointer items-end justify-center rounded-xl outline-none focus-visible:ring-[3px]\"\n      @mouseenter=\"hoveredId = item.id\"\n      @mouseleave=\"hoveredId = null\"\n      @click=\"item.handler?.()\"\n      @keydown.enter=\"item.handler?.()\"\n      @keydown.space.prevent=\"item.handler?.()\"\n    >\n      <!-- Tooltip -->\n      <span\n        v-if=\"showTooltips && hoveredId === item.id\"\n        class=\"border-border bg-popover text-popover-foreground pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2 rounded-md border px-2 py-1 text-xs whitespace-nowrap shadow-md\"\n      >\n        {{ item.label }}\n      </span>\n\n      <!-- Icon tile -->\n      <span\n        :class=\"\n          cn(\n            'flex items-center justify-center rounded-xl border transition-[width,height] duration-100 ease-out will-change-[width,height]',\n            item.active\n              ? 'border-primary/40 bg-primary/10 text-primary'\n              : 'border-border/50 bg-muted/40 text-foreground hover:bg-muted',\n          )\n        \"\n        :style=\"{ width: `${sizes[index]}px`, height: `${sizes[index]}px` }\"\n      >\n        <component :is=\"item.icon\" :style=\"{ width: `${sizes[index] * 0.5}px`, height: `${sizes[index] * 0.5}px` }\" />\n      </span>\n\n      <!-- Active indicator dot -->\n      <span v-if=\"item.active\" class=\"bg-primary absolute -bottom-1.5 size-1 rounded-full\" aria-hidden=\"true\" />\n    </div>\n  </div>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/dock/Dock.vue"
    },
    {
      "path": "packages/registry-vue/components/dock/index.ts",
      "content": "export { default as Dock } from './Dock.vue'\nexport type { DockItem } from './Dock.vue'\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/dock/index.ts"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "macOS-style dock menu with magnification on hover. Items expand as the cursor approaches using a cosine bell curve. Supports an items array (icon + label + handler), magnification scale, base size, tooltips on hover, click handlers, and an active state indicator.",
  "categories": [
    "navigation"
  ]
}