fix: restore popup predictions on Reddit/Lexical contenteditable#274
Merged
bartekplus merged 4 commits intomasterfrom Mar 6, 2026
Merged
fix: restore popup predictions on Reddit/Lexical contenteditable#274bartekplus merged 4 commits intomasterfrom
bartekplus merged 4 commits intomasterfrom
Conversation
126b4e4 to
551c532
Compare
Three issues prevented the suggestion popup from appearing on Reddit's Lexical-based editor when typing a single character that triggers auto-capitalization: 1. Premature input event cancels fallback observer Lexical can fire the input event before its DOM reconciliation produces the actual text mutation. shouldDeferContentEditableInputToFallback now defers the input when the text hasn't changed yet but the fallback is still inside its mutation-wait window. 2. Failed grammar edit corrupts selection state When the grammar rule dispatches insertReplacementText beforeinput, ContentEditableAdapter.replaceTextByOffsets expands the selection to cover the replacement range. If Lexical preventDefault()s without mutating the DOM, the non-collapsed selection is left behind, causing resolveEditableCursorContext to see empty beforeCursor and afterCursor. The original selection anchors are now restored when the host prevents the edit without changing text. 3. Prediction uses lowercase text after blocked grammar edit When the grammar edit (e.g. capitalize w->W) cannot be applied to the DOM, processEntryAfterEdit now applies the intended text transformation and sends the prediction request directly with the capitalized text, bypassing the corrupted cursor-context resolution.
551c532 to
a540b4e
Compare
Pressing Enter in a contenteditable element (e.g. CKEditor) always moves the caret to a new block, making existing predictions invalid. Previously the popup lingered until the fallback reconcile timer fired (~140ms) because: 1. shouldDismissSuggestionsOnKeydown did not include 'Enter' 2. selectionchange fired but reconcileEntrySelection skipped the context check (lastKeydownKey was 'Enter', not null) Fix: in onElementKeyDown, after the standard dismissal check, add an explicit guard that calls dismissEntry whenever Enter is pressed on a contenteditable and was not consumed by autocomplete. The insert- fallback path still runs so that predictions for the new line are scheduled normally. Add E2E regression test: CKEditor popup dismisses immediately when Enter is pressed. Also register the new behavior in coverage-matrix and coverage-baseline-ids.
…nts on selectionchange
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The suggestion popup did not appear on Reddit's Lexical-based editor when typing a character that triggers auto-capitalization (e.g. typing "p" → capitalized to "P"). Without the `capitalizeSentenceStart` grammar rule enabled, the popup worked fine.
Root Causes
1. Premature input event cancels fallback observer
Lexical fires the `input` event before its DOM reconciliation actually produces the text mutation. `shouldDeferContentEditableInputToFallback` now defers the input when text hasn't changed yet but the fallback is still inside its mutation-wait window.
2. Failed grammar edit corrupts selection state
When the grammar rule dispatches `insertReplacementText` `beforeinput`, `ContentEditableAdapter.replaceTextByOffsets` expands the selection to cover the replacement range `[0,1]`. If Lexical `preventDefault()`s without mutating the DOM, the non-collapsed selection is left behind — causing `resolveEditableCursorContext` to see empty `beforeCursor` and `afterCursor`. The original selection anchors are now restored when the host prevents the edit without changing text.
3. Prediction uses lowercase text after blocked grammar edit
When the grammar edit (e.g. capitalize w→W) cannot be applied to the DOM, `processEntryAfterEdit` now applies the intended text transformation and sends the prediction request directly with the capitalized text.
Testing