@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
117 lines (116 loc) • 4.18 kB
JavaScript
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details.
v3.2.1 */
import { c as customElement } from "../../chunks/runtime.js";
import { html } from "lit";
import { LitElement } from "@arcgis/lumina";
import { useWatchAttributes } from "@arcgis/lumina/controllers";
import { h as focusFirstTabbable, d as focusElementInGroup, s as slotChangeGetAssignedElements, b as focusElement } from "../../chunks/dom.js";
import { c as componentFocusable } from "../../chunks/component.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { css } from "@lit/reactive-element/css-tag.js";
const styles = css`:host{display:flex}ul{margin:0;display:inline-flex;block-size:100%;align-items:center;padding:0}:host([layout=vertical]) ul{display:flex;inline-size:100%;flex-direction:column}:host([hidden]){display:none}[hidden]{display:none}`;
class Menu extends LitElement {
constructor() {
super();
this.attributeWatch = useWatchAttributes(["role"], this.handleGlobalAttributesChanged);
this.menuItems = [];
this.messages = useT9n();
this.layout = "horizontal";
this.listen("calciteInternalMenuItemKeyEvent", this.calciteInternalNavMenuItemKeyEvent);
}
static {
this.properties = { label: 1, layout: [3, {}, { reflect: true }], messageOverrides: [0, {}, { attribute: false }] };
}
static {
this.shadowRootOptions = { mode: "open", delegatesFocus: true };
}
static {
this.styles = styles;
}
async setFocus() {
await componentFocusable(this);
focusFirstTabbable(this.menuItems[0]);
}
willUpdate(changes) {
if (changes.has("layout") && (this.hasUpdated || this.layout !== "horizontal")) {
this.setMenuItemLayout(this.menuItems, this.layout);
}
}
handleGlobalAttributesChanged() {
this.requestUpdate();
this.setMenuItemLayout(this.menuItems, this.layout);
}
calciteInternalNavMenuItemKeyEvent(event) {
const target = event.target;
const submenuItems = event.detail.children;
const key = event.detail.event.key;
event.stopPropagation();
if (key === "ArrowDown") {
if (target.layout === "vertical") {
focusElementInGroup(this.menuItems, target, "next", false);
} else {
if (event.detail.isSubmenuOpen) {
submenuItems[0].setFocus();
}
}
} else if (key === "ArrowUp") {
if (this.layout === "vertical") {
focusElementInGroup(this.menuItems, target, "previous", false);
} else {
if (event.detail.isSubmenuOpen) {
submenuItems[submenuItems.length - 1].setFocus();
}
}
} else if (key === "ArrowRight") {
if (this.layout === "horizontal") {
focusElementInGroup(this.menuItems, target, "next", false);
} else {
if (event.detail.isSubmenuOpen) {
submenuItems[0].setFocus();
}
}
} else if (key === "ArrowLeft") {
if (this.layout === "horizontal") {
focusElementInGroup(this.menuItems, target, "previous", false);
} else {
if (event.detail.isSubmenuOpen) {
this.focusParentElement(event.target);
}
}
} else if (key === "Escape") {
this.focusParentElement(event.target);
}
event.preventDefault();
}
handleMenuSlotChange(event) {
this.menuItems = slotChangeGetAssignedElements(event);
this.setMenuItemLayout(this.menuItems, this.layout);
}
focusParentElement(el) {
const parentEl = el.parentElement;
if (parentEl) {
focusElement(parentEl);
parentEl.open = false;
}
}
setMenuItemLayout(items, layout) {
items.forEach((item) => {
item.layout = layout;
if (this.getEffectiveRole() === "menubar") {
item.isTopLevelItem = true;
item.topLevelMenuLayout = this.layout;
}
});
}
getEffectiveRole() {
return this.el.role || "menubar";
}
render() {
return html`<ul .ariaLabel=${this.label} .role=${this.getEffectiveRole()}><slot =${this.handleMenuSlotChange}></slot></ul>`;
}
}
customElement("calcite-menu", Menu);
export {
Menu
};