kaikai/src/pages/context/Editor.tsx

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))
);
}