55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { createEffect, createSignal, createUniqueId, onCleanup, type JSX } from "solid-js";
|
|
import { ProfileMenu } from "./ProfileMenu";
|
|
import { UserNavButton } from "./UserNavButton";
|
|
import styles from "./UserNav.module.scss";
|
|
|
|
export const UserNav = (): JSX.Element => {
|
|
const [isOpen, setIsOpen] = createSignal(false);
|
|
const menuId = createUniqueId();
|
|
let rootRef: HTMLDivElement | undefined;
|
|
let menuRef: HTMLDivElement | undefined;
|
|
|
|
const closeMenu = (): void => {
|
|
setIsOpen(false);
|
|
};
|
|
|
|
const toggleMenu = (): void => {
|
|
setIsOpen((open) => !open);
|
|
};
|
|
|
|
createEffect(() => {
|
|
if (!isOpen()) return;
|
|
|
|
const handlePointerDown = (event: PointerEvent): void => {
|
|
if (!rootRef) return;
|
|
|
|
const target = event.target;
|
|
if (target instanceof Node && !rootRef.contains(target)) {
|
|
closeMenu();
|
|
}
|
|
};
|
|
|
|
const handleKeyDown = (event: KeyboardEvent): void => {
|
|
if (event.key === "Escape") {
|
|
closeMenu();
|
|
}
|
|
};
|
|
|
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
document.addEventListener("keydown", handleKeyDown);
|
|
menuRef?.querySelector<HTMLButtonElement>("[role='menuitem']")?.focus();
|
|
|
|
onCleanup(() => {
|
|
document.removeEventListener("pointerdown", handlePointerDown);
|
|
document.removeEventListener("keydown", handleKeyDown);
|
|
});
|
|
});
|
|
|
|
return (
|
|
<div class={styles.root} ref={rootRef}>
|
|
<UserNavButton isOpen={isOpen()} menuId={menuId} onToggle={toggleMenu} />
|
|
{isOpen() ? <ProfileMenu id={menuId} menuRef={(element) => (menuRef = element)} onSelect={closeMenu} /> : null}
|
|
</div>
|
|
);
|
|
};
|