Skip to content

fix: add CKEditor-5 host editor bridge to fix text handling bugs#357

Merged
bartekplus merged 2 commits intomasterfrom
fix/ckeditor5-text-handling-356
Apr 4, 2026
Merged

fix: add CKEditor-5 host editor bridge to fix text handling bugs#357
bartekplus merged 2 commits intomasterfrom
fix/ckeditor5-text-handling-356

Conversation

@bartekplus
Copy link
Copy Markdown
Owner

Summary

  • Adds CKEditor-5 as a recognized host editor (same pattern as CodeMirror) by detecting element.ckeditorInstance and routing text edits through CKEditor-5's model API
  • Routes grammar edits and suggestion acceptance through the host editor session, with fallback offset translation for BR-separated lines
  • Maps between DOM text offsets and CKEditor-5 model offsets, correctly handling softBreak elements, zero-width filler characters, and text attribute preservation (bold, italic)

Fixes #356

Test plan

  • Unit tests: 1620 pass, 0 fail (12 new tests added)
  • bun run check passes (lint, format, typecheck)
  • E2E verified on CKEditor-5 feature-rich demo:
    • Type before 'T' in existing text — no duplicate characters
    • Shift+Enter + type + grammar capitalize — cursor stays on correct line
    • Type "This is a test. " — cursor stays in paragraph
    • Shift+Enter + type + accept suggestion — suggestion placed on correct line, softBreak preserved
    • Edit inside bold text + accept suggestion — bold formatting preserved
    • Accept suggestion on line before softBreak — cursor stays on same line, break not eaten

🤖 Generated with Claude Code

bartekplus and others added 2 commits April 4, 2026 11:21
CKEditor-5 manages its own model and doesn't correctly handle synthetic
beforeinput events dispatched by FluentTyper. This caused duplicate
character insertion, cursor jumping across lines, suggestions landing at
wrong positions, and lost formatting when accepting suggestions.

The fix adds CKEditor-5 as a recognized host editor (same pattern as
CodeMirror) by detecting `element.ckeditorInstance` and routing grammar
edits and suggestion acceptance through CKEditor-5's model API. Key
details:

- Detect CKEditor-5 via `ckeditorInstance` property on the editable element
- Map between DOM text offsets and CKEditor-5 model offsets, accounting
  for softBreak elements that occupy 1 model unit but 0 text characters
- Use "end" endpoint for range-end and cursor offsets so replacements at
  softBreak boundaries don't consume the break element
- Strip zero-width filler characters when matching BR-separated line
  context against the host's full-block text
- Preserve text attributes (bold, italic) when inserting replacement text
- Route grammar edits through the host session, with fallback offset
  translation for BR-separated lines within a single model block

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix #1: Use "end" cursor endpoint only when cursor is at the
  replacement boundary; use "start" when cursor is past it (avoids
  wrong mapping for degenerate softBreak-at-offset-0 edge case)
- Fix #2: Count filler characters per-position instead of using a
  global total, so interspersed fillers produce correct clean offsets
- Fix #3: Add else clause in extractModelBlockMapping for nodes
  without an `is()` method (exotic 3rd-party CKEditor plugins)
- Fix #4: Filter out softBreaks inside the deleted range before
  shifting survivors in updatedSoftBreakOffsets
- Fix #5: Cache findCKEditor5Instance results in a WeakMap to avoid
  re-walking the ancestor chain on every keystroke

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartekplus bartekplus merged commit 3a875ab into master Apr 4, 2026
8 checks passed
@bartekplus bartekplus deleted the fix/ckeditor5-text-handling-356 branch April 4, 2026 09:35
@DustinReynoldsPE
Copy link
Copy Markdown

Thank you so much!!!

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.

[Bug]: Odd text handling with ckeditor-5

2 participants