"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useFocusOutside = useFocusOutside;
const react_1 = require("react");
const hooks_1 = require("../../../hooks");
const dispatchCustomEvent_1 = require("./dispatchCustomEvent");
/**
 * Tracks focus outside a React subtree. Returns props for the subtree root.
 */
function useFocusOutside(callback, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document, enabled = true) {
    const handleFocusOutside = (0, hooks_1.useEventCallback)(callback);
    const isFocusInsideReactTreeRef = (0, react_1.useRef)(false);
    const skipFocusCheckRef = (0, react_1.useRef)(false);
    const timeout = (0, hooks_1.useTimeout)();
    (0, react_1.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.
                 */
                (0, dispatchCustomEvent_1.dispatchCustomEvent)(dispatchCustomEvent_1.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