diff --git a/web/src/components/app/advisor/AdvisorCard.tsx b/web/src/components/app/advisor/AdvisorCard.tsx
index 69790e2c8..6e59a6547 100644
--- a/web/src/components/app/advisor/AdvisorCard.tsx
+++ b/web/src/components/app/advisor/AdvisorCard.tsx
@@ -39,7 +39,7 @@ import {
import { useConfirm } from "@/hooks/context/confirm";
import {
useAdvisorFeedback,
- useClickOutsideAdvisorFinding,
+ useDismissAdvisorFinding,
useSnoozeAdvisorFinding,
useUndoAdvisorFinding,
} from "@/lib/api/hooks/app/advisor/useAdvisor";
@@ -63,7 +63,7 @@ export default function AdvisorCard({ finding, onFix, compact = false, defaultOp
const confirm = useConfirm();
const snooze = useSnoozeAdvisorFinding();
- const dismiss = useClickOutsideAdvisorFinding();
+ const dismiss = useDismissAdvisorFinding();
const undo = useUndoAdvisorFinding();
const feedback = useAdvisorFeedback();
diff --git a/web/src/components/app/campaigns/sequences/ImageControls.tsx b/web/src/components/app/campaigns/sequences/ImageControls.tsx
index aaefc5625..05af1845e 100644
--- a/web/src/components/app/campaigns/sequences/ImageControls.tsx
+++ b/web/src/components/app/campaigns/sequences/ImageControls.tsx
@@ -59,20 +59,6 @@ export function ImageMenu({ editor }: { editor: Editor }) {
const del = useDeleteEmailImage();
const confirm = useConfirm();
- React.useEffect(() => {
- if (!open) return;
- const onKey = (e: KeyboardEvent) => {
- if (e.key !== "Escape") return;
- // The delete confirmation sits above this menu, so Escape belongs
- // to it first: only the innermost layer closes.
- if (document.querySelector("[role='alertdialog']")) return;
- e.stopPropagation();
- setOpen(false);
- };
- document.addEventListener("keydown", onKey, true);
- return () => document.removeEventListener("keydown", onKey, true);
- }, [open]);
-
const pick = async (files: FileList | File[] | null) => {
const file = Array.from(files ?? [])[0];
if (!file) return;
diff --git a/web/src/components/app/emails/import/MailboxImportsMenu.tsx b/web/src/components/app/emails/import/MailboxImportsMenu.tsx
index b519fb9f4..2de1c7528 100644
--- a/web/src/components/app/emails/import/MailboxImportsMenu.tsx
+++ b/web/src/components/app/emails/import/MailboxImportsMenu.tsx
@@ -11,7 +11,7 @@ import {
PopoverMenuTrigger,
} from "@/components/ui/popover-menu";
import useMailboxImports from "@/lib/api/hooks/app/emails/useMailboxImports";
-import { useClickOutsideMailboxImport } from "@/lib/api/hooks/app/emails/useMailboxImportActions";
+import { useDismissMailboxImport } from "@/lib/api/hooks/app/emails/useMailboxImportActions";
import { type MailboxImport } from "@/lib/api/models/app/emails/MailboxImport";
import { vendorLabel } from "@/lib/api/models/app/emails/MailboxSources";
import { useConfirm } from "@/hooks/context/confirm";
@@ -143,7 +143,7 @@ export default function MailboxImportsMenu() {
function ImportEntry({ job, onOpen }: { job: MailboxImport; onOpen: () => void }) {
const confirm = useConfirm();
- const dismiss = useClickOutsideMailboxImport();
+ const dismiss = useDismissMailboxImport();
const st = jobState(job);
const live = job.status === "running";
diff --git a/web/src/hooks/useClickOutside.test.tsx b/web/src/hooks/useClickOutside.test.tsx
index e8eaee8d5..e2ede53f2 100644
--- a/web/src/hooks/useClickOutside.test.tsx
+++ b/web/src/hooks/useClickOutside.test.tsx
@@ -85,6 +85,28 @@ describe("useClickOutside", () => {
document.removeEventListener("keydown", onKey);
});
+ it("leaves Escape to a confirm opened above it, and still takes it inside a modal", () => {
+ const { unmount } = render(
+ <>
+