Portal/rsconcept/frontend/src/dialogs/DlgShowAST/ASTFlow.tsx

75 lines
1.8 KiB
TypeScript

'use client';
import { useLayoutEffect } from 'react';
import { Edge, MarkerType, Node, ReactFlow, useEdgesState, useNodesState, useReactFlow } from 'reactflow';
import { SyntaxTree } from '@/models/rslang';
import { ASTEdgeTypes } from './graph/ASTEdgeTypes';
import { applyLayout } from './graph/ASTLayout';
import { ASTNodeTypes } from './graph/ASTNodeTypes';
interface ASTFlowProps {
data: SyntaxTree;
onNodeEnter: (node: Node) => void;
onNodeLeave: (node: Node) => void;
}
function ASTFlow({ data, onNodeEnter, onNodeLeave }: ASTFlowProps) {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges] = useEdgesState([]);
const flow = useReactFlow();
useLayoutEffect(() => {
const newNodes = data.map(node => ({
id: String(node.uid),
data: node,
position: { x: 0, y: 0 },
type: 'token'
}));
const newEdges: Edge[] = [];
data.forEach(node => {
if (node.parent !== node.uid) {
newEdges.push({
id: String(node.uid),
source: String(node.parent),
target: String(node.uid),
type: 'dynamic',
focusable: false,
markerEnd: {
type: MarkerType.ArrowClosed,
width: 20,
height: 20
}
});
}
});
applyLayout(newNodes, newEdges);
setNodes(newNodes);
setEdges(newEdges);
}, [data, setNodes, setEdges, flow]);
return (
<ReactFlow
nodes={nodes}
edges={edges}
edgesFocusable={false}
nodesFocusable={false}
onNodeMouseEnter={(_, node) => onNodeEnter(node)}
onNodeMouseLeave={(_, node) => onNodeLeave(node)}
onNodesChange={onNodesChange}
nodeTypes={ASTNodeTypes}
edgeTypes={ASTEdgeTypes}
fitView
maxZoom={2}
minZoom={0.5}
nodesConnectable={false}
/>
);
}
export default ASTFlow;