Fix bug & quality review checklist items

Fix bug & quality review checklist items

#3 in Riparion/riparion-editor — merged 2026-06-02

Works through the bug & quality review checklist.

Correctness

  • H1add_block builds its snapshot from the frozen() view while a block is active (re-splits body() only when idle), so a block's internal blank lines can't fragment it or misplace the inserted block.
  • M2open_fence now enforces CommonMark's 3-space indent limit (4+ spaces / leading tab → indented code, not a fence), and split_blocks only opens a fence at a block boundary (doc start or after a blank line), so a mid-paragraph ``` no longer swallows the rest of the block. Adds two tests.
  • L2 — Double-Enter lands the caret at the start of the moved tail (pending_caret = 0).

DRY / KISS

  • D1 — Extract ensure_paragraph_break(&mut String) (used by add_block and handle_enter).
  • D2 — Extract commit_block(i, text) (used by oninput and handle_inline_format).
  • K1 — Decompose the ~225-line onkeydown into handle_enter / handle_arrow_nav / handle_inline_format; onkeydown now just handles Esc and dispatches.
  • K2 — Replace the positional (String, String, bool, bool) spec with a named WrapSpec struct.

Other

  • L1 — Document the example's dangerous_inner_html + Options::all() XSS risk and recommend a sanitizer for untrusted input.
  • L3 — Content-derived render keys (block_keys) for the drag list and inactive blocks; the active textarea keeps a constant key so it doesn't remount and lose focus while typing.

Not in this PR

  • M1 (second-click / wrong-block-on-click) is timing-dependent and needs browser confirmation. The L3 content-keys change should reduce the node-reuse churn behind it; re-test in a browser before closing.

Verification

  • cargo test — 11 passed (+2 for M2)
  • cargo clippy --all-targets — clean
  • cargo clippy --features web --target wasm32-unknown-unknown (lib + example) — clean
  • cargo fmt applied

🤖 Generated with Claude Code

Last updated 2026-06-03