make some overall QoL improvements
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
||||
const stack = [];
|
||||
|
||||
function focusables(modal) {
|
||||
return [...modal.querySelectorAll(focusableSelector)].filter(element =>
|
||||
element.getClientRects().length && !element.closest('.hidden, [hidden]'));
|
||||
}
|
||||
|
||||
export function openModal(modal, preferredFocus) {
|
||||
const previous = document.activeElement;
|
||||
modal.classList.remove('hidden');
|
||||
stack.push({modal, previous});
|
||||
(preferredFocus || focusables(modal)[0] || modal.querySelector('[role="dialog"]'))?.focus();
|
||||
}
|
||||
|
||||
export function closeModal(modal) {
|
||||
const index = stack.findLastIndex(entry => entry.modal === modal);
|
||||
if (index < 0) return;
|
||||
const [{previous}] = stack.splice(index, 1);
|
||||
modal.classList.add('hidden');
|
||||
if (index === stack.length) {
|
||||
const target = stack.length ? focusables(stack.at(-1).modal)[0] : previous;
|
||||
if (target?.isConnected) target.focus();
|
||||
}
|
||||
}
|
||||
|
||||
export function topModal() { return stack.at(-1)?.modal || null; }
|
||||
|
||||
document.addEventListener('keydown', event => {
|
||||
if (event.key !== 'Tab' || !stack.length) return;
|
||||
const modal = topModal();
|
||||
const elements = focusables(modal);
|
||||
if (!elements.length) { event.preventDefault(); modal.querySelector('[role="dialog"]')?.focus(); return; }
|
||||
const first = elements[0], last = elements.at(-1);
|
||||
if (event.shiftKey && (document.activeElement === first || !modal.contains(document.activeElement))) {
|
||||
event.preventDefault(); last.focus();
|
||||
} else if (!event.shiftKey && (document.activeElement === last || !modal.contains(document.activeElement))) {
|
||||
event.preventDefault(); first.focus();
|
||||
}
|
||||
}, true);
|
||||
Reference in New Issue
Block a user