{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "workspace-switcher",
  "type": "registry:ui",
  "title": "Workspace switcher",
  "description": "Manages workspace identity, recent state, and selection changes in a compact control.",
  "dependencies": [
    "motion"
  ],
  "categories": [
    "overlays-surfaces"
  ],
  "docs": "https://motion-lexicon.pages.dev/en/components/workspace-switcher/",
  "meta": {
    "engines": [
      "motion"
    ],
    "runtimeCost": "light",
    "signature": "Identity and selection hand off inside one control",
    "sceneFamily": "product-mono",
    "motionRole": "ui",
    "primaryState": "Current workspace switcher button",
    "assetProvenance": "self-contained"
  },
  "files": [
    {
      "path": "src/registry/components/workspace-switcher.tsx",
      "type": "registry:ui",
      "target": "components/motion-lexicon/workspace-switcher.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useId, useRef, useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\n\nexport type WorkspaceSwitcherItem = { id: string; name: string; detail?: string; initials: string; tone?: string };\nexport type WorkspaceSwitcherProps = { workspaces: readonly WorkspaceSwitcherItem[]; label?: string; initialId?: string; onChange?: (workspace: WorkspaceSwitcherItem) => void; className?: string };\n\nexport function WorkspaceSwitcher({ workspaces, label = \"Switch workspace\", initialId, onChange, className = \"\" }: WorkspaceSwitcherProps) {\n  const reduced = useReducedMotion() === true; const buttonId = useId(); const rootRef = useRef<HTMLDivElement>(null); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(() => Math.max(0, workspaces.findIndex((item) => item.id === initialId))); const active = workspaces[selected];\n  useEffect(() => { const close = (event: MouseEvent) => { if (!rootRef.current?.contains(event.target as Node)) setOpen(false); }; document.addEventListener(\"mousedown\", close); return () => document.removeEventListener(\"mousedown\", close); }, []);\n  if (!active) return null;\n  const choose = (index: number) => { const next = workspaces[index]; if (!next) return; setSelected(index); setOpen(false); onChange?.(next); };\n  return <div ref={rootRef} className={`relative inline-block ${className}`}><button id={buttonId} type=\"button\" aria-label={`${label}: ${active.name}`} aria-haspopup=\"listbox\" aria-expanded={open} onClick={() => setOpen((value) => !value)} onKeyDown={(event) => { if (event.key === \"ArrowDown\") { event.preventDefault(); setOpen(true); } if (event.key === \"Escape\") setOpen(false); }} className=\"flex min-h-11 items-center gap-2 rounded-[10px] border border-black/[.1] bg-white px-2.5 text-left outline-none shadow-[0_8px_22px_-18px_rgba(30,30,30,.38)] focus-visible:ring-2 focus-visible:ring-[#4568FF]\"><span className=\"grid size-6 place-items-center rounded-md text-[9px] font-medium text-white\" style={{ background: active.tone ?? \"#242424\" }}>{active.initials}</span><span className=\"max-w-32 truncate text-[12px] font-medium text-[#292929]\">{active.name}</span><span aria-hidden className=\"text-[10px] text-neutral-500\">⌄</span></button><AnimatePresence>{open ? <motion.ul role=\"listbox\" aria-labelledby={buttonId} initial={reduced ? false : { opacity: 0, y: -5 }} animate={{ opacity: 1, y: 0 }} exit={reduced ? undefined : { opacity: 0, y: -4 }} transition={{ duration: reduced ? 0 : .16 }} className=\"absolute z-30 mt-1 min-w-[230px] rounded-[11px] border border-black/[.1] bg-white p-1 shadow-[0_18px_38px_-20px_rgba(26,26,26,.35)]\">{workspaces.map((item, index) => <li key={item.id} role=\"option\" aria-selected={index === selected}><button type=\"button\" onClick={() => choose(index)} onKeyDown={(event) => { if (event.key === \"ArrowDown\") { event.preventDefault(); (event.currentTarget.parentElement?.nextElementSibling?.querySelector(\"button\") as HTMLButtonElement | null)?.focus(); } if (event.key === \"ArrowUp\") { event.preventDefault(); (event.currentTarget.parentElement?.previousElementSibling?.querySelector(\"button\") as HTMLButtonElement | null)?.focus(); } if (event.key === \"Escape\") setOpen(false); }} className={`flex min-h-11 w-full items-center gap-2 rounded-lg px-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-[#4568FF] ${index === selected ? \"bg-[#eef0ed]\" : \"hover:bg-neutral-50\"}`}><span className=\"grid size-7 place-items-center rounded-md text-[9px] text-white\" style={{ background: item.tone ?? \"#242424\" }}>{item.initials}</span><span><strong className=\"block text-[11px] text-[#292929]\">{item.name}</strong>{item.detail ? <span className=\"block text-[10px] text-neutral-500\">{item.detail}</span> : null}</span></button></li>)}</motion.ul> : null}</AnimatePresence></div>;\n}\n"
    }
  ]
}
