Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import Editor from "@monaco-editor/react"
|
|
import { useEffect, useMemo, useRef, useState } from "react"
|
|
|
|
import { useTheme } from "@/components/theme-provider"
|
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
import { monacoFontFamily, setupMonaco } from "./monacoSetup"
|
|
|
|
/**
|
|
* The embedded code editor, Python unless asked for JSON. Highlighting and
|
|
* bracket handling only: what the code actually does is checked by the engine,
|
|
* which reports load and run errors back onto the node.
|
|
*/
|
|
export default function NodeEditor({
|
|
value,
|
|
onChange,
|
|
onBlur,
|
|
language = "python",
|
|
readOnly = false,
|
|
autoFocus = false,
|
|
}: {
|
|
value: string
|
|
onChange: (next: string) => void
|
|
/** Focus left the editor, its find and suggest widgets included. */
|
|
onBlur?: () => void
|
|
language?: "python" | "json"
|
|
/** Generated code: readable, and not this panel's to change. */
|
|
readOnly?: boolean
|
|
/** Take the caret once mounted, as an editor opened on purpose should. */
|
|
autoFocus?: boolean
|
|
}) {
|
|
const { resolvedTheme } = useTheme()
|
|
const [ready, setReady] = useState(false)
|
|
const blur = useRef(onBlur)
|
|
blur.current = onBlur
|
|
|
|
useEffect(() => {
|
|
setupMonaco()
|
|
setReady(true)
|
|
}, [])
|
|
|
|
const fontFamily = useMemo(() => (ready ? monacoFontFamily() : ""), [ready])
|
|
|
|
if (!ready) return <Skeleton className="h-full w-full rounded-md" />
|
|
|
|
return (
|
|
<Editor
|
|
language={language}
|
|
theme={resolvedTheme === "dark" ? "fluksio-dark" : "fluksio-light"}
|
|
value={value}
|
|
onChange={(next) => onChange(next ?? "")}
|
|
onMount={(editor) => {
|
|
editor.onDidBlurEditorWidget(() => blur.current?.())
|
|
if (autoFocus) editor.focus()
|
|
}}
|
|
loading={<Skeleton className="h-full w-full rounded-md" />}
|
|
options={{
|
|
readOnly,
|
|
fontFamily,
|
|
fontSize: 13,
|
|
minimap: { enabled: false },
|
|
scrollBeyondLastLine: false,
|
|
automaticLayout: true,
|
|
tabSize: 4,
|
|
lineNumbersMinChars: 3,
|
|
padding: { top: 12, bottom: 12 },
|
|
renderLineHighlight: "line",
|
|
overviewRulerLanes: 0,
|
|
scrollbar: { verticalScrollbarSize: 8, horizontalScrollbarSize: 8 },
|
|
}}
|
|
/>
|
|
)
|
|
}
|