diff --git a/theme/boost/amd/build/aria.min.js b/theme/boost/amd/build/aria.min.js
index 2265ffa34e3..9e9de661344 100644
--- a/theme/boost/amd/build/aria.min.js
+++ b/theme/boost/amd/build/aria.min.js
@@ -1,2 +1,2 @@
-define ("theme_boost/aria",["exports","core/key_codes","jquery","core/pending"],function(a,b,c,d){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;c=e(c);d=e(d);function e(a){return a&&a.__esModule?a:{default:a}}var f=function(){var a=!1,e=function(){a=!0},f=function(){var b=a;a=!1;return b};document.addEventListener("keydown",function(a){if(a.target.matches("[data-toggle=\"dropdown\"]")){var c=a.which;if(c==b.arrowUp){e()}if(c==b.escape){var d=a.target.getAttribute("aria-expanded");a.preventDefault();if("false"==d){a.target.click()}}if(c==b.space||c==b.enter){a.preventDefault();a.target.click()}}});var g=function(a){setTimeout(function delayedFocus(b){a.focus();b.resolve()},50,new d.default("core/aria:delayed-focus"))};(0,c.default)(".dropdown").on("shown.bs.dropdown",function(a){var b=a.target.querySelector("[role=\"menu\"]"),c=!1,d=!1;if(b){c=b.querySelectorAll("[role=\"menuitem\"]")}if(c&&0.\n\n/**\n * Enhancements to Bootstrap components for accessibility.\n *\n * @module theme_boost/aria\n * @copyright 2018 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {end, escape, arrowUp, arrowDown, arrowLeft, arrowRight, home, enter, space} from 'core/key_codes';\nimport $ from 'jquery';\nimport Pending from 'core/pending';\n\n/**\n * Drop downs from bootstrap don't support keyboard accessibility by default.\n */\nconst dropdownFix = () => {\n let focusEnd = false;\n const setFocusEnd = () => {\n focusEnd = true;\n };\n const getFocusEnd = () => {\n const result = focusEnd;\n focusEnd = false;\n return result;\n };\n\n // Special handling for \"up\" keyboard control.\n document.addEventListener('keydown', e => {\n if (e.target.matches('[data-toggle=\"dropdown\"]')) {\n const trigger = e.which;\n\n // Up key opens the menu at the end.\n if (trigger == arrowUp) {\n // Focus the end of the menu, not the beginning.\n setFocusEnd();\n }\n\n // Escape key only closes the menu, it doesn't open it.\n if (trigger == escape) {\n const expanded = e.target.getAttribute('aria-expanded');\n e.preventDefault();\n if (expanded == \"false\") {\n e.target.click();\n }\n }\n\n // Space key or Enter key opens the menu.\n if (trigger == space || trigger == enter) {\n // Cancel random scroll.\n e.preventDefault();\n // Open the menu instead.\n e.target.click();\n }\n }\n });\n\n // Special handling for navigation keys when menu is open.\n const shiftFocus = element => {\n const delayedFocus = pendingPromise => {\n element.focus();\n pendingPromise.resolve();\n };\n setTimeout(delayedFocus, 50, new Pending('core/aria:delayed-focus'));\n };\n\n $('.dropdown').on('shown.bs.dropdown', e => {\n // We need to focus on the first menuitem.\n const menu = e.target.querySelector('[role=\"menu\"]');\n let menuItems = false;\n let foundMenuItem = false;\n\n if (menu) {\n menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n }\n if (menuItems && menuItems.length > 0) {\n if (getFocusEnd()) {\n foundMenuItem = menuItems[menuItems.length - 1];\n } else {\n // The first menu entry, pretty reasonable.\n foundMenuItem = menuItems[0];\n }\n }\n if (foundMenuItem) {\n shiftFocus(foundMenuItem);\n }\n });\n // Search for menu items by finding the first item that has\n // text starting with the typed character (case insensitive).\n document.addEventListener('keypress', e => {\n if (e.target.matches('.dropdown [role=\"menu\"] [role=\"menuitem\"]')) {\n const trigger = String.fromCharCode(e.which).toLowerCase();\n const menu = e.target.closest('[role=\"menu\"]');\n\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n\n for (let i = 0; i < menuItems.length; i++) {\n const item = menuItems[i];\n const itemText = item.text.trim().toLowerCase();\n if (itemText.indexOf(trigger) == 0) {\n shiftFocus(item);\n break;\n }\n }\n }\n });\n\n // Keyboard navigation for arrow keys, home and end keys.\n document.addEventListener('keydown', e => {\n if (e.target.matches('.dropdown [role=\"menu\"] [role=\"menuitem\"]')) {\n const trigger = e.which;\n let next = false;\n const menu = e.target.closest('[role=\"menu\"]');\n\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n // Down key.\n if (trigger == arrowDown) {\n for (let i = 0; i < menuItems.length - 1; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i + 1];\n break;\n }\n }\n if (!next) {\n // Wrap to first item.\n next = menuItems[0];\n }\n\n } else if (trigger == arrowUp) {\n // Up key.\n for (let i = 1; i < menuItems.length; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i - 1];\n break;\n }\n }\n if (!next) {\n // Wrap to last item.\n next = menuItems[menuItems.length - 1];\n }\n\n } else if (trigger == home) {\n // Home key.\n next = menuItems[0];\n\n } else if (trigger == end) {\n // End key.\n next = menuItems[menuItems.length - 1];\n }\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n shiftFocus(next);\n }\n return;\n }\n });\n\n $('.dropdown').on('hidden.bs.dropdown', e => {\n // We need to focus on the menu trigger.\n const trigger = e.target.querySelector('[data-toggle=\"dropdown\"]');\n if (trigger) {\n shiftFocus(trigger);\n }\n });\n};\n\n/**\n * After page load, focus on any element with special autofocus attribute.\n */\nconst autoFocus = () => {\n window.addEventListener(\"load\", () => {\n const alerts = document.querySelectorAll('[data-aria-autofocus=\"true\"][role=\"alert\"]');\n Array.prototype.forEach.call(alerts, autofocusElement => {\n // According to the specification an role=\"alert\" region is only read out on change to the content\n // of that region.\n autofocusElement.innerHTML += ' ';\n autofocusElement.removeAttribute('data-aria-autofocus');\n });\n });\n};\n\n/**\n * Changes the focus to the correct tab based on the key that is pressed.\n * @param {KeyboardEvent} e\n */\nconst updateTabFocus = e => {\n const tabList = e.target.closest('[role=\"tablist\"]');\n const vertical = tabList.getAttribute('aria-orientation') == 'vertical';\n const rtl = window.right_to_left();\n const arrowNext = vertical ? arrowDown : (rtl ? arrowLeft : arrowRight);\n const arrowPrevious = vertical ? arrowUp : (rtl ? arrowRight : arrowLeft);\n const tabs = Array.prototype.filter.call(\n tabList.querySelectorAll('[role=\"tab\"]'),\n tab => getComputedStyle(tab).display !== 'none'); // We only work with the visible tabs.\n\n for (let i = 0; i < tabs.length; i++) {\n tabs[i].index = i;\n }\n\n switch (e.keyCode) {\n case arrowNext:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index + 1]) {\n tabs[e.target.index + 1].focus();\n } else {\n tabs[0].focus();\n }\n break;\n case arrowPrevious:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index - 1]) {\n tabs[e.target.index - 1].focus();\n } else {\n tabs[tabs.length - 1].focus();\n }\n break;\n case home:\n e.preventDefault();\n tabs[0].focus();\n break;\n case end:\n e.preventDefault();\n tabs[tabs.length - 1].focus();\n break;\n case enter:\n case space:\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n};\n\n/**\n * Fix accessibility issues regarding tab elements focus and their tab order in Bootstrap navs.\n */\nconst tabElementFix = () => {\n document.addEventListener('keydown', e => {\n if ([arrowUp, arrowDown, arrowLeft, arrowRight, home, end, enter, space].includes(e.keyCode)) {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n updateTabFocus(e);\n }\n }\n });\n\n document.addEventListener('click', e => {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n const tabs = e.target.closest('[role=\"tablist\"]').querySelectorAll('[role=\"tab\"]');\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n });\n};\n\nexport const init = () => {\n dropdownFix();\n autoFocus();\n tabElementFix();\n};\n"],"file":"aria.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/aria.js"],"names":["dropdownFix","focusEnd","setFocusEnd","getFocusEnd","result","document","addEventListener","e","target","matches","trigger","key","expanded","getAttribute","preventDefault","click","shiftFocus","element","setTimeout","delayedFocus","pendingPromise","focus","resolve","Pending","on","menu","querySelector","menuItems","foundMenuItem","querySelectorAll","length","closest","toLowerCase","i","item","itemText","text","trim","indexOf","next","autoFocus","window","alerts","Array","prototype","forEach","call","autofocusElement","innerHTML","removeAttribute","updateTabFocus","tabList","vertical","rtl","right_to_left","arrowNext","arrowPrevious","tabs","filter","tab","getComputedStyle","display","index","tabIndex","tabElementFix","includes","init"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Enhancements to Bootstrap components for accessibility.\n *\n * @module theme_boost/aria\n * @copyright 2018 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Pending from 'core/pending';\n\n/**\n * Drop downs from bootstrap don't support keyboard accessibility by default.\n */\nconst dropdownFix = () => {\n let focusEnd = false;\n const setFocusEnd = () => {\n focusEnd = true;\n };\n const getFocusEnd = () => {\n const result = focusEnd;\n focusEnd = false;\n return result;\n };\n\n // Special handling for \"up\" keyboard control.\n document.addEventListener('keydown', e => {\n if (e.target.matches('[data-toggle=\"dropdown\"]')) {\n const trigger = e.key;\n\n // Up key opens the menu at the end.\n if (trigger == 'ArrowUp') {\n // Focus the end of the menu, not the beginning.\n setFocusEnd();\n }\n\n // Escape key only closes the menu, it doesn't open it.\n if (trigger == 'Escape') {\n const expanded = e.target.getAttribute('aria-expanded');\n e.preventDefault();\n if (expanded == \"false\") {\n e.target.click();\n }\n }\n\n // Space key or Enter key opens the menu.\n if (trigger == ' ' || trigger == 'Enter') {\n // Cancel random scroll.\n e.preventDefault();\n // Open the menu instead.\n e.target.click();\n }\n }\n });\n\n // Special handling for navigation keys when menu is open.\n const shiftFocus = element => {\n const delayedFocus = pendingPromise => {\n element.focus();\n pendingPromise.resolve();\n };\n setTimeout(delayedFocus, 50, new Pending('core/aria:delayed-focus'));\n };\n\n $('.dropdown').on('shown.bs.dropdown', e => {\n // We need to focus on the first menuitem.\n const menu = e.target.querySelector('[role=\"menu\"]');\n let menuItems = false;\n let foundMenuItem = false;\n\n if (menu) {\n menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n }\n if (menuItems && menuItems.length > 0) {\n if (getFocusEnd()) {\n foundMenuItem = menuItems[menuItems.length - 1];\n } else {\n // The first menu entry, pretty reasonable.\n foundMenuItem = menuItems[0];\n }\n }\n if (foundMenuItem) {\n shiftFocus(foundMenuItem);\n }\n });\n // Search for menu items by finding the first item that has\n // text starting with the typed character (case insensitive).\n document.addEventListener('keypress', e => {\n if (e.target.matches('.dropdown [role=\"menu\"] [role=\"menuitem\"]')) {\n const menu = e.target.closest('[role=\"menu\"]');\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n\n const trigger = e.key.toLowerCase();\n\n for (let i = 0; i < menuItems.length; i++) {\n const item = menuItems[i];\n const itemText = item.text.trim().toLowerCase();\n if (itemText.indexOf(trigger) == 0) {\n shiftFocus(item);\n break;\n }\n }\n }\n });\n\n // Keyboard navigation for arrow keys, home and end keys.\n document.addEventListener('keydown', e => {\n if (e.target.matches('.dropdown [role=\"menu\"] [role=\"menuitem\"]')) {\n const trigger = e.key;\n let next = false;\n const menu = e.target.closest('[role=\"menu\"]');\n\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n // Down key.\n if (trigger == 'ArrowDown') {\n for (let i = 0; i < menuItems.length - 1; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i + 1];\n break;\n }\n }\n if (!next) {\n // Wrap to first item.\n next = menuItems[0];\n }\n\n } else if (trigger == 'ArrowUp') {\n // Up key.\n for (let i = 1; i < menuItems.length; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i - 1];\n break;\n }\n }\n if (!next) {\n // Wrap to last item.\n next = menuItems[menuItems.length - 1];\n }\n\n } else if (trigger == 'Home') {\n // Home key.\n next = menuItems[0];\n\n } else if (trigger == 'End') {\n // End key.\n next = menuItems[menuItems.length - 1];\n }\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n shiftFocus(next);\n }\n return;\n }\n });\n\n $('.dropdown').on('hidden.bs.dropdown', e => {\n // We need to focus on the menu trigger.\n const trigger = e.target.querySelector('[data-toggle=\"dropdown\"]');\n if (trigger) {\n shiftFocus(trigger);\n }\n });\n};\n\n/**\n * After page load, focus on any element with special autofocus attribute.\n */\nconst autoFocus = () => {\n window.addEventListener(\"load\", () => {\n const alerts = document.querySelectorAll('[data-aria-autofocus=\"true\"][role=\"alert\"]');\n Array.prototype.forEach.call(alerts, autofocusElement => {\n // According to the specification an role=\"alert\" region is only read out on change to the content\n // of that region.\n autofocusElement.innerHTML += ' ';\n autofocusElement.removeAttribute('data-aria-autofocus');\n });\n });\n};\n\n/**\n * Changes the focus to the correct tab based on the key that is pressed.\n * @param {KeyboardEvent} e\n */\nconst updateTabFocus = e => {\n const tabList = e.target.closest('[role=\"tablist\"]');\n const vertical = tabList.getAttribute('aria-orientation') == 'vertical';\n const rtl = window.right_to_left();\n const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight');\n const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft');\n const tabs = Array.prototype.filter.call(\n tabList.querySelectorAll('[role=\"tab\"]'),\n tab => getComputedStyle(tab).display !== 'none'); // We only work with the visible tabs.\n\n for (let i = 0; i < tabs.length; i++) {\n tabs[i].index = i;\n }\n\n switch (e.key) {\n case arrowNext:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index + 1]) {\n tabs[e.target.index + 1].focus();\n } else {\n tabs[0].focus();\n }\n break;\n case arrowPrevious:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index - 1]) {\n tabs[e.target.index - 1].focus();\n } else {\n tabs[tabs.length - 1].focus();\n }\n break;\n case 'Home':\n e.preventDefault();\n tabs[0].focus();\n break;\n case 'End':\n e.preventDefault();\n tabs[tabs.length - 1].focus();\n break;\n case 'Enter':\n case ' ':\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n};\n\n/**\n * Fix accessibility issues regarding tab elements focus and their tab order in Bootstrap navs.\n */\nconst tabElementFix = () => {\n document.addEventListener('keydown', e => {\n if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter', ' '].includes(e.key)) {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n updateTabFocus(e);\n }\n }\n });\n\n document.addEventListener('click', e => {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n const tabs = e.target.closest('[role=\"tablist\"]').querySelectorAll('[role=\"tab\"]');\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n });\n};\n\nexport const init = () => {\n dropdownFix();\n autoFocus();\n tabElementFix();\n};\n"],"file":"aria.min.js"}
\ No newline at end of file
diff --git a/theme/boost/amd/src/aria.js b/theme/boost/amd/src/aria.js
index de4049ebb86..f0358a9ab5f 100644
--- a/theme/boost/amd/src/aria.js
+++ b/theme/boost/amd/src/aria.js
@@ -21,7 +21,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-import {end, escape, arrowUp, arrowDown, arrowLeft, arrowRight, home, enter, space} from 'core/key_codes';
import $ from 'jquery';
import Pending from 'core/pending';
@@ -42,16 +41,16 @@ const dropdownFix = () => {
// Special handling for "up" keyboard control.
document.addEventListener('keydown', e => {
if (e.target.matches('[data-toggle="dropdown"]')) {
- const trigger = e.which;
+ const trigger = e.key;
// Up key opens the menu at the end.
- if (trigger == arrowUp) {
+ if (trigger == 'ArrowUp') {
// Focus the end of the menu, not the beginning.
setFocusEnd();
}
// Escape key only closes the menu, it doesn't open it.
- if (trigger == escape) {
+ if (trigger == 'Escape') {
const expanded = e.target.getAttribute('aria-expanded');
e.preventDefault();
if (expanded == "false") {
@@ -60,7 +59,7 @@ const dropdownFix = () => {
}
// Space key or Enter key opens the menu.
- if (trigger == space || trigger == enter) {
+ if (trigger == ' ' || trigger == 'Enter') {
// Cancel random scroll.
e.preventDefault();
// Open the menu instead.
@@ -103,9 +102,7 @@ const dropdownFix = () => {
// text starting with the typed character (case insensitive).
document.addEventListener('keypress', e => {
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) {
- const trigger = String.fromCharCode(e.which).toLowerCase();
const menu = e.target.closest('[role="menu"]');
-
if (!menu) {
return;
}
@@ -114,6 +111,8 @@ const dropdownFix = () => {
return;
}
+ const trigger = e.key.toLowerCase();
+
for (let i = 0; i < menuItems.length; i++) {
const item = menuItems[i];
const itemText = item.text.trim().toLowerCase();
@@ -128,7 +127,7 @@ const dropdownFix = () => {
// Keyboard navigation for arrow keys, home and end keys.
document.addEventListener('keydown', e => {
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) {
- const trigger = e.which;
+ const trigger = e.key;
let next = false;
const menu = e.target.closest('[role="menu"]');
@@ -140,7 +139,7 @@ const dropdownFix = () => {
return;
}
// Down key.
- if (trigger == arrowDown) {
+ if (trigger == 'ArrowDown') {
for (let i = 0; i < menuItems.length - 1; i++) {
if (menuItems[i] == e.target) {
next = menuItems[i + 1];
@@ -152,7 +151,7 @@ const dropdownFix = () => {
next = menuItems[0];
}
- } else if (trigger == arrowUp) {
+ } else if (trigger == 'ArrowUp') {
// Up key.
for (let i = 1; i < menuItems.length; i++) {
if (menuItems[i] == e.target) {
@@ -165,11 +164,11 @@ const dropdownFix = () => {
next = menuItems[menuItems.length - 1];
}
- } else if (trigger == home) {
+ } else if (trigger == 'Home') {
// Home key.
next = menuItems[0];
- } else if (trigger == end) {
+ } else if (trigger == 'End') {
// End key.
next = menuItems[menuItems.length - 1];
}
@@ -214,8 +213,8 @@ const updateTabFocus = e => {
const tabList = e.target.closest('[role="tablist"]');
const vertical = tabList.getAttribute('aria-orientation') == 'vertical';
const rtl = window.right_to_left();
- const arrowNext = vertical ? arrowDown : (rtl ? arrowLeft : arrowRight);
- const arrowPrevious = vertical ? arrowUp : (rtl ? arrowRight : arrowLeft);
+ const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight');
+ const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft');
const tabs = Array.prototype.filter.call(
tabList.querySelectorAll('[role="tab"]'),
tab => getComputedStyle(tab).display !== 'none'); // We only work with the visible tabs.
@@ -224,7 +223,7 @@ const updateTabFocus = e => {
tabs[i].index = i;
}
- switch (e.keyCode) {
+ switch (e.key) {
case arrowNext:
e.preventDefault();
if (e.target.index !== undefined && tabs[e.target.index + 1]) {
@@ -241,16 +240,16 @@ const updateTabFocus = e => {
tabs[tabs.length - 1].focus();
}
break;
- case home:
+ case 'Home':
e.preventDefault();
tabs[0].focus();
break;
- case end:
+ case 'End':
e.preventDefault();
tabs[tabs.length - 1].focus();
break;
- case enter:
- case space:
+ case 'Enter':
+ case ' ':
e.preventDefault();
$(e.target).tab('show');
tabs.forEach(tab => {
@@ -265,7 +264,7 @@ const updateTabFocus = e => {
*/
const tabElementFix = () => {
document.addEventListener('keydown', e => {
- if ([arrowUp, arrowDown, arrowLeft, arrowRight, home, end, enter, space].includes(e.keyCode)) {
+ if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter', ' '].includes(e.key)) {
if (e.target.matches('[role="tablist"] [role="tab"]')) {
updateTabFocus(e);
}