From 6ec259a0e71174651bae95d4628138bf6fd68742 Mon Sep 17 00:00:00 2001
From: kj_sh604
Date: Sun, 15 Mar 2026 16:19:35 -0400
Subject: refactor: packages/

---
 packages/excalidraw/components/Modal.tsx | 65 ++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 packages/excalidraw/components/Modal.tsx

(limited to 'packages/excalidraw/components/Modal.tsx')

diff --git a/packages/excalidraw/components/Modal.tsx b/packages/excalidraw/components/Modal.tsx
new file mode 100644
index 0000000..e8fff19
--- /dev/null
+++ b/packages/excalidraw/components/Modal.tsx
@@ -0,0 +1,65 @@
+import "./Modal.scss";
+
+import { createPortal } from "react-dom";
+import clsx from "clsx";
+import { KEYS } from "../keys";
+import type { AppState } from "../types";
+import { useCreatePortalContainer } from "../hooks/useCreatePortalContainer";
+import { useRef } from "react";
+
+export const Modal: React.FC<{
+  className?: string;
+  children: React.ReactNode;
+  maxWidth?: number;
+  onCloseRequest(): void;
+  labelledBy: string;
+  theme?: AppState["theme"];
+  closeOnClickOutside?: boolean;
+}> = (props) => {
+  const { closeOnClickOutside = true } = props;
+  const modalRoot = useCreatePortalContainer({
+    className: "excalidraw-modal-container",
+  });
+
+  const animationsDisabledRef = useRef(
+    document.body.classList.contains("excalidraw-animations-disabled"),
+  );
+
+  if (!modalRoot) {
+    return null;
+  }
+
+  const handleKeydown = (event: React.KeyboardEvent) => {
+    if (event.key === KEYS.ESCAPE) {
+      event.nativeEvent.stopImmediatePropagation();
+      event.stopPropagation();
+      props.onCloseRequest();
+    }
+  };
+
+  return createPortal(
+    <div
+      className={clsx("Modal", props.className, {
+        "animations-disabled": animationsDisabledRef.current,
+      })}
+      role="dialog"
+      aria-modal="true"
+      onKeyDown={handleKeydown}
+      aria-labelledby={props.labelledBy}
+      data-prevent-outside-click
+    >
+      <div
+        className="Modal__background"
+        onClick={closeOnClickOutside ? props.onCloseRequest : undefined}
+      />
+      <div
+        className="Modal__content"
+        style={{ "--max-width": `${props.maxWidth}px` }}
+        tabIndex={0}
+      >
+        {props.children}
+      </div>
+    </div>,
+    modalRoot,
+  );
+};
-- 
cgit v1.2.3

