@material/web
Version:
Material web components
107 lines • 3.67 kB
JavaScript
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { CloseReason, createDefaultCloseMenuEvent, isClosableKey } from './shared.js';
/**
* A controller that provides most functionality of an element that implements
* the MenuItem interface.
*/
export class MenuItemController {
/**
* @param host The MenuItem in which to attach this controller to.
* @param config The object that configures this controller's behavior.
*/
constructor(host, config) {
this.host = host;
this.internalTypeaheadText = null;
/**
* Bind this click listener to the interactive element. Handles closing the
* menu.
*/
this.onClick = () => {
if (this.host.keepOpen)
return;
this.host.dispatchEvent(createDefaultCloseMenuEvent(this.host, { kind: CloseReason.CLICK_SELECTION }));
};
/**
* Bind this click listener to the interactive element. Handles closing the
* menu.
*/
this.onKeydown = (event) => {
// Check if the interactive element is an anchor tag. If so, click it.
if (this.host.href && event.code === 'Enter') {
const interactiveElement = this.getInteractiveElement();
if (interactiveElement instanceof HTMLAnchorElement) {
interactiveElement.click();
}
}
if (this.host.keepOpen || event.defaultPrevented)
return;
const keyCode = event.code;
if (!event.defaultPrevented && isClosableKey(keyCode)) {
event.preventDefault();
this.host.dispatchEvent(createDefaultCloseMenuEvent(this.host, { kind: CloseReason.KEYDOWN, key: keyCode }));
}
};
const { getHeadlineElements, getInteractiveElement, } = config;
this.getHeadlineElements = getHeadlineElements;
this.getInteractiveElement = getInteractiveElement;
this.host.addController(this);
}
/**
* The text that is selectable via typeahead. If not set, defaults to the
* innerText of the item slotted into the `"headline"` slot.
*/
get typeaheadText() {
if (this.internalTypeaheadText !== null) {
return this.internalTypeaheadText;
}
const headlineElements = this.getHeadlineElements();
const textParts = [];
headlineElements.forEach((headlineElement) => {
if (headlineElement.textContent && headlineElement.textContent.trim()) {
textParts.push(headlineElement.textContent.trim());
}
});
return textParts.join(' ');
}
/**
* The recommended tag name to render as the list item.
*/
get tagName() {
const type = this.host.type;
switch (type) {
case 'link':
return 'a';
case 'button':
return 'button';
default:
case 'menuitem':
case 'option':
return 'li';
}
}
/**
* The recommended role of the menu item.
*/
get role() {
return this.host.type === 'option' ? 'option' : 'menuitem';
}
hostConnected() {
this.host.toggleAttribute('md-menu-item', true);
}
hostUpdate() {
if (this.host.href) {
this.host.type = 'link';
}
}
/**
* Use to set the typeaheadText when it changes.
*/
setTypeaheadText(text) {
this.internalTypeaheadText = text;
}
}
//# sourceMappingURL=menuItemController.js.map