import { useEffect, useRef } from "react";
import { useEventCallback, useTimeout } from "../../../hooks/index.js";
import { CUSTOM_EVENTS, dispatchCustomEvent, } from "./dispatchCustomEvent.js";
/**
 * Tracks focus outside a React subtree. Returns props for the subtree root.
 */
export function useFocusOutside(callback, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document, enabled = true) {
    const handleFocusOutside = useEventCallback(callback);
    const isFocusInsideReactTreeRef = useRef(false);
    const skipFocusCheckRef = useRef(false);
    const timeout = useTimeout();
    useEffect(() => {
        if (!enabled) {
            return;
        }
        const handleFocus = (event) => {
            if (event.target &&
                !isFocusInsideReactTreeRef.current &&
                !skipFocusCheckRef.current) {
                const eventDetail = { originalEvent: event };
                /**
                 * The `DismisableLayer`-API is based on the ability to stop events from propagating and in the end calling `onDismiss`
                 * if `useFocusOutside`-callback runs `event.preventDefault()`.
                 *
                 * Because of the `focusin`-event not being cancelable,
                 * we need to use a custom event to ensure that the event is cancelable.
                 * https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event
                 * > The focusin event is not cancelable.
                 */
                dispatchCustomEvent(CUSTOM_EVENTS.FOCUS_OUTSIDE, handleFocusOutside, eventDetail);
            }
        };
        ownerDocument.addEventListener("focusin", handleFocus);
        return () => {
            ownerDocument.removeEventListener("focusin", handleFocus);
        };
    }, [ownerDocument, handleFocusOutside, enabled]);
    /**
     * By directly setting isFocusInsideReactTreeRef on focus-events at the root of the "dismissable" element,
     * we can eliminate the need for DOM traversal to verify if the focused element is within the react tree.
     */
    return {
        onFocusCapture: () => {
            isFocusInsideReactTreeRef.current = true;
        },
        onBlurCapture: () => {
            isFocusInsideReactTreeRef.current = false;
        },
        onPointerDownCapture: () => {
            skipFocusCheckRef.current = true;
            timeout.start(0, () => {
                skipFocusCheckRef.current = false;
            });
        },
    };
}
//# sourceMappingURL=useFocusOutside.js.map