diff --git a/examples/react/src/App/routes.ts b/examples/react/src/App/routes.ts index 7cd3eb13..1d68c858 100644 --- a/examples/react/src/App/routes.ts +++ b/examples/react/src/App/routes.ts @@ -50,6 +50,7 @@ import UseNodesInitialized from '../examples/UseNodesInit'; import UseNodesData from '../examples/UseNodesData'; import UseHandleConnections from '../examples/UseHandleConnections'; import AddNodeOnEdgeDrop from '../examples/AddNodeOnEdgeDrop'; +import DevTools from '../examples/DevTools'; export interface IRoute { name: string; @@ -113,6 +114,11 @@ const routes: IRoute[] = [ path: 'default-nodes', component: DefaultNodes, }, + { + name: 'DevTools', + path: 'devtools', + component: DevTools, + }, { name: 'Drag Handle', path: 'draghandle', diff --git a/examples/react/src/examples/DevTools/ReactFlowDevTools/NodeInspector.tsx b/examples/react/src/examples/DevTools/ReactFlowDevTools/NodeInspector.tsx new file mode 100644 index 00000000..34ebc361 --- /dev/null +++ b/examples/react/src/examples/DevTools/ReactFlowDevTools/NodeInspector.tsx @@ -0,0 +1,40 @@ +import { useNodes, ViewportPortal } from '@xyflow/react'; + +type NodeInspectorProps = { + color: string; +}; + +export default function NodeInspector({ color = '#aaa' }: NodeInspectorProps) { + const nodes = useNodes(); + + return ( + + {nodes.map((node) => { + const x = node.computed?.positionAbsolute?.x || 0; + const y = node.computed?.positionAbsolute?.y || 0; + const height = node.computed?.height || 0; + + return ( + + id: {node.id} + type: {node.type} + + position: {x.toFixed(1)}, {y.toFixed(1)} + + data: {JSON.stringify(node.data, null, 2)} + + ); + })} + + ); +} diff --git a/examples/react/src/examples/DevTools/ReactFlowDevTools/index.tsx b/examples/react/src/examples/DevTools/ReactFlowDevTools/index.tsx new file mode 100644 index 00000000..8c521aa0 --- /dev/null +++ b/examples/react/src/examples/DevTools/ReactFlowDevTools/index.tsx @@ -0,0 +1,22 @@ +import { useState } from 'react'; +import { Panel, PanelPosition } from '@xyflow/react'; + +import NodeInspector from './NodeInspector'; + +type ReactFlowDevToolsProps = { + position?: PanelPosition; + color?: string; +}; + +export default function ReactFlowDevTools({ color = '#aaa', position = 'top-left' }: ReactFlowDevToolsProps) { + const [isNodeInspectorActive, setIsNodeInspectorActive] = useState(false); + + return ( + <> + + setIsNodeInspectorActive((a) => !a)}>node inspector + + {isNodeInspectorActive && } + > + ); +} diff --git a/examples/react/src/examples/DevTools/index.tsx b/examples/react/src/examples/DevTools/index.tsx new file mode 100644 index 00000000..153b0897 --- /dev/null +++ b/examples/react/src/examples/DevTools/index.tsx @@ -0,0 +1,59 @@ +import { useCallback } from 'react'; +import { ReactFlow, addEdge, Node, Connection, Edge, useNodesState, useEdgesState } from '@xyflow/react'; +import ReactFlowDevTools from './ReactFlowDevTools'; + +const initNodes: Node[] = [ + { + id: '1a', + type: 'input', + data: { label: 'Node 1' }, + position: { x: 250, y: 5 }, + className: 'light', + ariaLabel: 'Input Node 1', + }, + { + id: '2a', + data: { label: 'Node 2' }, + position: { x: 100, y: 100 }, + className: 'light', + ariaLabel: 'Default Node 2', + }, + { + id: '3a', + data: { label: 'Node 3' }, + position: { x: 400, y: 100 }, + className: 'light', + }, + { + id: '4a', + data: { label: 'Node 4' }, + position: { x: 400, y: 200 }, + className: 'light', + }, +]; + +const initEdges: Edge[] = [ + { id: 'e1-2', source: '1a', target: '2a', ariaLabel: undefined }, + { id: 'e1-3', source: '1a', target: '3a' }, +]; + +const BasicFlow = () => { + const [nodes, setNodes, onNodesChange] = useNodesState(initNodes); + const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges); + + const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]); + + return ( + + + + ); +}; + +export default BasicFlow;