"use strict";
const jsxRuntime = require("react/jsx-runtime");
const React = require("react");
const FocusLock = require("react-focus-lock");
const styles_lib_components_Box_Box_cjs = require("../../Box/Box.cjs");
const styles_lib_components_TooltipRenderer_TooltipRenderer_cjs = require("../../TooltipRenderer/TooltipRenderer.cjs");
const styles_lib_components_private_Modal_ModalExternalGutter_cjs = require("./ModalExternalGutter.cjs");
const styles_lib_components_private_Modal_ModalContent_cjs = require("./ModalContent.cjs");
const styles_lib_components_private_Modal_Modal_css_cjs = require("./Modal.css.cjs");
const _interopDefaultCompat = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
const FocusLock__default = /* @__PURE__ */ _interopDefaultCompat(FocusLock);
const defaultParent = typeof document !== "undefined" ? document.body : null;
let counterMap = /* @__PURE__ */ new WeakMap();
let uncontrolledNodes = /* @__PURE__ */ new WeakMap();
let markerMap = {};
let lockCount = 0;
const ariaHideOthers = (originalTarget, {
  parentNode = defaultParent,
  markerName = "data-aria-hidden",
  delay = 0
} = {}) => {
  const targets = Array.isArray(originalTarget) ? originalTarget : [originalTarget];
  if (!markerMap[markerName]) {
    markerMap[markerName] = /* @__PURE__ */ new WeakMap();
  }
  const markerCounter = markerMap[markerName];
  const hiddenNodes = [];
  const walk = (parent) => {
    if (!parent || targets.indexOf(parent) >= 0) {
      return;
    }
    Array.prototype.forEach.call(parent.children, (node) => {
      if (targets.some((target) => node.contains(target))) {
        walk(node);
      } else if (node.nodeName !== "SCRIPT" && node.nodeName !== "STYLE") {
        const attr = node.getAttribute("aria-hidden");
        const alreadyHidden = attr !== null && attr !== "false";
        const counterValue = (counterMap.get(node) || 0) + 1;
        const markerValue = (markerCounter.get(node) || 0) + 1;
        counterMap.set(node, counterValue);
        markerCounter.set(node, markerValue);
        hiddenNodes.push(node);
        if (counterValue === 1 && alreadyHidden) {
          uncontrolledNodes.set(node, true);
        }
        if (markerValue === 1) {
          node.setAttribute(markerName, "true");
        }
        if (!alreadyHidden) {
          node.setAttribute("aria-hidden", "true");
        }
      }
    });
  };
  const timeout = delay ? setTimeout(() => walk(parentNode), delay) : (walk(parentNode), null);
  lockCount++;
  return () => {
    if (timeout) {
      clearTimeout(timeout);
    }
    hiddenNodes.forEach((node) => {
      const counterValue = (counterMap.get(node) ?? 1) - 1;
      const markerValue = (markerCounter.get(node) ?? 1) - 1;
      counterMap.set(node, counterValue);
      markerCounter.set(node, markerValue);
      if (!counterValue) {
        if (!uncontrolledNodes.has(node)) {
          node.removeAttribute("aria-hidden");
        }
        uncontrolledNodes.delete(node);
      }
      if (!markerValue) {
        node.removeAttribute(markerName);
      }
    });
    lockCount--;
    if (!lockCount) {
      counterMap = /* @__PURE__ */ new WeakMap();
      counterMap = /* @__PURE__ */ new WeakMap();
      uncontrolledNodes = /* @__PURE__ */ new WeakMap();
      markerMap = {};
    }
  };
};
const AllowCloseContext = React.createContext(true);
const ModalPortal = ({ children }) => {
  const [modalElement, setElement] = React.useState(null);
  React.useEffect(() => {
    const modalContainerId = "braid-modal-container";
    let element = document.getElementById(modalContainerId);
    if (!element) {
      element = document.createElement("div");
      element.setAttribute("id", modalContainerId);
      element.setAttribute("class", styles_lib_components_private_Modal_Modal_css_cjs.fixedStackingContext);
      document.body.appendChild(element);
    }
    setElement(element);
  }, []);
  if (!modalElement) {
    return null;
  }
  return /* @__PURE__ */ jsxRuntime.jsx(styles_lib_components_TooltipRenderer_TooltipRenderer_cjs.BraidPortal, { container: modalElement, children });
};
const OPEN_MODAL = 1;
const CLOSE_MODAL = 2;
const ANIMATION_COMPLETE = 3;
const INITIAL = 1;
const OPEN = 2;
const OPENING = 3;
const CLOSED = 4;
const CLOSING = 5;
const reducer = (prevState, action) => {
  switch (action) {
    case OPEN_MODAL: {
      switch (prevState) {
        case INITIAL:
        case CLOSING:
        case CLOSED: {
          return OPENING;
        }
      }
    }
    case CLOSE_MODAL: {
      switch (prevState) {
        case OPEN:
        case OPENING: {
          return CLOSING;
        }
      }
    }
    case ANIMATION_COMPLETE: {
      switch (prevState) {
        case CLOSING: {
          return CLOSED;
        }
        case OPENING: {
          return OPEN;
        }
      }
    }
  }
  return prevState;
};
const ANIMATION_DURATION = 300;
const Modal = ({
  id,
  open,
  children,
  description,
  onClose,
  width,
  closeLabel,
  illustration,
  title,
  headingLevel,
  position,
  ...restProps
}) => {
  const [trapActive, setTrapActive] = React.useState(true);
  const [state, dispatch] = React.useReducer(reducer, INITIAL);
  const allowClose = React.useContext(AllowCloseContext);
  const shouldFocus = typeof document !== "undefined" && typeof document.hasFocus === "function" && document.hasFocus();
  const openRef = React.useRef(open);
  const modalRef = React.useRef(null);
  const headingRef = React.useRef(null);
  const closeHandlerRef = React.useRef(onClose);
  const initiateClose = () => {
    if (allowClose) {
      const result = closeHandlerRef.current(false);
      if (result === false) {
        return result;
      }
      if (openRef.current) {
        dispatch(CLOSE_MODAL);
      }
    }
  };
  React.useEffect(() => {
    openRef.current = open;
    dispatch(open ? OPEN_MODAL : CLOSE_MODAL);
  }, [open]);
  const closing = state === CLOSING;
  React.useEffect(() => {
    if (closing) {
      const timer = setTimeout(() => {
        dispatch(ANIMATION_COMPLETE);
      }, ANIMATION_DURATION);
      return () => clearTimeout(timer);
    }
  }, [closing]);
  const shouldAriaHideOthers = state === OPEN || state === CLOSING;
  React.useEffect(() => {
    if (shouldAriaHideOthers && modalRef.current) {
      return ariaHideOthers(modalRef.current, { delay: ANIMATION_DURATION });
    }
  }, [shouldAriaHideOthers]);
  React.useEffect(() => {
    if (typeof onClose === "function") {
      closeHandlerRef.current = onClose;
    }
  }, [onClose]);
  React.useEffect(() => {
    const event = trapActive ? "blur" : "focus";
    const handleEvent = () => setTrapActive(!trapActive);
    window.addEventListener(event, handleEvent);
    return () => {
      window.removeEventListener(event, handleEvent);
    };
  }, [trapActive]);
  return state === OPENING || state === OPEN || state === CLOSING ? /* @__PURE__ */ jsxRuntime.jsx(ModalPortal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
    FocusLock__default.default,
    {
      className: styles_lib_components_private_Modal_Modal_css_cjs.resetStackingContext,
      disabled: !trapActive,
      autoFocus: false,
      onActivation: () => {
        if (state === OPEN) {
          return;
        }
        if (headingRef.current && shouldFocus) {
          headingRef.current.focus();
        }
        dispatch(ANIMATION_COMPLETE);
      },
      returnFocus: true,
      children: [
        /* @__PURE__ */ jsxRuntime.jsx(
          styles_lib_components_Box_Box_cjs.Box,
          {
            onClick: state === OPEN ? initiateClose : void 0,
            position: "fixed",
            inset: 0,
            zIndex: "modalBackdrop",
            transition: position === "center" ? "fast" : void 0,
            opacity: state !== OPEN ? 0 : void 0,
            pointerEvents: state === CLOSING ? "none" : void 0,
            className: [
              styles_lib_components_private_Modal_Modal_css_cjs.backdrop,
              position === "left" || position === "right" && styles_lib_components_private_Modal_Modal_css_cjs.horiztontalTransition
            ]
          }
        ),
        /* @__PURE__ */ jsxRuntime.jsx(
          styles_lib_components_Box_Box_cjs.Box,
          {
            position: "fixed",
            inset: 0,
            zIndex: "modal",
            pointerEvents: "none",
            transition: "fast",
            opacity: state !== OPEN ? 0 : void 0,
            paddingLeft: position === "right" ? ["none", "xlarge"] : void 0,
            paddingRight: position === "left" ? ["none", "xlarge"] : void 0,
            padding: position === "center" ? styles_lib_components_private_Modal_ModalExternalGutter_cjs.externalGutter : void 0,
            className: [
              styles_lib_components_private_Modal_Modal_css_cjs.modalContainer,
              (position === "left" || position === "right") && styles_lib_components_private_Modal_Modal_css_cjs.horiztontalTransition,
              state === OPENING && styles_lib_components_private_Modal_Modal_css_cjs.entrance[position],
              state === CLOSING && position in styles_lib_components_private_Modal_Modal_css_cjs.exit && styles_lib_components_private_Modal_Modal_css_cjs.exit[position]
            ],
            children: /* @__PURE__ */ jsxRuntime.jsx(
              styles_lib_components_private_Modal_ModalContent_cjs.ModalContent,
              {
                id,
                description,
                onClose: initiateClose,
                width,
                closeLabel,
                illustration,
                title,
                headingLevel,
                headingRef,
                modalRef,
                position,
                scrollLock: !(state === CLOSING),
                ...restProps,
                children
              }
            )
          }
        )
      ]
    }
  ) }) : null;
};
exports.AllowCloseContext = AllowCloseContext;
exports.Modal = Modal;
