const ITEMS = "button, a[href], input, select, [tabindex]";
const TOGGLES = new Set(["button", "checkbox", "submit", "reset"]);
function items(toolbar ) {
return [...toolbar.querySelectorAll (ITEMS)].filter(
(el) => !(el ).disabled && el.closest("[role='toolbar']") === toolbar,
);
}
function rove(list , target ) {
for (const el of list) el.tabIndex = el === target ? 0 : -1;
}
export function bindToolbar(toolbar ) {
const initial = items(toolbar);
const chosen = initial.find((el) => el.getAttribute("tabindex") === "0") ?? initial[0];
if (chosen) rove(initial, chosen);
const onKeyDown = (event ) => {
const list = items(toolbar);
const active = document.activeElement ;
const current = list.indexOf(active);
if (current < 0) return;
if (active instanceof HTMLSelectElement) return;
if (active instanceof HTMLInputElement && !TOGGLES.has(active.type)) return;
const vertical = toolbar.getAttribute("aria-orientation") === "vertical";
const rtl = getComputedStyle(toolbar).direction === "rtl";
const next = vertical ? "ArrowDown" : rtl ? "ArrowLeft" : "ArrowRight";
const prev = vertical ? "ArrowUp" : rtl ? "ArrowRight" : "ArrowLeft";
let index ;
if (event.key === next) index = (current + 1) % list.length;
else if (event.key === prev) index = (current - 1 + list.length) % list.length;
else if (event.key === "Home") index = 0;
else if (event.key === "End") index = list.length - 1;
else return;
event.preventDefault();
rove(list, list[index]);
list[index].focus();
};
const onFocusIn = (event ) => {
const list = items(toolbar);
const target = event.target ;
if (list.includes(target)) rove(list, target);
};
const reconcile = () => {
const list = items(toolbar);
if (list.length && !list.some((el) => el.tabIndex === 0)) rove(list, list[0]);
};
const observer = typeof MutationObserver === "function" ? new MutationObserver(reconcile) : null;
observer?.observe(toolbar, { subtree: true, childList: true, attributes: true, attributeFilter: ["disabled"] });
toolbar.addEventListener("keydown", onKeyDown);
toolbar.addEventListener("focusin", onFocusIn);
return () => {
observer?.disconnect();
toolbar.removeEventListener("keydown", onKeyDown);
toolbar.removeEventListener("focusin", onFocusIn);
};
}
export function bindToolbars(root = document) {
return [...root.querySelectorAll ("[role='toolbar']")].map(bindToolbar);
}