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,
- };
-}