Init commit

This commit is contained in:
NikitaKalitov
2026-07-13 15:44:13 +03:00
commit 5b6bdc0a1f
22 changed files with 2193 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
import { useCallback, useMemo, useState } from 'react';
import {
ReactFlow,
ReactFlowProvider,
Background,
Controls,
MiniMap,
addEdge,
applyNodeChanges,
applyEdgeChanges,
type Node,
type Edge,
type OnConnect,
type NodeChange,
type EdgeChange,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { nodeTypes } from './nodes';
import { debounce, serializeDocument } from './serialize';
import type { DiagramDocument } from './types';
import './diagram.css';
interface DiagramEditorProps {
initialValue: DiagramDocument | null;
onChange: (doc: DiagramDocument) => void;
}
function toRfNodes(doc: DiagramDocument | null): Node[] {
return (doc?.nodes ?? []).map((node) => ({
id: node.id,
type: node.type,
position: node.position,
data: node.data,
}));
}
function toRfEdges(doc: DiagramDocument | null): Edge[] {
return (doc?.edges ?? []).map((edge) => ({
id: edge.id,
source: edge.source,
target: edge.target,
type: edge.type,
data: edge.data,
}));
}
function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
const [nodes, setNodes] = useState<Node[]>(() => toRfNodes(initialValue));
const [edges, setEdges] = useState<Edge[]>(() => toRfEdges(initialValue));
const emitChange = useMemo(
() => debounce((n: Node[], e: Edge[]) => onChange(serializeDocument(n, e)), 400),
[onChange],
);
const onNodesChange = useCallback(
(changes: NodeChange[]) => {
setNodes((current) => {
const next = applyNodeChanges(changes, current);
emitChange(next, edges);
return next;
});
},
[edges, emitChange],
);
const onEdgesChange = useCallback(
(changes: EdgeChange[]) => {
setEdges((current) => {
const next = applyEdgeChanges(changes, current);
emitChange(nodes, next);
return next;
});
},
[nodes, emitChange],
);
const onConnect: OnConnect = useCallback(
(connection) => {
setEdges((current) => {
const next = addEdge(connection, current);
emitChange(nodes, next);
return next;
});
},
[nodes, emitChange],
);
return (
<div className="diagram-canvas">
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
>
<Background />
<Controls />
<MiniMap />
</ReactFlow>
</div>
);
}
export function DiagramEditor(props: DiagramEditorProps) {
return (
<ReactFlowProvider>
<DiagramCanvas {...props} />
</ReactFlowProvider>
);
}