@@ -12,6 +12,7 @@ import {
1212 useOnSelectionChange ,
1313} from '@xyflow/react' ;
1414import '@xyflow/react/dist/style.css' ;
15+ import { ReactFlowProvider } from '@xyflow/react' ;
1516
1617
1718import TextUpdaterNode from './TextUpdaterNode.jsx' ;
@@ -20,6 +21,8 @@ import {getLayoutedNodes2} from './useElkLayout';
2021
2122import './text-updater-node.css' ;
2223import './widget.css' ;
24+ import './ContextMenu.css' ;
25+ import ContextMenu from './ContextMenu' ;
2326
2427/**
2528 * Author: Joerg Neugebauer
@@ -79,6 +82,9 @@ const render = createRender(() => {
7982 const selectedNodes = [ ] ;
8083 const selectedEdges = [ ] ;
8184
85+ const [ menu , setMenu ] = useState ( null ) ;
86+ const ref = useRef ( null ) ;
87+
8288 const nodeTypes = {
8389 textUpdater : TextUpdaterNode ,
8490 customNode : CustomNode ,
@@ -89,6 +95,37 @@ const render = createRender(() => {
8995 setNodes ( layoutedNodes ) ;
9096 // setTimeout(() => fitView(), 0);
9197 } ;
98+
99+ const outputFunction = ( data ) => {
100+ // direct output of node to output widget
101+ console . log ( 'output: ' , data . label )
102+ model . set ( "commands" , `output: ${ data . label } ` ) ;
103+ model . save_changes ( ) ;
104+ }
105+
106+ const sourceFunction = ( data ) => {
107+ // show source code of node
108+ console . log ( 'source: ' , data . label )
109+ model . set ( "commands" , `source: ${ data . label } ` ) ;
110+ model . save_changes ( ) ;
111+ }
112+
113+ const onNodeContextMenu = useCallback (
114+ ( event , node ) => {
115+ // Prevent native context menu from showing
116+ event . preventDefault ( ) ;
117+
118+ const wrapperRect = reactFlowWrapper . current . getBoundingClientRect ( ) ;
119+ setMenu ( {
120+ id : node . id ,
121+ top : event . clientY - wrapperRect . top , // relative to wrapper top
122+ left : event . clientX - wrapperRect . left , // relative to wrapper left
123+ data : node . data
124+ } ) ;
125+ } ,
126+ ) ;
127+
128+ const onPaneClick = useCallback ( ( ) => setMenu ( null ) , [ setMenu ] ) ;
92129
93130 useEffect ( ( ) => {
94131 layoutNodes ( ) ;
@@ -381,7 +418,8 @@ const render = createRender(() => {
381418 } , [ model , reactFlowWrapper ] ) ;
382419
383420 return (
384- < div style = { { position : "relative" , height : "100%" , width : "100%" } } >
421+ < ReactFlowProvider >
422+ < div ref = { reactFlowWrapper } style = { { position : "relative" , height : "100%" , width : "100%" } } >
385423 < UpdateDataContext . Provider value = { updateData } >
386424 < ReactFlow
387425 nodes = { nodes }
@@ -393,10 +431,10 @@ const render = createRender(() => {
393431 onNodesDelete = { onNodesDelete }
394432 onMoveEnd = { onMoveEnd }
395433 nodeTypes = { nodeTypes }
434+ onPaneClick = { onPaneClick }
435+ onNodeContextMenu = { onNodeContextMenu }
396436 fitView
397437 style = { rfStyle }
398- // makes sure that reactFlowWrapper wrapper contains a ref to this element
399- ref = { reactFlowWrapper }
400438 /*debugMode={true}*/
401439 >
402440 { /*
@@ -461,8 +499,10 @@ const render = createRender(() => {
461499 Reset Layout
462500 </ button >
463501 </ ReactFlow >
502+ { menu && < ContextMenu onOutput = { outputFunction } onSource = { sourceFunction } onClick = { onPaneClick } { ...menu } /> }
464503 </ UpdateDataContext . Provider >
465504 </ div >
505+ </ ReactFlowProvider >
466506 ) ;
467507} ) ;
468508
0 commit comments