import { Dispatch, SetStateAction, createContext } from "react"; import { Connection, EdgeType, NodeType, addEdge } from "@xyflow/react"; type Pos = {x: int, y: int,}; export interface Iface { add(type: string, pos: Pos, data: any): string; remove(id: string[]): void; modify(id: string, data: any): void; connect(conn: Connection): void; disconnect(conn: Connection[]): void; }; export const Editor = createContext(undefined); export default Editor; type SetNodes = Dispatch>; type SetEdges = Dispatch>; export class Impl implements Iface { _setNodes: SetNodes; _setEdges: SetEdges; _nextId: number = 0; constructor(setNodes: SetNodes, setEdges: SetEdges, nextId: number = 0) { this._setNodes = setNodes; this._setEdges = setEdges; this._nextId = nextId; } add(type: string, pos: Pos, data: any): string { const ret = this._genNextId(); this._setNodes((nds)=>[...nds, { id: ret, type: type, pos: pos, data: data, }]); return ret; } remove(ids: string[]): void { this._setNodes((nds)=>nds.filter((x)=>!ids.includes(x.id))); } modify(id: string, data: any): void { this._setNodes( (nds)=>nds.map((n)=>n.id === id? {...n, data: data}: n) ); } connect(c: Connection): void { this._setEdges((eds)=>addEdge({ ...c, deletable: true, }, eds)); } disconnect(cs: Connection[]): void { this._setEdges((eds)=>eds.filter((e)=>!cs.some(c=>matchEdgeAndConn(e, c)))); } _genNextId(): number { return "n"+(_nextId++); } }; function matchEdgeAndConn(e: Edge, c: Connection) { return ( (e.source === c.source) && ((e.sourceHandle??null) == (c.sourceHandle??null)) && (e.target == c.target) && ((e.targetHandle??null) == (c.targetHandle??null)) ); }