Horizontal nav with dropdown submenus, hover-intent delay, keyboard-accessible trigger/content parts, and full Zod v4 schema + ComponentMeta.
54 lines
1.7 KiB
TypeScript
54 lines
1.7 KiB
TypeScript
import type { JSX } from "solid-js";
|
|
import { splitProps } from "solid-js";
|
|
import { useNavigationMenuContext, useNavigationMenuItemContext } from "./navigation-menu-context";
|
|
import type { NavigationMenuTriggerProps } from "./navigation-menu.props";
|
|
|
|
/**
|
|
* Button that opens the associated NavigationMenu.Content on click or hover.
|
|
* Manages hover-intent via the root context's scheduleOpen/cancelAndClose.
|
|
*/
|
|
export function NavigationMenuTrigger(props: NavigationMenuTriggerProps): JSX.Element {
|
|
const [local, rest] = splitProps(props, [
|
|
"children",
|
|
"onClick",
|
|
"onPointerEnter",
|
|
"onPointerLeave",
|
|
]);
|
|
|
|
const ctx = useNavigationMenuContext();
|
|
const itemCtx = useNavigationMenuItemContext();
|
|
|
|
const handleClick: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (e) => {
|
|
if (typeof local.onClick === "function") local.onClick(e);
|
|
const next = ctx.value() === itemCtx.value ? "" : itemCtx.value;
|
|
ctx.setValue(next);
|
|
};
|
|
|
|
const handlePointerEnter: JSX.EventHandler<HTMLButtonElement, PointerEvent> = (e) => {
|
|
if (typeof local.onPointerEnter === "function") local.onPointerEnter(e);
|
|
ctx.scheduleOpen(itemCtx.value);
|
|
};
|
|
|
|
const handlePointerLeave: JSX.EventHandler<HTMLButtonElement, PointerEvent> = (e) => {
|
|
if (typeof local.onPointerLeave === "function") local.onPointerLeave(e);
|
|
ctx.cancelAndClose();
|
|
};
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
role="menuitem"
|
|
data-scope="navigation-menu"
|
|
data-part="trigger"
|
|
aria-expanded={itemCtx.isActive()}
|
|
data-active={itemCtx.isActive() ? "" : undefined}
|
|
onClick={handleClick}
|
|
onPointerEnter={handlePointerEnter}
|
|
onPointerLeave={handlePointerLeave}
|
|
{...rest}
|
|
>
|
|
{local.children}
|
|
</button>
|
|
);
|
|
}
|