From a14c36e996043cb7d8a3847407ed57953fc5f788 Mon Sep 17 00:00:00 2001 From: Elena Torro Date: Fri, 30 Jan 2026 11:11:14 +0100 Subject: [PATCH] :books: Add embedded text editor MVP documentation --- render-wasm/docs/text_editor.md | 217 ++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 render-wasm/docs/text_editor.md diff --git a/render-wasm/docs/text_editor.md b/render-wasm/docs/text_editor.md new file mode 100644 index 0000000000..8b65fb1f22 --- /dev/null +++ b/render-wasm/docs/text_editor.md @@ -0,0 +1,217 @@ +# Text Editor Architecture + +## Overview (Simplified) + +```mermaid +flowchart TB + subgraph Browser["Browser / DOM"] + CE[contenteditable] + Events[DOM Events] + end + + subgraph CLJS["ClojureScript"] + InputHandler[text_editor_input.cljs] + Bindings[text_editor.cljs] + ContentCache[(content cache)] + end + + subgraph WASM["WASM Boundary"] + FFI["_text_editor_* functions"] + end + + subgraph Rust["Rust"] + subgraph StateModule["state/text_editor.rs"] + TES[TextEditorState] + Selection[TextSelection] + Cursor[TextCursor] + end + + subgraph WASMImpl["wasm/text_editor.rs"] + StateOps[start / stop] + CursorOps[cursor / selection] + EditOps[insert / delete] + ExportOps[export content] + end + + subgraph RenderMod["render/text_editor.rs"] + RenderOverlay[render_overlay] + end + + Shapes[(ShapesPool)] + end + + subgraph Skia["Skia"] + Canvas[Canvas] + Paragraph[Paragraph layout] + end + + %% Flow + CE --> Events + Events --> InputHandler + InputHandler --> Bindings + Bindings --> FFI + FFI --> StateOps & CursorOps & EditOps & ExportOps + + StateOps --> TES + CursorOps --> TES + EditOps --> TES + EditOps --> Shapes + ExportOps --> Shapes + TES --> Selection --> Cursor + + RenderOverlay --> TES + RenderOverlay --> Shapes + Shapes --> Paragraph + RenderOverlay --> Canvas + Paragraph --> Canvas + + ExportOps --> ContentCache + ContentCache --> InputHandler +``` + +--- + +## Detailed Architecture + +```mermaid +flowchart TB + subgraph Browser["Browser / DOM"] + CE[contenteditable element] + KeyEvents[keydown / keyup] + MouseEvents[mousedown / mousemove] + IME[compositionstart / end] + end + + subgraph CLJS["ClojureScript Layer"] + subgraph InputMod["text_editor_input.cljs"] + EventHandler[Event Handler] + BlinkLoop[RAF Blink Loop] + SyncFn[sync-content!] + end + + subgraph BindingsMod["text_editor.cljs"] + direction TB + StartStop[start / stop] + CursorFns[set-cursor / move] + SelectFns[select-all / extend] + EditFns[insert / delete] + ExportFns[export-content] + StyleFns[apply-style] + end + + ContentCache[(shape-text-contents
atom)] + end + + subgraph WASM["WASM Boundary"] + direction TB + FFI_State["_text_editor_start
_text_editor_stop
_text_editor_is_active"] + FFI_Cursor["_text_editor_set_cursor_from_point
_text_editor_move_cursor
_text_editor_select_all"] + FFI_Edit["_text_editor_insert_text
_text_editor_delete_backward
_text_editor_insert_paragraph"] + FFI_Query["_text_editor_export_content
_text_editor_get_selection
_text_editor_poll_event"] + FFI_Render["_text_editor_render_overlay
_text_editor_update_blink"] + end + + subgraph Rust["Rust Layer"] + subgraph StateMod["state/text_editor.rs"] + TES[TextEditorState] + Selection[TextSelection] + Cursor[TextCursor] + Events[EditorEvent queue] + end + + subgraph WASMMod["wasm/text_editor.rs"] + direction TB + WStateOps[State ops] + WCursorOps[Cursor ops] + WEditOps[Edit ops] + WQueryOps[Query ops] + end + + subgraph RenderMod["render/text_editor.rs"] + RenderOverlay[render_overlay] + RenderCursor[render_cursor] + RenderSelection[render_selection] + end + + Shapes[(ShapesPool
TextContent)] + end + + subgraph Skia["Skia"] + Canvas[Canvas] + SkParagraph[textlayout::Paragraph] + TextBoxes[get_rects_for_range] + end + + %% Browser to CLJS + CE --> KeyEvents & MouseEvents & IME + KeyEvents --> EventHandler + MouseEvents --> EventHandler + IME --> EventHandler + + %% CLJS internal + EventHandler --> StartStop & CursorFns & EditFns & SelectFns + BlinkLoop --> FFI_Render + SyncFn --> ExportFns + ExportFns --> ContentCache + ContentCache --> SyncFn + StyleFns --> ContentCache + + %% CLJS to WASM + StartStop --> FFI_State + CursorFns --> FFI_Cursor + SelectFns --> FFI_Cursor + EditFns --> FFI_Edit + ExportFns --> FFI_Query + + %% WASM to Rust impl + FFI_State --> WStateOps + FFI_Cursor --> WCursorOps + FFI_Edit --> WEditOps + FFI_Query --> WQueryOps + FFI_Render --> RenderOverlay + + %% Rust internal + WStateOps --> TES + WCursorOps --> TES + WEditOps --> TES + WEditOps --> Shapes + WQueryOps --> TES + WQueryOps --> Shapes + + TES --> Selection + Selection --> Cursor + TES --> Events + + %% Render flow + RenderOverlay --> RenderCursor & RenderSelection + RenderCursor --> TES + RenderSelection --> TES + RenderCursor --> Shapes + RenderSelection --> Shapes + + %% Skia + Shapes --> SkParagraph + SkParagraph --> TextBoxes + RenderCursor --> Canvas + RenderSelection --> Canvas +``` + +--- + +## Key Files + +| Layer | File | Purpose | +|-------|------|---------| +| DOM | - | contenteditable captures keyboard/IME input | +| CLJS | `text_editor_input.cljs` | Event handling, blink loop, content sync | +| CLJS | `text_editor.cljs` | WASM bindings, content cache, style application | +| Rust | `state/text_editor.rs` | TextEditorState, TextSelection, TextCursor | +| Rust | `wasm/text_editor.rs` | WASM exported functions | +| Rust | `render/text_editor.rs` | Cursor & selection overlay rendering | + +## Data Flow + +1. **Input**: DOM events → ClojureScript handler → WASM function → Rust state +2. **Edit**: Rust modifies TextContent in ShapesPool → triggers layout +3. **Sync**: Export content → merge with cached styles → update shape +4. **Render**: RAF loop → render_overlay → Skia draws cursor/selection