Skip to content

Commit 7548c52

Browse files
committed
refactor(toolbar): use labelAttr for generic activation and add tests (#2515)
Replace hardcoded setFontSize/setFontFamily check with item.labelAttr for flexible dropdown activation when editor is unfocused. Add unit tests for the activation path and a behavior test for the overflow menu font selection scenario.
1 parent cbddd43 commit 7548c52

3 files changed

Lines changed: 95 additions & 5 deletions

File tree

packages/super-editor/src/components/toolbar/super-toolbar.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,11 +1138,9 @@ export class SuperToolbar extends EventEmitter {
11381138
// until the next selection update (after the user clicks into the editor).
11391139
if (!wasFocused && isMarkToggle) {
11401140
this.pendingMarkCommands.push({ command, argument, item });
1141-
const shouldPassActivationAttrs = item?.command === 'setFontSize' || item?.command === 'setFontFamily';
1142-
if (shouldPassActivationAttrs) {
1143-
const itemName = item?.name?.value;
1144-
const activationAttrs = argument && itemName ? { [itemName]: argument } : {};
1145-
item?.activate?.(activationAttrs);
1141+
const labelAttr = item?.labelAttr?.value;
1142+
if (labelAttr && argument) {
1143+
item?.activate?.({ [labelAttr]: argument });
11461144
} else {
11471145
item?.activate?.();
11481146
}

packages/super-editor/src/tests/toolbar/super-toolbar-commands.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,43 @@ describe('SuperToolbar sticky mark persistence', () => {
280280
expect(throwingSetFontSize).not.toHaveBeenCalled();
281281
expect(toolbar.pendingMarkCommands).toHaveLength(0);
282282
});
283+
284+
it('passes activation attrs to activate() for setFontSize when editor is unfocused', () => {
285+
mockEditor.view.hasFocus = vi.fn(() => false);
286+
const item = {
287+
command: 'setFontSize',
288+
name: { value: 'fontSize' },
289+
labelAttr: { value: 'fontSize' },
290+
activate: vi.fn(),
291+
};
292+
293+
toolbar.emitCommand({ item, argument: '24pt' });
294+
295+
expect(item.activate).toHaveBeenCalledWith({ fontSize: '24pt' });
296+
});
297+
298+
it('passes activation attrs to activate() for setFontFamily when editor is unfocused', () => {
299+
mockEditor.view.hasFocus = vi.fn(() => false);
300+
const item = {
301+
command: 'setFontFamily',
302+
name: { value: 'fontFamily' },
303+
labelAttr: { value: 'fontFamily' },
304+
activate: vi.fn(),
305+
};
306+
307+
toolbar.emitCommand({ item, argument: 'Arial, sans-serif' });
308+
309+
expect(item.activate).toHaveBeenCalledWith({ fontFamily: 'Arial, sans-serif' });
310+
});
311+
312+
it('calls activate() without attrs for non-font mark toggles when editor is unfocused', () => {
313+
mockEditor.view.hasFocus = vi.fn(() => false);
314+
const item = { command: 'toggleBold', name: { value: 'bold' }, activate: vi.fn() };
315+
316+
toolbar.emitCommand({ item });
317+
318+
expect(item.activate).toHaveBeenCalledWith();
319+
});
283320
});
284321

285322
describe('SuperToolbar error handling for command failures', () => {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { test, expect } from '../../fixtures/superdoc.js';
2+
3+
test.use({ config: { toolbar: 'full' } });
4+
5+
test('font family applies and label updates when selected from overflow menu', async ({ superdoc }) => {
6+
await superdoc.type('Hello world');
7+
await superdoc.waitForStable();
8+
9+
// Select the text
10+
const pos = await superdoc.findTextPos('Hello world');
11+
await superdoc.setTextSelection(pos, pos + 'Hello world'.length);
12+
await superdoc.waitForStable();
13+
14+
// Shrink viewport so toolbar items overflow
15+
await superdoc.page.setViewportSize({ width: 400, height: 600 });
16+
await superdoc.waitForStable();
17+
18+
// Skip if overflow menu doesn't appear
19+
const overflowBtn = superdoc.page.locator('[data-item="btn-overflow"]');
20+
if (!(await overflowBtn.isVisible())) {
21+
test.skip();
22+
}
23+
24+
// Open overflow menu
25+
await overflowBtn.click();
26+
await superdoc.page.locator('.overflow-menu_items').waitFor({ state: 'visible', timeout: 5000 });
27+
await superdoc.waitForStable();
28+
29+
// Select Georgia from font family dropdown
30+
await superdoc.page.locator('[data-item="btn-fontFamily"]').click();
31+
await superdoc.waitForStable();
32+
await superdoc.page.locator('[data-item="btn-fontFamily-option"]').filter({ hasText: 'Georgia' }).click();
33+
await superdoc.waitForStable();
34+
35+
// Click into the editor to trigger pending command execution
36+
await superdoc.page
37+
.locator('.presentation-editor__viewport')
38+
.first()
39+
.click({ position: { x: 50, y: 50 } });
40+
await superdoc.waitForStable();
41+
42+
// Verify the font was applied to the text
43+
await superdoc.assertTextMarkAttrs('Hello world', 'textStyle', { fontFamily: 'Georgia, serif' });
44+
45+
// Re-select text and check the toolbar label updated
46+
const newPos = await superdoc.findTextPos('Hello world');
47+
await superdoc.setTextSelection(newPos, newPos + 'Hello world'.length);
48+
await superdoc.waitForStable();
49+
50+
// Restore viewport to see font family in main toolbar
51+
await superdoc.page.setViewportSize({ width: 1600, height: 1200 });
52+
await superdoc.waitForStable();
53+
54+
await expect(superdoc.page.locator('[data-item="btn-fontFamily"]')).toContainText('Georgia');
55+
});

0 commit comments

Comments
 (0)