/** Read-only derived output. Loading this entry does not load CodeMirror until opened. */ export async function mountBuilderSourceEditor( parent: HTMLElement, language: "text" | "xml", content: string, options: { label?: string; theme?: "tokens" } = {}, ) { const [ { EditorView, basicSetup }, { EditorState, Compartment }, { xml }, { HighlightStyle, syntaxHighlighting }, { tags }, ] = await Promise.all([ import("codemirror"), import("@codemirror/state"), import("@codemirror/lang-xml"), import("@codemirror/language"), import("@lezer/highlight"), ]); if (!parent.isConnected) return null; const stopShortcut = (event: KeyboardEvent) => event.stopPropagation(); parent.addEventListener("keydown", stopShortcut); const wrapping = new Compartment(); const color = (token: string, legacy: string) => options.theme === "tokens" ? `var(--wrn-color-${token})` : legacy; const view = new EditorView({ parent, doc: content, extensions: [ basicSetup, EditorState.readOnly.of(true), EditorView.editable.of(false), EditorView.contentAttributes.of({ tabindex: "0", "aria-label": options.label ?? "Generated email source", }), language === "xml" ? xml() : [], wrapping.of([]), syntaxHighlighting( HighlightStyle.define([ { tag: tags.tagName, color: color("primary", "#7dd3fc") }, { tag: tags.attributeName, color: color("text", "#c4b5fd") }, { tag: tags.attributeValue, color: color("primary", "#a7f3d0") }, { tag: tags.angleBracket, color: color("muted", "#94a3b8") }, { tag: tags.comment, color: color("muted", "#94a3b8") }, ]), ), EditorView.theme({ "&": { height: "100%", fontSize: "12px", backgroundColor: color("surface", "#111827"), color: color("text", "#e5e7eb"), }, ".cm-scroller": { overflow: "auto", fontFamily: "ui-monospace, Consolas, monospace" }, ".cm-gutters": { backgroundColor: color("surface", "#111827"), color: color("muted", "#94a3b8"), borderColor: color("border", "#334155"), }, ".cm-activeLine, .cm-activeLineGutter": { backgroundColor: "transparent" }, "&.cm-focused": { outline: "2px solid var(--wrn-color-primary)", outlineOffset: "-2px" }, }), ], }); let destroyed = false; const observer = new MutationObserver(() => { if (!parent.isConnected) destroy(); }); function destroy() { if (destroyed) return; destroyed = true; observer.disconnect(); parent.removeEventListener("keydown", stopShortcut); view.destroy(); } observer.observe(parent.ownerDocument.documentElement, { childList: true, subtree: true }); return { update(value: string) { if (!destroyed && view.state.doc.toString() !== value) view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: value } }); }, wrap(enabled: boolean) { if (!destroyed) view.dispatch({ effects: wrapping.reconfigure(enabled ? EditorView.lineWrapping : []) }); }, destroy, }; }