diff --git a/src/pg/patterns/core/tabs/_tabs.js b/src/pg/patterns/core/tabs/_tabs.js index d83eda3..13d4f60 100644 --- a/src/pg/patterns/core/tabs/_tabs.js +++ b/src/pg/patterns/core/tabs/_tabs.js @@ -1,6 +1,6 @@ -/* DS2 core (c) 2024 Alexander McIlwraith - Released under Creative Commons Attribution-ShareAlike 4.0 International - */ +/* DS2 core (c) 2024–2026 Alexander McIlwraith + Released under Creative Commons Attribution-ShareAlike 4.0 International +*/ // create a pure JS mouse click event const click = new MouseEvent('click', { @@ -9,48 +9,56 @@ const click = new MouseEvent('click', { cancelable: true }); +// wait for an element to appear in the DOM const waitForElement = (selector) => { - return new Promise(resolve => { - if (document.querySelector(selector)) { - return resolve(document.querySelector(selector)); - } + return new Promise(resolve => { + if (document.querySelector(selector)) { + return resolve(document.querySelector(selector)); + } + const observer = new MutationObserver(() => { + if (document.querySelector(selector)) { + observer.disconnect(); + resolve(document.querySelector(selector)); + } + }); + observer.observe(document.body, { + childList: true, + subtree: true + }); + }); +}; - const observer = new MutationObserver(mutations => { - if (document.querySelector(selector)) { - observer.disconnect(); - resolve(document.querySelector(selector)); - } - }); - - // If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336 - observer.observe(document.body, { - childList: true, - subtree: true - }); - }); -} +// Tab logic +const tabNamespace = "#tab:"; const chooseTab = (tab) => { const siblings = Array.from(tab.parentNode.children); siblings.forEach(sibling => sibling.classList.remove("selected")); tab.classList.add("selected"); - - const tabPanels = Array.from(tab.parentNode.parentNode.children) + + const tabPanels = Array.from(tab.parentNode.parentNode.children); tabPanels.forEach(panel => panel.classList.remove("open")); - const tabPanelId = tab.getAttribute("id").replace("tab", "tab-panel"); - document.getElementById(tabPanelId).classList.add("open"); -} + const tabPanelId = tab + .getAttribute("id") + .replace("tab", "tab-panel"); -let pushState = 0; + document + .getElementById(tabPanelId) + .classList.add("open"); +}; + +let pushStateCount = 0; let tabsetCount = 0; -export function init(container = document, spacer = true, args = {}) { +export function init(container = document, spacer = true) { + container.querySelectorAll(".tab-group, tabset").forEach(tabGroup => { - if (tabGroup.querySelector("[role=tablist]") === null) { + + if (tabGroup.querySelector('[role="tablist"]') === null) { + if (tabGroup.getAttribute("id") == null) { - tabGroup.setAttribute("id", "tab-group-" + tabsetCount); - tabsetCount++; + tabGroup.setAttribute("id", `tab-group-${tabsetCount++}`); } const tabgroup = tabGroup.getAttribute("id"); @@ -58,24 +66,22 @@ export function init(container = document, spacer = true, args = {}) { Array.from(tabGroup.children).forEach(child => { - // is details? - let dtls = child.nodeName == "DETAILS" ? true : false; + const isDetails = child.nodeName === "DETAILS"; + const tabLabel = + isDetails + ? child.querySelector("summary")?.innerHTML + : child.getAttribute("tab") || child.getAttribute("data-tab"); - // get the tab text - let tab = dtls ? child.querySelector("summary").innerHTML : child.getAttribute("tab") || child.getAttribute("data-tab"); + if (tabLabel !== null) { - // if the tab text is not blank - if (tab !== null) { - const tabID = tab.replace(/\W+/g, "-").toLowerCase(); - + const tabID = tabLabel.replace(/\W+/g, "-").toLowerCase(); + let tabPanel; - // define the tab panel content - let tabPanel = null; - if (dtls) { + if (isDetails) { tabPanel = child; tabPanel.setAttribute("open", ""); } else { - tabPanel = document.createElement('div'); + tabPanel = document.createElement("div"); tabPanel.appendChild(child.cloneNode(true)); } @@ -83,76 +89,104 @@ export function init(container = document, spacer = true, args = {}) { tabPanel.className = tablist === "" ? "open" : ""; tabPanel.setAttribute("role", "tabpanel"); tabPanel.setAttribute("tabindex", "0"); - tabPanel.setAttribute("aria-labelledby", `tab-${tabgroup}-${tabID}`); + tabPanel.setAttribute( + "aria-labelledby", + `tab-${tabgroup}-${tabID}` + ); + child.parentNode.replaceChild(tabPanel, child); - tablist += `