Skip to content

Place the caret before an inline decorator when Gecko drops the selection - #1204

Open
lyubomir-bozhinov wants to merge 1 commit into
basecamp:mainfrom
lyubomir-bozhinov:fix/1149-caret-before-inline-decorator
Open

Place the caret before an inline decorator when Gecko drops the selection#1204
lyubomir-bozhinov wants to merge 1 commit into
basecamp:mainfrom
lyubomir-bozhinov:fix/1149-caret-before-inline-decorator

Conversation

@lyubomir-bozhinov

@lyubomir-bozhinov lyubomir-bozhinov commented Jul 17, 2026

Copy link
Copy Markdown

Fixes #1149.

The bug

With a mention at the start of a paragraph, clicking just before it and typing did nothing in Firefox. The keystrokes were silently dropped.

Why

The click leaves the editor with no selection at all, so there is nothing for typing to act on. document.caretPositionFromPoint() at the same coordinates explains why:

resolves to resulting selection
Blink P @0 — the paragraph itself RangeSelection, element point, offset 0
Gecko #text:"Zacharias" @0 — inside the mention null (rangeCount: 0)

Gecko descends into the decorator's contenteditable="false" subtree. That text node is rendered by the decorator and is not part of the editor state, so no selection point maps to it and Lexical ends up with none. There is no text node before the mention to hold a caret, so nothing recovers it.

The fix

CLICK_COMMAND already handles clicks that land on a decorator. This adds the neighbouring case: when a click leaves us with no selection and the clicked point resolves inside an inline decorator, place the caret at that decorator's index in its parent — the same element point Blink produces natively.

The guard is $getSelection() !== null, so Blink and WebKit never reach this path.

Scope

Deliberately limited to inline decorators (mentions), which is the reported bug. Block attachments (e.g. an uploaded file) have an analogous Gecko caret-drop at their vertical boundary, but the correct before/after placement there depends on the click's Y position rather than X, so it is a separate change rather than something to fold in here. The isInline() guard makes the boundary explicit, and the method is named #placeCaretBeforeInlineDecorator because the null-selection case only ever occurs on the leading edge (clicking after an inline decorator resolves natively in Gecko).

Tests

test/browser/tests/prompts/typing_before_mention.test.js, driven with a real page.mouse.click():

  • clicking before a leading mention places the caret before it — fails on Firefox without this change, passes with it
  • clicking after a trailing mention places the caret after it — guards against the new path hijacking clicks Gecko already handles

Both assert the mention still exists (toHaveCount(1)) so the ordering check can't pass vacuously. Verified on Chromium, Firefox and WebKit. prompts/ and attachments/ are green on Firefox; yarn lint and yarn test are clean.

@lyubomir-bozhinov
lyubomir-bozhinov force-pushed the fix/1149-caret-before-inline-decorator branch from 425a956 to 5b51fb1 Compare July 17, 2026 19:01
@lyubomir-bozhinov
lyubomir-bozhinov marked this pull request as ready for review July 17, 2026 20:06
Copilot AI review requested due to automatic review settings July 17, 2026 20:06

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Firefox/Gecko-specific edge case where clicking immediately before a leading inline decorator (mention) leaves Lexical with no selection, causing subsequent typing to be dropped. The change detects the null-selection + inline-decorator-from-point condition and explicitly places the caret at the decorator’s index in its parent, matching the element-point behavior seen in Blink.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Changes:

  • Extend CLICK_COMMAND handling to recover from Gecko’s “null selection” by placing the caret before an inline decorator found at the click point.
  • Add a Playwright regression test covering typing before a leading mention on Firefox, plus a guard test for clicking after a trailing mention.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/editor/selection.js Adds a null-selection recovery path for Gecko clicks that resolve inside inline decorator DOM, placing the caret before the decorator.
test/browser/tests/prompts/typing_before_mention.test.js Adds browser-level coverage to reproduce and prevent regressions for typing adjacent to mentions (especially Firefox).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@lyubomir-bozhinov lyubomir-bozhinov changed the title Place the caret beside an inline decorator when Gecko drops the selection Place the caret before an inline decorator when Gecko drops the selection Jul 18, 2026
…tion

Clicking just before a mention that starts a paragraph left the editor
with no selection in Firefox, so anything typed afterwards was silently
dropped.

Gecko resolves such a click to a text node inside the decorator's
contenteditable="false" subtree. That node is not part of the editor
state, so no selection point maps to it and Lexical ends up with none.
Blink resolves the same click to the paragraph itself at offset 0.

Place the caret before the decorator ourselves when a click leaves us
without a selection, which matches what Blink does natively.
Copilot AI review requested due to automatic review settings August 1, 2026 19:43
@lyubomir-bozhinov
lyubomir-bozhinov force-pushed the fix/1149-caret-before-inline-decorator branch from 5b51fb1 to 88df0d5 Compare August 1, 2026 19:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

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.

[Firefox] Cannot type before a mention.

2 participants