/**
 * Constrains keyboard Tab navigation to stay within a given container element.
 *
 * This function implements a simple "focus loop" (a.k.a. focus trap) behavior.
 * When the user presses Tab on the last focusable element, focus will wrap to
 * the first focusable element. When pressing Shift+Tab on the first focusable
 * element, focus will wrap to the last.
 *
 * Use this in keyboard event handlers (typically onKeyDown) when building
 * components such as modals, popovers, drawers, or any UI that should trap
 * focus within a defined scope.
 *
 * @param element - The container within which focus should be scoped.
 * @param keyboardEvent - The keyboard event from React (usually from onKeyDown).
 */
export function scopeTab(element, keyboardEvent) {
    const focusableSelectors = [
        'a[href]',
        'button:not([disabled])',
        'input:not([disabled])',
        'select:not([disabled])',
        'textarea:not([disabled])',
        "[tabindex]:not([tabindex='-1'])",
    ];
    const getFocusable = () => Array.from(element.querySelectorAll(focusableSelectors.join(','))).filter(isVisible);
    const focusables = getFocusable();
    if (focusables.length === 0) {
        return;
    }
    const first = focusables[0];
    const last = focusables[focusables.length - 1];
    const active = document.activeElement;
    if (element === active && keyboardEvent.shiftKey) {
        // Shift + Tab on the container itself
        keyboardEvent.preventDefault();
        last.focus();
    }
    else if (keyboardEvent.shiftKey) {
        // Shift + Tab
        if (active === first) {
            keyboardEvent.preventDefault();
            last.focus();
        }
    }
    else {
        // Tab
        if (active === last) {
            keyboardEvent.preventDefault();
            first.focus();
        }
    }
}
function isVisible(el) {
    if (!el) {
        return false;
    }
    const style = window.getComputedStyle(el);
    if (style.display === 'none') {
        return false;
    }
    if (style.visibility === 'hidden') {
        return false;
    }
    if (el.getAttribute('aria-hidden') === 'true') {
        return false;
    }
    return true;
}
//# sourceMappingURL=scopeTab.js.map