UNPKG

@material/web

Version:
267 lines (266 loc) 9.31 kB
/** * @license * Copyright 2023 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import '../../focus/md-focus-ring.js'; import '../../elevation/elevation.js'; import { LitElement, PropertyValues } from 'lit'; import { MenuItem } from './controllers/menuItemController.js'; import { FocusState } from './controllers/shared.js'; import { Corner, SurfacePositionTarget } from './controllers/surfacePositionController.js'; import { TypeaheadController } from './controllers/typeaheadController.js'; export { Corner } from './controllers/surfacePositionController.js'; /** * The default value for the typeahead buffer time in Milliseconds. */ export declare const DEFAULT_TYPEAHEAD_BUFFER_TIME = 200; /** * @fires opening Fired before the opening animation begins * @fires opened Fired once the menu is open, after any animations * @fires closing Fired before the closing animation begins * @fires closed Fired once the menu is closed, after any animations */ export declare abstract class Menu extends LitElement { private readonly surfaceEl; private readonly slotEl; /** * The ID of the element in the same root node in which the menu should align * to. Overrides setting `anchorElement = elementReference`. * * __NOTE__: anchor or anchorElement must either be an HTMLElement or resolve * to an HTMLElement in order for menu to open. */ anchor: string; /** * Whether the positioning algorithim should calculate relative to the parent * of the anchor element (absolute) or relative to the window (fixed). * * Examples for `position = 'fixed'`: * * - If there is no `position:relative` in the given parent tree and the * surface is `position:absolute` * - If the surface is `position:fixed` * - If the surface is in the "top layer" * - The anchor and the surface do not share a common `position:relative` * ancestor * * When using positioning = fixed, in most cases, the menu should position * itself above most other `position:absolute` or `position:fixed` elements * when placed inside of them. e.g. using a menu inside of an `md-dialog`. * * __NOTE__: Fixed menus will not scroll with the page and will be fixed to * the window instead. */ positioning: 'absolute' | 'fixed'; /** * Skips the opening and closing animations. */ quick: boolean; /** * Displays overflow content like a submenu. * * __NOTE__: This may cause adverse effects if you set * `md-menu {max-height:...}` * and have items overflowing items in the "y" direction. */ hasOverflow: boolean; /** * Opens the menu and makes it visible. Alternative to the `.show()` and * `.close()` methods */ open: boolean; /** * Offsets the menu's inline alignment from the anchor by the given number in * pixels. This value is direction aware and will follow the LTR / RTL * direction. * * e.g. LTR: positive -> right, negative -> left * RTL: positive -> left, negative -> right */ xOffset: number; /** * Offsets the menu's block alignment from the anchor by the given number in * pixels. * * e.g. positive -> down, negative -> up */ yOffset: number; /** * The max time between the keystrokes of the typeahead menu behavior before * it clears the typeahead buffer. */ typeaheadDelay: number; /** * The corner of the anchor which to align the menu in the standard logical * property style of <block>-<inline> e.g. `'end-start'`. * * NOTE: This value may not be respected by the menu positioning algorithm * if the menu would render outisde the viewport. */ anchorCorner: Corner; /** * The corner of the menu which to align the anchor in the standard logical * property style of <block>-<inline> e.g. `'start-start'`. * * NOTE: This value may not be respected by the menu positioning algorithm * if the menu would render outisde the viewport. */ menuCorner: Corner; /** * Keeps the user clicks outside the menu. * * NOTE: clicking outside may still cause focusout to close the menu so see * `stayOpenOnFocusout`. */ stayOpenOnOutsideClick: boolean; /** * Keeps the menu open when focus leaves the menu's composed subtree. * * NOTE: Focusout behavior will stop propagation of the focusout event. Set * this property to true to opt-out of menu's focuout handling altogether. */ stayOpenOnFocusout: boolean; /** * After closing, does not restore focus to the last focused element before * the menu was opened. */ skipRestoreFocus: boolean; /** * The element that should be focused by default once opened. * * NOTE: When setting default focus to 'LIST_ROOT', remember to change * `tabindex` to `0` and change md-menu's display to something other than * `display: contents` when necessary. */ defaultFocus: FocusState; protected slotItems: HTMLElement[]; private typeaheadActive; /** * Whether or not the current menu is a submenu and should not handle specific * navigation keys. * * @exports */ isSubmenu: boolean; /** * The event path of the last window pointerdown event. */ private pointerPath; private readonly openCloseAnimationSignal; private readonly listController; /** * Whether the menu is animating upwards or downwards when opening. This is * helpful for calculating some animation calculations. */ private get openDirection(); /** * The element that was focused before the menu opened. */ private lastFocusedElement; /** * Handles typeahead navigation through the menu. */ typeaheadController: TypeaheadController; private currentAnchorElement; /** * The element which the menu should align to. If `anchor` is set to a * non-empty idref string, then `anchorEl` will resolve to the element with * the given id in the same root node. Otherwise, `null`. */ get anchorElement(): HTMLElement & Partial<SurfacePositionTarget> | null; set anchorElement(element: HTMLElement & Partial<SurfacePositionTarget> | null); private readonly internals; constructor(); /** * Handles positioning the surface and aligning it to the anchor as well as * keeping it in the viewport. */ private readonly menuPositionController; /** * The menu items associated with this menu. The items must be `MenuItem`s and * have both the `md-menu-item` and `md-list-item` attributes. */ get items(): MenuItem[]; protected willUpdate(changed: PropertyValues<Menu>): void; update(changed: PropertyValues<Menu>): void; connectedCallback(): void; disconnectedCallback(): void; protected render(): import("lit-html").TemplateResult<1>; /** * Renders the positionable surface element and its contents. */ private renderSurface; /** * Renders the menu items' slot */ private renderMenuItems; /** * Renders the elevation component. */ private renderElevation; private getSurfaceClasses; private readonly handleFocusout; private captureKeydown; /** * Saves the last focused element focuses the new element based on * `defaultFocus`, and animates open. */ private readonly onOpened; /** * Animates closed. */ private readonly beforeClose; /** * Focuses the last focused element. */ private readonly onClosed; /** * Performs the opening animation: * * https://direct.googleplex.com/#/spec/295000003+271060003 * * @return A promise that resolve to `true` if the animation was aborted, * `false` if it was not aborted. */ private animateOpen; /** * Performs the closing animation: * * https://direct.googleplex.com/#/spec/295000003+271060003 */ private animateClose; private handleKeydown; private setUpGlobalEventListeners; private cleanUpGlobalEventListeners; private readonly onWindowPointerdown; /** * We cannot listen to window click because Safari on iOS will not bubble a * click event on window if the item clicked is not a "clickable" item such as * <body> */ private readonly onDocumentClick; private onCloseMenu; private onDeactivateItems; private onRequestActivation; private handleDeactivateTypeahead; private handleActivateTypeahead; private handleStayOpenOnFocusout; private handleCloseOnFocusout; close(): void; show(): void; /** * Activates the next item in the menu. If at the end of the menu, the first * item will be activated. * * @return The activated menu item or `null` if there are no items. */ activateNextItem(): MenuItem; /** * Activates the previous item in the menu. If at the start of the menu, the * last item will be activated. * * @return The activated menu item or `null` if there are no items. */ activatePreviousItem(): MenuItem; }