60 lines
1.3 KiB
TypeScript
60 lines
1.3 KiB
TypeScript
"use client"
|
|
|
|
import {
|
|
createContext,
|
|
useCallback,
|
|
useContext,
|
|
useId,
|
|
useState,
|
|
type ReactNode,
|
|
} from "react"
|
|
import { MenubarSub } from "@/components/ui/menubar"
|
|
|
|
type ExclusiveMenuSubContextValue = {
|
|
openId: string | null
|
|
setOpenId: (id: string | null) => void
|
|
}
|
|
|
|
const ExclusiveMenuSubContext = createContext<ExclusiveMenuSubContextValue | null>(null)
|
|
|
|
/** Ensures only one MenubarSub stays open while hovering across sibling sub-triggers. */
|
|
export function DocsExclusiveMenuSubRoot({ children }: { children: ReactNode }) {
|
|
const [openId, setOpenId] = useState<string | null>(null)
|
|
return (
|
|
<ExclusiveMenuSubContext.Provider value={{ openId, setOpenId }}>
|
|
{children}
|
|
</ExclusiveMenuSubContext.Provider>
|
|
)
|
|
}
|
|
|
|
export function DocsExclusiveMenuSub({
|
|
id,
|
|
children,
|
|
}: {
|
|
id: string
|
|
children: ReactNode
|
|
}) {
|
|
const ctx = useContext(ExclusiveMenuSubContext)
|
|
const fallbackId = useId()
|
|
const subId = id || fallbackId
|
|
|
|
const open = ctx?.openId === subId
|
|
const onOpenChange = useCallback(
|
|
(next: boolean) => {
|
|
if (!ctx) return
|
|
ctx.setOpenId(next ? subId : null)
|
|
},
|
|
[ctx, subId]
|
|
)
|
|
|
|
if (!ctx) {
|
|
return <MenubarSub>{children}</MenubarSub>
|
|
}
|
|
|
|
return (
|
|
<MenubarSub open={open} onOpenChange={onOpenChange}>
|
|
{children}
|
|
</MenubarSub>
|
|
)
|
|
}
|