diff --git a/example/src/CustomNode/index.js b/example/src/CustomNode/index.js index 3a2e77c1..6716a9e3 100644 --- a/example/src/CustomNode/index.js +++ b/example/src/CustomNode/index.js @@ -65,6 +65,8 @@ const CustomNodeFlow = () => { const onConnect = (params) => setElements((els) => addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, els)); + console.log('example', elements); + return ( { - const elements = useStoreState((store) => store.elements); + const nodes = useStoreState((store) => store.nodes); const transform = useStoreState((store) => store.transform); const setSelectedElements = useStoreActions((actions) => actions.setSelectedElements); - const nodes = elements.filter(isNode); const selectAll = () => { setSelectedElements(nodes.map((node) => ({ id: node.id, type: node.type }))); diff --git a/src/additional-components/MiniMap/index.tsx b/src/additional-components/MiniMap/index.tsx index 4fbef432..0a810a44 100644 --- a/src/additional-components/MiniMap/index.tsx +++ b/src/additional-components/MiniMap/index.tsx @@ -2,7 +2,7 @@ import React, { memo } from 'react'; import cc from 'classcat'; import { useStoreState } from '../../store/hooks'; -import { getRectOfNodes, getBoundsofRects, isNode } from '../../utils/graph'; +import { getRectOfNodes, getBoundsofRects } from '../../utils/graph'; import { Node, Rect } from '../../types'; import MiniMapNode from './MiniMapNode'; @@ -33,8 +33,7 @@ const MiniMap = ({ const containerWidth = useStoreState((s) => s.width); const containerHeight = useStoreState((s) => s.height); const [tX, tY, tScale] = useStoreState((s) => s.transform); - const elements = useStoreState((s) => s.elements); - const nodes = elements.filter(isNode); + const nodes = useStoreState((s) => s.nodes); const mapClasses = cc(['react-flow__minimap', className]); const elementWidth = (style?.width || defaultWidth)! as number; diff --git a/src/components/NodesSelection/index.tsx b/src/components/NodesSelection/index.tsx index 21630dac..79cd5172 100644 --- a/src/components/NodesSelection/index.tsx +++ b/src/components/NodesSelection/index.tsx @@ -29,8 +29,7 @@ export default ({ const selectedElements = useStoreState((state) => state.selectedElements); const snapToGrid = useStoreState((state) => state.snapToGrid); const snapGrid = useStoreState((state) => state.snapGrid); - const elements = useStoreState((state) => state.elements); - const nodes = elements.filter(isNode); + const nodes = useStoreState((state) => state.nodes); const updateNodePosDiff = useStoreActions((actions) => actions.updateNodePosDiff); diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx index ded4a2e3..8876ef7b 100644 --- a/src/container/EdgeRenderer/index.tsx +++ b/src/container/EdgeRenderer/index.tsx @@ -2,7 +2,7 @@ import React, { memo, CSSProperties, useCallback } from 'react'; import { useStoreState } from '../../store/hooks'; import ConnectionLine from '../../components/ConnectionLine/index'; -import { isEdge, isNode } from '../../utils/graph'; +import { isEdge } from '../../utils/graph'; import MarkerDefinitions from './MarkerDefinitions'; import { getEdgePositions, getHandle, isEdgeVisible, getSourceTargetNodes } from './utils'; import { @@ -169,7 +169,8 @@ const Edge = ({ const EdgeRenderer = (props: EdgeRendererProps) => { const transform = useStoreState((state) => state.transform); - const elements = useStoreState((state) => state.elements); + const nodes = useStoreState((state) => state.nodes); + const edges = useStoreState((state) => state.edges); const connectionNodeId = useStoreState((state) => state.connectionNodeId); const connectionHandleId = useStoreState((state) => state.connectionHandleId); const connectionHandleType = useStoreState((state) => state.connectionHandleType); @@ -180,9 +181,6 @@ const EdgeRenderer = (props: EdgeRendererProps) => { const width = useStoreState((state) => state.width); const height = useStoreState((state) => state.height); - const edges = elements.filter(isEdge); - const nodes = elements.filter(isNode); - if (!width) { return null; } diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx index d1c332e6..6173ad00 100644 --- a/src/container/NodeRenderer/index.tsx +++ b/src/container/NodeRenderer/index.tsx @@ -1,6 +1,6 @@ import React, { memo, useMemo, ComponentType, MouseEvent } from 'react'; -import { getNodesInside, isNode } from '../../utils/graph'; +import { getNodesInside } from '../../utils/graph'; import { useStoreState, useStoreActions } from '../../store/hooks'; import { Node, NodeTypesType, WrapNodeProps, Edge } from '../../types'; interface NodeRendererProps { @@ -27,11 +27,10 @@ const NodeRenderer = (props: NodeRendererProps) => { const elementsSelectable = useStoreState((state) => state.elementsSelectable); const width = useStoreState((state) => state.width); const height = useStoreState((state) => state.height); - const elements = useStoreState((state) => state.elements); + const nodes = useStoreState((state) => state.nodes); const batchUpdateNodeDimensions = useStoreActions((actions) => actions.batchUpdateNodeDimensions); - const viewportBox = { x: 0, y: 0, width, height }; - const nodes = elements.filter(isNode); + const viewportBox = useMemo(() => ({ x: 0, y: 0, width, height }), [width, height]); const visibleNodes = props.onlyRenderVisibleElements ? getNodesInside(nodes, viewportBox, transform, true) : nodes; const transformStyle = useMemo( diff --git a/src/hooks/useGlobalKeyHandler.ts b/src/hooks/useGlobalKeyHandler.ts index f123e9b4..c43997a9 100644 --- a/src/hooks/useGlobalKeyHandler.ts +++ b/src/hooks/useGlobalKeyHandler.ts @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { useStore, useStoreActions } from '../store/hooks'; import useKeyPress from './useKeyPress'; -import { isNode, getConnectedEdges, isEdge } from '../utils/graph'; +import { isNode, getConnectedEdges } from '../utils/graph'; import { Elements, KeyCode, ElementId, FlowElement } from '../types'; interface HookParams { @@ -22,8 +22,7 @@ export default ({ deleteKeyCode, multiSelectionKeyCode, onElementsRemove }: Hook const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode); useEffect(() => { - const { elements, selectedElements } = store.getState(); - const edges = elements.filter(isEdge); + const { edges, selectedElements } = store.getState(); if (onElementsRemove && deleteKeyPressed && selectedElements) { const selectedNodes = selectedElements.filter(isNode); diff --git a/src/hooks/useZoomPanHelper.ts b/src/hooks/useZoomPanHelper.ts index 32443a16..1c470e0c 100644 --- a/src/hooks/useZoomPanHelper.ts +++ b/src/hooks/useZoomPanHelper.ts @@ -3,7 +3,7 @@ import { zoomIdentity } from 'd3-zoom'; import { useStoreState, useStore } from '../store/hooks'; import { clamp } from '../utils'; -import { getRectOfNodes, isNode } from '../utils/graph'; +import { getRectOfNodes } from '../utils/graph'; import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, Transform } from '../types'; const DEFAULT_PADDING = 0.1; @@ -56,8 +56,7 @@ const useZoomPanHelper = (): ZoomPanHelperFunctions => { d3Zoom.transform(d3Selection, nextTransform); }, fitView: (options: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => { - const { elements, width, height, minZoom, maxZoom } = store.getState(); - const nodes = elements.filter(isNode); + const { nodes, width, height, minZoom, maxZoom } = store.getState(); if (!nodes.length) { return; diff --git a/src/store/index.ts b/src/store/index.ts index 0e055a4f..6640d9e0 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -6,12 +6,10 @@ export const initialState: ReactFlowState = { width: 0, height: 0, transform: [0, 0, 1], - elements: [], - // nodes: computed((state) => state.elements.filter(isNode)), - // edges: computed((state) => state.elements.filter(isEdge)), + nodes: [], + edges: [], selectedElements: null, selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 }, - // viewportBox: computed((state) => ({ x: 0, y: 0, width: state.width, height: state.height })), d3Zoom: null, d3Selection: null, diff --git a/src/store/reducer.ts b/src/store/reducer.ts index 99e58213..bc60d45c 100644 --- a/src/store/reducer.ts +++ b/src/store/reducer.ts @@ -1,112 +1,109 @@ import isEqual from 'fast-deep-equal'; import { getDimensions } from '../utils'; -import { getNodesInside, getConnectedEdges, getRectOfNodes, isNode, isEdge, parseElement } from '../utils/graph'; +import { + getNodesInside, + getConnectedEdges, + getRectOfNodes, + isNode, + isEdge, + parseNode, + parseEdge, +} from '../utils/graph'; import { getHandleBounds } from '../components/Nodes/utils'; -import { ReactFlowState, FlowElement, Node, XYPosition } from '../types'; -import { - ADD_SELECTED_ELEMENTS, - BATCH_UPDATE_NODE_DIMENSIONS, - INIT_D3ZOOM, - RESET_SELECTED_ELEMENTS, - SET_CONNECTION_MODE, - SET_CONNECTION_NODEID, - SET_CONNECTION_POSITION, - SET_ELEMENTS, - SET_ELEMENTS_SELECTABLE, - SET_INTERACTIVE, - SET_MAXZOOM, - SET_MINZOOM, - SET_MULTI_SELECTION_ACTIVE, - SET_NODES_CONNECTABLE, - SET_NODES_DRAGGABLE, - SET_NODE_EXTENT, - SET_ON_CONNECT, - SET_ON_CONNECT_END, - SET_ON_CONNECT_START, - SET_ON_CONNECT_STOP, - SET_SELECTED_ELEMENTS, - SET_SNAPGRID, - SET_SNAPTOGRID, - SET_TRANSLATEEXTENT, - SET_USER_SELECTION, - UNSET_USER_SELECTION, - UPDATE_NODE_DIMENSIONS, - UPDATE_NODE_POS, - UPDATE_NODE_POS_DIFF, - UPDATE_SIZE, - UPDATE_TRANSFORM, - UPDATE_USER_SELECTION, -} from './contants'; +import { ReactFlowState, Node, XYPosition, Edge } from '../types'; +import * as constants from './contants'; import { ReactFlowAction } from './actions'; import { initialState } from './index'; +type ElementsSplitted = { + nodeElements: Node[]; + edgeElements: Edge[]; +}; + export default function reactFlowReducer(state = initialState, action: ReactFlowAction): ReactFlowState { switch (action.type) { - case SET_ELEMENTS: { + case constants.SET_ELEMENTS: { const propElements = action.payload; + const elementsSplitted: ElementsSplitted = { + nodeElements: [], + edgeElements: [], + }; + const { nodeElements, edgeElements } = propElements.reduce((res, item): ElementsSplitted => { + if (isNode(item)) { + res.nodeElements.push(item); + } else if (isEdge(item)) { + res.edgeElements.push(item); + } - const nextElements = propElements.map((el: FlowElement) => { - let storeElement = state.elements.find((se) => se.id === el.id); + return res; + }, elementsSplitted); + + const nextNodes = nodeElements.map((propNode: Node) => { + let storeNode = state.nodes.find((node) => node.id === propNode.id); // update existing element - if (storeElement) { - if (isNode(storeElement)) { - const propNode = el as Node; - const positionChanged = - storeElement.position.x !== propNode.position.x || storeElement.position.y !== propNode.position.y; - const typeChanged = typeof propNode.type !== 'undefined' && propNode.type !== storeElement.type; + if (storeNode) { + const positionChanged = + storeNode.position.x !== propNode.position.x || storeNode.position.y !== propNode.position.y; + const typeChanged = typeof propNode.type !== 'undefined' && propNode.type !== storeNode.type; - storeElement = { - ...storeElement, - ...propNode, - }; + storeNode = { + ...storeNode, + ...propNode, + }; - if (positionChanged) { - (storeElement as Node).__rf.position = propNode.position; - } - - if (typeChanged) { - // we reset the elements dimensions here in order to force a re-calculation of the bounds. - // When the type of a node changes it is possible that the number or positions of handles changes too. - (storeElement as Node).__rf.width = null; - } - } else { - storeElement = { - ...storeElement, - ...el, - }; + if (positionChanged) { + storeNode.__rf.position = propNode.position; } - return storeElement; + if (typeChanged) { + // we reset the elements dimensions here in order to force a re-calculation of the bounds. + // When the type of a node changes it is possible that the number or positions of handles changes too. + storeNode.__rf.width = null; + } + + return storeNode; } else { // add new element - return parseElement(el, state.nodeExtent); + return parseNode(propNode, state.nodeExtent); } }); - return { ...state, elements: nextElements }; + const nextEdges = edgeElements.map((propEdge: Edge) => { + let storeEdge = state.edges.find((se) => se.id === propEdge.id); + + if (storeEdge) { + return { + ...storeEdge, + ...propEdge, + }; + } else { + return parseEdge(propEdge); + } + }); + + return { ...state, nodes: nextNodes, edges: nextEdges }; } - case BATCH_UPDATE_NODE_DIMENSIONS: { - const updatedElements = state.elements.map((el) => { - const update = action.payload.find((u) => u.id === el.id); + case constants.BATCH_UPDATE_NODE_DIMENSIONS: { + const updatedNodes = state.nodes.map((node) => { + const update = action.payload.find((u) => u.id === node.id); if (update) { const dimensions = getDimensions(update.nodeElement); - const nodeToUpdate = el as Node; if ( dimensions.width && dimensions.height && - (nodeToUpdate.__rf.width !== dimensions.width || nodeToUpdate.__rf.height !== dimensions.height) + (node.__rf.width !== dimensions.width || node.__rf.height !== dimensions.height) ) { const handleBounds = getHandleBounds(update.nodeElement, state.transform[2]); return { - ...nodeToUpdate, + ...node, __rf: { - ...nodeToUpdate.__rf, + ...node.__rf, ...dimensions, handleBounds, }, @@ -114,15 +111,15 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow } } - return el; + return node; }); return { ...state, - elements: updatedElements, + nodes: updatedNodes, }; } - case UPDATE_NODE_DIMENSIONS: { + case constants.UPDATE_NODE_DIMENSIONS: { const { nodeElement, id } = action.payload; const dimensions = getDimensions(nodeElement); @@ -130,14 +127,14 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow return state; } - const nextElements = state.elements.map((el) => { - if (el.id === id && isNode(el)) { + const nextNodes = state.nodes.map((node) => { + if (node.id === id) { const handleBounds = getHandleBounds(nodeElement, state.transform[2]); return { - ...el, + ...node, __rf: { - ...el.__rf, + ...node.__rf, width: dimensions.width, height: dimensions.height, handleBounds, @@ -145,12 +142,12 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow }; } - return el; + return node; }); - return { ...state, elements: nextElements }; + return { ...state, nodes: nextNodes }; } - case UPDATE_NODE_POS: { + case constants.UPDATE_NODE_POS: { const { id, pos } = action.payload; let position: XYPosition = pos; @@ -163,56 +160,56 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow }; } - const nextElements = state.elements.map((el) => { - if (el.id === id && isNode(el)) { + const nextNodes = state.nodes.map((node) => { + if (node.id === id) { return { - ...el, + ...node, __rf: { - ...el.__rf, + ...node.__rf, position, }, }; } - return el; + return node; }); - return { ...state, elements: nextElements }; + return { ...state, nodes: nextNodes }; } - case UPDATE_NODE_POS_DIFF: { + case constants.UPDATE_NODE_POS_DIFF: { const { id, diff, isDragging } = action.payload; - const nextElements = state.elements.map((el) => { - if (isNode(el) && (id === el.id || state.selectedElements?.find((sNode) => sNode.id === el.id))) { + const nextNodes = state.nodes.map((node) => { + if (id === node.id || state.selectedElements?.find((sNode) => sNode.id === node.id)) { if (diff) { return { - ...el, + ...node, __rf: { - ...el.__rf, + ...node.__rf, isDragging, position: { - x: el.__rf.position.x + diff.x, - y: el.__rf.position.y + diff.y, + x: node.__rf.position.x + diff.x, + y: node.__rf.position.y + diff.y, }, }, }; } return { - ...el, + ...node, __rf: { - ...el.__rf, + ...node.__rf, isDragging, }, }; } - return el; + return node; }); - return { ...state, elements: nextElements }; + return { ...state, nodes: nextNodes }; } - case SET_USER_SELECTION: { + case constants.SET_USER_SELECTION: { const mousePos = action.payload; const userSelectionRect = { @@ -231,7 +228,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow selectionActive: true, }; } - case UPDATE_USER_SELECTION: { + case constants.UPDATE_USER_SELECTION: { const mousePos = action.payload; const startX = state.userSelectionRect.startX || 0; const startY = state.userSelectionRect.startY || 0; @@ -247,11 +244,8 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow height: Math.abs(mousePos.y - startY), }; - const nodes = state.elements.filter(isNode); - const edges = state.elements.filter(isEdge); - - const selectedNodes = getNodesInside(nodes, nextUserSelectRect, state.transform); - const selectedEdges = getConnectedEdges(selectedNodes, edges); + const selectedNodes = getNodesInside(state.nodes, nextUserSelectRect, state.transform); + const selectedEdges = getConnectedEdges(selectedNodes, state.edges); const nextSelectedElements = [...selectedNodes, ...selectedEdges]; const selectedElementsUpdated = !isEqual(nextSelectedElements, state.selectedElements); @@ -269,7 +263,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow userSelectionRect: nextUserSelectRect, }; } - case UNSET_USER_SELECTION: { + case constants.UNSET_USER_SELECTION: { const selectedNodes = state.selectedElements?.filter((node) => isNode(node) && node.__rf) as Node[]; const selectionActive = false; @@ -298,7 +292,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow nodesSelectionActive: true, }; } - case SET_SELECTED_ELEMENTS: { + case constants.SET_SELECTED_ELEMENTS: { const elements = action.payload; const selectedElementsArr = Array.isArray(elements) ? elements : [elements]; const selectedElementsUpdated = !isEqual(selectedElementsArr, state.selectedElements); @@ -309,7 +303,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow selectedElements, }; } - case ADD_SELECTED_ELEMENTS: { + case constants.ADD_SELECTED_ELEMENTS: { const { multiSelectionActive, selectedElements } = state; const elements = action.payload; const selectedElementsArr = Array.isArray(elements) ? elements : [elements]; @@ -325,7 +319,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow return { ...state, selectedElements: nextSelectedElements }; } - case INIT_D3ZOOM: { + case constants.INIT_D3ZOOM: { const { d3Zoom, d3Selection, d3ZoomHandler, transform } = action.payload; return { @@ -336,7 +330,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow transform, }; } - case SET_MINZOOM: { + case constants.SET_MINZOOM: { const minZoom = action.payload; if (state.d3Zoom) { @@ -349,7 +343,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow }; } - case SET_MAXZOOM: { + case constants.SET_MAXZOOM: { const maxZoom = action.payload; if (state.d3Zoom) { @@ -361,7 +355,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow maxZoom, }; } - case SET_TRANSLATEEXTENT: { + case constants.SET_TRANSLATEEXTENT: { const translateExtent = action.payload; if (state.d3Zoom) { @@ -373,24 +367,24 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow translateExtent, }; } - case SET_ON_CONNECT: - case SET_ON_CONNECT_START: - case SET_ON_CONNECT_STOP: - case SET_ON_CONNECT_END: - case RESET_SELECTED_ELEMENTS: - case UPDATE_TRANSFORM: - case UPDATE_SIZE: - case SET_CONNECTION_POSITION: - case SET_CONNECTION_NODEID: - case SET_SNAPTOGRID: - case SET_SNAPGRID: - case SET_INTERACTIVE: - case SET_NODES_DRAGGABLE: - case SET_NODES_CONNECTABLE: - case SET_ELEMENTS_SELECTABLE: - case SET_MULTI_SELECTION_ACTIVE: - case SET_CONNECTION_MODE: - case SET_NODE_EXTENT: + case constants.SET_ON_CONNECT: + case constants.SET_ON_CONNECT_START: + case constants.SET_ON_CONNECT_STOP: + case constants.SET_ON_CONNECT_END: + case constants.RESET_SELECTED_ELEMENTS: + case constants.UPDATE_TRANSFORM: + case constants.UPDATE_SIZE: + case constants.SET_CONNECTION_POSITION: + case constants.SET_CONNECTION_NODEID: + case constants.SET_SNAPTOGRID: + case constants.SET_SNAPGRID: + case constants.SET_INTERACTIVE: + case constants.SET_NODES_DRAGGABLE: + case constants.SET_NODES_CONNECTABLE: + case constants.SET_ELEMENTS_SELECTABLE: + case constants.SET_MULTI_SELECTION_ACTIVE: + case constants.SET_CONNECTION_MODE: + case constants.SET_NODE_EXTENT: return { ...state, ...action.payload }; default: return state; diff --git a/src/types/index.ts b/src/types/index.ts index 902e98be..f8a78efb 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -382,12 +382,10 @@ export interface ReactFlowState { width: number; height: number; transform: Transform; - elements: Elements; - // nodes: Computed; - // edges: Computed; + nodes: Node[]; + edges: Edge[]; selectedElements: Elements | null; selectedNodesBbox: Rect; - // viewportBox: Computed; d3Zoom: ZoomBehavior | null; d3Selection: D3Selection | null; diff --git a/src/utils/graph.ts b/src/utils/graph.ts index 3831dba5..41a7d9f9 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -146,35 +146,31 @@ export const onLoadProject = (currentStore: Store) => { }; }; -export const parseElement = (element: Node | Edge, nodeExtent: NodeExtent): Node | Edge => { - if (!element.id) { - throw new Error('All nodes and edges need to have an id.'); - } - - if (isEdge(element)) { - return { - ...element, - source: element.source.toString(), - target: element.target.toString(), - sourceHandle: element.sourceHandle ? element.sourceHandle.toString() : null, - targetHandle: element.targetHandle ? element.targetHandle.toString() : null, - id: element.id.toString(), - type: element.type || 'default', - }; - } - +export const parseNode = (node: Node, nodeExtent: NodeExtent): Node => { return { - ...element, - id: element.id.toString(), - type: element.type || 'default', + ...node, + id: node.id.toString(), + type: node.type || 'default', __rf: { - position: clampPosition(element.position, nodeExtent), + position: clampPosition(node.position, nodeExtent), width: null, height: null, handleBounds: {}, isDragging: false, }, - } as Node; + }; +}; + +export const parseEdge = (edge: Edge): Edge => { + return { + ...edge, + source: edge.source.toString(), + target: edge.target.toString(), + sourceHandle: edge.sourceHandle ? edge.sourceHandle.toString() : null, + targetHandle: edge.targetHandle ? edge.targetHandle.toString() : null, + id: edge.id.toString(), + type: edge.type || 'default', + }; }; const getBoundsOfBoxes = (box1: Box, box2: Box): Box => ({ @@ -272,9 +268,7 @@ const parseElements = (nodes: Node[], edges: Edge[]): Elements => { export const onLoadGetElements = (currentStore: Store) => { return (): Elements => { - const { elements = [] } = currentStore.getState(); - const nodes = elements.filter(isNode); - const edges = elements.filter(isEdge); + const { nodes = [], edges = [] } = currentStore.getState(); return parseElements(nodes, edges); }; @@ -282,9 +276,7 @@ export const onLoadGetElements = (currentStore: Store) => { export const onLoadToObject = (currentStore: Store) => { return (): FlowExportObject => { - const { elements = [], transform } = currentStore.getState(); - const nodes = elements.filter(isNode); - const edges = elements.filter(isEdge); + const { nodes = [], edges = [], transform } = currentStore.getState(); return { elements: parseElements(nodes, edges),