The editor lays a transparent <textarea> over a syntax-coloured <app-code-viewer>. The complaint about that arrangement is fair, but it aims slightly off the target — so first, what is not wrong with it, to keep anyone from "fixing" it:
.editor-stack lets the parent container scroll rather than either layer, so the classic failure of this trick — the two layers drifting apart on scroll — is designed out, with no scrollTop synchronisation anywhere.
- The font stack is monospace all the way down (
'JetBrains Mono', ui-monospace, …, monospace) and the family is shipped with the binary through @fontsource, so character alignment cannot break on a missing webfont. The trailing , serif on those rules is unreachable noise, not a risk.
- The
<textarea> carries the accessible text and the viewer is aria-hidden, which is the right way round.
What is actually missing, and it is not the colouring
A <textarea> has no editing intelligence, and no amount of work on the layer underneath adds any:
- No
Tab to indent — Tab leaves the field. That is a deliberate accessibility choice, and for writing code it is a real handicap.
- No auto-closing brackets or quotes, no bracket matching, no folding.
- No find-and-replace inside a note, no multiple selections.
- Nothing marks
{{fields}}. They are coloured by whatever the language grammar happens to think they are — in a SQL snippet, {{host}} is just text. This is the one that matters most here, because fields are the application's own vocabulary, and it is impossible with the overlay and trivial with a real editor (a decoration).
The question that decides it
Do people write in DevBox, or file into it what they wrote elsewhere? If it is filing, the textarea is adequate and a real editor is dead weight. If it is writing — and mixed-content notes and runbooks point that way — it pays for itself.
Options
A — Keep the overlay, add what is cheap. Tab handling with an accessible escape (Tab indents, Escape then Tab leaves — the established pattern), auto-closing pairs. A session or two, ceiling unchanged, {{fields}} still invisible.
B — CodeMirror 6. Everything above, plus decorations for the fields. The costs, in full:
- An imperative island in a zoneless, signal-based application: it owns its DOM, so it needs
afterNextRender, an explicit teardown, and to stay out of the signal graph.
- The draft path has to be rewired. Today the body is a
linkedSignal keyed on the note id, committed on blur and on every closing path — Escape, backdrop and close button produce no blur, which is why requestClose() commits first. That contract has to survive the change.
- Its own theming system, which must answer
data-theme in both directions plus prefers-color-scheme, like every other colour in this codebase.
- Two highlighters to maintain. The cards must stay on highlight.js — CodeMirror on a three-line truncated preview, multiplied by every card on the canvas, is absurd. So
_code-theme.scss and a CodeMirror theme both have to track the palette.
- Bundled locally, never from a CDN: the CSP forbids it.
C — Monaco. No. Heavy, worker-based, awkward under this CSP, and far more editor than a snippet needs.
Done when: the choice is written down with its reason — and if it is A, the cheap gaps are closed rather than left open indefinitely.
The editor lays a transparent
<textarea>over a syntax-coloured<app-code-viewer>. The complaint about that arrangement is fair, but it aims slightly off the target — so first, what is not wrong with it, to keep anyone from "fixing" it:.editor-stacklets the parent container scroll rather than either layer, so the classic failure of this trick — the two layers drifting apart on scroll — is designed out, with noscrollTopsynchronisation anywhere.'JetBrains Mono', ui-monospace, …, monospace) and the family is shipped with the binary through@fontsource, so character alignment cannot break on a missing webfont. The trailing, serifon those rules is unreachable noise, not a risk.<textarea>carries the accessible text and the viewer isaria-hidden, which is the right way round.What is actually missing, and it is not the colouring
A
<textarea>has no editing intelligence, and no amount of work on the layer underneath adds any:Tabto indent — Tab leaves the field. That is a deliberate accessibility choice, and for writing code it is a real handicap.{{fields}}. They are coloured by whatever the language grammar happens to think they are — in a SQL snippet,{{host}}is just text. This is the one that matters most here, because fields are the application's own vocabulary, and it is impossible with the overlay and trivial with a real editor (a decoration).The question that decides it
Do people write in DevBox, or file into it what they wrote elsewhere? If it is filing, the textarea is adequate and a real editor is dead weight. If it is writing — and mixed-content notes and runbooks point that way — it pays for itself.
Options
A — Keep the overlay, add what is cheap.
Tabhandling with an accessible escape (Tab indents, Escape then Tab leaves — the established pattern), auto-closing pairs. A session or two, ceiling unchanged,{{fields}}still invisible.B — CodeMirror 6. Everything above, plus decorations for the fields. The costs, in full:
afterNextRender, an explicit teardown, and to stay out of the signal graph.linkedSignalkeyed on the note id, committed on blur and on every closing path — Escape, backdrop and close button produce no blur, which is whyrequestClose()commits first. That contract has to survive the change.data-themein both directions plusprefers-color-scheme, like every other colour in this codebase._code-theme.scssand a CodeMirror theme both have to track the palette.C — Monaco. No. Heavy, worker-based, awkward under this CSP, and far more editor than a snippet needs.
Done when: the choice is written down with its reason — and if it is A, the cheap gaps are closed rather than left open indefinitely.