UNPKG

@itwin/itwinui-react

Version:

A react component library for iTwinUI

106 lines (105 loc) 4.5 kB
import * as React from 'react'; import type { PolymorphicForwardRefComponent, PortalProps } from '../../utils/index.js'; import { usePopover } from '../Popover/Popover.js'; import { useInteractions, type UseListNavigationProps } from '@floating-ui/react'; type UsePopoverProps = Parameters<typeof usePopover>[0]; type MenuProps = { /** * Menu items. Recommended to use `MenuItem` components. * * If you have custom actionable items, they should have `tabIndex={-1}` for better keyboard navigation support * and selected item should have `aria-selected={true}`. */ children: React.ReactNode; /** * The trigger that opens the menu. */ trigger: React.ReactNode; /** * You can use this optional prop when the position reference is not the trigger. * * This can be either a real element, or a [virtual element](https://floating-ui.com/docs/virtual-elements) * containing a `getBoundingClientRect` method. */ positionReference?: Parameters<ReturnType<typeof usePopover>['refs']['setPositionReference']>[0]; /** * Use this prop to override the default props passed to `usePopover` and `useListNavigation`. */ popoverProps?: Omit<UsePopoverProps, 'interactions'> & { interactions?: UsePopoverProps['interactions'] & { listNavigation?: Partial<UseListNavigationProps>; }; }; /** * If not passed, uses the `portal` from its parent `Menu`. * @see {@link PortalProps.portal} for docs on the prop. */ portal?: PortalProps['portal']; }; /** * @private * * Used for dropdown components. E.g. `DropdownMenu`, `SplitButton`. * * What needs to be handled **manually**: * - Menu items need to spread `MenuContext.popover.getItemProps()`. * - Menu items need to focus itself on hover. * * What is handled automatically: * - the portaling: use the optional `portal` prop for more customization * - conditional rendering based on the popover's open state * - spreading the popover props `getFloatingProps` and `getReferenceProps`. * - As mentioned above, `getItemProps` need to be spread **manually** in the menu item. * - setting the refs: use the optional`positionReference` prop to set the position reference * - keyboard navigation: use the `interactions.listNavigation` prop for more customization * - registering a `FloatingNode` in the `FloatingTree` if an ancestral `FloatingTree` is found * - focus management: * - focuses items on hover. * - if *not* in a `FloatingTree`, focus moves to the trigger when the menu is closed. * If in a `FloatingTree`, focus does not move back to the trigger since menu items handle the focus. * - setting `aria-expanded` accordingly depending on the menu open state * * All `Menu` popover interactions are identical to `usePopover`'s interactions. Exception: * - `hover`: When the `Menu` is within a `FloatingTree`, if a submenu has focus, the hover interaction is automatically * disabled. This helps to keep the last hovered/focused submenu open even upon hovering out. * * @example * const trigger = <Button>Menu</Button>; * const [positionReference, setPositionReference] = React.useState<HTMLDivElement | null>(null); * const popoverProps = { matchWidth: true }; * const nodeId = useFloatingNodeId(); * * return ( * <Box ref={setPositionReference}> * <Menu * trigger={trigger} * positionReference={positionReference} * nodeId={nodeId} * popoverProps={popoverProps} * > * <MenuItem>Item 1</MenuItem> * <MenuItem>Item 2</MenuItem> * </Menu> * </Box> * ); */ export declare const Menu: PolymorphicForwardRefComponent<"div", MenuProps>; export type TreeEvent = { nodeId: string; parentId: string | null; }; type PopoverGetItemProps = ({ focusableItemIndex, userProps, }: { /** * Index of this item out of all the focusable items in the parent `Menu` */ focusableItemIndex: number | undefined; userProps?: Parameters<NonNullable<ReturnType<typeof useInteractions>['getItemProps']>>[0]; }) => ReturnType<ReturnType<typeof useInteractions>['getItemProps']>; export declare const MenuContext: React.Context<{ popoverGetItemProps: PopoverGetItemProps; focusableElements: HTMLElement[]; } | undefined>; export declare const MenuPortalContext: React.Context<boolean | { to: HTMLElement | null | undefined | (() => HTMLElement | null | undefined); } | undefined>; export {};