Skip to content

Latest commit

 

History

History
1208 lines (982 loc) · 58.7 KB

File metadata and controls

1208 lines (982 loc) · 58.7 KB

MintedTextEditor — Development Plan

A best-in-class, fully custom-drawn Rich Text Editor for .NET MAUI (and future .NET platforms). All rendering is performed on a SkiaSharp canvas — zero native UI controls. Architecture mirrors KumikoUI: platform-independent core → swappable drawing backend → platform host.

Workflow: Each phase is implemented, reviewed, and committed to git before proceeding to the next.


Table of Contents


Phase 0 — Repository & Solution Scaffolding

Set up the repository, solution file, project structure, and build infrastructure mirroring the KumikoUI pattern.

Solution Structure

  • Create MintedTextEditor.sln with solution folders: src, tests, samples, [ Solution ], Build
  • Create Directory.Build.props with shared NuGet metadata (Authors, License, SourceLink, PackageIcon, README)
  • Create .gitignore (Visual Studio / .NET / macOS / JetBrains)
  • Create LICENSE (MIT)
  • Create placeholder README.md
  • Create images/ folder with logo placeholder

Projects

  • src/MintedTextEditor.Core/MintedTextEditor.Core.csprojnet10.0, platform-independent core library
  • src/MintedTextEditor.SkiaSharp/MintedTextEditor.SkiaSharp.csprojnet10.0, SkiaSharp drawing implementation, references Core
  • src/MintedTextEditor.Maui/MintedTextEditor.Maui.csproj — multi-targeted MAUI host (net10.0-android, net10.0-ios, net10.0-maccatalyst, net10.0-windows10.0.19041.0), references Core + SkiaSharp
  • tests/MintedTextEditor.Core.Tests/MintedTextEditor.Core.Tests.csprojnet10.0, xUnit + coverlet
  • samples/SampleApp.Maui/SampleApp.Maui.csproj — MAUI sample application

Initial Files

  • Create empty marker classes / namespaces so all projects compile
  • Verify dotnet build succeeds for the entire solution

Git

  • git init, initial commit with scaffolding

Phase 1 — Core Abstractions & Document Model

Define the platform-independent rendering abstractions and the rich-text document model that all higher layers build upon.

Drawing Abstractions (MintedTextEditor.Core/Rendering/)

  • IDrawingContext interface — mirrors KumikoUI pattern: DrawRect, FillRect, DrawRoundRect, FillRoundRect, DrawLine, DrawText, DrawTextInRect, MeasureText, GetFontMetrics, ClipRect, Save, Restore, Translate, DrawImage
  • Extended text drawing: DrawTextRun (draw a run of styled text at a position), MeasureTextRun
  • ITextShaper interface — for advanced text shaping (ligatures, complex scripts); simple pass-through default implementation
  • Primitives: EditorRect, EditorSize, EditorPoint, EditorColor, EditorPaint, EditorFont, EditorFontMetrics
  • Enums: TextAlignment, VerticalAlignment, PaintStyle
  • PaintCache — pooled/cached paint objects to avoid per-frame allocations

Document Model (MintedTextEditor.Core/Document/)

  • Document — root container; holds a list of Block elements
  • Block (abstract) — base for block-level elements (paragraph, heading, list item, table, horizontal rule)
  • Paragraph : Block — holds an InlineCollection (list of Inline elements)
  • Inline (abstract) — base for inline content
  • TextRun : Inline — a contiguous span of text with a single TextStyle
  • ImageInline : Inline — an inline image with source, alt text, width, height
  • HyperlinkInline : Inline — wraps child inlines with a URL and optional title
  • LineBreak : Inline — explicit line break within a paragraph
  • TextStyle — immutable value type: font family, font size, bold, italic, underline, strikethrough, subscript, superscript, text color, highlight color, baseline offset
  • ParagraphStyle — alignment (left/center/right/justify), indent level, line spacing, space before/after, list type (none/bullet/number), heading level (0=none, 1-6), text direction (LTR/RTL)
  • DocumentPosition — (blockIndex, inlineIndex, offset) for cursor addressing
  • TextRange — (start: DocumentPosition, end: DocumentPosition) for selections
  • Document change notifications: IDocumentChangeListener / DocumentChanged event

Document Manipulation (MintedTextEditor.Core/Document/)

  • DocumentEditor — stateless helper methods for safe document mutations:
    • InsertText(Document, DocumentPosition, string, TextStyle) → DocumentPosition
    • DeleteRange(Document, TextRange) → DocumentPosition
    • SplitBlock(Document, DocumentPosition) → DocumentPosition
    • MergeBlocks(Document, int blockIndex) → DocumentPosition
    • ApplyTextStyle(Document, TextRange, Action<TextStyle>) → void
    • ApplyParagraphStyle(Document, TextRange, Action<ParagraphStyle>) → void

Tests

  • Document creation and block manipulation tests
  • TextRun splitting and merging tests
  • DocumentEditor.InsertText / DeleteRange round-trip tests
  • DocumentPosition comparison and navigation tests
  • TextStyle immutability and equality tests

Git

  • Commit: "Phase 1 — Core abstractions & document model"

Phase 2 — Text Layout Engine & Basic Rendering

Build the layout engine that converts the document model into positioned visual lines, and render them using the drawing abstractions.

Text Layout (MintedTextEditor.Core/Layout/)

  • LayoutLine — a single visual line: list of LayoutRun items, y-offset, line height, baseline
  • LayoutRun — a positioned text segment: text, x-offset, width, associated TextRun reference, style
  • LayoutBlock — layout result for one Block: list of LayoutLine, total height, block index
  • DocumentLayout — full layout result: list of LayoutBlock, total document height, viewport width
  • TextLayoutEngine — performs word-wrapping and line-breaking:
    • Input: Document + viewport width + IDrawingContext (for measuring)
    • Output: DocumentLayout
    • Supports: word-wrap, character-wrap fallback for long words, respects paragraph indent levels
  • LayoutCache — caches layout results per block; invalidates selectively on edits

