From 49c0349923d344bd3335de3cafb82d569a78aadb Mon Sep 17 00:00:00 2001 From: ModestFun <61576426+ModestFun@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:20:44 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20nodes=20and=20edges=20life?= =?UTF-8?q?=20cycle=20(#87)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :bug: fix: flow view docs * :sparkles: feat: add nodes onchange * :sparkles: feat: flow editor nodesChange cb done * :sparkles: feat: flow editor edge change * :sparkles: feat: basic node render * :bug: fix: demo refix * :sparkles: feat: on node change * :bug: feat: new nodes change life cycle * :bug: feat: ci * :bug: fix: some thing * :bug: fix: flow provider ci * :bug: fix: rm repeat call --------- Co-authored-by: jiangchu --- src/BasicGroupNode/index.tsx | 8 +- src/BasicNode/index.tsx | 8 +- src/FlowEditor/container/FlowEditor.tsx | 192 ++++++++---------- .../container/StoreUpdater/Common.tsx | 14 ++ .../container/StoreUpdater/index.tsx | 8 + src/FlowEditor/container/index.tsx | 24 +-- src/FlowEditor/demos/index.tsx | 31 ++- src/FlowEditor/hooks/useFlowEditor.ts | 2 + src/FlowEditor/store/initialState.ts | 9 + src/FlowEditor/store/slices/edgesSlice.ts | 61 +++++- src/FlowEditor/store/slices/nodesSlice.ts | 84 +++++++- src/FlowEditor/utils/convertChange.ts | 70 +++++++ .../demos/FlowStoreProvider.tsx | 4 +- src/FlowView/hooks/useFlowView.ts | 13 +- 14 files changed, 388 insertions(+), 140 deletions(-) create mode 100644 src/FlowEditor/utils/convertChange.ts diff --git a/src/BasicGroupNode/index.tsx b/src/BasicGroupNode/index.tsx index 22b39b2..da4df83 100644 --- a/src/BasicGroupNode/index.tsx +++ b/src/BasicGroupNode/index.tsx @@ -72,11 +72,13 @@ const BasicNodeGroup: React.FC<{ style={{ position: 'absolute', zIndex: 10, - top: `-${zoomNum(24, zoom, true)}px`, - padding: `${2 / zoom}px ${1 / zoom}px ${2 / zoom}px 0`, + transform: `translate(0, -${zoomNum(20, zoom, true)}px) scale(${1 / zoom})`, + // top: `-${zoomNum(24, zoom, true)}px`, + // padding: `${2 / zoom}px ${1 / zoom}px ${2 / zoom}px 0`, color: `rgba(0, 0, 0, 0.45)`, borderRadius: `4px`, - fontSize: `${14 / zoom}px`, + // fontSize: `${14 / zoom}px`, + fontSize: `${14}px`, whiteSpace: `nowrap`, }} > diff --git a/src/BasicNode/index.tsx b/src/BasicNode/index.tsx index 4a58f4a..7795145 100644 --- a/src/BasicNode/index.tsx +++ b/src/BasicNode/index.tsx @@ -55,11 +55,13 @@ const BasicNode: React.FC<{ style={{ position: 'absolute', zIndex: 10, - top: `-${zoomNum(24, zoom, true)}px`, - padding: `${2 / zoom}px ${1 / zoom}px ${2 / zoom}px 0`, + transform: `translate(0, -${zoomNum(20, zoom, true)}px) scale(${1 / zoom})`, + // top: `-${zoomNum(24, zoom, true)}px`, + // padding: `${2 / zoom}px ${1 / zoom}px ${2 / zoom}px 0`, color: `rgba(0, 0, 0, 0.45)`, borderRadius: `4px`, - fontSize: `${14 / zoom}px`, + // fontSize: `${14 / zoom}px`, + fontSize: `${14}px`, whiteSpace: `nowrap`, }} > diff --git a/src/FlowEditor/container/FlowEditor.tsx b/src/FlowEditor/container/FlowEditor.tsx index beae465..ed8ea98 100644 --- a/src/FlowEditor/container/FlowEditor.tsx +++ b/src/FlowEditor/container/FlowEditor.tsx @@ -1,6 +1,6 @@ import { createStyles, cx } from 'antd-style'; import isEqual from 'fast-deep-equal'; -import { debounce, throttle } from 'lodash-es'; +import { debounce } from 'lodash-es'; import { JSXElementConstructor, forwardRef, useCallback, useEffect, useMemo } from 'react'; import { Flexbox } from 'react-layout-kit'; import ReactFlow, { @@ -8,9 +8,7 @@ import ReactFlow, { BackgroundVariant, Connection, Edge, - EdgeChange, Node, - NodeChange, NodeTypes, SelectionMode, Viewport, @@ -72,13 +70,13 @@ export interface FlowEditorAppProps { onNodesInitChange?: (init: boolean) => void; // nodes 事件 - beforeNodesChange?: (changes: NodeChange[]) => boolean; - onNodesChange?: (changes: NodeChange[]) => void; - afterNodesChange?: (changes: NodeChange[]) => void; + // beforeNodesChange?: (changes: NodeChange[]) => boolean; + // onNodesChange?: (changes: NodeChange[]) => void; + // afterNodesChange?: (changes: NodeChange[]) => void; // edges 事件 - beforeEdgesChange?: (changes: EdgeChange[]) => boolean; - onEdgesChange?: (changes: EdgeChange[]) => void; - afterEdgeChange?: (changes: EdgeChange[]) => void; + // beforeEdgesChange?: (changes: EdgeChange[]) => boolean; + // onEdgesChange?: (changes: EdgeChange[]) => void; + // afterEdgeChange?: (changes: EdgeChange[]) => void; // connection 事件 beforeConnect?: (connection: Connection) => boolean; onConnect?: (connection: Connection) => void; @@ -105,17 +103,10 @@ const FlowEditor = forwardRef( background = true, miniMap = true, onNodesInit, - beforeNodesChange = () => true, - onNodesChange = () => {}, - afterNodesChange = () => {}, beforeConnect = () => true, onConnect = () => {}, afterConnect = () => {}, - - beforeEdgesChange = () => true, - onEdgesChange, - afterEdgeChange = () => {}, }, ref, ) => { @@ -140,23 +131,17 @@ const FlowEditor = forwardRef( }, [nodes, nodesInitialized]); const [ - // onNodesChange, + handleNodesChange, + handleEdgesChange, updateEdgesOnConnection, - updateEdgesOnEdgeChange, onViewPortChange, - onElementSelectChange, // onEdgesChange, - dispatchNodes, - deselectElement, ] = useStore((s) => [ - // s.onNodesChange, + s.handleNodesChange, + s.handleEdgesChange, s.updateEdgesOnConnection, - s.updateEdgesOnEdgeChange, s.onViewPortChange, - s.onElementSelectChange, // s.onEdgesChange, - s.dispatchNodes, - s.deselectElement, ]); const instance = useReactFlow(); @@ -183,90 +168,87 @@ const FlowEditor = forwardRef( } }, [nodesInitialized]); - const handleNodesChange = useCallback((changes: NodeChange[]) => { - if (!beforeNodesChange(changes)) { - return; - } - // 选择逻辑 nodes 和 edges 一致 - changes.forEach((c) => { - switch (c.type) { - case 'add': - dispatchNodes({ type: 'addNode', node: c.item }); - break; - case 'position': - // 结束拖拽时,会触发一次 position,此时 dragging 为 false - if (!c.dragging) break; - - dispatchNodes({ type: 'updateNodePosition', position: c.position, id: c.id }); - - break; - - case 'remove': - deselectElement(c.id); - dispatchNodes({ type: 'deleteNode', id: c.id }); - break; - case 'select': - onElementSelectChange(c.id, c.selected); + // const handleNodesChange = useCallback( + // (changes: NodeChange[]) => { + // if (!get().beforeNodesChange(changes)) { + // return; + // } + // // 选择逻辑 nodes 和 edges 一致 + // changes.forEach((c) => { + // switch (c.type) { + // case 'add': + // dispatchNodes({ type: 'addNode', node: c.item }); + // break; + // case 'position': + // // 结束拖拽时,会触发一次 position,此时 dragging 为 false + // if (!c.dragging) break; + + // dispatchNodes({ type: 'updateNodePosition', position: c.position, id: c.id }); + + // break; + // case 'remove': + // deselectElement(c.id); + // dispatchNodes({ type: 'deleteNode', id: c.id }); + // break; + // case 'select': + // onElementSelectChange(c.id, c.selected); + // } + // }); + + // if (onNodesChange) { + // throttle(onNodesChange, 50)(changes); + // } + + // if (afterNodesChange) { + // afterNodesChange(changes); + // } + // }, + // [onNodesChange], + // ); + + // const handleEdgesChange = useCallback((changes: EdgeChange[]) => { + // if (!beforeEdgesChange(changes)) { + // return; + // } + + // // reactflow 的 edges change 事件,只有 select 和 remove + // updateEdgesOnEdgeChange(changes); + + // // 选择逻辑 nodes 和 edges 一致 + // changes.forEach((c) => { + // switch (c.type) { + // case 'select': + // onElementSelectChange(c.id, c.selected); + // } + // }); + + // if (onEdgesChange) { + // onEdgesChange(changes); + // } + + // if (afterEdgeChange) { + // afterEdgeChange(changes); + // } + // }, []); + + const handleConnect = useCallback( + (connection: Connection) => { + if (!beforeConnect(connection)) { + return; } - }); - - if (onNodesChange) { - throttle(onNodesChange, 50)(changes); - } - - if (afterNodesChange) { - afterNodesChange(changes); - } - }, []); - const handleEdgesChange = useCallback((changes: EdgeChange[]) => { - if (!beforeEdgesChange(changes)) { - return; - } - - // reactflow 的 edges change 事件,只有 select 和 remove - updateEdgesOnEdgeChange(changes); - - // 选择逻辑 nodes 和 edges 一致 - changes.forEach((c) => { - switch (c.type) { - case 'select': - onElementSelectChange(c.id, c.selected); + if (onConnect) { + onConnect(connection); } - }); - if (onEdgesChange) { - onEdgesChange(changes); - } + const edge = updateEdgesOnConnection(connection); - if (afterEdgeChange) { - afterEdgeChange(changes); - } - }, []); - - const handleConnect = useCallback((connection: Connection) => { - if (!beforeConnect(connection)) { - return; - } - - if (onConnect) { - onConnect(connection); - } - - const edge = updateEdgesOnConnection(connection); - - if (afterConnect && edge) { - // 触发 edges change 事件 - handleEdgesChange([ - { - item: edge, - type: 'add', - }, - ]); - - afterConnect(edge); - } - }, []); + if (afterConnect && edge) { + afterConnect(edge); + } + }, + [onConnect, beforeConnect, afterConnect], + ); return ( diff --git a/src/FlowEditor/container/StoreUpdater/Common.tsx b/src/FlowEditor/container/StoreUpdater/Common.tsx index 88d3773..0171c2c 100644 --- a/src/FlowEditor/container/StoreUpdater/Common.tsx +++ b/src/FlowEditor/container/StoreUpdater/Common.tsx @@ -10,9 +10,13 @@ export interface CommonUpdaterProps FlowEditorStore, | 'flattenEdges' | 'onEdgesChange' + | 'beforeEdgesChange' + | 'afterEdgesChange' | 'flattenNodes' | 'onFlattenNodesChange' | 'onNodesChange' + | 'beforeNodesChange' + | 'afterNodesChange' | 'onFlattenEdgesChange' | 'onNodesTreeChange' > @@ -27,7 +31,11 @@ export interface CommonUpdaterProps const CommonStoreUpdater: FC = ({ onFlattenNodesChange, onNodesChange, + beforeNodesChange, + afterNodesChange, onEdgesChange, + beforeEdgesChange, + afterEdgesChange, onFlattenEdgesChange, onNodesTreeChange, editorRef, @@ -46,7 +54,13 @@ const CommonStoreUpdater: FC = ({ useStoreUpdater('onFlattenEdgesChange', onFlattenEdgesChange); useStoreUpdater('onNodesChange', onNodesChange); + useStoreUpdater('beforeNodesChange', beforeNodesChange); + useStoreUpdater('afterNodesChange', afterNodesChange); + useStoreUpdater('onEdgesChange', onEdgesChange); + useStoreUpdater('beforeEdgesChange', beforeEdgesChange); + useStoreUpdater('afterEdgesChange', afterEdgesChange); + useStoreUpdater('onNodesTreeChange', onNodesTreeChange); // 将 store 传递到外部 diff --git a/src/FlowEditor/container/StoreUpdater/index.tsx b/src/FlowEditor/container/StoreUpdater/index.tsx index ccce404..c217305 100644 --- a/src/FlowEditor/container/StoreUpdater/index.tsx +++ b/src/FlowEditor/container/StoreUpdater/index.tsx @@ -16,8 +16,12 @@ const StoreUpdater: FC = ({ flattenNodes, onFlattenNodesChange, onNodesChange, + beforeNodesChange, + afterNodesChange, flattenEdges, onEdgesChange, + beforeEdgesChange, + afterEdgesChange, onFlattenEdgesChange, onNodesTreeChange, onViewPortChange, @@ -55,6 +59,10 @@ const StoreUpdater: FC = ({ editorRef={editorRef} onEdgesChange={onEdgesChange} onNodesChange={onNodesChange} + beforeNodesChange={beforeNodesChange} + beforeEdgesChange={beforeEdgesChange} + afterEdgesChange={afterEdgesChange} + afterNodesChange={afterNodesChange} onNodesTreeChange={onNodesTreeChange} onFlattenEdgesChange={onFlattenEdgesChange} onFlattenNodesChange={onFlattenNodesChange} diff --git a/src/FlowEditor/container/index.tsx b/src/FlowEditor/container/index.tsx index a985c4f..7ce7ec4 100644 --- a/src/FlowEditor/container/index.tsx +++ b/src/FlowEditor/container/index.tsx @@ -16,14 +16,14 @@ const FlowEditor = forwardRef( onNodesInit, // edge change - beforeEdgesChange, - onEdgesChange, - afterEdgeChange, + // beforeEdgesChange, + // onEdgesChange, + // afterEdgeChange, // node change - beforeNodesChange, - onNodesChange, - afterNodesChange, + // beforeNodesChange, + // onNodesChange, + // afterNodesChange, // Connect beforeConnect, @@ -50,13 +50,13 @@ const FlowEditor = forwardRef( miniMap={miniMap} background={background} onNodesInit={onNodesInit} - beforeNodesChange={beforeNodesChange} - beforeEdgesChange={beforeEdgesChange} + // beforeNodesChange={beforeNodesChange} + // beforeEdgesChange={beforeEdgesChange} beforeConnect={beforeConnect} - onEdgesChange={onEdgesChange} - afterEdgeChange={afterEdgeChange} - onNodesChange={onNodesChange} - afterNodesChange={afterNodesChange} + // onEdgesChange={onEdgesChange} + // afterEdgeChange={afterEdgeChange} + // onNodesChange={onNodesChange} + // afterNodesChange={afterNodesChange} onConnect={onConnect} afterConnect={afterConnect} contextMenuEnabled={contextMenuEnabled} diff --git a/src/FlowEditor/demos/index.tsx b/src/FlowEditor/demos/index.tsx index f7379bd..d343c4c 100644 --- a/src/FlowEditor/demos/index.tsx +++ b/src/FlowEditor/demos/index.tsx @@ -73,7 +73,36 @@ const ProFlowDemo = () => { return (
- + { + // console.log('beforeNodesChange', nodes); + // return true; + // }} + // onNodesChange={(nodes) => { + // console.log('onNodesChange', nodes); + // }} + // afterNodesChange={(nodes) => { + // console.log('afterNodesChange', nodes); + // }} + // onFlattenNodesChange={(e) => { + // console.log(e); + // }} + + // onEdgesChange done + // beforeEdgesChange={(edges) => { + // console.log('beforeEdgesChange', edges); + // return true; + // }} + + // afterEdgesChange={(edges) => { + // console.log('afterEdgesChange', edges); + // }} + // onFlattenEdgesChange={(e) => { + // console.log('flattenEdgesChange', e); + // }} + >
); }; diff --git a/src/FlowEditor/hooks/useFlowEditor.ts b/src/FlowEditor/hooks/useFlowEditor.ts index 7e12628..2179990 100644 --- a/src/FlowEditor/hooks/useFlowEditor.ts +++ b/src/FlowEditor/hooks/useFlowEditor.ts @@ -27,6 +27,8 @@ export const useFlowEditor = (): FlowEditorInstance => { onEdgesChange, onFlattenEdgesChange, onNodesChange, + beforeNodesChange, + afterNodesChange, onViewPortChange, onNodesTreeChange, onSelectionChange, diff --git a/src/FlowEditor/store/initialState.ts b/src/FlowEditor/store/initialState.ts index 3bdc425..347132c 100644 --- a/src/FlowEditor/store/initialState.ts +++ b/src/FlowEditor/store/initialState.ts @@ -12,8 +12,17 @@ export interface FlowEditorState { selectedKeys: string[]; onSelectionChange?: (selection: string[]) => void; + + // nodes change 相关事件 onNodesChange?: (nodeChanges: NodeChange[]) => void; + beforeNodesChange?: (nodeChanges: NodeChange[]) => boolean; + afterNodesChange?: (nodeChanges: NodeChange[]) => void; + + // edges change 相关事件 onEdgesChange?: (edges: EdgeChange[]) => void; + beforeEdgesChange?: (edges: EdgeChange[]) => boolean; + afterEdgesChange?: (edges: EdgeChange[]) => void; + onNodesTreeChange?: (nodesTree: FlowTreeNode[]) => void; onViewPortChange?: (viewport: Viewport) => void; diff --git a/src/FlowEditor/store/slices/edgesSlice.ts b/src/FlowEditor/store/slices/edgesSlice.ts index 000628e..3483f74 100644 --- a/src/FlowEditor/store/slices/edgesSlice.ts +++ b/src/FlowEditor/store/slices/edgesSlice.ts @@ -1,8 +1,8 @@ +import { convertEdgeChange } from '@/FlowEditor/utils/convertChange'; +import { generateEdgeId } from '@/FlowEditor/utils/edge'; import isEqual from 'fast-deep-equal'; import { Connection, Edge, EdgeChange } from 'reactflow'; import { StateCreator } from 'zustand'; - -import { generateEdgeId } from '@/FlowEditor/utils/edge'; import { ActionOptions, ActionPayload, FlattenEdges } from '../../types'; import { FlowEditorStore } from '../actions'; import { EdgeDispatch, edgesReducer } from '../reducers/edge'; @@ -22,8 +22,14 @@ export interface PublicEdgesAction { } export interface EdgesSlice extends PublicEdgesAction { internalUpdateEdges: (flattenEdges: FlattenEdges, payload: ActionPayload) => void; + handleEdgesChange: (changes: EdgeChange[]) => void; updateEdgesOnConnection: (connection: Connection) => Edge | undefined; updateEdgesOnEdgeChange: (changes: EdgeChange[]) => void; + edgesChangeLifecycle: ( + changes: EdgeChange[], + doSomething?: (...args: any) => void, + doSomethingParams?: any, + ) => void; } export const edgesSlice: StateCreator< @@ -39,10 +45,15 @@ export const edgesSlice: StateCreator< }, dispatchEdges: (payload, { recordHistory = true } = { recordHistory: true }) => { const { type, ...res } = payload; + + const { edgesChangeLifecycle, internalUpdateEdges, yjsDoc } = get(); + + const changes = convertEdgeChange(payload); + const flattenEdges = edgesReducer(get().flattenEdges, payload); if (isEqual(flattenEdges, get().flattenEdges)) return; - const { internalUpdateEdges, yjsDoc } = get(); + edgesChangeLifecycle(changes); internalUpdateEdges(flattenEdges, { type: `dispatchFlattenEdges/${type}`, @@ -124,4 +135,48 @@ export const edgesSlice: StateCreator< options, ); }, + + handleEdgesChange: (changes) => { + const { dispatchEdges, onElementSelectChange, edgesChangeLifecycle, deselectElement } = get(); + + changes.forEach((c) => { + switch (c.type) { + case 'add': + dispatchEdges({ + type: 'addEdge', + edge: c.item, + }); + break; + case 'remove': + deselectElement(c.id); + dispatchEdges({ type: 'deleteEdge', id: c.id }); + break; + case 'select': + edgesChangeLifecycle(changes, onElementSelectChange, { + id: c.id, + selected: c.selected, + }); + } + }); + }, + + edgesChangeLifecycle: (changes, doSomething, doSomethingParams) => { + const { beforeEdgesChange, onEdgesChange, afterEdgesChange } = get(); + + if (beforeEdgesChange && !beforeEdgesChange(changes)) { + return; + } + + if (onEdgesChange) { + onEdgesChange(changes); + } + + if (doSomething) { + doSomething(...doSomethingParams); + } + + if (afterEdgesChange) { + afterEdgesChange(changes); + } + }, }); diff --git a/src/FlowEditor/store/slices/nodesSlice.ts b/src/FlowEditor/store/slices/nodesSlice.ts index f7a1497..2e05691 100644 --- a/src/FlowEditor/store/slices/nodesSlice.ts +++ b/src/FlowEditor/store/slices/nodesSlice.ts @@ -1,7 +1,8 @@ import isEqual from 'fast-deep-equal'; -import { Node } from 'reactflow'; +import { Node, NodeChange } from 'reactflow'; import { StateCreator } from 'zustand'; +import { convertNodeChange } from '@/FlowEditor/utils/convertChange'; import { ActionOptions, ActionPayload, FlattenNodes, MetaData, NodeState } from '../../types'; import { FlowEditorStore } from '../actions'; import { NodeDispatch, nodeReducer } from '../reducers/node'; @@ -86,6 +87,12 @@ export interface PublicNodesAction { export interface NodesSlice extends PublicNodesAction { internalUpdateNodes: (flattenNodes: FlattenNodes, payload: ActionPayload) => void; + handleNodesChange: (changes: NodeChange[]) => void; + nodesChangeLifecycle: ( + changes: NodeChange[], + doSomething?: (...args: any) => void, + doSomethingParams?: any, + ) => void; } export const nodesSlice: StateCreator< @@ -103,17 +110,20 @@ export const nodesSlice: StateCreator< }, dispatchNodes: (payload, { recordHistory = true } = { recordHistory: true }) => { + const { nodesChangeLifecycle, internalUpdateNodes, yjsDoc } = get(); const { type, ...res } = payload; + const changes = convertNodeChange(payload); + const flattenNodes = nodeReducer(get().flattenNodes, payload); if (isEqual(flattenNodes, get().flattenNodes)) return; - get().internalUpdateNodes(flattenNodes, { + nodesChangeLifecycle(changes); + + internalUpdateNodes(flattenNodes, { type: `dispatchFlattenNodes/${type}`, payload: res, }); - const { yjsDoc } = get(); - if (recordHistory) { yjsDoc.recordHistoryData( { flattenNodes }, @@ -147,19 +157,81 @@ export const nodesSlice: StateCreator< }, addNode: (node) => { - get().dispatchNodes({ type: 'addNode', node }); + get().dispatchNodes({ + type: 'addNode', + node, + }); }, + addNodes: (nodes, options) => { - get().dispatchNodes({ type: 'addNodes', nodes }, options); + get().dispatchNodes( + { + type: 'addNodes', + nodes, + }, + options, + ); }, + deleteNode: (id) => { get().deselectElement(id); get().dispatchNodes({ type: 'deleteNode', id }); }, + deleteNodes: (ids) => { ids.forEach((id) => { get().deselectElement(id); get().dispatchNodes({ type: 'deleteNode', id }); }); }, + + handleNodesChange: (changes) => { + const { dispatchNodes, onElementSelectChange, deselectElement, nodesChangeLifecycle } = get(); + + changes.forEach((c) => { + switch (c.type) { + case 'add': + dispatchNodes({ + type: 'addNode', + node: c.item, + }); + break; + case 'position': + // 结束拖拽时,会触发一次 position,此时 dragging 为 false + if (!c.dragging) break; + + dispatchNodes({ type: 'updateNodePosition', position: c.position, id: c.id }); + break; + case 'remove': + deselectElement(c.id); + dispatchNodes({ type: 'deleteNode', id: c.id }); + break; + case 'select': + nodesChangeLifecycle(changes, onElementSelectChange, { + id: c.id, + selected: true, + }); + } + }); + }, + + nodesChangeLifecycle: (changes, doSomething, doSomethingParams) => { + const { beforeNodesChange, onNodesChange, afterNodesChange } = get(); + + if (beforeNodesChange && !beforeNodesChange(changes)) { + return; + } + + if (onNodesChange) { + onNodesChange(changes); + } + + if (doSomething) { + doSomething(...doSomethingParams); + } + + if (afterNodesChange) { + afterNodesChange(changes); + } + }, }); diff --git a/src/FlowEditor/utils/convertChange.ts b/src/FlowEditor/utils/convertChange.ts new file mode 100644 index 0000000..bb73e25 --- /dev/null +++ b/src/FlowEditor/utils/convertChange.ts @@ -0,0 +1,70 @@ +import { EdgeChange, NodeChange } from 'reactflow'; +import { EdgeDispatch } from '../store/reducers/edge'; +import { NodeDispatch } from '../store/reducers/node'; + +export function convertNodeChange(c: NodeDispatch): NodeChange[] { + switch (c.type) { + case 'addNode': { + return [ + { + item: c.node, + type: 'add', + }, + ]; + } + case 'addNodes': { + return Object.keys(c.nodes).map((key) => ({ + item: c.nodes[key], + type: 'add', + })); + } + case 'deleteNode': { + return [ + { + id: c.id, + type: 'remove', + }, + ]; + } + case 'updateNodePosition': { + return [ + { + id: c.id, + type: 'position', + position: c.position, + }, + ]; + } + default: + return []; + } +} + +export function convertEdgeChange(c: EdgeDispatch): EdgeChange[] { + switch (c.type) { + case 'addEdge': { + return [ + { + item: c.edge, + type: 'add', + }, + ]; + } + case 'addEdges': { + return Object.keys(c.edges).map((key) => ({ + item: c.edges[key], + type: 'add', + })); + } + case 'deleteEdge': { + return [ + { + id: c.id, + type: 'remove', + }, + ]; + } + default: + return []; + } +} diff --git a/src/FlowStoreProvider/demos/FlowStoreProvider.tsx b/src/FlowStoreProvider/demos/FlowStoreProvider.tsx index 211d71b..a8f0426 100644 --- a/src/FlowStoreProvider/demos/FlowStoreProvider.tsx +++ b/src/FlowStoreProvider/demos/FlowStoreProvider.tsx @@ -1,7 +1,7 @@ /** * description: FlowStoreProvider 包裹后的子级可以获得 editor 实例,使用 editor 提供的各种数据操作方法 */ -import { DataPreviewer } from '@ant-design/pro-editor'; +// import { DataPreviewer } from '@ant-design/pro-editor'; import { FlowStoreProvider, IFlowBasicNode, useFlowEditor } from '@ant-design/pro-flow'; import { Button } from 'antd'; import { useState } from 'react'; @@ -19,7 +19,7 @@ const App = () => { 插入 abc key 为随机数 - + {/* */} ); }; diff --git a/src/FlowView/hooks/useFlowView.ts b/src/FlowView/hooks/useFlowView.ts index a5f2403..ef0c10d 100644 --- a/src/FlowView/hooks/useFlowView.ts +++ b/src/FlowView/hooks/useFlowView.ts @@ -33,11 +33,14 @@ export const useFlowViewer = () => { flowViewRef, } = useContext(FlowViewContext); - const getNode = useCallback((nodeId: string) => { - if (reactFlowInstance) { - return reactFlowInstance.getNode(nodeId); - } - }, []); + const getNode = useCallback( + (nodeId: string) => { + if (reactFlowInstance) { + return reactFlowInstance.getNode(nodeId); + } + }, + [reactFlowInstance], + ); const getNodes = useCallback(() => { if (reactFlowInstance) {