73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
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<Iface|undefined>(undefined);
|
|
export default Editor;
|
|
|
|
type SetNodes = Dispatch<SetStateAction<NodeType[]>>;
|
|
type SetEdges = Dispatch<SetStateAction<EdgeType[]>>;
|
|
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))
|
|
);
|
|
}
|