From 377fa9a6b892dfa3eb745dbb4864f17562b86b4d Mon Sep 17 00:00:00 2001 From: Matthew Connelly Date: Wed, 3 Jun 2026 15:30:26 -0400 Subject: [PATCH] fix: prevent focus stealing from external contenteditable editors (SD-3365) SuperDoc's PresentationInputBridge was intercepting keyboard events from external TipTap/ProseMirror editors on the same page. Now checks if events originate from a contenteditable outside SuperDoc's DOM tree before intercepting. Co-Authored-By: Claude Opus 4.5 --- .../input/PresentationInputBridge.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/super-editor/src/editors/v1/core/presentation-editor/input/PresentationInputBridge.ts b/packages/super-editor/src/editors/v1/core/presentation-editor/input/PresentationInputBridge.ts index 41f54261d0..6c0f667072 100644 --- a/packages/super-editor/src/editors/v1/core/presentation-editor/input/PresentationInputBridge.ts +++ b/packages/super-editor/src/editors/v1/core/presentation-editor/input/PresentationInputBridge.ts @@ -299,6 +299,18 @@ export class PresentationInputBridge { : originNode?.parentElement instanceof HTMLElement ? originNode.parentElement : null; + + // Skip events from external contenteditable elements (e.g., other TipTap/ProseMirror editors). + // If the event target is in a contenteditable that's not part of our editor, don't intercept. + const originContentEditable = originElement?.closest?.('[contenteditable="true"]') as HTMLElement | null; + if (originContentEditable) { + const targetDom = this.#getTargetDom?.(); + const targetRoot = targetDom?.closest?.('.presentation-editor') ?? targetDom?.parentElement; + if (targetRoot && !targetRoot.contains(originContentEditable)) { + return null; + } + } + const staleEditorTarget = originElement?.closest?.('.ProseMirror[contenteditable="true"]') as HTMLElement | null; if (!staleEditorTarget || staleEditorTarget === activeTarget) {