diff --git a/example/src/Basic/index.tsx b/example/src/Basic/index.tsx index 513c7621..aa854864 100644 --- a/example/src/Basic/index.tsx +++ b/example/src/Basic/index.tsx @@ -13,7 +13,6 @@ import ReactFlow, { EdgeChange, OnLoadParams, Connection, - nodeHelper, } from 'react-flow-renderer'; const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node); @@ -30,38 +29,35 @@ const initialNodes: Node[] = [ position: { x: 400, y: 200 }, className: 'light', style: { backgroundColor: 'rgba(255, 0, 0, .2)' }, - childNodes: [ - { - id: '4a', - draggable: false, - data: { label: 'Node 4a', isNested: true }, - position: { x: 400, y: 400 }, - className: 'light', - }, - { - id: '4b', - data: { label: 'Node 4b' }, - position: { x: 500, y: 500 }, - className: 'light', - style: { backgroundColor: 'rgba(255, 0, 0, .2)' }, - childNodes: [ - { - id: '4b1', - draggable: false, - data: { label: 'Node 4b1', isNested: true }, - position: { x: 450, y: 450 }, - className: 'light', - }, - { - id: '4b2', - draggable: false, - data: { label: 'Node 4b2', isNested: true }, - position: { x: 550, y: 550 }, - className: 'light', - }, - ], - }, - ], + }, + { + id: '4a', + data: { label: 'Node 4a', isNested: true }, + position: { x: 400, y: 400 }, + className: 'light', + parentNode: '4', + }, + { + id: '4b', + data: { label: 'Node 4b' }, + position: { x: 500, y: 500 }, + className: 'light', + style: { backgroundColor: 'rgba(255, 0, 0, .2)' }, + parentNode: '4', + }, + { + id: '4b1', + data: { label: 'Node 4b1', isNested: true }, + position: { x: 450, y: 450 }, + className: 'light', + parentNode: '4b', + }, + { + id: '4b2', + data: { label: 'Node 4b2', isNested: true }, + position: { x: 550, y: 550 }, + className: 'light', + parentNode: '4b', }, ]; @@ -100,7 +96,7 @@ const BasicFlow = () => { const toggleClassnames = () => { setNodes((nds) => { - return nodeHelper(nds).map((n) => { + return nds.map((n) => { n.className = n.className === 'light' ? 'dark' : 'light'; return n; }); @@ -109,8 +105,8 @@ const BasicFlow = () => { const toggleChildNodes = () => { setNodes((nds) => { - return nodeHelper(nds).map((n) => { - n.isHidden = n.data.isNested && !n.isHidden; + return nds.map((n) => { + n.isHidden = !!n.parentNode && !n.isHidden; return n; }); }); diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index f69da656..8095b821 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -14,8 +14,6 @@ import { HandleType, ReactFlowState, } from '../../types'; -import { nodeHelper } from '../../utils/nodes'; - interface ConnectionLineProps { connectionNodeId: ElementId; connectionHandleId: ElementId | null; @@ -29,7 +27,7 @@ interface ConnectionLineProps { CustomConnectionLineComponent?: ConnectionLineComponent; } -const nodesSelector = (s: ReactFlowState) => nodeHelper(s.nodes).flatten(); +const nodesSelector = (s: ReactFlowState) => s.nodes; export default ({ connectionNodeId, diff --git a/src/container/EdgeRenderer/utils.ts b/src/container/EdgeRenderer/utils.ts index f6ad4360..d3e4ac20 100644 --- a/src/container/EdgeRenderer/utils.ts +++ b/src/container/EdgeRenderer/utils.ts @@ -3,7 +3,6 @@ import { ComponentType } from 'react'; import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../components/Edges'; import wrapEdge from '../../components/Edges/wrapEdge'; import { rectToBox } from '../../utils/graph'; -import { nodeHelper } from '../../utils/nodes'; import { EdgeTypesType, @@ -172,18 +171,16 @@ type SourceTargetNode = { }; export const getSourceTargetNodes = (edge: Edge, nodes: Node[]): SourceTargetNode => { - return nodeHelper(nodes) - .flatten() - .reduce( - (res, node) => { - if (node.id === edge.source) { - res.sourceNode = node; - } - if (node.id === edge.target) { - res.targetNode = node; - } - return res; - }, - { sourceNode: null, targetNode: null } as SourceTargetNode - ); + return nodes.reduce( + (res, node) => { + if (node.id === edge.source) { + res.sourceNode = node; + } + if (node.id === edge.target) { + res.targetNode = node; + } + return res; + }, + { sourceNode: null, targetNode: null } as SourceTargetNode + ); }; diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx index 2f8be03f..58026bff 100644 --- a/src/container/NodeRenderer/index.tsx +++ b/src/container/NodeRenderer/index.tsx @@ -77,8 +77,16 @@ function Nodes({ typeof node.height !== 'undefined'; let childRect; - if (node.childNodes) { - childRect = getRectOfNodes(node.childNodes); + const childNodes = nodes.filter((n) => n.parentNode === node.id); + + // if (childNodes.length) { + // console.log(node.id, childNodes, getRectOfNodes(childNodes)); + // } + + // console.log(childNodes); + + if (childNodes.length) { + childRect = getRectOfNodes(childNodes); node.position = node.isDragging ? node.position : { x: Math.round(childRect.x) - 10, y: Math.round(childRect.y) - 10 }; @@ -126,20 +134,6 @@ function Nodes({ dragHandle={node.dragHandle} zIndex={3 + recursionDepth} /> - {node.childNodes && ( - - )} ); }); diff --git a/src/index.ts b/src/index.ts index 139872f6..47989de5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,8 +26,6 @@ export { applyEdgeChanges, } from './utils/graph'; -export { nodeHelper } from './utils/nodes'; - export { default as useZoomPanHelper } from './hooks/useZoomPanHelper'; export { default as useUpdateNodeInternals } from './hooks/useUpdateNodeInternals'; diff --git a/src/store/index.ts b/src/store/index.ts index 210d9d33..9da0b50c 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -28,7 +28,6 @@ import { NodePositionChange, } from '../types'; import { isNode, isEdge, getRectOfNodes, getNodesInside, getConnectedEdges } from '../utils/graph'; -import { nodeHelper } from '../utils/nodes'; import { getHandleBounds } from '../components/Nodes/utils'; const { Provider, useStore, useStoreApi } = createContext(); @@ -127,7 +126,7 @@ const createStore = () => const { onNodesChange, nodes, transform } = get(); const nodesToChange: NodeChange[] = updates.reduce((res, update) => { - const node = nodeHelper(nodes).find((n) => n.id === update.id); + const node = nodes.find((n) => n.id === update.id); if (node) { const dimensions = getDimensions(update.nodeElement); @@ -181,12 +180,11 @@ const createStore = () => const { onNodesChange, nodes, nodeExtent } = get(); if (onNodesChange) { - const matchingNodes = nodeHelper(nodes).filter((n) => n.id === id || !!n.isSelected); - const changingNodes = nodeHelper(matchingNodes).flatten(); + const matchingNodes = nodes.filter((n) => n.id === id || n.parentNode === id || !!n.isSelected); - if (changingNodes?.length) { + if (matchingNodes?.length) { onNodesChange( - changingNodes.map((n) => { + matchingNodes.map((n) => { const change: NodePositionChange = { id: n.id, type: 'position', @@ -304,12 +302,10 @@ const createStore = () => unselectNodesAndEdges: () => { const { nodes, edges, onNodesChange, onEdgesChange } = get(); - const nodesToUnselect = nodeHelper(nodes) - .flatten() - .map((n) => { - n.isSelected = false; - return createNodeOrEdgeSelectionChange(false)(n); - }) as NodeChange[]; + const nodesToUnselect = nodes.map((n) => { + n.isSelected = false; + return createNodeOrEdgeSelectionChange(false)(n); + }) as NodeChange[]; const edgesToUnselect = edges.map(createNodeOrEdgeSelectionChange(false)) as EdgeChange[]; if (nodesToUnselect.length) { diff --git a/src/types/index.ts b/src/types/index.ts index b3133c0a..23fbb7e1 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -86,7 +86,7 @@ export interface Node { width?: number | null; height?: number | null; handleBounds?: NodeHandleBounds; - childNodes?: Node[]; + parentNode?: ElementId; } export enum ArrowHeadType { diff --git a/src/utils/nodes.ts b/src/utils/nodes.ts deleted file mode 100644 index c5520b1b..00000000 --- a/src/utils/nodes.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Node } from '../types'; - -function flat(arr: Node[], target: Node[]) { - arr.forEach(function (el) { - target.push(el); - if (el.childNodes) { - flat(el.childNodes, target); - } - }); -} - -const filterNodes = (condition: (node: Node) => boolean, nodes: Node[]): Node[] => { - let res = []; - - for (let i = 0; i < nodes.length; i++) { - const n = nodes[i]; - - if (condition(n)) { - res.push(n); - } - - if (n.childNodes) { - const matches = filterNodes(condition, n.childNodes); - - for (let j = 0; j < matches.length; j++) { - res.push(matches[j]); - } - } - } - - return res; -}; - -const mapNodes = (accessor: (node: Node) => any, nodes: Node[]): Node[] => { - let res = []; - - for (let i = 0; i < nodes.length; i++) { - const n = nodes[i]; - res.push(accessor(n)); - - if (n.childNodes) { - n.childNodes = mapNodes(accessor, n.childNodes); - } - } - - return res; -}; - -const forEachNode = (accessor: (node: Node) => any, nodes: Node[]): void => { - for (let i = 0; i < nodes.length; i++) { - const n = nodes[i]; - accessor(n); - - if (n.childNodes) { - forEachNode(accessor, n.childNodes); - } - } -}; - -function findNode(accessor: (node: Node) => boolean, nodes: Node[]): Node | undefined { - let res = undefined; - - for (let i = 0; i < nodes.length; i++) { - const n = nodes[i]; - - if (accessor(n)) { - return n; - } - - if (n.childNodes) { - res = findNode(accessor, n.childNodes); - - if (res) { - return res; - } - } - } - - return res; -} - -export interface NodeHelper { - filter: (accessor: (node: Node) => boolean) => Node[]; - map: (accessor: (node: Node) => any) => Node[]; - find: (accessor: (node: Node) => boolean) => Node | undefined; - forEach: (accessor: (node: Node) => void) => void; - flatten: () => Node[]; -} - -export function nodeHelper(nodes: Node[]): NodeHelper { - const flatten: NodeHelper['flatten'] = () => { - const flattened: Node[] = []; - flat(nodes, flattened); - return flattened; - }; - - const filter: NodeHelper['filter'] = (accessor) => { - return filterNodes(accessor, nodes); - }; - - const forEach: NodeHelper['forEach'] = (accessor) => { - return forEachNode(accessor, nodes); - }; - - const find: NodeHelper['find'] = (accessor) => { - return findNode(accessor, nodes); - }; - - const map: NodeHelper['map'] = (accessor) => { - return mapNodes(accessor, nodes); - }; - - return { - filter, - forEach, - flatten, - find, - map, - }; -}