summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/unifiedtoolbar/content/unified-toolbar-tab.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/unifiedtoolbar/content/unified-toolbar-tab.mjs')
-rw-r--r--comm/mail/components/unifiedtoolbar/content/unified-toolbar-tab.mjs119
1 files changed, 119 insertions, 0 deletions
diff --git a/comm/mail/components/unifiedtoolbar/content/unified-toolbar-tab.mjs b/comm/mail/components/unifiedtoolbar/content/unified-toolbar-tab.mjs
new file mode 100644
index 0000000000..134aec6cf1
--- /dev/null
+++ b/comm/mail/components/unifiedtoolbar/content/unified-toolbar-tab.mjs
@@ -0,0 +1,119 @@
+/* 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",
+ "chrome://messenger/skin/shared/unifiedToolbarTab.css"
+ );
+
+ 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);