{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"one-open","title":"One open","description":"Keeps one hover card open at a time, so sweeping across a row of badges never stacks two cards.","files":[{"path":"src/registry/catman/lib/one-open.ts","content":"import { useCallback, useId, useSyncExternalStore } from \"react\"\n\n/**\n * One hover card open at a time. A badge in a row of badges opens on hover\n * and lingers a beat so the pointer can reach it; without this, sweeping to\n * the next badge opens a second card over the first. Opening any card that\n * uses this closes whichever was open.\n *\n * Part of the twelfth catman registry (`@twelfth/one-open`).\n */\nlet openId: string | null = null\nconst listeners = new Set<() => void>()\n\nfunction setOpenId(next: string | null) {\n  if (openId === next) return\n  openId = next\n  for (const listener of listeners) listener()\n}\n\nfunction subscribe(listener: () => void) {\n  listeners.add(listener)\n  return () => listeners.delete(listener)\n}\n\n/** `[open, onOpenChange]` for a controlled popover or tooltip. */\nexport function useOneOpen(): [boolean, (open: boolean) => void] {\n  const id = useId()\n  const current = useSyncExternalStore(subscribe, () => openId, () => null)\n  const onOpenChange = useCallback((open: boolean) => {\n    if (open) setOpenId(id)\n    else if (openId === id) setOpenId(null)\n  }, [id])\n  return [current === id, onOpenChange]\n}\n","type":"registry:lib"}],"type":"registry:lib"}