Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3662,7 +3662,13 @@ export class PresentationEditor extends EventEmitter {
// Keep selection visible when context menu (SlashMenu) is open
const slashMenuOpen = activeEditor?.state ? !!SlashMenuPluginKey.getState(activeEditor.state)?.open : false;

if (!hasFocus && !slashMenuOpen) {
// Keep selection visible when focus is on editor UI surfaces (toolbar, dropdowns).
// Naive-UI portals dropdown content under .v-binder-follower-content at <body> level,
// so it won't be inside [data-editor-ui-surface]. Check both.
const activeEl = document.activeElement;
const isOnEditorUi = !!(activeEl as Element)?.closest?.('[data-editor-ui-surface], .v-binder-follower-content');

if (!hasFocus && !slashMenuOpen && !isOnEditorUi) {
try {
this.#clearSelectedFieldAnnotationClass();
this.#localSelectionLayer.innerHTML = '';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { test, expect } from '../../fixtures/superdoc.js';

test.use({ config: { hideSelection: false } });

test('@behavior SD-1905 selection highlight preserved when focus moves to editor UI surface', async ({ superdoc }) => {
await superdoc.type('Select this text then open dropdown');
await superdoc.waitForStable();

// Select all text via keyboard shortcut
await superdoc.selectAll();
await superdoc.waitForStable();

// Verify selection overlay is rendered
const overlayChildCount = await superdoc.page.evaluate(() => {
const overlay = document.querySelector('.presentation-editor__selection-layer--local');
return overlay ? overlay.children.length : -1;
});
expect(overlayChildCount).toBeGreaterThan(0);

await superdoc.screenshot('sd-1905-selection-before-ui-focus');

// Simulate focus moving to an editor UI surface (e.g. toolbar dropdown).
// This is what happens when a user clicks a toolbar dropdown — focus leaves
// the ProseMirror editor and moves to a UI element marked as editor UI.
await superdoc.page.evaluate(() => {
const btn = document.createElement('button');
btn.setAttribute('data-editor-ui-surface', '');
btn.textContent = 'Fake toolbar button';
btn.id = 'sd-1905-test-ui-surface';
document.body.appendChild(btn);
btn.focus();
});
await superdoc.waitForStable();

// Selection overlay should still be visible after focus moved to UI surface
const overlayAfterUiFocus = await superdoc.page.evaluate(() => {
const overlay = document.querySelector('.presentation-editor__selection-layer--local');
return overlay ? overlay.children.length : -1;
});
expect(overlayAfterUiFocus).toBeGreaterThan(0);

await superdoc.screenshot('sd-1905-selection-with-ui-surface-focused');

// Clean up test element
await superdoc.page.evaluate(() => {
document.getElementById('sd-1905-test-ui-surface')?.remove();
});
});
Loading