UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

117 lines (116 loc) 4.18 kB
/*! 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 @slotchange=${this.handleMenuSlotChange}></slot></ul>`; } } customElement("calcite-menu", Menu); export { Menu };