SkiaSharp Implementation (MintedTextEditor.SkiaSharp/)

  • SkiaDrawingContext : IDrawingContext, IDisposable — maps all drawing calls to SKCanvas, with per-frame paint/font caching (mirrors KumikoUI's SkiaDrawingContext)
  • DrawTextRun / MeasureTextRun implementation using SKFont and SKPaint

Document Renderer (MintedTextEditor.Core/Rendering/)

  • DocumentRenderer — traverses DocumentLayout and draws each run via IDrawingContext
    • Draws backgrounds (highlight colors)
    • Draws text runs with appropriate styles
    • Draws block decorations (list bullets/numbers, heading emphasis)
    • Handles vertical scrolling offset
    • Clips to viewport bounds

Tests

  • Layout engine: single-paragraph word-wrap tests
  • Layout engine: multi-paragraph layout tests
  • Layout engine: inline style boundary alignment tests
  • Layout cache invalidation tests

Git

  • Commit: "Phase 2 — Text layout engine & basic rendering"

Phase 3 — Caret, Cursor & Text Navigation

Implement the blinking caret, hit-testing from pixel coordinates to document positions, and keyboard/pointer navigation.

Hit Testing (MintedTextEditor.Core/Input/)

  • HitTestResult — (DocumentPosition, LayoutLine, LayoutRun, isAtLineEnd, isAfterLastBlock)
  • DocumentHitTester — given (x, y) and DocumentLayout, returns HitTestResult
    • Character-level hit testing within runs
    • Snap-to-nearest-character logic
    • Line-level hit testing for click-on-margin behavior

Caret (MintedTextEditor.Core/Editing/)

  • Caret — current DocumentPosition, preferred X for vertical navigation, blink state
  • CaretRenderer — draws the caret line at the correct pixel position using DocumentLayout
  • Caret blink timer integration (on/off cycle, reset on input)

Navigation (MintedTextEditor.Core/Editing/)

  • Arrow keys: left/right (character), up/down (visual line), maintaining preferred X
  • Word navigation: Ctrl/Cmd + Left/Right (jump by word boundary)
  • Line navigation: Home/End (line start/end)
  • Document navigation: Ctrl+Home / Ctrl+End
  • Page navigation: PageUp / PageDown (viewport-height steps)
  • Pointer click: single-click positions caret via hit testing
  • Ensure caret remains visible: auto-scroll viewport when caret moves beyond visible area

Input Abstractions (MintedTextEditor.Core/Input/)

  • EditorPointerEventArgs — (x, y, action, button, modifiers, clickCount, timestamp)
  • EditorKeyEventArgs — (key, character, modifiers, isKeyDown)
  • EditorKey enum — arrows, Home, End, PageUp, PageDown, Tab, Enter, Escape, Backspace, Delete, A-Z, etc.
  • InputAction enum — Pressed, Released, Moved, Scroll, DoubleTap, LongPress
  • InputModifiers [Flags] — None, Shift, Control, Alt, Meta
  • EditorInputController — central input dispatcher (mirrors KumikoUI's GridInputController)

Tests

  • Hit testing: click within a word returns correct position
  • Hit testing: click in margin snaps to line start/end
  • Navigation: arrow keys in single-line and multi-line scenarios
  • Navigation: word-jump boundaries
  • Navigation: Ctrl+Home / Ctrl+End

Git

  • Commit: "Phase 3 — Caret, cursor & text navigation"

Phase 4 — Text Selection

Extend the caret into a selection range with visual highlighting and keyboard/pointer selection gestures.

Selection Model (MintedTextEditor.Core/Editing/)

  • Selection — anchor position + active position (caret) forming a TextRange; supports zero-length (caret-only) and ranged selection
  • SelectionRenderer — draws selection highlight rectangles across multiple lines
  • Selection normalization: ordered start/end regardless of anchor vs. active direction

Selection Gestures

  • Shift + Arrow keys: extend selection character/line/word at a time
  • Shift + Home/End: extend selection to line boundaries
  • Shift + Ctrl+Home/End: extend to document start/end
  • Ctrl/Cmd + A: select all
  • Mouse/touch drag: click-and-drag to select a range
  • Double-click/tap: select word
  • Triple-click/tap: select paragraph/block
  • Shift + click: extend selection from anchor to click position

Selection Utilities

  • GetSelectedText(Document, TextRange) → string — extracts plain text from selection
  • GetSelectedDocument(Document, TextRange) → Document — extracts a sub-document (for rich copy)

Tests

  • Shift+arrow extends selection
  • Double-click selects word
  • Triple-click selects paragraph
  • Select-all returns entire document text
  • Drag selection across multiple blocks

Git

  • Commit: "Phase 4 — Text selection"

Phase 5 — Text Input & Basic Editing

Handle keyboard text entry, backspace, delete, Enter (paragraph split), and typed-over selections.

Text Entry (MintedTextEditor.Core/Editing/)

  • Character input: insert typed character at caret position
  • If selection is active, delete selection first, then insert
  • Backspace: delete character before caret (or delete selection)
  • Delete: delete character after caret (or delete selection)
  • Enter: split current block at caret position (DocumentEditor.SplitBlock)
  • Backspace at start of block: merge with previous block (DocumentEditor.MergeBlocks)
  • Delete at end of block: merge with next block
  • Tab key behavior (configurable: insert tab character, increase indent, or move focus)

Input Method / Keyboard Proxy (MintedTextEditor.Maui/)

  • Hidden KeyboardProxy overlay for keyboard capture — transparent 1×1 View focused on touch, sits above the SKCanvasView in a Grid
  • Platform-specific keyboard configuration (Android BaseInputConnection IME, iOS/Mac Catalyst UIKeyInput + UIKeyCommand for nav keys)
  • Translate platform text events into EditorKeyEventArgs / character input → EditorInputController

Tests

  • Insert character at various positions
  • Backspace and delete at boundaries
  • Enter splits paragraph correctly
  • Type-over-selection replaces selected text
  • Backspace at block boundary merges blocks

Git

  • Commit: "Phase 5 — Text input & basic editing"

Phase 6 — Clipboard Operations

Implement cut, copy, and paste with both plain text and rich text support.

Clipboard (MintedTextEditor.Core/Editing/)

  • IClipboardProvider interface — SetTextAsync(string), GetTextAsync()
  • ClipboardOperations — static helpers: CopyAsync, CutAsync, PasteAsync using IClipboardProvider
  • Keyboard shortcuts: Ctrl/Cmd + C (copy), Ctrl/Cmd + X (cut), Ctrl/Cmd + V (paste)
  • Rich paste: if clipboard contains rich content (HTML/RTF), parse and insert styled content
  • Plain paste: insert plain text with current caret style
  • Paste with style matching: Ctrl/Cmd + Shift + V (paste as plain text)

MAUI Clipboard Provider (MintedTextEditor.Maui/)

  • MauiClipboardProvider : IClipboardProvider — wraps Clipboard.Default from MAUI Essentials

Tests

  • Copy selected text, verify clipboard content
  • Cut removes selection and places on clipboard
  • Paste inserts at caret
  • Paste replaces selection

Git

  • Commit: "Phase 6 — Clipboard operations"

Phase 7 — Undo / Redo

Implement a robust undo/redo stack for all document mutations.

Undo System (MintedTextEditor.Core/Editing/)

  • IUndoableAction interface — Execute(), Undo(), Redo(), Description (string), MergeWith(IUndoableAction) → bool
  • Concrete actions: InsertTextAction, DeleteRangeAction, SplitBlockAction, MergeBlocksAction, ApplyStyleAction, CompositeAction
  • UndoManager — manages undo/redo stacks with configurable max depth
    • Push(IUndoableAction) — adds action, clears redo stack
    • Undo() — pops from undo, pushes to redo, restores state
    • Redo() — pops from redo, pushes to undo, re-applies
    • CanUndo / CanRedo properties
    • UndoStackChanged event
  • Action merging: consecutive character inserts merge into a single action (with timeout)
  • DocumentEditor integration: all mutations route through undo system
  • Keyboard shortcuts: Ctrl/Cmd + Z (undo), Ctrl/Cmd + Y / Ctrl/Cmd + Shift + Z (redo)

Tests

  • Insert text, undo, verify original state
  • Undo + redo round-trip
  • Action merging: rapid typing groups into single undo step
  • Max stack depth eviction
  • Style changes are undoable

Git

  • Commit: "Phase 7 — Undo / redo"

Phase 8 — Character Formatting

Apply inline text styles: bold, italic, underline, strikethrough, subscript, superscript.

Formatting API (MintedTextEditor.Core/Formatting/)

  • FormattingEngine — applies/removes/toggles character formats over a TextRange:
    • ToggleBold(Document, TextRange)
    • ToggleItalic(Document, TextRange)
    • ToggleUnderline(Document, TextRange)
    • ToggleStrikethrough(Document, TextRange)
    • ToggleSubscript(Document, TextRange)
    • ToggleSuperscript(Document, TextRange)
    • ClearFormatting(Document, TextRange) — reset to default text style
  • Toggle logic: if entire range is already bold → remove bold; otherwise → apply bold
  • When no selection: set "pending style" so next typed character inherits the toggled format
  • Keyboard shortcuts: Ctrl/Cmd + B (bold), Ctrl/Cmd + I (italic), Ctrl/Cmd + U (underline)

Rendering Support

  • DocumentRenderer draws underline decoration (line below text baseline)
  • DocumentRenderer draws strikethrough decoration (line through text center)
  • DocumentRenderer handles superscript/subscript (reduced font size + baseline offset)
  • SkiaDrawingContext supports bold/italic font resolution via SKTypeface

Tests

  • Toggle bold on a range: verify TextStyle.IsBold on affected runs
  • Toggle on partially-formatted range: splits runs correctly
  • Clear formatting resets all styles
  • Pending style applies to next typed character
  • Underline and strikethrough render at correct positions

Git

  • Commit: "Phase 8 — Character formatting"

Phase 9 — Paragraph Formatting

Block-level formatting: alignment, lists, indentation, headings.

Paragraph Formatting (MintedTextEditor.Core/Formatting/)

  • ParagraphFormattingEngine:
    • SetAlignment(Document, TextRange, TextAlignment) — Left, Center, Right, Justify
    • ToggleBulletList(Document, TextRange) — toggle unordered list
    • ToggleNumberList(Document, TextRange) — toggle ordered list
    • IncreaseIndent(Document, TextRange) — increase indent level
    • DecreaseIndent(Document, TextRange) — decrease indent level
    • SetHeadingLevel(Document, TextRange, int level) — 0 = normal, 1-6 = heading
    • SetParagraphFormat(Document, TextRange, string format) — "Normal", "Heading1"–"Heading6", "Quote"
    • SetLineSpacing(Document, TextRange, float spacing) — 1.0, 1.5, 2.0, etc.

Rendering Support

  • Bullet rendering: draw bullet glyph (•) at indent position before paragraph
  • Number rendering: draw sequential number at indent position before paragraph
  • Indent rendering: apply left margin based on indent level
  • Heading rendering: apply heading-level font sizes and weights
  • Justify alignment: distribute extra space between words on each line (except last line)
  • Block quote rendering: left border + background tint

Tests

  • Set alignment on paragraph, verify rendering positions
  • Toggle bullet list on/off
  • Nested indent levels
  • Heading levels apply correct font sizes
  • Number list sequential numbering across multiple paragraphs

Git

  • Commit: "Phase 9 — Paragraph formatting"

Phase 10 — Font Manipulation

Font family, font size, text color, and highlight/background color.

Font API (MintedTextEditor.Core/Formatting/)

  • FontFormattingEngine:
    • ApplyFontFamily(Document, TextRange, string family)
    • ApplyFontSize(Document, TextRange, float size)
    • ApplyTextColor(Document, TextRange, EditorColor color)
    • ApplyHighlightColor(Document, TextRange, EditorColor color)
    • RemoveHighlightColor(Document, TextRange)
  • Query current format at caret: GetCurrentTextStyle(Document, DocumentPosition) → TextStyle
  • Query format of selection: GetTextStyleForRange(Document, TextRange) → TextStyle? (returns null for mixed values)

Rendering Support

  • SkiaDrawingContext resolves font families to SKTypeface with fallback chain
  • Draw highlight backgrounds per-run before text
  • Text color per-run

Tests

  • Apply font family to range splits runs
  • Apply font size to range
  • Apply text color
  • Apply highlight color and verify background rendering
  • Mixed-format query returns null

Git

  • Commit: "Phase 10 — Font manipulation"

Phase 11 — Hyperlinks

Insert, edit, remove, detect, and open hyperlinks.

Hyperlink Support (MintedTextEditor.Core/Document/, MintedTextEditor.Core/Formatting/)

  • HyperlinkInline in document model (from Phase 1) — URL, title, child inlines
  • HyperlinkEngine:
    • InsertHyperlink(Document, TextRange, string url, string? title) — wraps selected text (or inserts new text) as a hyperlink
    • EditHyperlink(Document, HyperlinkInline, string newUrl, string? newTitle)
    • RemoveHyperlink(Document, TextRange) — unwraps hyperlink, keeps text
    • GetHyperlinkAtPosition(Document, DocumentPosition) → HyperlinkInline?
  • Auto-detect URLs while typing (optional, configurable)
  • Open hyperlink action: IHyperlinkHandler interface for platform-specific URL opening

Rendering Support

  • Hyperlink text rendered with underline + accent color (configurable)
  • Hover/pointer-over cursor change indication
  • Ctrl/Cmd + click to open hyperlink

MAUI Integration

  • MauiHyperlinkHandler : IHyperlinkHandler — uses Launcher.Default.OpenAsync(uri)

Events

  • HyperlinkClicked event with URL and cancel support
  • IsHyperlinkSelectedChanged event

Tests

  • Insert hyperlink wraps text
  • Remove hyperlink preserves text
  • Edit hyperlink URL
  • Auto-detect URL on space after typing "https://..."
  • Hit-test returns hyperlink at position

Git

  • Commit: "Phase 11 — Hyperlinks"

Phase 12 — Image Support

Insert, display, resize, and manage inline images.

Image Model (MintedTextEditor.Core/Document/)

  • ImageInline (from Phase 1) — source (byte[] or stream reference), alt text, width, height, aspect ratio lock
  • IImageProvider interface — LoadImageAsync(source) → object (returns platform-specific image handle)

Image Operations (MintedTextEditor.Core/Formatting/)

  • ImageEngine:
    • InsertImage(Document, DocumentPosition, ImageSource) → ImageInline
    • RemoveImage(Document, ImageInline)
    • ResizeImage(Document, ImageInline, float width, float height)
    • ReplaceImage(Document, ImageInline, ImageSource)

Rendering Support

  • DocumentRenderer draws ImageInline using IDrawingContext.DrawImage
  • Image selection: click on image selects it; draw selection handles (8 resize grips)
  • Drag resize handles to resize (maintain aspect ratio by default, free-resize with Shift)
  • Image placeholder while loading

MAUI Integration

  • MauiImageProvider : IImageProvider — loads from file path, stream, or gallery picker
  • ImageRequested event (mirrors Syncfusion) for custom image source dialogs

SkiaSharp Integration

  • Load images as SKImage / SKBitmap for rendering
  • Scale/clip images to fit layout bounds

Tests

  • Insert image at position
  • Resize image maintains aspect ratio
  • Remove image from document
  • Layout accounts for image dimensions in line height

Git

  • Commit: "Phase 12 — Image support"

Phase 13 — Table Support

Insert and edit tables with rows, columns, cell merging, and styling.

Table Model (MintedTextEditor.Core/Document/)

  • TableBlock : Block — rows × columns grid of TableCell
  • TableCell — contains a mini-Document (list of Block), column span, row span, background color, borders
  • TableRow — list of TableCell, row height
  • TableStyle — border style, cell padding, header row style

Table Operations (MintedTextEditor.Core/Formatting/)

  • TableEngine:
    • InsertTable(Document, DocumentPosition, int rows, int cols) → TableBlock
    • InsertRow(TableBlock, int afterRowIndex)
    • InsertColumn(TableBlock, int afterColIndex)
    • DeleteRow(TableBlock, int rowIndex)
    • DeleteColumn(TableBlock, int colIndex)
    • MergeCells(TableBlock, range)
    • SplitCell(TableBlock, cell)
    • SetCellBackground(TableCell, EditorColor)

Rendering Support

  • Table layout engine: column widths (auto, fixed, percentage), row heights
  • Cell content layout: each cell lays out its own document
  • Draw table borders, cell backgrounds
  • Tab / Shift+Tab key navigates between cells
  • Caret navigation within and between cells
  • User-resizable table columns via drag handles (persisted column widths)
  • User-resizable table rows via drag handles (persisted row heights)
  • Tapping below a terminal table moves caret to a writable paragraph below the table

Table UX Parity (Research-Informed)

  • Align keyboard behavior with common editors (ProseMirror/Tiptap, CKEditor 5, Lexical):
    • Tab/Shift+Tab moves cell-to-cell
    • Structural table edit commands are exposed from keyboard when focus is inside a cell
    • Users can move the caret out of a table without using pointer/context menu
  • Add table escape behavior:
    • From boundary cells, keyboard navigation can move before/after the table
    • If no adjacent block exists, create an empty paragraph to avoid caret trapping
  • Add keyboard shortcuts for structural operations while in a table:
    • Insert row above/below
    • Insert column left/right
    • Delete current row/column
    • Delete current table

Tests

  • Insert table with specified dimensions
  • Add/remove rows and columns
  • Cell merging across columns
  • Tab navigation between cells
  • Shift+Tab reverse navigation between cells
  • Keyboard escape from last cell to block after table
  • Keyboard structural shortcuts (insert/delete row/column, delete table)
  • Nested content in cells

Git

  • Commit: "Phase 13 — Table support"

Phase 14 — Command System & Events

Formalize all editor actions as commands (ICommand) and expose a rich event system.

Command System (MintedTextEditor.Core/Commands/)

  • IEditorCommandExecute(EditorContext), CanExecute(EditorContext), Name, Description
  • EditorContext — bundles Document, Selection, UndoManager, FormattingEngine, etc.
  • Built-in commands (one per action):
    • ToggleBoldCommand, ToggleItalicCommand, ToggleUnderlineCommand, ToggleStrikethroughCommand
    • ToggleSubscriptCommand, ToggleSuperscriptCommand
    • AlignLeftCommand, AlignCenterCommand, AlignRightCommand, AlignJustifyCommand
    • ToggleBulletListCommand, ToggleNumberListCommand
    • IncreaseIndentCommand, DecreaseIndentCommand
    • UndoCommand, RedoCommand
    • CopyCommand, CutCommand, PasteCommand
    • SelectAllCommand, ClearFormattingCommand
    • InsertHyperlinkCommand, RemoveHyperlinkCommand, OpenHyperlinkCommand
    • InsertImageCommand, RemoveImageCommand
    • InsertTableCommand
    • ApplyFontFamilyCommand, ApplyFontSizeCommand
    • ApplyTextColorCommand, ApplyHighlightColorCommand
    • SetHeadingLevelCommand, SetParagraphFormatCommand
  • EditorCommandRegistry — register, look up, and invoke commands by name
  • Key binding system: map keyboard shortcuts to commands (configurable)

Events (MintedTextEditor.Core/Events/)

  • SelectionChanged — fires when caret/selection moves
  • TextChanged — fires on any document content change
  • FontFamilyChanged — fires when font family at caret changes
  • FontSizeChanged — fires when font size at caret changes
  • FontAttributesChanged — fires when bold/italic state at caret changes
  • TextDecorationsChanged — fires when underline/strikethrough at caret changes
  • TextFormattingChanged — aggregate event for any formatting change
  • HorizontalTextAlignmentChanged — fires when paragraph alignment changes
  • ListTypeChanged — fires when list type at caret changes
  • TextColorChanged, HighlightTextColorChanged
  • HyperlinkClicked, IsHyperlinkSelectedChanged
  • IsReadOnlyChanged
  • ContentLoaded — fires after HTML/content import completes
  • ImageInserted, ImageRemoved

Tests

  • Commands execute and update document
  • CanExecute returns false when inappropriate (e.g., copy with no selection)
  • Events fire on corresponding actions
  • Custom commands can be registered

Git

  • Commit: "Phase 14 — Command system & events"

Phase 15 — Toolbar

A fully custom-drawn toolbar supporting auto-generated and user-customizable button layouts.

Toolbar Model (MintedTextEditor.Core/Toolbar/)

  • ToolbarItem (abstract) — base for toolbar elements
  • ToolbarButton : ToolbarItem — icon, label, associated IEditorCommand, toggle state
  • ToolbarSeparator : ToolbarItem — visual divider
  • ToolbarDropdown : ToolbarItem — dropdown picker (font family, font size, heading level, color picker)
  • ToolbarColorPicker : ToolbarItem — color swatch grid for text color / highlight color
  • ToolbarGroup — logical grouping of items
  • ToolbarDefinition — configurable list of ToolbarItem/ToolbarGroup items with layout mode:
    • Wrap — items wrap to multiple rows on desktop
    • Scroll — horizontal scroll on mobile
    • Overflow — overflow items collapse into a "more" menu

Default Toolbar Layout

  • Auto-generated default toolbar matching Telerik/Syncfusion feature set:
    • Group: Undo, Redo
    • Separator
    • Group: Font Family dropdown, Font Size dropdown
    • Separator
    • Group: Bold, Italic, Underline, Strikethrough
    • Separator
    • Group: Text Color, Highlight Color
    • Separator
    • Group: Align Left, Align Center, Align Right, Align Justify
    • Separator
    • Group: Bullet List, Number List, Decrease Indent, Increase Indent
    • Separator
    • Group: Subscript, Superscript
    • Separator
    • Group: Insert Hyperlink, Insert Image, Insert Table
    • Separator
    • Group: Edit actions dropdown (Copy/Cut/Paste/Select All)
    • Separator
    • Group: Object actions dropdown (Open/Remove Link, Remove Image)
    • Separator
    • Group: Table actions dropdown (insert/delete row/column, delete table)
    • Separator
    • Group: Heading dropdown, Clear Formatting

Toolbar Rendering (MintedTextEditor.Core/Toolbar/)

  • ToolbarRenderer — fully custom-drawn toolbar using IDrawingContext
  • Button hit testing and press/hover states
  • Toggle state visual (depressed/highlighted for active bold, italic, etc.)
  • Dropdown rendering: popup overlay with selectable items
  • Color picker rendering: grid of color swatches
  • Icon rendering normalized to avoid clipping/cutoff across button sizes
  • Toolbar responds to selection changes (updates toggle states, current font display)
  • ShowToolbar property — show/hide toolbar
  • ToolbarItems collection — customizable set of items

Canvas-Integrated Toolbar (MintedTextEditor.Maui/)

The toolbar is rendered entirely inside the SKCanvasView paint surface — no native XAML controls.

  • ToolbarRenderer wired into MintedEditorView.OnPaintSurface — drawn above the document viewport
  • ShowToolbar bindable property on MintedEditorView (default true) — controls toolbar visibility
  • ToolbarDefinition bindable property on MintedEditorView — swaps active ToolbarRenderer instance
  • Touch routing in OnCanvasTouch — Y < toolbarHHitTestIEditorCommand.Execute(EditorContext)InvalidateCanvas()
  • Document viewport offset by toolbarH so document content never overlaps toolbar
  • Theme colours forwarded each frame: ToolbarBackground, ToolbarButtonColor, ToolbarActiveColor, ToolbarSeparatorColor
  • Async icon loading via FileSystem.OpenAppPackageFileAsyncSKBitmap.Decode_iconCache
  • IconResolver delegate set on _toolbarRenderer so icons render as bitmaps; unknown keys fall back to text labels
  • Icon key → bundle filename mapping for all 20 default toolbar icons (handles number-listtb_ordered_list.png, clear-formattingtb_clear_format.png)
  • XAML sample (MainPage.xaml) uses only <minted:MintedEditorView ShowToolbar="True"/> — no native toolbar overlay

Tests

  • Default toolbar generates all expected items
  • Button click executes associated command
  • Toggle state reflects current selection format
  • Dropdown selection applies formatting
  • Custom toolbar definition renders correctly

Git

  • Commit: "Phase 15 — Toolbar"
  • Commit: "Canvas-integrated toolbar with async icon loading"

Phase 16 — Context Menu

Right-click / long-press context menu with standard and extensible items.

Context Menu (MintedTextEditor.Core/ContextMenu/)

  • ContextMenuItem — label, icon, associated IEditorCommand, enabled state, separator-after flag
  • ContextMenuDefinition — ordered list of ContextMenuItem
  • Default context menu:
    • Cut, Copy, Paste
    • Separator
    • Select All
    • Separator
    • Insert Hyperlink / Edit Hyperlink / Remove Hyperlink (context-dependent)
    • Open Hyperlink (if hyperlink selected)
    • Separator
    • Insert Image
    • Insert Table (if applicable)
  • Extensibility: ContextMenuItemsRequested event allows adding/removing items before display
  • ContextMenuRenderer — fully custom-drawn popup using IDrawingContext
    • Rounded rectangle background with shadow
    • Hover highlight on items
    • Keyboard navigation (arrow keys, Enter to select, Escape to dismiss)

Trigger

  • Right-click (secondary button) on desktop
  • Long-press on mobile
  • Positioned at pointer location, clamped to viewport bounds

Tests

  • Context menu shows correct items for context (hyperlink vs. no hyperlink)
  • Menu item click executes command
  • Menu dismisses on click outside or Escape
  • Custom items added via event

Git

  • Commit: "Phase 16 — Context menu"

Phase 17 — HTML Import / Export

Load content from HTML strings/streams and export document to HTML.

HTML Parser (MintedTextEditor.Core/Html/)

  • HtmlImporter — parses HTML string/stream into Document model
    • Supported tags: <p>, <br>, <strong>/<b>, <em>/<i>, <u>, <s>/<del>/<strike>, <sub>, <sup>, <span> (with inline styles), <a>, <img>, <h1><h6>, <ul>, <ol>, <li>, <blockquote>, <table>, <tr>, <td>, <th>, <div>
    • Parse inline CSS: font-family, font-size, color, background-color, text-align, text-decoration, font-weight, font-style
    • Graceful handling of unsupported tags (preserve content, ignore formatting)
    • Uses a lightweight/simple HTML parser — no heavy dependency (consider custom or HtmlAgilityPack)

HTML Serializer (MintedTextEditor.Core/Html/)

  • HtmlExporter — serializes Document to clean, semantic HTML string
    • Generates minimal inline styles (only non-default attributes)
    • Produces well-formed HTML5
    • Options: include/exclude <html>/<body> wrapper, CSS class mode vs. inline style mode

Public API

  • LoadHtml(string html) — replace document content from HTML
  • LoadHtml(Stream stream) — replace document content from HTML stream
  • GetHtml() → string — export current document as HTML
  • GetHtml(TextRange) → string — export selection as HTML

Tests

  • Round-trip: Document → HTML → Document preserves content and styles
  • Parse complex HTML with nested formatting
  • Export generates valid HTML5
  • Unsupported tags don't crash parser
  • Inline CSS is correctly mapped to TextStyle

Git

  • Commit: "Phase 17 — HTML import / export"

Phase 18 — Theming & Styling

Comprehensive theming system with built-in themes and full customization.

Theme System (MintedTextEditor.Core/Theming/)

  • EditorThemeMode enum — Light, Dark, HighContrast
  • EditorStyle — comprehensive style class covering all visual properties:
    • Editor background, border color, border width
    • Default text color, font family, font size
    • Caret color, caret width
    • Selection highlight color, selection text color
    • Hyperlink color, hyperlink hover color
    • Toolbar background, toolbar button color, toolbar separator color, toolbar hover color, toolbar active/toggle color
    • Context menu background, context menu text color, context menu hover color
    • Scrollbar track/thumb colors
    • Focus ring color
    • Line spacing, paragraph spacing
    • Padding (top, right, bottom, left)
  • EditorTheme factory — Create(EditorThemeMode) returns preconfigured EditorStyle
    • CreateLight() — clean white theme
    • CreateDark() — dark mode theme
    • CreateHighContrast() — high-contrast accessibility theme
  • Runtime theme switching: changing theme triggers full re-render
  • Custom theme support: users supply their own EditorStyle
  • System theme follow mode in MAUI view (UseSystemTheme) with automatic light/dark selection
  • Theme-aware default text rendering so dark mode no longer renders default text as black
  • Theme-aware hyperlink color application in layout/render pipeline

Typography UX

  • Font-family/font-size changes at collapsed caret apply to subsequently typed text (pending style behavior)

Tests

  • All three built-in themes create valid styles
  • Custom style overrides are respected
  • Theme switch triggers re-layout and re-render

Git

  • Commit: "Phase 18 — Theming & styling"

Phase 19 — Accessibility, Localization & RTL

Make the editor accessible, localizable, and support right-to-left text.

Accessibility

  • Semantic properties on the MAUI view (SemanticProperties.Description, AutomationProperties)
  • Screen-reader announcements for formatting changes
  • High-contrast theme support (from Phase 18)
  • Keyboard-only navigation for all features (toolbar, context menu, editor)
  • Focus indicator styling
  • ARIA-equivalent descriptions for toolbar buttons

Localization

  • Resource files for all UI strings (toolbar tooltips, context menu labels, dialog prompts)
  • IStringLocalizer integration or simple resource-based approach
  • Default language: English
  • Support for plugging in additional languages

RTL Support

  • TextDirection on ParagraphStyle (LTR / RTL / Auto)
  • RTL text layout: right-aligned by default, mirrored indent
  • RTL caret behavior: caret on right side, moves right-to-left
  • Mixed LTR/RTL content within a single paragraph (bidirectional text)
  • Toolbar mirroring in RTL mode

Tests

  • Semantic properties are set on the MAUI view
  • Localized strings load correctly
  • RTL paragraph renders text right-to-left
  • Bidirectional text scenario

Git

  • Commit: "Phase 19 — Accessibility, localization & RTL"

Phase 20 — Testing Infrastructure

Comprehensive test coverage across all layers.

Unit Tests (tests/MintedTextEditor.Core.Tests/)

  • Document model creation, mutation, and validation
  • Text layout engine: word-wrap, multi-paragraph, inline styles
  • Caret navigation: all directions, word/line/document boundaries
  • Selection: keyboard and pointer gestures, multi-line, word/paragraph select
  • Text input: insert, delete, backspace, Enter, Tab, type-over-selection
  • Clipboard: copy, cut, paste (mock clipboard)
  • Undo/redo: all operation types, merging, stack limits
  • Character formatting: all toggle operations, pending style
  • Paragraph formatting: alignment, lists, indent, headings
  • Font formatting: family, size, color, highlight
  • Hyperlinks: CRUD, auto-detect, hit-test
  • Images: insert, resize, remove, layout impact
  • Tables: CRUD rows/columns, cell merging, Tab navigation
  • Commands: execute, canExecute, registry
  • HTML import: parse various HTML structures
  • HTML export: serialize and validate output
  • Theming: all built-in themes, custom overrides
  • Hit-testing: various viewport positions

Integration Tests

  • Full editing flow: type text → format → undo → redo → export HTML → re-import → compare
  • Large document: performance baseline for layout/render with 10,000+ paragraphs

Test Helpers

  • MockDrawingContext : IDrawingContext — records draw calls for assertion
  • MockClipboardProvider : IClipboardProvider — in-memory clipboard
  • TestDocumentBuilder — fluent API for creating test documents

Git

  • Commit: "Phase 20 — Testing infrastructure"

Phase 21 — CI / CD Pipeline

GitHub Actions workflows for build, test, and NuGet package publishing.

CI Workflow (.github/workflows/ci.yml)

  • Trigger: push/PR to main and develop branches (ignore **.md, docs/**)
  • Concurrency: cancel in-progress runs for same ref
  • Job 1 — Build & Test (Core + SkiaSharp) on ubuntu-latest:
    • Setup .NET 10
    • Restore, build, test (MintedTextEditor.Core.Tests)
    • Upload test results artifact (TRX)
    • Pack dry-run to validate packaging
  • Job 2 — Build (MAUI) on windows-latest (requires Windows for Windows TFM):
    • Setup .NET 10 + MAUI workloads (cached)
    • Restore, build MintedTextEditor.Maui
    • Pack dry-run to validate packaging

Publish Workflow (.github/workflows/publish.yml)

  • Trigger: push tag v* or workflow_dispatch with version input
  • Resolve version from tag or input
  • Job 1 — Pack Core & SkiaSharp on ubuntu-latest:
    • Build + pack with source-link, symbol packages
    • Upload .nupkg and .snupkg artifacts
  • Job 2 — Pack MAUI on windows-latest:
    • Build + pack with source-link, symbol packages
    • Upload .nupkg and .snupkg artifacts
  • Job 3 — Publish to NuGet.org:
    • Download all package artifacts
    • dotnet nuget push to NuGet.org using NUGET_API_KEY secret
  • Job 4 — Create GitHub Release:
    • Generate release notes
    • Attach .nupkg files to release

Git

  • Commit: "Phase 21 — CI/CD pipeline"

Phase 22 — Documentation & README

Comprehensive documentation for users and contributors.

README.md

  • Project overview and tagline
  • Feature highlights with screenshots/GIFs
  • Architecture diagram (Core → SkiaSharp → MAUI layers)
  • Quick start guide:
    • NuGet install commands
    • builder.UseMintedTextEditor() in MauiProgram.cs
    • XAML and C# usage examples
  • Feature comparison table vs. Telerik / Syncfusion
  • Platform support matrix (iOS, Android, Mac Catalyst, Windows)
  • Configuration reference (toolbar customization, theming, events)
  • Contributing guide link
  • License badge, NuGet badge, CI badge

API Documentation (docs/)

  • docs/getting-started.md — installation, basic setup, first editor
  • docs/document-model.md — explains Block, Inline, TextRun, etc.
  • docs/formatting.md — character and paragraph formatting guide
  • docs/toolbar-customization.md — custom toolbar layouts
  • docs/theming.md — built-in themes, custom themes
  • docs/commands-events.md — command system, event reference
  • docs/html-interop.md — HTML import/export
  • docs/images-hyperlinks.md — image and hyperlink handling
  • docs/tables.md — table creation and editing
  • docs/accessibility.md — accessibility features and guidelines
  • docs/architecture.md — in-depth architecture overview for contributors

Other Files

  • CONTRIBUTING.md — contribution guidelines, code style, PR process
  • CODE_OF_CONDUCT.md — standard code of conduct
  • CHANGELOG.md — version history (initially empty template)

Git

  • Commit: "Phase 22 — Documentation & README"

Phase 23 — Sample Application

A .NET MAUI sample app demonstrating all editor features.

Sample App (samples/SampleApp.Maui/)

  • Main page: full-featured editor with default toolbar
  • Demo pages:
    • Basic text editing
    • Rich formatting showcase (all character + paragraph styles)
    • Custom toolbar layout
    • HTML import/export (textarea for HTML source)
    • Load/save document
    • Theme switcher (Light / Dark / High Contrast)
    • Hyperlink and image demo
    • Table editing demo
    • Read-only mode demo
    • Event monitor (displays fired events in a log panel)
    • Custom command demo
    • Localization demo
  • Navigation: Shell or TabbedPage with demo list
  • Supports all MAUI platforms (iOS, Android, Mac Catalyst, Windows)

Git

  • Commit: "Phase 23 — Sample application"

Phase 24 — Performance & Polish

Final optimization pass and quality improvements.

Performance

  • Profile rendering: ensure <16ms frame time for typical documents
  • Virtualized rendering: only render visible blocks/lines (skip off-screen content)
  • Layout caching: only re-layout changed blocks, not entire document
  • Paint object pooling: ensure zero per-frame allocations for paints/fonts
  • Large document support: test with 50,000+ paragraph documents
  • Image downsampling for display — IImageProvider interface with DownsampleAsync + IsAvailable
  • Lazy layout: defer layout of off-screen content

Scrolling

  • Smooth scrolling with inertia — InertialScroller (5-sample window, friction=0.92, 60fps tick)
  • Mouse wheel / trackpad scroll
  • Touch-based panning with velocity tracking — integrated in MintedEditorView.OnCanvasTouch
  • Scrollbar rendering: vertical scrollbar (track + thumb) — DocumentRenderer.RenderScrollbar; optional via ShowScrollbar bindable property
  • Scroll-to-position API

Polish

  • Word-wrap toggle — TextLayoutEngine.WordWrap; IsWordWrap bindable property on MintedEditorView
  • Read-only mode — IsReadOnly property disables all editing (implemented in prior phase)
  • Placeholder text when document is empty
  • Line numbers (optional gutter) — DocumentRenderer.RenderLineNumbersGutter; ShowLineNumbers bindable property
  • Find & Replace — FindReplaceEngine with Find, FindNext, FindPrevious, FindAll, Replace, ReplaceAll; FindOptions (MatchCase, WholeWord, WrapAround)
  • Spell-check integration point — ISpellCheckProvider interface
  • Print support integration point — IPrintProvider interface
  • Focus management — EditorFocusChanged event; Focus()/Unfocus() overrides on MintedEditorView

Git

  • Commit: "Phase 24 — Performance & polish"

Phase 25 — UX Parity Hardening (Post-Review)

Targeted fixes identified during end-to-end QA against Telerik/Syncfusion/CKEditor/Tiptap interaction patterns.

Table Editing Parity

  • Resize columns by drag handle with persisted per-column widths
  • Resize rows by drag handle with persisted per-row heights
  • Insert/delete row and column from toolbar-accessible controls
  • Delete table from toolbar-accessible controls
  • Ensure users can place caret and type below a terminal table via tap

Toolbar Parity & Usability

  • Expose all core editing/insert/table/object operations through toolbar controls
  • Add context-aware action dropdowns (Edit/Object/Table) to reduce toolbar clutter
  • Improve icon fit and control sizing to prevent clipped/cutoff glyph rendering

Theme & Font Behavior

  • Add configurable system-theme following behavior for MAUI host
  • Fix dark-mode readability by honoring theme default text color for default-styled runs
  • Fix collapsed-caret font switching so subsequent typing uses selected font settings

Validation

  • Focused core test suites: table/input/toolbar/font/theme/layout
  • MAUI iOS simulator build validation after UX parity changes

Git

  • Commit: "Phase 25 — UX parity hardening"

Phase 26 — Toolbar & Selection Quality Fixes (Post-Review II)

Targeted fixes identified during end-to-end QA on mobile (iOS/Android) and desktop targets.

Toolbar Icon Rendering

  • Fix blurry/low-resolution toolbar icon rendering — use high-quality SKPaint filter when drawing SKBitmap icons in SkiaDrawingContext.DrawImage
  • Increase SVG rasterization target size from max(64, 36×scale) to max(96, ButtonSize×2×scale) so icons are always sharp at HiDPI density
  • Increase bitmap icon draw area from 56 % of button size to 72 % so icons are more legible

Toolbar Icon Clipping / Proportional Layout

  • Replace all hardcoded pixel offsets in vector icon helpers (DrawVectorIcon) with proportional fractions of the current rect so icons render correctly at every ButtonSize
  • Add a Save/ClipRect/Restore guard around each vector-icon drawing call to guarantee icons never draw outside their allocated button rectangle
  • Fix undo/redo arc representation to use proportional curves rather than plain lines

Toolbar Overflow — configurable max rows with ellipsis overflow button

  • Add MaxRows property to ToolbarDefinition (0 = unlimited) and parallel MaxRows property on ToolbarRenderer
  • When LayoutMode == Wrap && MaxRows > 0, items that would start on a row beyond MaxRows are collected as overflow items instead of being drawn
  • Reserve a fixed OverflowButtonWidth slot at the trailing edge of the last allowed row and render a button there
  • Extend HitTest to return the synthetic overflow button; tapping it opens a drop-down panel listing all overflow items
  • Overflow panel items fire their normal commands just like regular toolbar items
  • Expose ToolbarMaxRows bindable property on MintedEditorView (default 0 = unlimited)

Text Selection Stability After Formatting

  • Add DocumentEditor.NormalizePosition(Document doc, DocumentPosition pos) — converts a DocumentPosition to a canonical (blockIndex, inlineIndex, offset) by walking inline lengths so stale inline indices after run-splitting are corrected
  • Call NormalizePosition on Selection.Anchor and Selection.Active inside MintedEditorView.ExecuteToolbarCommand after every formatting command that touches the document
  • Guard SelectionRenderer.Render with an inline-length bounds check so an out-of-range offset never throws and visually shows the nearest valid position instead

Tests

  • Toolbar overflow: ToolbarRendererTests — verify items beyond MaxRows are excluded and the overflow button rect is populated
  • Selection normalization: add cases to SelectionTests verifying anchor/active remain correct after bold/italic/underline toggles that split runs

Git

  • Commit: "Phase 26 — Toolbar & selection quality fixes"

Architecture Summary

┌──────────────────────────────────────────────────────────────┐
│                    MintedTextEditor.Maui                      │
│  ┌────────────────┐  ┌──────────────┐  ┌──────────────────┐ │
│  │ EditorView      │  │ Keyboard     │  │ MAUI Providers   │ │
│  │ (SKCanvasView)  │  │ Proxy        │  │ (Clipboard,      │ │
│  │                 │  │ (hidden      │  │  Hyperlink,      │ │
│  │                 │  │  Entry)      │  │  Image)          │ │
│  └───────┬─────────┘  └──────┬───────┘  └────────┬─────────┘ │
│          │ Touch/Pointer      │ Key events        │            │
└──────────┼────────────────────┼───────────────────┼────────────┘
           │                    │                   │
           ▼                    ▼                   │
┌──────────────────────────────────────────────────────────────┐
│                 MintedTextEditor.SkiaSharp                    │
│  ┌────────────────────────────────────────────────────────┐  │
│  │ SkiaDrawingContext : IDrawingContext                     │  │
│  │ (SKCanvas, cached SKPaint/SKFont/SKTypeface per frame) │  │
│  └────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘
           │ implements
           ▼
┌──────────────────────────────────────────────────────────────┐
│                   MintedTextEditor.Core                       │
│                                                              │
│  Rendering/          Document/         Editing/              │
│  ├─ IDrawingContext   ├─ Document       ├─ Caret             │
│  ├─ EditorPaint       ├─ Block          ├─ Selection         │
│  ├─ EditorFont        ├─ Paragraph      ├─ DocumentEditor    │
│  ├─ EditorRect        ├─ TextRun        ├─ UndoManager       │
│  ├─ EditorColor       ├─ ImageInline    ├─ EditSession       │
│  └─ PaintCache        ├─ HyperlinkInl.  └─ IClipboardProv.  │
│                       ├─ TableBlock                          │
│  Layout/              ├─ TextStyle     Formatting/           │
│  ├─ TextLayoutEngine  ├─ ParaStyle     ├─ FormattingEngine   │
│  ├─ LayoutLine        └─ DocPosition   ├─ ParagraphFmtEng.  │
│  ├─ LayoutRun                          ├─ FontFmtEngine     │
│  ├─ LayoutBlock       Input/           ├─ HyperlinkEngine   │
│  ├─ DocumentLayout    ├─ EditorInput   ├─ ImageEngine       │
│  └─ LayoutCache       ├─ HitTester    └─ TableEngine       │
│                       └─ InputEvents                        │
│  Commands/            Toolbar/         Html/                 │
│  ├─ IEditorCommand    ├─ ToolbarItem   ├─ HtmlImporter      │
│  ├─ CommandRegistry   ├─ ToolbarDef.   └─ HtmlExporter      │
│  └─ Built-in cmds    └─ ToolbarRndr                        │
│                                                              │
│  Theming/             ContextMenu/     Events/               │
│  ├─ EditorTheme       ├─ ContextMenu   └─ (all editor       │
│  └─ EditorStyle       └─ CtxMenuRndr      events)           │
└──────────────────────────────────────────────────────────────┘

Feature Parity Reference

Feature Telerik Syncfusion MintedTextEditor
Bold / Italic / Underline Phase 8
Strikethrough Phase 8
Subscript / Superscript Phase 8
Font Family Phase 10
Font Size Phase 10
Text Color Phase 10
Highlight Color Phase 10
Text Alignment (L/C/R/J) Phase 9
Bullet List Phase 9
Numbered List Phase 9
Indent / Outdent Phase 9
Headings (H1–H6) Phase 9
Hyperlink CRUD Phase 11
Open Hyperlink Phase 11
Image Insert / Edit Phase 12
Image Resize Phase 12
Tables Phase 13
Undo / Redo Phase 7
Copy / Cut / Paste Phase 6
Select All Phase 4
Clear Formatting Phase 8
Toolbar (auto-generated) Phase 15
Toolbar (custom layout) Phase 15
Context Menu Phase 16
Commands (ICommand) Phase 14
Rich Event System Phase 14
HTML Import / Export Phase 17
Theming (Light/Dark/HC) Phase 18
RTL Support Phase 19
Localization Phase 19
Accessibility Phase 19
Read-Only Mode Phase 24
Placeholder Text Phase 24
Find & Replace Phase 24
Spell Check Integration Phase 24
Word Wrap Toggle Phase 24
Cross-platform Core ✅ (by design)
Swappable Drawing Backend ✅ (by design)
No Native UI Controls ✅ (by design)

Key Design Decisions

  1. Document Model: Tree-based (DocumentBlockInlineTextRun) rather than flat-buffer. Enables clean structural operations (split/merge paragraphs, table cells as sub-documents).

  2. Undo System: Action-based (command pattern) rather than state-snapshot. Lower memory usage, supports fine-grained merging of character inserts.

  3. Layout Engine: Block-level caching — only re-layout blocks that changed. Each block's layout is independent, enabling efficient partial updates.

  4. Rendering Pipeline: DocumentTextLayoutEngineDocumentLayoutDocumentRendererIDrawingContext. Clean one-way data flow.

  5. Input Architecture: Platform events → EditorInputController → command dispatch. Mirrors KumikoUI's GridInputController pattern for clean separation.

  6. Toolbar: Fully custom-drawn on the same canvas (not native widgets). Consistent look across platforms, themeable, extensible.

  7. HTML as Interchange Format: HTML is the primary import/export format (matching Telerik). Rich clipboard also uses HTML.

  8. Extensibility Points: IDrawingContext (rendering backend), IClipboardProvider (clipboard), IHyperlinkHandler (link opening), IImageProvider (image loading), ISpellCheckProvider (spell-check), IEditorCommand (custom commands), events for all operations.