"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// packages/components/src/modal/index.tsx
var modal_exports = {};
__export(modal_exports, {
  Modal: () => Modal,
  default: () => modal_default
});
module.exports = __toCommonJS(modal_exports);
var import_clsx = __toESM(require("clsx"), 1);
var import_element = require("@wordpress/element");
var import_compose = require("@wordpress/compose");
var import_i18n = require("@wordpress/i18n");
var import_icons = require("@wordpress/icons");
var import_dom = require("@wordpress/dom");
var ariaHelper = __toESM(require("./aria-helper.cjs"), 1);
var import_button = __toESM(require("../button/index.cjs"), 1);
var import_style_provider = __toESM(require("../style-provider/index.cjs"), 1);
var import_with_ignore_ime_events = require("../utils/with-ignore-ime-events.cjs");
var import_spacer = require("../spacer/index.cjs");
var import_use_modal_exit_animation = require("./use-modal-exit-animation.cjs");
var import_jsx_runtime = require("react/jsx-runtime");
var ModalContext = (0, import_element.createContext)(/* @__PURE__ */ new Set());
ModalContext.displayName = "ModalContext";
var bodyOpenClasses = /* @__PURE__ */ new Map();
function UnforwardedModal(props, forwardedRef) {
  const {
    bodyOpenClassName = "modal-open",
    role = "dialog",
    title = null,
    focusOnMount = true,
    shouldCloseOnEsc = true,
    shouldCloseOnClickOutside = true,
    isDismissible = true,
    /* Accessibility. */
    aria = {
      labelledby: void 0,
      describedby: void 0
    },
    onRequestClose,
    icon,
    closeButtonLabel,
    children,
    style,
    overlayClassName: overlayClassnameProp,
    className,
    contentLabel,
    onKeyDown,
    isFullScreen = false,
    size,
    headerActions = null,
    __experimentalHideHeader = false
  } = props;
  const ref = (0, import_element.useRef)();
  const instanceId = (0, import_compose.useInstanceId)(Modal);
  const headingId = title ? `components-modal-header-${instanceId}` : aria.labelledby;
  const focusOnMountRef = (0, import_compose.useFocusOnMount)(focusOnMount === "firstContentElement" ? "firstElement" : focusOnMount);
  const constrainedTabbingRef = (0, import_compose.useConstrainedTabbing)();
  const focusReturnRef = (0, import_compose.useFocusReturn)();
  const contentRef = (0, import_element.useRef)(null);
  const childrenContainerRef = (0, import_element.useRef)(null);
  const [hasScrolledContent, setHasScrolledContent] = (0, import_element.useState)(false);
  const [hasScrollableContent, setHasScrollableContent] = (0, import_element.useState)(false);
  let sizeClass;
  if (isFullScreen || size === "fill") {
    sizeClass = "is-full-screen";
  } else if (size) {
    sizeClass = `has-size-${size}`;
  }
  const isContentScrollable = (0, import_element.useCallback)(() => {
    if (!contentRef.current) {
      return;
    }
    const closestScrollContainer = (0, import_dom.getScrollContainer)(contentRef.current);
    if (contentRef.current === closestScrollContainer) {
      setHasScrollableContent(true);
    } else {
      setHasScrollableContent(false);
    }
  }, [contentRef]);
  (0, import_element.useEffect)(() => {
    ariaHelper.modalize(ref.current);
    return () => ariaHelper.unmodalize();
  }, []);
  const onRequestCloseRef = (0, import_element.useRef)();
  (0, import_element.useEffect)(() => {
    onRequestCloseRef.current = onRequestClose;
  }, [onRequestClose]);
  const dismissers = (0, import_element.useContext)(ModalContext);
  const [nestedDismissers] = (0, import_element.useState)(() => /* @__PURE__ */ new Set());
  (0, import_element.useEffect)(() => {
    dismissers.add(onRequestCloseRef);
    for (const dismisser of dismissers) {
      if (dismisser !== onRequestCloseRef) {
        dismisser.current?.();
      }
    }
    return () => {
      for (const dismisser of nestedDismissers) {
        dismisser.current?.();
      }
      dismissers.delete(onRequestCloseRef);
    };
  }, [dismissers, nestedDismissers]);
  (0, import_element.useEffect)(() => {
    var _bodyOpenClasses$get;
    const theClass = bodyOpenClassName;
    const oneMore = 1 + ((_bodyOpenClasses$get = bodyOpenClasses.get(theClass)) !== null && _bodyOpenClasses$get !== void 0 ? _bodyOpenClasses$get : 0);
    bodyOpenClasses.set(theClass, oneMore);
    document.body.classList.add(bodyOpenClassName);
    return () => {
      const oneLess = bodyOpenClasses.get(theClass) - 1;
      if (oneLess === 0) {
        document.body.classList.remove(theClass);
        bodyOpenClasses.delete(theClass);
      } else {
        bodyOpenClasses.set(theClass, oneLess);
      }
    };
  }, [bodyOpenClassName]);
  const {
    closeModal,
    frameRef,
    frameStyle,
    overlayClassname
  } = (0, import_use_modal_exit_animation.useModalExitAnimation)();
  (0, import_element.useLayoutEffect)(() => {
    if (!window.ResizeObserver || !childrenContainerRef.current) {
      return;
    }
    const resizeObserver = new ResizeObserver(isContentScrollable);
    resizeObserver.observe(childrenContainerRef.current);
    isContentScrollable();
    return () => {
      resizeObserver.disconnect();
    };
  }, [isContentScrollable, childrenContainerRef]);
  function handleEscapeKeyDown(event) {
    if (shouldCloseOnEsc && (event.code === "Escape" || event.key === "Escape") && !event.defaultPrevented) {
      event.preventDefault();
      closeModal().then(() => onRequestClose(event));
    }
  }
  const onContentContainerScroll = (0, import_element.useCallback)((e) => {
    var _e$currentTarget$scro;
    const scrollY = (_e$currentTarget$scro = e?.currentTarget?.scrollTop) !== null && _e$currentTarget$scro !== void 0 ? _e$currentTarget$scro : -1;
    if (!hasScrolledContent && scrollY > 0) {
      setHasScrolledContent(true);
    } else if (hasScrolledContent && scrollY <= 0) {
      setHasScrolledContent(false);
    }
  }, [hasScrolledContent]);
  let pressTarget = null;
  const overlayPressHandlers = {
    onPointerDown: (event) => {
      if (event.target === event.currentTarget) {
        pressTarget = event.target;
        event.preventDefault();
      }
    },
    // Closes the modal with two exceptions. 1. Opening the context menu on
    // the overlay. 2. Pressing on the overlay then dragging the pointer
    // over the modal and releasing. Due to the modal being a child of the
    // overlay, such a gesture is a `click` on the overlay and cannot be
    // excepted by a `click` handler. Thus the tactic of handling
    // `pointerup` and comparing its target to that of the `pointerdown`.
    onPointerUp: ({
      target,
      button
    }) => {
      const isSameTarget = target === pressTarget;
      pressTarget = null;
      if (button === 0 && isSameTarget) {
        closeModal().then(() => onRequestClose());
      }
    }
  };
  const modal = (
    // eslint-disable-next-line jsx-a11y/no-static-element-interactions
    /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
      ref: (0, import_compose.useMergeRefs)([ref, forwardedRef]),
      className: (0, import_clsx.default)("components-modal__screen-overlay", overlayClassname, overlayClassnameProp),
      onKeyDown: (0, import_with_ignore_ime_events.withIgnoreIMEEvents)(handleEscapeKeyDown),
      ...shouldCloseOnClickOutside ? overlayPressHandlers : {},
      children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_style_provider.default, {
        document,
        children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
          className: (0, import_clsx.default)("components-modal__frame", sizeClass, className),
          style: {
            ...frameStyle,
            ...style
          },
          ref: (0, import_compose.useMergeRefs)([frameRef, constrainedTabbingRef, focusReturnRef, focusOnMount !== "firstContentElement" ? focusOnMountRef : null]),
          role,
          "aria-label": contentLabel,
          "aria-labelledby": contentLabel ? void 0 : headingId,
          "aria-describedby": aria.describedby,
          tabIndex: -1,
          onKeyDown,
          children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
            className: (0, import_clsx.default)("components-modal__content", {
              "hide-header": __experimentalHideHeader,
              "is-scrollable": hasScrollableContent,
              "has-scrolled-content": hasScrolledContent
            }),
            role: "document",
            onScroll: onContentContainerScroll,
            ref: contentRef,
            "aria-label": hasScrollableContent ? (0, import_i18n.__)("Scrollable section") : void 0,
            tabIndex: hasScrollableContent ? 0 : void 0,
            children: [!__experimentalHideHeader && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
              className: "components-modal__header",
              children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
                className: "components-modal__header-heading-container",
                children: [icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
                  className: "components-modal__icon-container",
                  "aria-hidden": true,
                  children: icon
                }), title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
                  id: headingId,
                  className: "components-modal__header-heading",
                  children: title
                })]
              }), headerActions, isDismissible && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
                children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_spacer.Spacer, {
                  marginBottom: 0,
                  marginLeft: 2
                }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_button.default, {
                  size: "compact",
                  onClick: (event) => closeModal().then(() => onRequestClose(event)),
                  icon: import_icons.close,
                  label: closeButtonLabel || (0, import_i18n.__)("Close")
                })]
              })]
            }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
              ref: (0, import_compose.useMergeRefs)([childrenContainerRef, focusOnMount === "firstContentElement" ? focusOnMountRef : null]),
              className: "components-modal__children-container",
              children
            })]
          })
        })
      })
    })
  );
  return (0, import_element.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalContext.Provider, {
    value: nestedDismissers,
    children: modal
  }), document.body);
}
var Modal = (0, import_element.forwardRef)(UnforwardedModal);
var modal_default = Modal;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  Modal
});
//# sourceMappingURL=index.cjs.map
