Skip to content

Commit 2987fc4

Browse files
npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6wtellaho
andcommitted
fix(composer): make formatting sub-toolbar tooltips click-through
The formatting sub-toolbar (Bold/Italic/lists/Quote) rendered a bare TooltipContent that still blocked the message textarea floating beneath it. These are raw <button>s with custom active styling, not the shared Button, so bake pointer-events-none onto that one TooltipContent rather than swap in ComposerIconButton. Content only — the trigger keeps pointer/focus (WCAG content-on-hover-or-focus). Adds an e2e case opening the formatting toolbar and asserting the Bold tooltip is click-through. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Co-authored-by: npub1223z34h <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
1 parent eb05787 commit 2987fc4

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

desktop/src/features/messages/ui/FormattingToolbar.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,14 @@ export const FormattingToolbar = React.memo(function FormattingToolbar({
291291
<item.icon className="h-4 w-4" />
292292
</button>
293293
</TooltipTrigger>
294-
<TooltipContent>
294+
{/* pointer-events-none keeps these label tooltips click-through so
295+
they don't block the message textarea floating beneath them,
296+
matching ComposerIconButton. Content only — the trigger button
297+
keeps its pointer/focus behavior (WCAG content-on-hover-or-focus).
298+
These formatting buttons are raw <button>s with custom active
299+
styling, so we apply the override here rather than swap in
300+
ComposerIconButton. */}
301+
<TooltipContent className="pointer-events-none">
295302
{"shortcut" in item
296303
? `${item.label} (${item.shortcut})`
297304
: item.label}

desktop/tests/e2e/screenshot-tooltip-pointer-events.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,27 @@ test("composer tooltip is visible but click-through (pointer-events:none)", asyn
4343
await page.keyboard.type("clickthrough-ok");
4444
await expect(editor).toContainText("clickthrough-ok");
4545
});
46+
47+
test("formatting sub-toolbar tooltip is visible but click-through (pointer-events:none)", async ({
48+
page,
49+
}) => {
50+
await page.goto("/");
51+
await page.getByTestId("channel-general").click();
52+
await expect(page.getByTestId("chat-title")).toHaveText("general");
53+
54+
// Open the formatting sub-toolbar (Bold / Italic / lists / Quote …).
55+
await page.getByRole("button", { name: "Toggle formatting" }).first().click();
56+
57+
// Hover a formatting icon button to surface its label tooltip.
58+
const bold = page.getByRole("button", { name: "Bold" });
59+
await expect(bold).toBeVisible();
60+
await bold.hover();
61+
62+
// Tooltip text is "<label> (<shortcut>)" for items that carry a shortcut.
63+
const tip = page.getByRole("tooltip", { name: "Bold (⌘B)" });
64+
await expect(tip).toBeVisible();
65+
66+
// Money check: the sub-toolbar tooltip popup must be click-through too.
67+
const pe = await tip.evaluate((el) => getComputedStyle(el).pointerEvents);
68+
expect(pe).toBe("none");
69+
});

0 commit comments

Comments
 (0)