|
// retoor <retoor@molodetz.nl>
|
|
|
|
let tabsSeq = 0;
|
|
|
|
class Tabs {
|
|
constructor() {
|
|
document.querySelectorAll("[data-tabs]").forEach((root) => this.init(root));
|
|
}
|
|
|
|
init(root) {
|
|
const tabs = [...root.querySelectorAll("[data-tab]")];
|
|
const panes = [...root.querySelectorAll("[data-tab-pane]")];
|
|
if (!tabs.length) return;
|
|
|
|
const list = tabs[0].parentElement;
|
|
if (list && !list.getAttribute("role")) {
|
|
list.setAttribute("role", "tablist");
|
|
}
|
|
|
|
const base = `tabs-${tabsSeq++}`;
|
|
tabs.forEach((tab, index) => {
|
|
const name = tab.dataset.tab;
|
|
const pane = panes.find((p) => p.dataset.tabPane === name);
|
|
const tabId = tab.id || `${base}-tab-${name}`;
|
|
tab.id = tabId;
|
|
tab.setAttribute("role", "tab");
|
|
if (pane) {
|
|
const paneId = pane.id || `${base}-pane-${name}`;
|
|
pane.id = paneId;
|
|
pane.setAttribute("role", "tabpanel");
|
|
pane.setAttribute("aria-labelledby", tabId);
|
|
const focusable = pane.querySelector(
|
|
"a[href], button, input, select, textarea, [tabindex]"
|
|
);
|
|
if (!focusable && !pane.hasAttribute("tabindex")) {
|
|
pane.setAttribute("tabindex", "0");
|
|
}
|
|
tab.setAttribute("aria-controls", paneId);
|
|
}
|
|
});
|
|
|
|
const show = (name, focusTab) => {
|
|
tabs.forEach((tab) => {
|
|
const selected = tab.dataset.tab === name;
|
|
tab.classList.toggle("active", selected);
|
|
tab.setAttribute("aria-selected", selected ? "true" : "false");
|
|
tab.setAttribute("tabindex", selected ? "0" : "-1");
|
|
if (selected && focusTab) tab.focus();
|
|
});
|
|
panes.forEach((p) => {
|
|
const selected = p.dataset.tabPane === name;
|
|
p.classList.toggle("active", selected);
|
|
});
|
|
};
|
|
|
|
tabs.forEach((tab, index) => {
|
|
tab.addEventListener("click", () => {
|
|
show(tab.dataset.tab);
|
|
history.replaceState(null, "", "#" + tab.dataset.tab);
|
|
});
|
|
tab.addEventListener("keydown", (e) => {
|
|
let next = null;
|
|
if (e.key === "ArrowRight" || e.key === "ArrowDown") next = index + 1;
|
|
else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = index - 1;
|
|
else if (e.key === "Home") next = 0;
|
|
else if (e.key === "End") next = tabs.length - 1;
|
|
if (next === null) return;
|
|
e.preventDefault();
|
|
const target = tabs[(next + tabs.length) % tabs.length];
|
|
show(target.dataset.tab, true);
|
|
history.replaceState(null, "", "#" + target.dataset.tab);
|
|
});
|
|
});
|
|
|
|
const hash = (location.hash || "").slice(1);
|
|
const initial = tabs.some((t) => t.dataset.tab === hash) ? hash : tabs[0].dataset.tab;
|
|
show(initial);
|
|
}
|
|
}
|
|
|
|
window.Tabs = Tabs;
|
|
export { Tabs };
|