{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "popover",
  "title": "Popover",
  "author": "Zubeyr <https://zubeyr.dev>",
  "description": "A lightweight popover anchored to any trigger: opens beside or above it, stays on screen and escapes scrolling containers, closes on outside click or Escape, and hands a close() to its content.",
  "files": [
    {
      "path": "registry/dashboard/components/popover/popover.tsx",
      "content": "'use client'\n\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react'\n\nimport { cn } from '@/lib/utils'\n\ntype PopoverProps = {\n  trigger: (props: { open: boolean; toggle: () => void }) => React.ReactNode\n  align?: 'start' | 'end'\n  side?: 'top' | 'bottom'\n  className?: string\n  block?: boolean\n  children: React.ReactNode | ((close: () => void) => React.ReactNode)\n}\n\ntype Place = { top: number; left: number; minWidth: number }\n\nexport function placePanel(\n  anchor: DOMRect,\n  panel: { width: number; height: number },\n  align: 'start' | 'end',\n  side: 'top' | 'bottom',\n): { top: number; left: number } {\n  const gap = 6\n  const below = window.innerHeight - anchor.bottom - gap\n  const above = anchor.top - gap\n  const up =\n    side === 'top' ? above >= panel.height || above > below : below < panel.height && above > below\n  const top = up ? anchor.top - gap - panel.height : anchor.bottom + gap\n  const rawLeft = align === 'end' ? anchor.right - panel.width : anchor.left\n  const left = Math.max(8, Math.min(rawLeft, window.innerWidth - panel.width - 8))\n  return { top: Math.max(8, top), left }\n}\n\nexport function useFloating(\n  open: boolean,\n  align: 'start' | 'end' = 'start',\n  side: 'top' | 'bottom' = 'bottom',\n) {\n  const anchor = useRef<HTMLDivElement>(null)\n  const panel = useRef<HTMLDivElement>(null)\n  const [place, setPlace] = useState<Place | null>(null)\n\n  useLayoutEffect(() => {\n    if (!open) return\n    const update = () => {\n      if (!anchor.current || !panel.current) return\n      const a = anchor.current.getBoundingClientRect()\n      const p = panel.current.getBoundingClientRect()\n      setPlace({ ...placePanel(a, p, align, side), minWidth: a.width })\n    }\n    update()\n    window.addEventListener('scroll', update, true)\n    window.addEventListener('resize', update)\n    return () => {\n      window.removeEventListener('scroll', update, true)\n      window.removeEventListener('resize', update)\n    }\n  }, [open, align, side])\n\n  return { anchor, panel, place }\n}\n\nexport function Popover({\n  trigger,\n  align = 'start',\n  side = 'bottom',\n  className,\n  block = false,\n  children,\n}: PopoverProps) {\n  const [open, setOpen] = useState(false)\n  const { anchor, panel, place } = useFloating(open, align, side)\n\n  useEffect(() => {\n    if (!open) return\n    const onPointer = (event: PointerEvent) => {\n      if (!anchor.current?.contains(event.target as Node)) setOpen(false)\n    }\n    document.addEventListener('pointerdown', onPointer)\n    return () => document.removeEventListener('pointerdown', onPointer)\n  }, [open, anchor])\n\n  return (\n    <div\n      ref={anchor}\n      className={cn('relative', block ? 'flex w-full' : 'inline-flex')}\n      onKeyDown={(event) => {\n        if (event.key !== 'Escape' || !open) return\n        event.stopPropagation()\n        setOpen(false)\n      }}\n    >\n      {trigger({ open, toggle: () => setOpen(!open) })}\n      {open && (\n        <div\n          ref={panel}\n          style={{\n            top: place?.top ?? 0,\n            left: place?.left ?? 0,\n            minWidth: place?.minWidth,\n            visibility: place ? 'visible' : 'hidden',\n          }}\n          className={cn(\n            'fixed z-[60] min-w-48 rounded-xl bg-popover p-1.5 text-popover-foreground shadow-(--shadow-overlay)',\n            className?.replace(/\\bw-full\\b/g, ''),\n          )}\n        >\n          {typeof children === 'function' ? children(() => setOpen(false)) : children}\n        </div>\n      )}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/dashboard/popover.tsx"
    }
  ],
  "cssVars": {
    "light": {
      "shadow-overlay": "0 16px 40px rgb(0 0 0 / 0.12), 0 0 0 1px rgb(0 0 0 / 0.08)"
    },
    "dark": {
      "shadow-overlay": "0 16px 40px rgb(0 0 0 / 0.5), 0 0 0 1px #0e0e0e"
    }
  },
  "meta": {
    "scenario": "dashboard",
    "kind": "components"
  },
  "categories": [
    "dashboard",
    "overlays"
  ],
  "type": "registry:component"
}