import { jsx as _jsx } from "react/jsx-runtime";
// (C) 2025 GoodData Corporation
import { cloneElement, useEffect, useMemo, useState, } from "react";
import { resolveRef } from "./utils.js";
import { getFocusableElements, isElementFocusable, isElementTextInput } from "../../utils/domUtilities.js";
/**
 * Provides a ref that will autofocus the element when it is mounted, or when `refocusKey` changes.
 *
 * @internal
 */
export const useUiAutofocusConnectors = ({ active = true, refocusKey, initialFocus, } = {}) => {
    const [element, setElement] = useState(null);
    // If the element is outside of the viewport, calling focus() will not work.
    // This can happen for example with floating elements, that are repositioned after they mount
    useEffect(() => {
        const elementToFocus = getElementToFocus(element, initialFocus, true);
        if (!elementToFocus || !active) {
            return undefined;
        }
        const observer = new IntersectionObserver(([{ target }]) => {
            // Focusing a newly created element sometimes fails if not done through requestAnimationFrame()
            window.requestAnimationFrame(() => {
                if (element?.contains(document.activeElement) ||
                    target.contains(document.activeElement) ||
                    isElementTextInput(document.activeElement)) {
                    observer.disconnect();
                    return;
                }
                target.focus();
                if (document.activeElement === target) {
                    observer.disconnect();
                }
            });
        });
        observer.observe(elementToFocus);
        return () => observer.disconnect();
    }, [refocusKey, element, initialFocus, active]);
    return useMemo(() => ({ ref: setElement }), []);
};
function getElementToFocus(element, initialFocus, includeHidden) {
    const initialFocusElement = resolveRef(initialFocus);
    const elementToCheck = initialFocusElement ?? element;
    return isElementFocusable(elementToCheck, includeHidden)
        ? elementToCheck
        : getFocusableElements(elementToCheck, includeHidden).firstElement;
}
/**
 * Wrapper that focuses the first focusable child when it mounts, or when `refocusKey` changes.
 *
 * @internal
 */
export function UiAutofocus({ root, children, ...options }) {
    const rootElement = root || _jsx("div", { style: { display: "contents" } });
    const connectors = useUiAutofocusConnectors(options);
    return cloneElement(rootElement, { ...rootElement.props, ...connectors }, children);
}
//# sourceMappingURL=UiAutofocus.js.map