{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "menu",
  "title": "Menu",
  "description": "A menu that pours out of its button like liquid.",
  "dependencies": [
    "@base-ui/react@^1.8.0"
  ],
  "registryDependencies": [
    "https://liquikit.dev/r/button.json",
    "https://liquikit.dev/r/core.json",
    "https://liquikit.dev/r/glass.json",
    "https://liquikit.dev/r/popup.json"
  ],
  "files": [
    {
      "path": "src/menu.tsx",
      "content": "\"use client\";\n\nimport { Menu as BaseMenu } from \"@base-ui/react/menu\";\nimport {\n\tcreateContext,\n\ttype MouseEvent,\n\ttype ReactNode,\n\ttype RefObject,\n\tuseContext,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Button, type ButtonProps } from \"./button\";\nimport type { GlassRefraction, GlassTheme } from \"./glass\";\nimport { Handoff, MorphPane, PopupState, usePopupState } from \"./popup\";\nimport { cx } from \"./types\";\nimport \"./liquikit.css\";\n\nexport const PressedAt = createContext<\n\tRefObject<{ x: number; y: number } | null>\n>({\n\tcurrent: null,\n});\n\nconst overTrigger: NonNullable<BaseMenu.Positioner.Props[\"sideOffset\"]> = ({\n\tside,\n\tanchor,\n}) => -(side === \"top\" || side === \"bottom\" ? anchor.height : anchor.width);\n\ntype Placement = {\n\tside: BaseMenu.Positioner.Props[\"side\"];\n\talign: BaseMenu.Positioner.Props[\"align\"];\n\tsideOffset: BaseMenu.Positioner.Props[\"sideOffset\"];\n\talignOffset?: BaseMenu.Positioner.Props[\"alignOffset\"];\n};\n\nexport const MenuPlacement = createContext<Placement>({\n\tside: \"bottom\",\n\talign: \"start\",\n\tsideOffset: overTrigger,\n});\nconst BESIDE: Placement = {\n\tside: \"inline-end\",\n\talign: \"start\",\n\tsideOffset: 6,\n\talignOffset: -6,\n};\n\nexport type MenuRootProps = Omit<BaseMenu.Root.Props, \"open\"> & {\n\topen?: boolean;\n};\n\nfunction Root({\n\topen: openProp,\n\tdefaultOpen = false,\n\tonOpenChange,\n\t...rootProps\n}: MenuRootProps) {\n\tconst [uncontrolled, setUncontrolled] = useState(defaultOpen);\n\tconst open = openProp ?? uncontrolled;\n\tconst trigger = useRef<HTMLElement | null>(null);\n\tconst pressedAt = useRef<{ x: number; y: number } | null>(null);\n\tconst state = useMemo(() => ({ open, trigger }), [open]);\n\n\treturn (\n\t\t<PopupState.Provider value={state}>\n\t\t\t<PressedAt.Provider value={pressedAt}>\n\t\t\t\t<BaseMenu.Root\n\t\t\t\t\t{...rootProps}\n\t\t\t\t\topen={open}\n\t\t\t\t\tonOpenChange={(next, eventDetails) => {\n\t\t\t\t\t\tif (openProp === undefined) setUncontrolled(next);\n\t\t\t\t\t\tonOpenChange?.(next, eventDetails);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</PressedAt.Provider>\n\t\t</PopupState.Provider>\n\t);\n}\n\nfunction Trigger(props: ButtonProps) {\n\tconst { trigger } = usePopupState();\n\tconst pressedAt = useContext(PressedAt);\n\treturn (\n\t\t<BaseMenu.Trigger\n\t\t\tref={(element: HTMLElement | null) => {\n\t\t\t\ttrigger.current = element;\n\t\t\t}}\n\t\t\tonMouseDown={(event) => {\n\t\t\t\tpressedAt.current = { x: event.clientX, y: event.clientY };\n\t\t\t}}\n\t\t\trender={<Button {...props} />}\n\t\t/>\n\t);\n}\n\nfunction useStayPut() {\n\tconst pressedAt = useContext(PressedAt);\n\treturn (event: MouseEvent & { preventBaseUIHandler?: () => void }) => {\n\t\tconst at = pressedAt.current;\n\t\tif (!at) return;\n\t\tpressedAt.current = null;\n\t\tif (Math.hypot(event.clientX - at.x, event.clientY - at.y) < 6) {\n\t\t\tevent.preventBaseUIHandler?.();\n\t\t}\n\t};\n}\n\nexport type MenuPopupProps = Omit<\n\tBaseMenu.Popup.Props,\n\t\"className\" | \"render\"\n> & {\n\tside?: BaseMenu.Positioner.Props[\"side\"];\n\talign?: BaseMenu.Positioner.Props[\"align\"];\n\tsideOffset?: BaseMenu.Positioner.Props[\"sideOffset\"];\n\ttheme?: GlassTheme;\n\trefraction?: GlassRefraction;\n\tclassName?: string;\n\tchildren?: ReactNode;\n};\n\nfunction Popup({\n\tside,\n\talign,\n\tsideOffset,\n\ttheme,\n\trefraction,\n\tclassName,\n\tchildren,\n\t...popupProps\n}: MenuPopupProps) {\n\tconst placement = useContext(MenuPlacement);\n\treturn (\n\t\t<BaseMenu.Portal>\n\t\t\t<BaseMenu.Positioner\n\t\t\t\tclassName=\"glass-ui-positioner\"\n\t\t\t\tside={side ?? placement.side}\n\t\t\t\talign={align ?? placement.align}\n\t\t\t\tsideOffset={sideOffset ?? placement.sideOffset}\n\t\t\t\talignOffset={placement.alignOffset}\n\t\t\t>\n\t\t\t\t<BaseMenu.Popup\n\t\t\t\t\t{...popupProps}\n\t\t\t\t\tclassName={cx(\"glass-ui-popup glass-ui-menu\", className)}\n\t\t\t\t\trender={(props) => (\n\t\t\t\t\t\t<MorphPane {...props} theme={theme} refraction={refraction} />\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<div className=\"glass-ui-menu__list\">{children}</div>\n\t\t\t\t</BaseMenu.Popup>\n\t\t\t</BaseMenu.Positioner>\n\t\t</BaseMenu.Portal>\n\t);\n}\n\nfunction Item({\n\tclassName,\n\ticon,\n\tchildren,\n\tonMouseUp,\n\t...itemProps\n}: Omit<BaseMenu.Item.Props, \"className\"> & {\n\tclassName?: string;\n\ticon?: ReactNode;\n}) {\n\tconst stayPut = useStayPut();\n\treturn (\n\t\t<BaseMenu.Item\n\t\t\t{...itemProps}\n\t\t\tclassName={cx(\"glass-ui-menu__item\", className)}\n\t\t\tonMouseUp={(event) => {\n\t\t\t\tonMouseUp?.(event);\n\t\t\t\tstayPut(event);\n\t\t\t}}\n\t\t>\n\t\t\t<span className=\"glass-ui-menu__text\">{children}</span>\n\t\t\t{icon ? (\n\t\t\t\t<span className=\"glass-ui-menu__icon\" aria-hidden=\"true\">\n\t\t\t\t\t{icon}\n\t\t\t\t</span>\n\t\t\t) : null}\n\t\t</BaseMenu.Item>\n\t);\n}\n\nfunction CheckboxItem({\n\tclassName,\n\tchildren,\n\tonMouseUp,\n\t...itemProps\n}: Omit<BaseMenu.CheckboxItem.Props, \"className\"> & { className?: string }) {\n\tconst stayPut = useStayPut();\n\treturn (\n\t\t<BaseMenu.CheckboxItem\n\t\t\t{...itemProps}\n\t\t\tclassName={cx(\"glass-ui-menu__item glass-ui-menu__check\", className)}\n\t\t\tonMouseUp={(event) => {\n\t\t\t\tonMouseUp?.(event);\n\t\t\t\tstayPut(event);\n\t\t\t}}\n\t\t>\n\t\t\t<BaseMenu.CheckboxItemIndicator\n\t\t\t\tclassName=\"glass-ui-menu__tick\"\n\t\t\t\tkeepMounted\n\t\t\t>\n\t\t\t\t<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n\t\t\t\t\t<path d=\"M3.5 8.5l3 3 6-7\" />\n\t\t\t\t</svg>\n\t\t\t</BaseMenu.CheckboxItemIndicator>\n\t\t\t<span className=\"glass-ui-menu__text\">{children}</span>\n\t\t</BaseMenu.CheckboxItem>\n\t);\n}\n\nfunction RadioGroup(props: BaseMenu.RadioGroup.Props) {\n\treturn <BaseMenu.RadioGroup {...props} />;\n}\n\nfunction RadioItem({\n\tclassName,\n\tchildren,\n\tonMouseUp,\n\t...itemProps\n}: Omit<BaseMenu.RadioItem.Props, \"className\"> & { className?: string }) {\n\tconst stayPut = useStayPut();\n\treturn (\n\t\t<BaseMenu.RadioItem\n\t\t\t{...itemProps}\n\t\t\tclassName={cx(\"glass-ui-menu__item glass-ui-menu__check\", className)}\n\t\t\tonMouseUp={(event) => {\n\t\t\t\tonMouseUp?.(event);\n\t\t\t\tstayPut(event);\n\t\t\t}}\n\t\t>\n\t\t\t<BaseMenu.RadioItemIndicator className=\"glass-ui-menu__tick\" keepMounted>\n\t\t\t\t<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n\t\t\t\t\t<path d=\"M3.5 8.5l3 3 6-7\" />\n\t\t\t\t</svg>\n\t\t\t</BaseMenu.RadioItemIndicator>\n\t\t\t<span className=\"glass-ui-menu__text\">{children}</span>\n\t\t</BaseMenu.RadioItem>\n\t);\n}\n\nfunction LinkItem({\n\tclassName,\n\ticon,\n\tchildren,\n\t...itemProps\n}: Omit<BaseMenu.LinkItem.Props, \"className\"> & {\n\tclassName?: string;\n\ticon?: ReactNode;\n}) {\n\treturn (\n\t\t<BaseMenu.LinkItem\n\t\t\t{...itemProps}\n\t\t\tclassName={cx(\"glass-ui-menu__item\", className)}\n\t\t>\n\t\t\t<span className=\"glass-ui-menu__text\">{children}</span>\n\t\t\t{icon ? (\n\t\t\t\t<span className=\"glass-ui-menu__icon\" aria-hidden=\"true\">\n\t\t\t\t\t{icon}\n\t\t\t\t</span>\n\t\t\t) : null}\n\t\t</BaseMenu.LinkItem>\n\t);\n}\n\nexport type MenuSubmenuRootProps = Omit<BaseMenu.SubmenuRoot.Props, \"open\"> & {\n\topen?: boolean;\n};\n\nfunction SubmenuRoot({\n\topen: openProp,\n\tdefaultOpen = false,\n\tonOpenChange,\n\t...rootProps\n}: MenuSubmenuRootProps) {\n\tconst [uncontrolled, setUncontrolled] = useState(defaultOpen);\n\tconst open = openProp ?? uncontrolled;\n\tconst trigger = useRef<HTMLElement | null>(null);\n\tconst state = useMemo(() => ({ open, trigger }), [open]);\n\treturn (\n\t\t<PopupState.Provider value={state}>\n\t\t\t<Handoff.Provider value={null}>\n\t\t\t\t<MenuPlacement.Provider value={BESIDE}>\n\t\t\t\t\t<BaseMenu.SubmenuRoot\n\t\t\t\t\t\t{...rootProps}\n\t\t\t\t\t\topen={open}\n\t\t\t\t\t\tonOpenChange={(next, eventDetails) => {\n\t\t\t\t\t\t\tif (openProp === undefined) setUncontrolled(next);\n\t\t\t\t\t\t\tonOpenChange?.(next, eventDetails);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</MenuPlacement.Provider>\n\t\t\t</Handoff.Provider>\n\t\t</PopupState.Provider>\n\t);\n}\n\nfunction SubmenuTrigger({\n\tclassName,\n\tchildren,\n\t...triggerProps\n}: Omit<BaseMenu.SubmenuTrigger.Props, \"className\"> & { className?: string }) {\n\tconst { trigger } = usePopupState();\n\treturn (\n\t\t<BaseMenu.SubmenuTrigger\n\t\t\t{...triggerProps}\n\t\t\tref={(element: HTMLElement | null) => {\n\t\t\t\ttrigger.current = element;\n\t\t\t}}\n\t\t\tclassName={cx(\"glass-ui-menu__item\", className)}\n\t\t>\n\t\t\t<span className=\"glass-ui-menu__text\">{children}</span>\n\t\t\t<span className=\"glass-ui-menu__icon\" aria-hidden=\"true\">\n\t\t\t\t<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n\t\t\t\t\t<path\n\t\t\t\t\t\td=\"M6 3.5 10.5 8 6 12.5\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth=\"1.8\"\n\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t</span>\n\t\t</BaseMenu.SubmenuTrigger>\n\t);\n}\n\nfunction Separator({\n\tclassName,\n\t...separatorProps\n}: Omit<BaseMenu.Separator.Props, \"className\"> & { className?: string }) {\n\treturn (\n\t\t<BaseMenu.Separator\n\t\t\t{...separatorProps}\n\t\t\tclassName={cx(\"glass-ui-menu__separator\", className)}\n\t\t/>\n\t);\n}\n\nfunction Group(props: BaseMenu.Group.Props) {\n\treturn <BaseMenu.Group {...props} />;\n}\n\nfunction GroupLabel({\n\tclassName,\n\t...labelProps\n}: Omit<BaseMenu.GroupLabel.Props, \"className\"> & { className?: string }) {\n\treturn (\n\t\t<BaseMenu.GroupLabel\n\t\t\t{...labelProps}\n\t\t\tclassName={cx(\"glass-ui-menu__label\", className)}\n\t\t/>\n\t);\n}\n\nexport const Menu = {\n\tRoot,\n\tTrigger,\n\tPopup,\n\tItem,\n\tLinkItem,\n\tCheckboxItem,\n\tRadioGroup,\n\tRadioItem,\n\tSubmenuRoot,\n\tSubmenuTrigger,\n\tSeparator,\n\tGroup,\n\tGroupLabel,\n};\n\nexport const MenuRoot = Menu.Root;\nexport const MenuTrigger = Menu.Trigger;\nexport const MenuPopup = Menu.Popup;\nexport const MenuItem = Menu.Item;\nexport const MenuLinkItem = Menu.LinkItem;\nexport const MenuCheckboxItem = Menu.CheckboxItem;\nexport const MenuRadioGroup = Menu.RadioGroup;\nexport const MenuRadioItem = Menu.RadioItem;\nexport const MenuSubmenuRoot = Menu.SubmenuRoot;\nexport const MenuSubmenuTrigger = Menu.SubmenuTrigger;\nexport const MenuSeparator = Menu.Separator;\nexport const MenuGroup = Menu.Group;\nexport const MenuGroupLabel = Menu.GroupLabel;\n",
      "type": "registry:ui",
      "target": "@components/liquikit/menu.tsx"
    }
  ],
  "type": "registry:ui"
}