Flow Prototype
parent
6665d418b8
commit
00c22ac2be
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import ReactFlow, {
|
||||||
|
Background,
|
||||||
|
Controls,
|
||||||
|
ReactFlowInstance,
|
||||||
|
} from "react-flow-renderer";
|
||||||
|
import useStore from "../../lib/FlowEditor/FlowEditorStore";
|
||||||
|
|
||||||
|
const Flow = () => {
|
||||||
|
const [reactFlowInstance, setReactFlowInstance] =
|
||||||
|
useState<ReactFlowInstance>();
|
||||||
|
|
||||||
|
const onInit = (rfi: ReactFlowInstance) => {
|
||||||
|
setReactFlowInstance(rfi);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { nodes, edges, onNodesChange, onEdgesChange, onConnect } = useStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flow h-screen w-full">
|
||||||
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
edges={edges}
|
||||||
|
onNodesChange={onNodesChange}
|
||||||
|
onEdgesChange={onEdgesChange}
|
||||||
|
onConnect={onConnect}
|
||||||
|
onInit={onInit}
|
||||||
|
fitView
|
||||||
|
snapToGrid={true}
|
||||||
|
>
|
||||||
|
<Controls />
|
||||||
|
<Background />
|
||||||
|
</ReactFlow>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Flow;
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { DndContext } from "@dnd-kit/core";
|
||||||
|
import { ReactFlowProvider } from "react-flow-renderer";
|
||||||
|
import Flow from "./Flow";
|
||||||
|
import Panel from "./Panel";
|
||||||
|
|
||||||
|
const FlowEditorComponent = () => {
|
||||||
|
return (
|
||||||
|
<DndContext>
|
||||||
|
<Panel />
|
||||||
|
<Flow />
|
||||||
|
</DndContext>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FlowEditor = () => {
|
||||||
|
return (
|
||||||
|
<div className="flow-editor">
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<FlowEditorComponent />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FlowEditor;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
const Panel = () => {
|
||||||
|
return <aside className="flow-panel"></aside>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Panel;
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
import create from "zustand";
|
||||||
|
import {
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
EdgeChange,
|
||||||
|
Node,
|
||||||
|
NodeChange,
|
||||||
|
addEdge,
|
||||||
|
OnNodesChange,
|
||||||
|
OnEdgesChange,
|
||||||
|
OnConnect,
|
||||||
|
applyNodeChanges,
|
||||||
|
applyEdgeChanges,
|
||||||
|
XYPosition,
|
||||||
|
} from "react-flow-renderer";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
|
import initialNodes from "./nodes";
|
||||||
|
import initialEdges from "./edges";
|
||||||
|
|
||||||
|
type FlowEditorStore = {
|
||||||
|
nodes: Node[];
|
||||||
|
edges: Edge[];
|
||||||
|
panelClosed: boolean;
|
||||||
|
onNodesChange: OnNodesChange;
|
||||||
|
onEdgesChange: OnEdgesChange;
|
||||||
|
onConnect: OnConnect;
|
||||||
|
addNode: (type: string, position: XYPosition) => void;
|
||||||
|
togglePanelState: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStore = create<FlowEditorStore>((set, get) => ({
|
||||||
|
nodes: initialNodes,
|
||||||
|
edges: initialEdges,
|
||||||
|
panelClosed: false,
|
||||||
|
onNodesChange: (changes: NodeChange[]) => {
|
||||||
|
set({
|
||||||
|
nodes: applyNodeChanges(changes, get().nodes),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onEdgesChange: (changes: EdgeChange[]) => {
|
||||||
|
set({
|
||||||
|
edges: applyEdgeChanges(changes, get().edges),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onConnect: (connection: Connection) => {
|
||||||
|
set({
|
||||||
|
edges: addEdge(connection, get().edges),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addNode: (type: string, position: XYPosition) => {
|
||||||
|
const newNode: Node = {
|
||||||
|
id: `node_${nanoid()}`,
|
||||||
|
type: type,
|
||||||
|
position: position,
|
||||||
|
data: { label: `${type} node` },
|
||||||
|
};
|
||||||
|
set({
|
||||||
|
nodes: get().nodes.concat(newNode),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
togglePanelState: () => {
|
||||||
|
set({
|
||||||
|
panelClosed: !get().panelClosed,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
export default useStore;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { Edge } from "react-flow-renderer";
|
||||||
|
|
||||||
|
const initialEdges: Edge[] = [];
|
||||||
|
|
||||||
|
export default initialEdges;
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Node } from "react-flow-renderer";
|
||||||
|
|
||||||
|
const initialNodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
type: "input",
|
||||||
|
data: { label: "Старт" },
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default initialNodes;
|
||||||
|
|
@ -12,7 +12,8 @@
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-flow-renderer": "^10.3.9",
|
"react-flow-renderer": "^10.3.9",
|
||||||
"react-icons": "^4.4.0"
|
"react-icons": "^4.4.0",
|
||||||
|
"zustand": "^4.0.0-rc.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "17.0.4",
|
"@types/node": "17.0.4",
|
||||||
|
|
@ -4682,6 +4683,22 @@
|
||||||
"react-dom": "16 || 17 || 18"
|
"react-dom": "16 || 17 || 18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-flow-renderer/node_modules/zustand": {
|
||||||
|
"version": "3.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
|
||||||
|
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.7.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-icons": {
|
"node_modules/react-icons": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz",
|
||||||
|
|
@ -5888,16 +5905,23 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zustand": {
|
"node_modules/zustand": {
|
||||||
"version": "3.7.2",
|
"version": "4.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
|
"integrity": "sha512-qgcs7zLqBdHu0PuT3GW4WCIY5SgXdsv30GQMu9Qpp1BA2aS+sNS8l4x0hWuyEhjXkN+701aGWawhKDv6oWJAcw==",
|
||||||
|
"dependencies": {
|
||||||
|
"use-sync-external-store": "1.1.0"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.7.0"
|
"node": ">=12.7.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
"immer": ">=9.0",
|
||||||
"react": ">=16.8"
|
"react": ">=16.8"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
|
"immer": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
|
|
@ -9124,6 +9148,14 @@
|
||||||
"d3-selection": "^3.0.0",
|
"d3-selection": "^3.0.0",
|
||||||
"d3-zoom": "^3.0.0",
|
"d3-zoom": "^3.0.0",
|
||||||
"zustand": "^3.7.2"
|
"zustand": "^3.7.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"zustand": {
|
||||||
|
"version": "3.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
|
||||||
|
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-icons": {
|
"react-icons": {
|
||||||
|
|
@ -10035,10 +10067,12 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"zustand": {
|
"zustand": {
|
||||||
"version": "3.7.2",
|
"version": "4.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
|
"integrity": "sha512-qgcs7zLqBdHu0PuT3GW4WCIY5SgXdsv30GQMu9Qpp1BA2aS+sNS8l4x0hWuyEhjXkN+701aGWawhKDv6oWJAcw==",
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"use-sync-external-store": "1.1.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-flow-renderer": "^10.3.9",
|
"react-flow-renderer": "^10.3.9",
|
||||||
"react-icons": "^4.4.0"
|
"react-icons": "^4.4.0",
|
||||||
|
"zustand": "^4.0.0-rc.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "17.0.4",
|
"@types/node": "17.0.4",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
import FlowEditor from "../components/FlowEditor/FlowEditor";
|
||||||
|
|
||||||
const Flow = () => {
|
const Flow = () => {
|
||||||
return "Визуальная среда";
|
return <FlowEditor />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Flow;
|
export default Flow;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue