2.5 KiB
type, id, title, status, date
| type | id | title | status | date |
|---|---|---|---|---|
| ADR | 0137 | Shared rich-editor input transforms | active | 2026-06-07 |
Context
Tolaria has several Markdown-style conveniences in the rich BlockNote editor:
typed arrows become ligatures, completed inline math becomes a math node, and
completed ==highlight== syntax becomes the durable highlight mark.
These features were added incrementally as separate beforeinput extensions.
Each extension repeated the same lifecycle work: reading the live ProseMirror
view, skipping IME composition, guarding stale views, dispatching transactions,
preventing native input only after a successful transform, and recovering known
BlockNote/ProseMirror transform failures. The syntax matchers differed, but the
execution shell was parallel enough that each new Markdown affordance risked a
slightly different edge-case policy.
Decision
Tolaria routes rich-editor Markdown input transforms through one shared
beforeinput execution path.
src/components/richEditorInputTransform.ts owns the common lifecycle,
dispatch, and recoverable-error behavior. Feature files such as
arrowLigaturesExtension.ts, mathInputExtension.ts, and
markdownHighlightInputExtension.ts expose small transform objects that only
decide whether the current input event should produce a transaction.
src/components/richEditorInputTransformExtension.ts composes the Markdown
transform set used by the main editor and hidden editor probe.
Options Considered
- Shared transform primitive with feature-owned matchers (chosen): removes duplicate listener, dispatch, composition, and recovery code while keeping each syntax rule local and testable.
- One monolithic Markdown input extension: reduces listener count, but mixes unrelated syntax rules in one file and makes each future input affordance harder to test independently.
- Keep one extension per feature: preserves local ownership, but keeps the repeated edge-case shell and invites divergence as more transforms are added.
Consequences
Editormounts one Markdown input-transform extension rather than separate arrow, math, and highlightbeforeinputlisteners.- Feature-specific files remain responsible for their syntax matching and transaction construction only.
- Recoverable transform errors use the same telemetry event and fallback policy across Markdown input transforms.
- New rich-editor Markdown input affordances should plug into the shared
transform primitive instead of adding another capture-phase
beforeinputextension.