@react-md/menu
Version:
Create menus that auto-position themselves within the viewport and adhere to the accessibility guidelines
136 lines (135 loc) • 5.25 kB
TypeScript
import type { KeyboardEventHandler, MouseEventHandler, MutableRefObject } from "react";
import type { FABPosition } from "@react-md/button";
import type { BaseMenuHookOptions, BaseMenuHookReturnValue, ProvidedMenuToggleProps } from "./types";
/** @remarks \@since 5.0.0 */
export interface MenuHookOptions<ToggleEl extends HTMLElement> extends BaseMenuHookOptions {
/**
* Boolean if the toggle component is currently disabled which will prevent
* the arrow keys from opening a menuitem's menu.
*
* @defaultValue `false`
*/
disabled?: boolean;
/**
* This is just used to update the default anchor behavior.
*
* @see {@link FABPosition}
* @defaultValue `null`
*/
floating?: FABPosition;
/**
* An optional click handler to merge with the
* {@link MenuHookReturnValue.onClick} behavior.
*/
onMenuClick?: MouseEventHandler<HTMLDivElement>;
/**
* An optional keydown handler to merge with the
* {@link MenuHookReturnValue.menuProps} behavior. Calling
* `event.stopPropagation()` will prevent the default behavior of closing the
* menu when the `"Escape"` key is pressed.
*/
onMenuKeyDown?: KeyboardEventHandler<HTMLDivElement>;
/**
* An optional click handler to merge with the toggle visibility behavior.
* Calling `event.stopPropagation()` will prevent the default behavior from
* occurring.
*/
onToggleClick?: MouseEventHandler<ToggleEl>;
/**
* An optional keydown handler to merge with the
* {@link ProvidedMenuToggleProps.onKeyDown} behavior.
*/
onToggleKeyDown?: KeyboardEventHandler<ToggleEl>;
/**
* An optional keydown handler to merge with the
* {@link ProvidedMenuToggleProps.onMouseEnter} behavior.
*/
onToggleMouseEnter?: MouseEventHandler<ToggleEl>;
/**
* An optional keydown handler to merge with the
* {@link ProvidedMenuToggleProps.onMouseLeave} behavior.
*/
onToggleMouseLeave?: MouseEventHandler<ToggleEl>;
}
/**
* @remarks \@since 5.0.0
*/
export interface MenuHookReturnValue<ToggleEl extends HTMLElement> extends BaseMenuHookReturnValue {
/**
* A ref that **must** be passed to the toggle element if the toggle should be
* refocused when the menu is closed via a keyboard press. This can also be
* used if you need access to the toggle element's DOM node for some reason.
*/
toggleRef: MutableRefObject<ToggleEl | null>;
/**
* An object of props that must be provided to the toggle element for the
* visibility functionality of menus to work.
*
* @see {@link ProvidedMenuToggleProps}
*/
toggleProps: ProvidedMenuToggleProps<ToggleEl>;
}
/**
* This hook provides all the functionality for a menu to:
* - toggle the `Menu`'s visibility when the `MenuButton` or `MenuItemButton`
* has been clicked
* - hide the `Menu` when an element outside of the `Menu` has been clicked
* - hide the `Menu` when the `Escape` or `Tab` key has been pressed
* - focus the `Menu` element when it gains visibility
* - refocus the `MenuButton` or `MenuItemButton` when the menu loses visibility
* - position the menu within the viewport with {@link useFixedPositioning}
* - show the `Menu` when the `ArrowRight` key is pressed for a vertical
* `MenuItemButton`
* - show the `Menu` when the `ArrowDown` key is pressed for a horizontal
* `MenuItemButton`
* - hide the `Menu` when the `ArrowRight` key is pressed in a vertical submenu
* - hide the `Menu` when the `ArrowDown` key is pressed in a horizontal
* submenu
* - conditionally hide the `Menu` if the page is scrolled while the `Menu` is
* visible
* - conditionally hide the `Menu` if the page is resized while the `Menu` is
* visible
* - conditionally move focus to the next `DropdownMenu` with keyboard movement
* when inside of a `MenuBar`
* - conditionally enable the visibility for a `DropdownMenu` when the mouse
* hovers over a `MenuItemButton` with a parent `MenuBar` that has been
* activated
* - conditionally show/hide the `Menu` based on a parent `MenuBar`'s `activeId`
*
* This hook will probably never need to be used externally since it has been
* integrated into the `DropdownMenu` component and `useContextMenu` hook.
*
* @example
* Simple Example
* ```tsx
* import { ReactElement, useState } from "react";
* import { useMenu, Menu, MenuButton, MenuItem } from "@react-md/menu";
*
* function Example(): ReactElement {
* const [visible, setVisible] = useState(false);
* const { menuRef, menuProps, toggleRef, toggleProps } = useMenu<
* HTMLButtonElement
* >({
* baseId: "custom-menu-button",
* visible,
* setVisible,
* });
*
* return (
* <>
* <MenuButton ref={toggleRef} {...toggleProps}>
* Button
* </MenuButton>
* <Menu ref={menuRef} {...menuProps}>
* <MenuItem>Item 1</MenuItem>
* <MenuItem>Item 2</MenuItem>
* <MenuItem>Item 3</MenuItem>
* </Menu>
* </>
* );
* }
* ```
*
* @remarks \@since 5.0.0
*/
export declare function useMenu<ToggleEl extends HTMLElement>(options: MenuHookOptions<ToggleEl>): MenuHookReturnValue<ToggleEl>;