From a4f4d460cab9b86b2d1a4ab6e340bfff33d38ff0 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Tue, 20 Jan 2026 14:42:40 +0100 Subject: [PATCH] Hide the menu container in changing it's visibility This way, the dimensions of the menu container don't depend on its visibility. This patch fixes few keyboard issues I noticed when reading: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/menu_role#keyboard_interactions --- web/menu.css | 11 +++++++++++ web/menu.js | 39 +++++++++++++++++++++++++++------------ web/viewer.html | 9 +++++---- web/views_manager.css | 6 ++++-- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/web/menu.css b/web/menu.css index 9fd4e34b2..5ed86cb1c 100644 --- a/web/menu.css +++ b/web/menu.css @@ -13,6 +13,16 @@ * limitations under the License. */ +button.hasPopupMenu { + &[aria-expanded="true"] + menu { + visibility: visible; + } + + &[aria-expanded="false"] + menu { + visibility: hidden; + } +} + .popupMenu { --menuitem-checkmark-icon: url(images/checkmark.svg); --menu-mark-icon-size: 0; @@ -75,6 +85,7 @@ top: 1px; margin: 0; padding: 5px; + box-sizing: border-box; background: var(--menu-bg); background-blend-mode: var(--menu-background-blend-mode); diff --git a/web/menu.js b/web/menu.js index 508c2c303..27218093d 100644 --- a/web/menu.js +++ b/web/menu.js @@ -56,7 +56,6 @@ class Menu { return; } const menu = this.#menu; - menu.classList.toggle("hidden", true); this.#triggeringButton.ariaExpanded = "false"; this.#openMenuAC.abort(); this.#openMenuAC = null; @@ -82,7 +81,6 @@ class Menu { } const menu = this.#menu; - menu.classList.toggle("hidden", false); this.#triggeringButton.ariaExpanded = "true"; this.#openMenuAC = new AbortController(); const signal = AbortSignal.any([ @@ -137,6 +135,13 @@ class Menu { .focus(); stopEvent(e); break; + default: + const char = e.key.toLocaleLowerCase(); + this.#goToNextItem(e.target, true, item => + item.textContent.trim().toLowerCase().startsWith(char) + ); + stopEvent(e); + break; } }, { signal, capture: true } @@ -148,32 +153,38 @@ class Menu { }); this.#triggeringButton.addEventListener( "keydown", - ev => { - if (!this.#openMenuAC) { - return; - } - switch (ev.key) { + e => { + switch (e.key) { + case " ": + case "Enter": case "ArrowDown": case "Home": + if (!this.#openMenuAC) { + this.#triggeringButton.click(); + } this.#menuItems .find( item => !item.disabled && !item.classList.contains("hidden") ) .focus(); - stopEvent(ev); + stopEvent(e); break; case "ArrowUp": case "End": + if (!this.#openMenuAC) { + this.#triggeringButton.click(); + } this.#menuItems .findLast( item => !item.disabled && !item.classList.contains("hidden") ) .focus(); - stopEvent(ev); + stopEvent(e); break; case "Escape": this.#closeMenu(); - stopEvent(ev); + stopEvent(e); + break; } }, { signal } @@ -185,7 +196,7 @@ class Menu { * @param {HTMLElement} element * @param {boolean} forward */ - #goToNextItem(element, forward) { + #goToNextItem(element, forward, check = () => true) { const index = this.#lastIndex === -1 ? this.#menuItems.indexOf(element) @@ -198,7 +209,11 @@ class Menu { i = (i + increment) % len ) { const menuItem = this.#menuItems[i]; - if (!menuItem.disabled && !menuItem.classList.contains("hidden")) { + if ( + !menuItem.disabled && + !menuItem.classList.contains("hidden") && + check(menuItem) + ) { menuItem.focus(); this.#lastIndex = i; break; diff --git a/web/viewer.html b/web/viewer.html index ac741b298..34c5e535e 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -130,7 +130,7 @@ See https://github.com/adobe-type-tools/cmap-resources
-