From 00c22ac2be3e6a07ac76e94da8d1979ffbb6c370 Mon Sep 17 00:00:00 2001 From: Klotske Date: Thu, 14 Jul 2022 17:50:12 +0000 Subject: [PATCH] Flow Prototype --- components/FlowEditor/Flow.tsx | 38 ++++++++++++++++ components/FlowEditor/FlowEditor.tsx | 25 ++++++++++ components/FlowEditor/Panel.tsx | 5 ++ lib/FlowEditor/FlowEditorStore.ts | 68 ++++++++++++++++++++++++++++ lib/FlowEditor/edges.ts | 5 ++ lib/FlowEditor/nodes.ts | 12 +++++ package-lock.json | 50 ++++++++++++++++---- package.json | 3 +- pages/flow.tsx | 4 +- 9 files changed, 200 insertions(+), 10 deletions(-) create mode 100644 components/FlowEditor/Flow.tsx create mode 100644 components/FlowEditor/FlowEditor.tsx create mode 100644 components/FlowEditor/Panel.tsx create mode 100644 lib/FlowEditor/FlowEditorStore.ts create mode 100644 lib/FlowEditor/edges.ts create mode 100644 lib/FlowEditor/nodes.ts diff --git a/components/FlowEditor/Flow.tsx b/components/FlowEditor/Flow.tsx new file mode 100644 index 0000000..4f25817 --- /dev/null +++ b/components/FlowEditor/Flow.tsx @@ -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(); + + const onInit = (rfi: ReactFlowInstance) => { + setReactFlowInstance(rfi); + }; + + const { nodes, edges, onNodesChange, onEdgesChange, onConnect } = useStore(); + + return ( +
+ + + + +
+ ); +}; + +export default Flow; diff --git a/components/FlowEditor/FlowEditor.tsx b/components/FlowEditor/FlowEditor.tsx new file mode 100644 index 0000000..f6371aa --- /dev/null +++ b/components/FlowEditor/FlowEditor.tsx @@ -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 ( + + + + + ); +}; + +const FlowEditor = () => { + return ( +
+ + + +
+ ); +}; + +export default FlowEditor; diff --git a/components/FlowEditor/Panel.tsx b/components/FlowEditor/Panel.tsx new file mode 100644 index 0000000..aef2131 --- /dev/null +++ b/components/FlowEditor/Panel.tsx @@ -0,0 +1,5 @@ +const Panel = () => { + return ; +}; + +export default Panel; diff --git a/lib/FlowEditor/FlowEditorStore.ts b/lib/FlowEditor/FlowEditorStore.ts new file mode 100644 index 0000000..32d5995 --- /dev/null +++ b/lib/FlowEditor/FlowEditorStore.ts @@ -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((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; diff --git a/lib/FlowEditor/edges.ts b/lib/FlowEditor/edges.ts new file mode 100644 index 0000000..36085cf --- /dev/null +++ b/lib/FlowEditor/edges.ts @@ -0,0 +1,5 @@ +import { Edge } from "react-flow-renderer"; + +const initialEdges: Edge[] = []; + +export default initialEdges; diff --git a/lib/FlowEditor/nodes.ts b/lib/FlowEditor/nodes.ts new file mode 100644 index 0000000..557c0ef --- /dev/null +++ b/lib/FlowEditor/nodes.ts @@ -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; diff --git a/package-lock.json b/package-lock.json index 5842d81..d3c9517 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" + } } } } diff --git a/package.json b/package.json index 0e0c2e5..303842c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pages/flow.tsx b/pages/flow.tsx index 021716e..2e4c404 100644 --- a/pages/flow.tsx +++ b/pages/flow.tsx @@ -1,5 +1,7 @@ +import FlowEditor from "../components/FlowEditor/FlowEditor"; + const Flow = () => { - return "Визуальная среда"; + return ; }; export default Flow;