basic function

This commit is contained in:
2026-03-06 23:03:42 +01:00
parent d690c94369
commit 49a6e5b4a3
4 changed files with 210 additions and 7 deletions

View File

@@ -0,0 +1,111 @@
import React, { memo, useCallback, useContext, useEffect, useRef, useState } from 'react'
import Editor, { loader } from '@monaco-editor/react'
import FlowContext from '../../lib/flowContext'
import {
BaseNode,
BaseNodeContent,
BaseNodeFooter,
BaseNodeHeader,
BaseNodeHeaderTitle,
} from './BaseNode'
import { InputHandle, OutputHandle } from './NodeHandles'
import { Code2 } from 'lucide-react'
loader.config({ paths: { vs: 'https://unpkg.com/monaco-editor@latest/min/vs' } })
type Props = {
id: string
data: { body?: string }
}
const DEFAULT_BODY = `// args[0], args[1], ... are the variable values (in order)
return args[0];
`
export const FunctionNode = memo(function FunctionNode({ id, data }: Props) {
const [value, setValue] = useState<string>(data?.body ?? DEFAULT_BODY)
const ctx = useContext(FlowContext)
const setNodes = ctx?.setNodes
const editorRef = useRef<any>(null)
const monacoRef = useRef<any>(null)
useEffect(() => {
if (setNodes) {
setNodes((nds: any[]) =>
nds.map((n) => (n.id === id ? { ...n, data: { ...n.data, body: value } } : n))
)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const onChange = useCallback(
(val?: string) => {
const v = val ?? ''
setValue(v)
if (setNodes) {
setNodes((nds: any[]) =>
nds.map((n) => (n.id === id ? { ...n, data: { ...n.data, body: v } } : n))
)
}
},
[id, setNodes]
)
const handleEditorMount = useCallback((editor: any, monaco: any) => {
editorRef.current = editor
monacoRef.current = monaco
try {
editor.onKeyDown((e: any) => e?.browserEvent?.stopPropagation())
editor.onMouseDown((e: any) => e?.event?.stopPropagation())
} catch {}
}, [])
const storedBody = ctx?.nodes?.find((n: any) => n.id === id)?.data?.body ?? ''
return (
<BaseNode className="w-72">
<BaseNodeHeader className="border-b">
<Code2 className="size-4" />
<BaseNodeHeaderTitle>{id}</BaseNodeHeaderTitle>
</BaseNodeHeader>
<BaseNodeContent>
<p className="text-[10px] text-muted-foreground mb-1">
Call in config: <code className="rounded bg-muted px-0.5">$&#123;{id}(var1, var2)&#125;</code>
</p>
<div style={{ height: 120 }} className="w-full nodrag nopan rounded border border-input overflow-hidden">
<Editor
height="100%"
defaultLanguage="javascript"
value={value}
theme="vs-light"
onMount={handleEditorMount}
onChange={onChange}
options={{
minimap: { enabled: false },
fontSize: 11,
lineHeight: 16,
lineNumbers: 'on',
lineDecorationsWidth: 2,
scrollBeyondLastLine: false,
padding: { top: 4, bottom: 4 },
}}
/>
</div>
</BaseNodeContent>
<BaseNodeFooter>
<div className="w-full text-xs text-muted-foreground">
Body: {storedBody ? `${storedBody.length} chars` : 'none'}
</div>
</BaseNodeFooter>
<InputHandle id="in" />
<OutputHandle id="out" />
</BaseNode>
)
})
FunctionNode.displayName = 'FunctionNode'
export default FunctionNode