Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Template ID: unifiedToolbarTabTemplate
* Attributes:
* - selected: If the tab is active.
* - aria-controls: The ID of the tab pane this controls.
* Events:
* - tabswitch: When the active tab is changed.
*/
class UnifiedToolbarTab extends HTMLElement {
/**
* @type {?HTMLButtonElement}
*/
#tab = null;
connectedCallback() {
if (this.shadowRoot) {
return;
}
this.setAttribute("role", "presentation");
const shadowRoot = this.attachShadow({ mode: "open" });
const template = document
.getElementById("unifiedToolbarTabTemplate")
.content.cloneNode(true);
this.#tab = template.querySelector("button");
this.#tab.tabIndex = this.hasAttribute("selected") ? 0 : -1;
if (this.hasAttribute("selected")) {
this.#tab.setAttribute("aria-selected", "true");
}
this.#tab.setAttribute("aria-controls", this.getAttribute("aria-controls"));
this.removeAttribute("aria-controls");
const styles = document.createElement("link");
styles.setAttribute("rel", "stylesheet");
styles.setAttribute(
"href",
);
shadowRoot.append(styles, template);
this.#tab.addEventListener("click", () => {
this.select();
});
this.#tab.addEventListener("keydown", this.#handleKey);
}
#handleKey = event => {
const rightIsForward = document.dir === "ltr";
const rightSibling =
(rightIsForward ? "next" : "previous") + "ElementSibling";
const leftSibling =
(rightIsForward ? "previous" : "next") + "ElementSibling";
switch (event.key) {
case "ArrowLeft":
this[leftSibling]?.focus();
break;
case "ArrowRight":
this[rightSibling]?.focus();
break;
case "Home":
this.parentNode.firstElementChild?.focus();
break;
case "End":
this.parentNode.lastElementChild?.focus();
break;
default:
return;
}
event.stopPropagation();
event.preventDefault();
};
#toggleTabPane(visible) {
this.pane.hidden = !visible;
}
/**
* Select this tab. Deselects the previously selected tab and shows the tab
* pane for this tab.
*/
select() {
this.parentElement
.querySelector("unified-toolbar-tab[selected]")
?.unselect();
this.#tab.setAttribute("aria-selected", "true");
this.#tab.tabIndex = 0;
this.setAttribute("selected", true);
this.#toggleTabPane(true);
const tabSwitchEvent = new Event("tabswitch", {
bubbles: true,
});
this.dispatchEvent(tabSwitchEvent);
}
/**
* Remove the selection for this tab and hide the associated tab pane.
*/
unselect() {
this.#tab.removeAttribute("aria-selected");
this.#tab.tabIndex = -1;
this.removeAttribute("selected");
this.#toggleTabPane(false);
}
focus() {
this.#tab.focus();
}
get pane() {
return document.getElementById(this.#tab.getAttribute("aria-controls"));
}
}
customElements.define("unified-toolbar-tab", UnifiedToolbarTab);