function select(doc, tab) {
const list = tab.closest('[role=tablist]');
if (!list) return;
for (const other of Array.from(list.querySelectorAll('[role=tab]'))) {
const active = other === tab;
other.setAttribute('aria-selected', String(active));
other.setAttribute('tabindex', active ? '0' : '-1');
const panel = doc.getElementById(other.getAttribute('aria-controls'));
if (panel) panel.hidden = !active;
}
}
function target(tab, key) {
const list = tab.closest('[role=tablist]');
if (!list) return null;
const tabs = Array.from(list.querySelectorAll('[role=tab]')).filter(
(candidate) => candidate === tab || !candidate.closest('[hidden]'),
);
const at = tabs.indexOf(tab);
switch (key) {
case 'ArrowRight':
return tabs[(at + 1) % tabs.length];
case 'ArrowLeft':
return tabs[(at - 1 + tabs.length) % tabs.length];
case 'Home':
return tabs[0];
case 'End':
return tabs[tabs.length - 1];
default:
return null;
}
}
function reveal(doc, control) {
let panel = control.closest && control.closest('[data-tab-panel]');
while (panel) {
if (panel.hidden) {
const tab = doc.getElementById(panel.getAttribute('aria-labelledby'));
if (tab) select(doc, tab);
}
panel = panel.parentElement && panel.parentElement.closest('[data-tab-panel]');
}
}
function tabOf(node) {
const tab = node.closest && node.closest('[role=tab]');
return tab && tab.closest('[data-tabs]') ? tab : null;
}
function install(doc, defer = (f) => setTimeout(f, 0)) {
doc.addEventListener('click', (e) => {
const tab = tabOf(e.target);
if (tab) select(doc, tab);
});
doc.addEventListener('keydown', (e) => {
const tab = tabOf(e.target);
const next = tab && target(tab, e.key);
if (!next) return;
e.preventDefault();
select(doc, next);
next.focus();
});
let checking = false;
doc.addEventListener(
'invalid',
(e) => {
if (checking) return;
checking = true;
defer(() => {
checking = false;
});
reveal(doc, e.target);
},
true,
);
}
if (typeof document !== 'undefined') {
install(document);
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = { install, reveal, select, target };
}