import { useEffect, useRef } from "react" import { EditorState } from "@codemirror/state" import { EditorView, lineNumbers } from "@codemirror/view" import { HighlightStyle, syntaxHighlighting } from "@codemirror/language" import { javascript } from "@codemirror/lang-javascript" import { tags as t } from "@lezer/highlight" const highlight = HighlightStyle.define([ { tag: [t.keyword, t.modifier, t.operatorKeyword], color: "var(--ds-accent)" }, { tag: [t.propertyName], color: "var(--ds-accent)" }, { tag: [t.string, t.regexp], color: "var(--ds-ok)" }, { tag: [t.number, t.bool, t.null], color: "var(--ds-warn)" }, { tag: [t.comment], color: "var(--ds-text-3)", fontStyle: "italic" }, ]) const theme = EditorView.theme({ "&": { backgroundColor: "var(--ds-bg)", color: "var(--ds-text-2)", fontSize: "12px" }, ".cm-content": { fontFamily: "var(--font-data, ui-monospace, monospace)", padding: "6px 0" }, ".cm-gutters": { backgroundColor: "var(--ds-bg)", color: "var(--ds-text-3)", border: "none" }, ".cm-scroller": { overflow: "auto", maxHeight: "360px" }, }) /** * Read-only CodeMirror view. JSON is valid JavaScript, so the JS grammar * highlights it; `lang="text"` skips highlighting for plain log lines. */ export const CodeBlock = ({ code, lang = "json", label }: { code: string; lang?: "json" | "text"; label: string }) => { const host = useRef(null) useEffect(() => { if (!host.current) return const view = new EditorView({ parent: host.current, state: EditorState.create({ doc: code, extensions: [ EditorState.readOnly.of(true), EditorView.editable.of(false), EditorView.lineWrapping, lineNumbers(), theme, ...(lang === "json" ? [javascript(), syntaxHighlighting(highlight)] : []), ], }), }) return () => view.destroy() }, [code, lang]) return
}