import * as React from "react"; import { classList, ControlProps, fireClickOnEnter } from "../util"; import { Button, ButtonBody, ButtonProps, inflateButtonProps } from "./Button"; import { FocusTrap } from "./FocusTrap"; import { CheckboxIcon } from "./Checkbox"; export type MenuItem = MenuDropdownItem | MenuSeparatorItem | MenuCheckboxItem | MenuLinkItem; export interface MenuDropdownItem extends ButtonProps { role: "menuitem"; ariaPosInSet?: undefined; ariaSetSize?: undefined; } export interface MenuSeparatorItem { role: "separator"; className?: string; } export interface MenuCheckboxItem extends ControlProps { role: "menuitemcheckbox"; label: string; isChecked: boolean; onChange: (isChecked: boolean) => void; } export interface MenuLinkItem extends ControlProps { role: "link"; label: string; href: string; onClick?: () => void; } export interface MenuDropdownProps extends ControlProps { id?: string; items: MenuItem[]; label?: string | JSX.Element; title: string; icon?: string; tabIndex?: number; disabled?: boolean; } export const MenuDropdown = (props: MenuDropdownProps) => { const { id, className, ariaHidden, ariaLabel, role, items, label, title, icon, tabIndex, disabled } = props; const [expanded, setExpanded] = React.useState(false); const openedByKeyboard = React.useRef(false); React.useEffect(() => { // Focus the first visible menuitem, menuitemcheckbox or menuitemradio when opened via keyboard. if (expanded && container && openedByKeyboard.current) { const menu = container.querySelector("[role=menu]"); if (!menu) { return; } const nodes = menu.querySelectorAll( "[role=menuitem], [role=menuitemcheckbox], [role=menuitemradio]" ) for (const node of nodes) { const el = node as HTMLElement; if (el.offsetParent !== null) { el.focus(); break; } } } }, [expanded]) let container: HTMLDivElement; let expandButton: HTMLButtonElement; const handleContainerRef = (ref: HTMLDivElement) => { if (!ref) return; container = ref; } const handleButtonRef = (ref: HTMLButtonElement) => { if (!ref) return; expandButton = ref; } const onMenuButtonClick = (e: React.MouseEvent) => { openedByKeyboard.current = e.detail === 0; setExpanded(!expanded); } const onSubpaneEscape = () => { setExpanded(false); if (expandButton) expandButton.focus(); } const onBlur = (e: React.FocusEvent) => { if (!container) return; if (expanded && !container.contains(e.relatedTarget as HTMLElement)) setExpanded(false); } const onKeydown = (e: React.KeyboardEvent) => { if (e.key === "ArrowDown" && !expanded) { openedByKeyboard.current = true; setExpanded(true); } } const classes = classList("common-menu-dropdown", className); const menuId = id + "-menu"; const menuGroups = getGroups(items); return