diff --git a/packages/core/src/extensions/FormattingToolbar/FormattingToolbar.ts b/packages/core/src/extensions/FormattingToolbar/FormattingToolbar.ts index b09a8385e9..8ab1d52b0a 100644 --- a/packages/core/src/extensions/FormattingToolbar/FormattingToolbar.ts +++ b/packages/core/src/extensions/FormattingToolbar/FormattingToolbar.ts @@ -88,7 +88,13 @@ export const FormattingToolbarExtension = createExtension(({ editor }) => { if (preventShowWhileMouseDown || preventShowWhileDragging) { return; } - store.setState(shouldShow()); + // Focus that comes back into the editor's UI rather than its + // content (e.g. a click on the drag handle) is not about the + // selection: showing the toolbar then would put it over the menu + // the UI opens. + if (editor.isFocused()) { + store.setState(shouldShow()); + } }, { includeEditorUI: true }, ); diff --git a/tests/src/end-to-end/draghandle/draghandle.test.tsx b/tests/src/end-to-end/draghandle/draghandle.test.tsx index 7b1b53c1d8..d8d6c9c56a 100644 --- a/tests/src/end-to-end/draghandle/draghandle.test.tsx +++ b/tests/src/end-to-end/draghandle/draghandle.test.tsx @@ -27,7 +27,7 @@ import { waitForSelector, waitForSelectorDetached, } from "../../utils/editor.js"; -import { moveMouseOverElement } from "../../utils/mouse.js"; +import { clickAt, getRect, moveMouseOverElement } from "../../utils/mouse.js"; import { executeSlashCommand } from "../../utils/slashmenu.js"; describe("Check Draghandle functionality", () => { @@ -237,4 +237,35 @@ describe("Check Draghandle functionality", () => { await compareDocToSnapshot("draghandlenesteddelete"); }); + + // #3186: the selection survives a blur, so focus coming back into the + // editor's UI (the drag handle) must not show the toolbar over the menu. + test("Clicking the drag handle while the editor is blurred keeps the formatting toolbar hidden", async () => { + await userEvent.keyboard("First paragraph"); + await userEvent.keyboard("{Enter}"); + await userEvent.keyboard("Second paragraph"); + + // Select a word: the formatting toolbar shows. + const word = getRect(page.getByText("First paragraph").element()); + await clickAt(word.x + 10, word.y + word.height / 2, 2); + await waitForSelector(".bn-formatting-toolbar"); + + // Focus something outside the editor: the toolbar hides. + const outside = document.createElement("button"); + outside.textContent = "Outside"; + document.body.append(outside); + try { + await userEvent.click(outside); + await waitForSelectorDetached(".bn-formatting-toolbar"); + + const second = page.getByText("Second paragraph").element(); + await moveMouseOverElement(second); + await userEvent.click(await waitForSelector(DRAG_HANDLE_SELECTOR)); + await waitForSelector(DRAG_HANDLE_MENU_SELECTOR); + await sleep(100); + expect(document.querySelector(".bn-formatting-toolbar")).toBeNull(); + } finally { + outside.remove(); + } + }); });