diff --git a/example/src/UseReactFlow/index.tsx b/example/src/UseReactFlow/index.tsx
index 83cb6b33..e9553bf3 100644
--- a/example/src/UseReactFlow/index.tsx
+++ b/example/src/UseReactFlow/index.tsx
@@ -33,7 +33,18 @@ const UseZoomPanHelperFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
- const { project, setCenter, zoomIn, zoomOut, fitView, addNodes, setNodes: setNodesHook, addEdges } = useReactFlow();
+ const {
+ project,
+ setCenter,
+ zoomIn,
+ zoomOut,
+ fitView,
+ addNodes,
+ setNodes: setNodesHook,
+ addEdges,
+ getNodes,
+ getEdges,
+ } = useReactFlow();
const onPaneClick = useCallback(
(evt: MouseEvent) => {
@@ -72,6 +83,11 @@ const UseZoomPanHelperFlow = () => {
addNodes(newNode);
}, [addNodes]);
+ const logNodes = useCallback(() => {
+ console.log('nodes', getNodes());
+ console.log('edges', getEdges());
+ }, [getNodes]);
+
useEffect(() => {
addEdges({ id: 'e3-4', source: '3', target: '4' });
}, [addEdges]);
@@ -97,6 +113,7 @@ const UseZoomPanHelperFlow = () => {
+
diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx
index 5a287ebf..2fa29ba0 100644
--- a/src/components/ConnectionLine/index.tsx
+++ b/src/components/ConnectionLine/index.tsx
@@ -6,6 +6,7 @@ import { getBezierPath } from '../Edges/BezierEdge';
import { getSmoothStepPath } from '../Edges/SmoothStepEdge';
import { ConnectionLineType, ConnectionLineComponent, HandleType, Node, ReactFlowState, Position } from '../../types';
import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge';
+import { internalsSymbol } from '../../utils';
interface ConnectionLineProps {
connectionNodeId: string;
@@ -37,12 +38,13 @@ export default ({
const { nodeInternals, transform } = useStore(selector, shallow);
const fromNode = useRef(nodeInternals.get(nodeId));
+ const fromHandleBounds = fromNode.current?.[internalsSymbol]?.handleBounds;
- if (!fromNode.current || !isConnectable || !fromNode.current.handleBounds?.[connectionHandleType]) {
+ if (!fromNode.current || !isConnectable || !fromHandleBounds?.[connectionHandleType]) {
return null;
}
- const handleBound = fromNode.current.handleBounds?.[connectionHandleType];
+ const handleBound = fromHandleBounds[connectionHandleType];
const fromHandle = handleId ? handleBound?.find((d) => d.id === handleId) : handleBound?.[0];
const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.current?.width ?? 0) / 2;
const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.current?.height ?? 0;
diff --git a/src/container/EdgeRenderer/utils.ts b/src/container/EdgeRenderer/utils.ts
index caa18181..c02d9361 100644
--- a/src/container/EdgeRenderer/utils.ts
+++ b/src/container/EdgeRenderer/utils.ts
@@ -13,7 +13,7 @@ import {
Transform,
XYPosition,
} from '../../types';
-import { rectToBox } from '../../utils';
+import { internalsSymbol, rectToBox } from '../../utils';
export type CreateEdgeTypes = (edgeTypes: EdgeTypes) => EdgeTypesWrapped;
@@ -168,10 +168,11 @@ export function isEdgeVisible({
export function getNodeData(nodeInternals: NodeInternals, nodeId: string): [Rect, NodeHandleBounds | null, boolean] {
const node = nodeInternals.get(nodeId);
- const handleBounds = node?.handleBounds;
+ const handleBounds = node?.[internalsSymbol]?.handleBounds || null;
+
const isInvalid =
!node ||
- !node.handleBounds ||
+ !handleBounds ||
!node.width ||
!node.height ||
typeof node.positionAbsolute?.x === 'undefined' ||
@@ -184,7 +185,7 @@ export function getNodeData(nodeInternals: NodeInternals, nodeId: string): [Rect
width: node?.width || 0,
height: node?.height || 0,
},
- handleBounds || null,
+ handleBounds,
!isInvalid,
];
}
diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx
index 671559e7..ba3ea773 100644
--- a/src/container/NodeRenderer/index.tsx
+++ b/src/container/NodeRenderer/index.tsx
@@ -11,6 +11,7 @@ import {
ReactFlowState,
WrapNodeProps,
} from '../../types';
+import { internalsSymbol } from '../../utils';
interface NodeRendererProps {
nodeTypes: NodeTypesWrapped;
@@ -117,8 +118,8 @@ const NodeRenderer = (props: NodeRendererProps) => {
isConnectable={isConnectable}
resizeObserver={resizeObserver}
dragHandle={node.dragHandle}
- zIndex={node.z ?? 0}
- isParent={!!node.isParent}
+ zIndex={node[internalsSymbol]?.z ?? 0}
+ isParent={!!node[internalsSymbol]?.isParent}
noDragClassName={props.noDragClassName}
noPanClassName={props.noPanClassName}
/>
diff --git a/src/hooks/useVisibleEdges.ts b/src/hooks/useVisibleEdges.ts
index 763f41ee..02f4db53 100644
--- a/src/hooks/useVisibleEdges.ts
+++ b/src/hooks/useVisibleEdges.ts
@@ -3,7 +3,7 @@ import { useCallback } from 'react';
import { useStore } from '../store';
import { isEdgeVisible } from '../container/EdgeRenderer/utils';
import { ReactFlowState, NodeInternals, Edge } from '../types';
-import { isNumeric } from '../utils';
+import { internalsSymbol, isNumeric } from '../utils';
const defaultEdgeTree = [{ level: 0, isMaxLevel: true, edges: [] }];
@@ -17,7 +17,10 @@ function groupEdgesByZLevel(edges: Edge[], nodeInternals: NodeInternals, elevate
if (elevateEdgesOnSelect) {
z = hasZIndex
? edge.zIndex!
- : Math.max(nodeInternals.get(edge.source)?.z || 0, nodeInternals.get(edge.target)?.z || 0);
+ : Math.max(
+ nodeInternals.get(edge.source)?.[internalsSymbol]?.z || 0,
+ nodeInternals.get(edge.target)?.[internalsSymbol]?.z || 0
+ );
}
if (tree[z]) {
diff --git a/src/store/index.ts b/src/store/index.ts
index e5c271a9..cfcd63b8 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -1,7 +1,7 @@
import create from 'zustand';
import createContext from 'zustand/context';
-import { clampPosition, getDimensions } from '../utils';
+import { clampPosition, getDimensions, internalsSymbol } from '../utils';
import { applyNodeChanges } from '../utils/changes';
import {
ReactFlowState,
@@ -60,7 +60,10 @@ const createStore = () =>
const handleBounds = getHandleBounds(update.nodeElement, transform[2]);
nodeInternals.set(node.id, {
...node,
- handleBounds,
+ [internalsSymbol]: {
+ ...node[internalsSymbol],
+ handleBounds,
+ },
...dimensions,
});
diff --git a/src/store/utils.ts b/src/store/utils.ts
index d7c5921e..3bc89963 100644
--- a/src/store/utils.ts
+++ b/src/store/utils.ts
@@ -1,7 +1,7 @@
import { zoomIdentity } from 'd3-zoom';
import { GetState, SetState } from 'zustand';
-import { isNumeric } from '../utils';
+import { internalsSymbol, isNumeric } from '../utils';
import { getD3Transition, getRectOfNodes, getTransformForBounds } from '../utils/graph';
import {
Edge,
@@ -30,7 +30,7 @@ function calculateXYZPosition(
return calculateXYZPosition(parentNode, nodeInternals, parentNodes, {
x: (result.x ?? 0) + (parentNode.position?.x ?? 0),
y: (result.y ?? 0) + (parentNode.position?.y ?? 0),
- z: (parentNode.z ?? 0) > (result.z ?? 0) ? parentNode.z ?? 0 : result.z ?? 0,
+ z: (parentNode[internalsSymbol]?.z ?? 0) > (result.z ?? 0) ? parentNode[internalsSymbol]?.z ?? 0 : result.z ?? 0,
});
}
@@ -45,18 +45,26 @@ export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals)
const internals: Node = {
width: currInternals?.width,
height: currInternals?.height,
- handleBounds: currInternals?.handleBounds,
...node,
positionAbsolute: {
x: node.position.x,
y: node.position.y,
},
- z,
};
+
if (node.parentNode) {
internals.parentNode = node.parentNode;
parentNodes[node.parentNode] = true;
}
+
+ Object.defineProperty(internals, internalsSymbol, {
+ enumerable: false,
+ value: {
+ handleBounds: currInternals?.[internalsSymbol]?.handleBounds,
+ z,
+ },
+ });
+
nextNodeInternals.set(node.id, internals);
});
@@ -68,7 +76,7 @@ export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals)
if (node.parentNode || parentNodes[node.id]) {
const { x, y, z } = calculateXYZPosition(node, nextNodeInternals, parentNodes, {
...node.position,
- z: node.z ?? 0,
+ z: node[internalsSymbol]?.z ?? 0,
});
node.positionAbsolute = {
@@ -76,10 +84,10 @@ export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals)
y,
};
- node.z = z;
+ node[internalsSymbol]!.z = z;
if (parentNodes[node.id]) {
- node.isParent = true;
+ node[internalsSymbol]!.isParent = true;
}
}
});
diff --git a/src/types/nodes.ts b/src/types/nodes.ts
index b8d0927e..d73b0c97 100644
--- a/src/types/nodes.ts
+++ b/src/types/nodes.ts
@@ -2,6 +2,7 @@ import { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
import { XYPosition, Position, CoordinateExtent } from './utils';
import { HandleElement } from './handles';
+import { internalsSymbol } from '../utils';
// interface for the user node items
export interface Node {
@@ -26,12 +27,14 @@ export interface Node {
zIndex?: number;
extent?: 'parent' | CoordinateExtent;
expandParent?: boolean;
+ positionAbsolute?: XYPosition;
// only used internally
- positionAbsolute?: XYPosition;
- z?: number;
- handleBounds?: NodeHandleBounds;
- isParent?: boolean;
+ [internalsSymbol]?: {
+ z?: number;
+ handleBounds?: NodeHandleBounds;
+ isParent?: boolean;
+ };
}
// props that get passed to a custom node
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 926977cb..9ef2661b 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -40,3 +40,5 @@ export const getBoundsofRects = (rect1: Rect, rect2: Rect): Rect =>
boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
export const isNumeric = (n: any): n is number => !isNaN(n) && isFinite(n);
+
+export const internalsSymbol = Symbol('internals');