Flow Prototype

nodeDev
Klotske 2022-07-14 17:50:12 +00:00
parent 6665d418b8
commit 00c22ac2be
9 changed files with 200 additions and 10 deletions

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,5 @@
const Panel = () => {
return <aside className="flow-panel"></aside>;
};
export default Panel;

View File

@ -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;

View File

@ -0,0 +1,5 @@
import { Edge } from "react-flow-renderer";
const initialEdges: Edge[] = [];
export default initialEdges;

View File

@ -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;

50
package-lock.json generated
View File

@ -12,7 +12,8 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-flow-renderer": "^10.3.9",
"react-icons": "^4.4.0"
"react-icons": "^4.4.0",
"zustand": "^4.0.0-rc.1"
},
"devDependencies": {
"@types/node": "17.0.4",
@ -4682,6 +4683,22 @@
"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": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz",
@ -5888,16 +5905,23 @@
}
},
"node_modules/zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"version": "4.0.0-rc.1",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.0.0-rc.1.tgz",
"integrity": "sha512-qgcs7zLqBdHu0PuT3GW4WCIY5SgXdsv30GQMu9Qpp1BA2aS+sNS8l4x0hWuyEhjXkN+701aGWawhKDv6oWJAcw==",
"dependencies": {
"use-sync-external-store": "1.1.0"
},
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"immer": ">=9.0",
"react": ">=16.8"
},
"peerDependenciesMeta": {
"immer": {
"optional": true
},
"react": {
"optional": true
}
@ -9124,6 +9148,14 @@
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0",
"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": {
@ -10035,10 +10067,12 @@
"dev": true
},
"zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"requires": {}
"version": "4.0.0-rc.1",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.0.0-rc.1.tgz",
"integrity": "sha512-qgcs7zLqBdHu0PuT3GW4WCIY5SgXdsv30GQMu9Qpp1BA2aS+sNS8l4x0hWuyEhjXkN+701aGWawhKDv6oWJAcw==",
"requires": {
"use-sync-external-store": "1.1.0"
}
}
}
}

View File

@ -13,7 +13,8 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-flow-renderer": "^10.3.9",
"react-icons": "^4.4.0"
"react-icons": "^4.4.0",
"zustand": "^4.0.0-rc.1"
},
"devDependencies": {
"@types/node": "17.0.4",

View File

@ -1,5 +1,7 @@
import FlowEditor from "../components/FlowEditor/FlowEditor";
const Flow = () => {
return "Визуальная среда";
return <FlowEditor />;
};
export default Flow;