Files
app/frontend/src/components/Flow/monacoSetup.ts
T
stroblmeandClaude Opus 5.5 2c1ad395de Edit JSON node settings in a dialog from a one-line preview
A free setting typed json and a declared object or array setting (a Switch
node's rules, HTTP headers) show one line of their value; clicking opens a
Monaco JSON editor in a dialog that saves only once the text parses.
Declared object settings were not shown at all before. Escape in a dialog
opened from a side panel no longer closes the panel too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-05 23:49:42 +02:00

82 lines
3.0 KiB
TypeScript

/**
* Monaco, self-hosted and themed from the design tokens.
*
* Only the base editor, the Python grammar and JSON (for settings holding JSON)
* are pulled in; the other seventy languages would triple the chunk for
* nothing. This module is imported by NodeEditor alone, which the panel loads
* lazily.
*/
import { loader } from "@monaco-editor/react"
import * as monaco from "monaco-editor/editor/editor.api"
// Only Python registers itself; `basic-languages` would pull in all seventy.
import "monaco-editor/languages/definitions/python/register"
import "monaco-editor/languages/features/json/register"
import editorWorker from "monaco-editor/editor/editor.worker?worker"
import jsonWorker from "monaco-editor/languages/features/json/json.worker?worker"
let configured = false
function defineThemes() {
const themes = [
{ id: "fluksio-light", base: "vs" as const },
{ id: "fluksio-dark", base: "vs-dark" as const },
]
for (const theme of themes) {
const dark = theme.id.endsWith("dark")
const background = dark ? "#1a1a1a" : "#ffffff"
const foreground = dark ? "#f5f5f5" : "#333232"
const muted = dark ? "#a3a3a3" : "#6b6b6b"
const accent = dark ? "#262626" : "#f5f5f5"
const primary = dark ? "#7ba3b8" : "#4a7189"
const success = dark ? "#87b596" : "#5e8b6d"
monaco.editor.defineTheme(theme.id, {
base: theme.base,
inherit: true,
rules: [
{ token: "keyword", foreground: primary.slice(1) },
{ token: "string", foreground: success.slice(1) },
{ token: "comment", foreground: muted.slice(1), fontStyle: "italic" },
{ token: "number", foreground: foreground.slice(1) },
// JSON names its tokens more specifically, so the base theme's
// colours would win over the generic ones above.
{ token: "string.key.json", foreground: foreground.slice(1) },
{ token: "string.value.json", foreground: success.slice(1) },
{ token: "keyword.json", foreground: primary.slice(1) },
],
colors: {
"editor.background": background,
"editor.foreground": foreground,
"editorLineNumber.foreground": muted,
"editorLineNumber.activeForeground": foreground,
"editor.lineHighlightBackground": accent,
"editorCursor.foreground": primary,
"editor.selectionBackground": `${primary}33`,
"editorIndentGuide.background1": accent,
"editorWidget.background": background,
"editorGutter.background": background,
},
})
}
}
export function setupMonaco(): typeof monaco {
if (configured) return monaco
configured = true
// Self-hosted: no CDN fetch, so the editor works on a LAN install.
self.MonacoEnvironment = {
getWorker: (_, label) =>
label === "json" ? new jsonWorker() : new editorWorker(),
}
loader.config({ monaco })
defineThemes()
return monaco
}
export const monacoFontFamily = (): string =>
getComputedStyle(document.documentElement)
.getPropertyValue("--font-mono")
.trim() || "ui-monospace, monospace"