UI: Rework Monaco editor theme to match Chakra UI palette#64748
UI: Rework Monaco editor theme to match Chakra UI palette#64748pierrejeambrun merged 5 commits intoapache:mainfrom
Conversation
@pierrejeambrun handled the nits and the PR is ready for local testing |
There was a problem hiding this comment.
Pull request overview
Registers custom airflow-light / airflow-dark Monaco themes derived from Chakra UI tokens, and wires them into all Monaco editor usages so editor chrome matches the app’s design system.
Changes:
- Add
useMonacoThemehook that defines and selects the Monaco theme based on current Chakra color mode. - Update all Monaco editor call sites (
Editor+DiffEditor) to use the hook’sbeforeMount+theme. - Add unit tests covering theme selection and one-time registration behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| airflow-core/src/airflow/ui/src/context/colorMode/useMonacoTheme.ts | Defines custom Monaco themes using Chakra CSS variables and exposes beforeMount + theme. |
| airflow-core/src/airflow/ui/src/context/colorMode/useMonacoTheme.test.ts | Tests theme name selection and single registration behavior. |
| airflow-core/src/airflow/ui/src/context/colorMode/index.ts | Exports useMonacoTheme from the colorMode barrel. |
| airflow-core/src/airflow/ui/src/pages/Dag/Code/Code.tsx | Uses useMonacoTheme for the DAG code viewer Monaco editor. |
| airflow-core/src/airflow/ui/src/pages/Dag/Code/CodeDiffViewer.tsx | Uses useMonacoTheme for the DAG code diff Monaco editor. |
| airflow-core/src/airflow/ui/src/components/JsonEditor.tsx | Uses useMonacoTheme for the JSON editor component. |
| airflow-core/src/airflow/ui/src/components/RenderedJsonField.tsx | Uses useMonacoTheme for read-only rendered JSON Monaco editor instances. |
Register custom airflow-light and airflow-dark Monaco themes derived from Chakra UI color tokens so that the DAG Code viewer, diff viewer, and JSON editors visually integrate with the rest of the app instead of using Monaco's default vs/vs-dark themes. The new useMonacoTheme hook rasterizes a single pixel through a 2D canvas and reads it back via getImageData to convert Chakra's OKLCH color values into the #rrggbb strings that Monaco's defineTheme accepts — ctx.fillStyle readback cannot be used because modern Chrome preserves the original OKLCH string. Themes are registered once via a module-level flag and then passed to every Monaco editor via the beforeMount callback. closes: apache#64253
Address review feedback: React Compiler handles memoization, so the useCallback wrapper around defineAirflowMonacoThemes is redundant. Pass the function reference directly instead. Also fix prettier formatting in tests.
Address review feedback: the canvas-based cssVarToHex was brittle (depended on Canvas2D rendering and browser-specific fillStyle behavior, and required canvas mocking in happy-dom tests). Replace it with culori's parse/formatHex, which handles OKLCH and other modern color spaces directly with no DOM rasterization. Also add afterEach(vi.restoreAllMocks()) to the tests so the getComputedStyle spy does not leak between runs.
061ca08 to
7dba46a
Compare
|
Pushed 7dba46a addressing review feedback: Canvas → culori for color conversion (@pierrejeambrun) |
unparseable -> unparsable.
…#64748) * UI: Rework Monaco editor theme to match Chakra UI palette Register custom airflow-light and airflow-dark Monaco themes derived from Chakra UI color tokens so that the DAG Code viewer, diff viewer, and JSON editors visually integrate with the rest of the app instead of using Monaco's default vs/vs-dark themes. The new useMonacoTheme hook rasterizes a single pixel through a 2D canvas and reads it back via getImageData to convert Chakra's OKLCH color values into the #rrggbb strings that Monaco's defineTheme accepts — ctx.fillStyle readback cannot be used because modern Chrome preserves the original OKLCH string. Themes are registered once via a module-level flag and then passed to every Monaco editor via the beforeMount callback. closes: #64253 * UI: Remove unnecessary useCallback in useMonacoTheme Address review feedback: React Compiler handles memoization, so the useCallback wrapper around defineAirflowMonacoThemes is redundant. Pass the function reference directly instead. Also fix prettier formatting in tests. * UI: Use culori for Monaco theme color conversion Address review feedback: the canvas-based cssVarToHex was brittle (depended on Canvas2D rendering and browser-specific fillStyle behavior, and required canvas mocking in happy-dom tests). Replace it with culori's parse/formatHex, which handles OKLCH and other modern color spaces directly with no DOM rasterization. Also add afterEach(vi.restoreAllMocks()) to the tests so the getComputedStyle spy does not leak between runs. * UI: Fix codespell typo in useMonacoTheme comment unparseable -> unparsable. (cherry picked from commit bfe46f6) Co-authored-by: Shivam Rastogi <6463385+shivaam@users.noreply.github.com>
Backport successfully created: v3-2-testNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
|
|
Cool! Thanks for this UX improvement! |
You are welcome. Happy to contribute:) |



Summary
Register custom
airflow-light/airflow-darkMonaco themes derived from Chakra UI color tokens so that every Monaco editor in the UI (DAG Code viewer, code diff viewer, JSON editor, RenderedJsonField) visually integrates with the rest of the app instead of using Monaco's defaultvs/vs-darkthemes.closes: #64253
Open Questions
themesRegisteredflag sodefineThemeonly runs on the first
beforeMount. Without it, pages with many editors (e.g.XCom table with ~50 rows) re-register themes on every mount. Measured cost without the guard: ~4ms on a 50-editor page. Negligible. Happy to drop the flag for simpler code + tests if you prefer..
defineThemeonly accepts#rrggbb. I convert by rasterizing a 1x1 canvas pixel and reading back sRGBvia
getImageData. I checkedctx.fillStylereadback — it preserves the OKLCH string unchanged on Chrome 111+, so that path silently fails (this is what PR Rework Monaco editor style to match Chakra UI color palette #64268 does).Implementation notes
useMonacoTheme(src/context/colorMode/useMonacoTheme.ts) — registers both custom themes exactly once via a module-level flag, returns a stablebeforeMountcallback and the correct theme name for the current color mode.inherit: true+ emptyrules— Monaco's default syntax highlighting (keywords, strings, comments) is preserved. Only editor shell colors (background, foreground, gutter, selection, scrollbar, line numbers) are overridden.getImageData— Chakra v3 uses OKLCH colors.ctx.fillStylereadback cannot be relied on because Chrome 111+ preserves the OKLCH string instead of converting to hex, which Monaco would silently ignore.RenderedJsonFieldrows) don't pay the cost on every mount.JsonEditor,RenderedJsonField,Code,CodeDiffViewer) are updated to use the hook. No changes to component structure, dynamic height behavior, or any other behavior beyond theme wiring.How to test
breeze start-airflow --dev-mode --load-example-dagsWas generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 4.6) following the guidelines