Skip to content

fix(desktop): keep caret after agent mention in WebKitGTK - #5235

Closed
kchung wants to merge 2 commits into
block:mainfrom
kchung:fix/mention-cursor-position
Closed

fix(desktop): keep caret after agent mention in WebKitGTK#5235
kchung wants to merge 2 commits into
block:mainfrom
kchung:fix/mention-cursor-position

Conversation

@kchung

@kchung kchung commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Problem

After typing @ and selecting a person/agent in the composer, the text caret lands in the middle of the mention chip (e.g. F|izz) instead of after it, on the Buzz Desktop app (Tauri/WebKitGTK on Linux).

Reported by Kevin Chung with a screenshot showing the caret between F and izz.

Root cause

Agent mentions are rendered via inline decorations (mentionHighlightExtension.ts): the literal @ gets a .agent-mention-at-hidden class and the name gets a .mention-chip.agent-mention-highlight chip whose left padding holds the bot-icon ::before.

.agent-mention-at-hidden collapsed the @ with display: inline-block; width: 0; overflow: hidden. WebKitGTK mis-measures the caret rect for a text position adjacent to a collapsed inline-block box and snaps the caret to the box's content origin. Because the following chip carries left padding for its icon, the caret rendered visually inside the chip — even though the ProseMirror selection was correctly positioned after the whole @Fizz mention (verified in useRichTextEditor.replacePlainTextRange / useMentions.insertMention: the model caret is correct).

Chromium positions the caret correctly with either rule, so the bug is WebKitGTK-specific — the same engine-difference class as the emoji-loupe issue (#5229).

Fix

Collapse the @ as plain inline text via display: inline; font-size: 0 instead of a zero-width inline-block. This keeps zero advance width (no layout shift; the chip's left edge is unchanged — verified at x=292px in both variants) while leaving the caret on the normal inline-text path, which WebKit positions correctly.

Single-file, CSS-only, defensive change in desktop/src/shared/styles/globals/markdown.css.

Validation

  • Full local gate green at the pushed commit: tsc clean, biome check clean on the changed file, 4535/4535 unit tests pass.
  • Confirmed in a Chromium box-model harness that both the old and new rules collapse the @ to zero width and leave the chip position identical (no regression / no visible effect in Chromium).

Honest caveat

I can't run WebKitGTK locally (agent-browser only offers Chromium here), so I couldn't reproduce the actual mid-chip caret in-engine. The fix targets the documented WebKit caret-snapping behavior around collapsed inline-block boxes and is verified to be a no-op layout change in Chromium. Please confirm on a real Buzz Desktop build that the caret now lands after the mention.

The hidden "@" prefix of an agent mention (`.agent-mention-at-hidden`)
was collapsed with `display: inline-block; width: 0`. WebKitGTK — the
Tauri webview on Linux — mis-measures the caret rect for a text
position adjacent to a collapsed inline-block box and snaps the caret
to the box's content origin. Because the following agent chip carries
left padding for its bot icon, the caret rendered visually *inside* the
chip (e.g. "F|izz") even though the ProseMirror selection was correctly
positioned after the whole mention.

Collapse the "@" as plain inline text via `display: inline; font-size: 0`
instead. This keeps zero advance width (no layout shift; the chip's left
edge is unchanged) while leaving the caret on the normal inline-text
path, which WebKit positions correctly. Chromium already rendered the
caret correctly with either rule, so this is a defensive engine-agnostic
change with no visible effect there.

Applies to the message composer, which carries the `message-markdown`
class so the agent-mention styles apply while editing.

Co-authored-by: Kevin Chung <chung@squareup.com>
Signed-off-by: Kevin Chung <chung@squareup.com>
@kchung

kchung commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Before / after — caret placement

mention-caret-fix

Illustration of the reported symptom vs. the fix. Underlying text is @Fizz ; the @ is hidden by a decoration.

  • Before (.agent-mention-at-hidden = display:inline-block; width:0): WebKitGTK snaps the caret to the collapsed inline-block box origin → renders visually inside the padded chip (F|izz).
  • After (display:inline; font-size:0): no inline-block box; the caret stays on the normal inline-text path → lands after the mention (Fizz|).

Verified in a Chromium box-model harness that both rules collapse the @ to zero advance width and leave the chip left edge unchanged (x=292px), so no layout shift. Chromium already positioned the caret correctly, so this is a no-op there and targets the WebKitGTK behavior specifically.

Regression origin

This is a regression. .agent-mention-at-hidden was introduced in #942 as color: transparent; font-size: 0; line-height: 0, then rewritten to the zero-width inline-block form in #1052 (fix(desktop): restore timeline zoom via rem tokens + chat-as-base type scale, 2026-06-16). That inline-block box is what WebKitGTK's caret code snaps to. This fix restores the original font-size: 0 collapse.

Screenshot is committed to the PR branch (pr-5235--*.png) purely for rendering here — drop it before merge.

Co-authored-by: Kevin Chung <chung@squareup.com>
Signed-off-by: Kevin Chung <chung@squareup.com>
@kchung

kchung commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Closing per Kevin Chung's request — another contributor is picking up this work. Note for whoever takes over: the caret bug is a regression from #1052, which rewrote .agent-mention-at-hidden from 'font-size:0' to a zero-width 'display:inline-block; width:0' that WebKitGTK snaps the caret onto. Reverting to the inline font-size:0 collapse fixes it.

@kchung kchung closed this Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant