feat: pilot Monaco editor in Code Formatter tool - #163
Conversation
Replace CodeMirror with Monaco (bundled locally, no CDN) behind an 'impl' prop on ToolEditorPane so only the Code Formatter page opts in. Other tools keep CodeMirror until the pilot is validated. - Add imperative MonacoCodeEditor/MonacoHighlightedCode with lazy workers setup and a devtoolbox theme derived from theme palettes (CSS var colors are resolved to hex; invalid tokens are skipped) - Expose palette via ThemeContext for editor theming - e2e: teach fillEditor/readEditorText about Monaco DOM and make the copy/typing helpers deterministic against EditContext commits
PR Review — #163 pilot Monaco in Code Formatter —
|
- normalizeColor: stop rejecting #RRGGBB (length check was wrong) and expand #RGB/#RGBA short forms; add table-driven unit tests - useMonacoDevtoolboxTheme: apply latest theme via ref after monaco loads and re-apply on theme change (no stale-capture race) - dispose models only when not already disposed - forward showLineNumbers to editable Monaco branch in ToolEditorPane - drop duplicate theme application in MonacoHighlightedCode create
PR Review — #163
|
PR Review — #163
|
- normalizeColor: accept only valid hex lengths (3/4 expanded, 6/8 kept), reject invalid 5/7-length forms with test coverage - add loadError fallback (textarea/pre) so a failed monaco chunk load degrades gracefully instead of showing Loading forever - render error border on Monaco panes via error prop - use globalThis instead of self; replace window.__monaco API leak with a minimal read-only __monacoModels() snapshot used by e2e helpers - add eslint-disable comments for intentional dep-less ref sync effects - document setValue undo-stack trade-off
Review — #163
|
- ToolLayout: make the layout container a column flexbox so the split grid's flex-1 engages; panes previously collapsed to content height (affected all tools, not just Monaco) - monacoSetup: import json/css/html language contributions and xml/swift Monarch definitions so output panes get real syntax colors
Review — #163
|
Review — #163
|
- monacoSetup: import css/html/xml/swift Monarch tokenizers (definitions/* register.js) so all pilot languages colorize, not just JSON - add wordWrap prop to Monaco editors; Code Formatter defaults it ON with a persisted toggle next to the highlight toggle - error display: stop double-red (output pane no longer borders on error); tighten the floating error block styling
Review — #163
|
…nd error handling
- Code Converter: impl="monaco" on both panes with a persisted word-wrap
toggle, matching the Code Formatter pilot
- shared editor e2e helper: set Monaco model value directly (bypassing
insertText auto-indent corruption) and read via a data-uri-mapped
__monacoGetValue so tabs/exact whitespace survive
- monacoSetup: expose __monacoGetValue/__monacoSetValue mapped by pane
data-testid (via .monaco-editor data-uri)
- CodeConverter page: surface the backend's structured {error} response
(HTTP 200) as a real error instead of setting it as output
- Code Formatter: add 8px top margin to the FilterBar for spacing from
the output pane; use genuinely-invalid input in the error test
Review — PR #163
|
Minimum allowed line rate is |








Summary
Pilots Monaco as the code editor in the Code Formatter tool only, behind an
impl="monaco"prop onToolEditorPane. All other tools continue using CodeMirror so we can A/B the experience before committing to a wider migration.?workerimports); no CDN dependency, keeping the app offline-firstMonacoCodeEditor/MonacoHighlightedCodecomponents (same props contract as their CodeMirror counterparts), lazy-loaded so only the pilot page pulls the ~2.6MB chunkThemeContextnow exposespalettefor editor themingview-lines) and wait for async editor init; clipboard/typing helpers made deterministic against EditContext commitsTesting
bun run test: 48 unit tests passbunx playwright test: full e2e suite green (172 passed), incl. all 12 Code Formatter specs run 4x consecutively against a production buildgo test ./internal/...: passScreenshots
N/A
Checklist
bun run format)