@@ -14,6 +14,8 @@ import CircularProgress from "@mui/material/CircularProgress";
1414import Tooltip from "@mui/material/Tooltip" ;
1515import IconButton from "@mui/material/IconButton" ;
1616import PlayArrowIcon from "@mui/icons-material/PlayArrow" ;
17+ import Stack from "@mui/material/Stack" ;
18+ import Button from "@mui/material/Button" ;
1719
1820import { useDispatch , useSelector } from "react-redux" ;
1921
@@ -32,7 +34,7 @@ import { MyMonaco } from "../MyMonaco";
3234
3335const nanoid = customAlphabet ( nolookalikes , 10 ) ;
3436
35- const ScopeNode = ( { data, id, isConnectable, selected } ) => {
37+ const ScopeNode = memo ( ( { data, id, isConnectable, selected } ) => {
3638 // add resize to the node
3739 const dispatch = useDispatch ( ) ;
3840 const ref = useRef ( null ) ;
@@ -98,7 +100,7 @@ const ScopeNode = ({ data, id, isConnectable, selected }) => {
98100 ) }
99101 </ Box >
100102 ) ;
101- } ;
103+ } ) ;
102104
103105const CodeNode = memo ( ( { data, id, isConnectable, selected } ) => {
104106 const pod = useSelector ( ( state ) => state . repo . pods [ id ] ) ;
@@ -306,44 +308,6 @@ const CodeNode = memo(({ data, id, isConnectable, selected }) => {
306308
307309const nodeTypes = { scope : ScopeNode , code : CodeNode } ;
308310
309- const NodeBar = ( ) => {
310- const onDragStart = ( event , nodeType ) => {
311- event . dataTransfer . setData ( "application/reactflow" , nodeType ) ;
312- event . dataTransfer . effectAllowed = "move" ;
313- } ;
314-
315- return (
316- < Box
317- sx = { {
318- zIndex : 4 ,
319- display : "flex" ,
320- flexDirection : "row" ,
321- } }
322- >
323- < Box
324- className = "dndnode input"
325- sx = { {
326- cursor : "grab" ,
327- zIndex : 4 ,
328- border : "1px solid #aaa" ,
329- } }
330- onDragStart = { ( event ) => onDragStart ( event , "code" ) }
331- draggable
332- >
333- Code
334- </ Box >
335- < Box
336- className = "dndnode output"
337- sx = { { cursor : "grab" , ml : 2 , border : "1px solid #aaa" } }
338- onDragStart = { ( event ) => onDragStart ( event , "scope" ) }
339- draggable
340- >
341- Scope
342- </ Box >
343- </ Box >
344- ) ;
345- } ;
346-
347311const level2color = {
348312 0 : "rgba(255, 0, 0, 0.2)" ,
349313 1 : "rgba(255, 0, 255, 0.2)" ,
@@ -419,7 +383,8 @@ export function Deck({ props }) {
419383 useEffect ( ( ) => {
420384 let nodes = getRealNodes ( "ROOT" , - 1 ) ;
421385 setNodes ( nodes ) ;
422- } , [ getRealNodes ] ) ;
386+ // eslint-disable-next-line react-hooks/exhaustive-deps
387+ } , [ ] ) ;
423388
424389 const onNodesChange = useCallback (
425390 ( changes ) => {
@@ -436,27 +401,13 @@ export function Deck({ props }) {
436401 [ setEdges ]
437402 ) ;
438403
439- const onDragOver = useCallback ( ( event ) => {
440- event . preventDefault ( ) ;
441- event . dataTransfer . dropEffect = "move" ;
442- } , [ ] ) ;
443-
444404 const [ reactFlowInstance , setReactFlowInstance ] = useState ( null ) ;
445405 const reactFlowWrapper = useRef ( null ) ;
446406
447407 const dispatch = useDispatch ( ) ;
448- const onDrop = useCallback (
449- ( event ) => {
450- event . preventDefault ( ) ;
451-
408+ const addNode = useCallback (
409+ ( x , y , type ) => {
452410 const reactFlowBounds = reactFlowWrapper . current . getBoundingClientRect ( ) ;
453- let type = event . dataTransfer . getData ( "application/reactflow" ) ;
454-
455- // check if the dropped element is valid
456- if ( typeof type === "undefined" || ! type ) {
457- return ;
458- }
459-
460411 let style ;
461412
462413 // if (type === "code") type = "default";
@@ -474,8 +425,8 @@ export function Deck({ props }) {
474425 }
475426
476427 const position = reactFlowInstance . project ( {
477- x : event . clientX - reactFlowBounds . left ,
478- y : event . clientY - reactFlowBounds . top ,
428+ x : x - reactFlowBounds . left ,
429+ y : y - reactFlowBounds . top ,
479430 } ) ;
480431 let id = "CP" + nanoid ( ) ;
481432 const newNode = {
@@ -510,7 +461,7 @@ export function Deck({ props }) {
510461 } )
511462 ) ;
512463 } ,
513- [ reactFlowInstance , dispatch , onResize ]
464+ [ dispatch , onResize , reactFlowInstance , setNodes ]
514465 ) ;
515466
516467 const getAbsPos = useCallback (
@@ -581,14 +532,6 @@ export function Deck({ props }) {
581532 x : event . clientX - reactFlowBounds . left ,
582533 y : event . clientY - reactFlowBounds . top ,
583534 } ) ;
584- // first, dispatch this to the store
585- dispatch (
586- repoSlice . actions . setPodPosition ( {
587- id : node . id ,
588- x : node . position . x ,
589- y : node . position . y ,
590- } )
591- ) ;
592535 // check if this position is inside parent scope
593536 if (
594537 mousePos . x < node . positionAbsolute . x ||
@@ -601,8 +544,30 @@ export function Deck({ props }) {
601544 }
602545 // Check which group is at this position.
603546 const scope = getScopeAt ( mousePos . x , mousePos . y , node . id ) ;
547+ let absX = node . position . x ;
548+ let absY = node . position . y ;
604549 if ( scope ) {
605550 console . log ( "dropped into scope:" , scope ) ;
551+ // compute the actual position
552+ let { x : _absX , y : _absY } = getAbsolutePos (
553+ node . positionAbsolute . x ,
554+ node . positionAbsolute . y ,
555+ scope ,
556+ nodes
557+ ) ;
558+ absX = _absX ;
559+ absY = _absY ;
560+ }
561+ // first, dispatch this to the store
562+ dispatch (
563+ repoSlice . actions . setPodPosition ( {
564+ id : node . id ,
565+ x : absX ,
566+ y : absY ,
567+ } )
568+ ) ;
569+
570+ if ( scope ) {
606571 dispatch (
607572 repoSlice . actions . setPodParent ( {
608573 id : node . id ,
@@ -628,20 +593,10 @@ export function Deck({ props }) {
628593 ...nd . style ,
629594 backgroundColor : level2color [ scope . level + 1 ] ,
630595 } ,
631- position : scope . positionAbsolute
632- ? {
633- x : node . positionAbsolute . x - scope . positionAbsolute . x ,
634- y : node . positionAbsolute . y - scope . positionAbsolute . y ,
635- }
636- : // I need to adjust for all the ancestor nodes' position.
637- // But there's no positionAbsolute field in the nodes.
638- // So, I need to calculate it.
639- getAbsolutePos (
640- node . positionAbsolute . x ,
641- node . positionAbsolute . y ,
642- scope ,
643- nds
644- ) ,
596+ position : {
597+ x : absX ,
598+ y : absY ,
599+ } ,
645600 } ;
646601 }
647602 return nd ;
@@ -665,6 +620,23 @@ export function Deck({ props }) {
665620 [ dispatch ]
666621 ) ;
667622
623+ const [ showContextMenu , setShowContextMenu ] = useState ( false ) ;
624+ const [ points , setPoints ] = useState ( { x : 0 , y : 0 } ) ;
625+ const [ client , setClient ] = useState ( { x : 0 , y : 0 } ) ;
626+
627+ const onPaneContextMenu = ( event ) => {
628+ event . preventDefault ( ) ;
629+ setShowContextMenu ( true ) ;
630+ setPoints ( { x : event . pageX , y : event . pageY } ) ;
631+ setClient ( { x : event . clientX , y : event . clientY } ) ;
632+ } ;
633+
634+ useEffect ( ( ) => {
635+ const handleClick = ( ) => setShowContextMenu ( false ) ;
636+ document . addEventListener ( "click" , handleClick ) ;
637+ return ( ) => document . removeEventListener ( "click" , handleClick ) ;
638+ } , [ ] ) ;
639+
668640 return (
669641 < Box
670642 style = { {
@@ -673,7 +645,6 @@ export function Deck({ props }) {
673645 flexDirection : "column" ,
674646 } }
675647 >
676- < NodeBar />
677648 < Box sx = { { height : "100%" } } ref = { reactFlowWrapper } >
678649 < ReactFlow
679650 nodes = { nodes }
@@ -682,14 +653,12 @@ export function Deck({ props }) {
682653 onEdgesChange = { onEdgesChange }
683654 onConnect = { onConnect }
684655 onInit = { setReactFlowInstance }
685- // onNodeDrag={onNodeDrag}
686656 onNodeDragStop = { onNodeDragStop }
687657 onNodesDelete = { onNodesDelete }
688658 fitView
689659 attributionPosition = "top-right"
690660 maxZoom = { 5 }
691- onDrop = { onDrop }
692- onDragOver = { onDragOver }
661+ onPaneContextMenu = { onPaneContextMenu }
693662 nodeTypes = { nodeTypes }
694663 zoomOnScroll = { false }
695664 panOnScroll = { true }
@@ -715,6 +684,38 @@ export function Deck({ props }) {
715684 < Background />
716685 </ Box >
717686 </ ReactFlow >
687+ { showContextMenu && (
688+ < Box
689+ sx = { {
690+ left : `${ points . x } px` ,
691+ top : `${ points . y } px` ,
692+ zIndex : 100 ,
693+ position : "absolute" ,
694+ boxShadow : "0px 1px 8px 0px rgba(0, 0, 0, 0.1)" ,
695+ // width: '200px',
696+ backgroundColor : "#fff" ,
697+ borderRadius : "5px" ,
698+ boxSizing : "border-box" ,
699+ } }
700+ >
701+ < Stack >
702+ < Button
703+ onClick = { ( ) => {
704+ addNode ( client . x , client . y , "code" ) ;
705+ } }
706+ >
707+ New Code{ " " }
708+ </ Button >
709+ < Button
710+ onClick = { ( ) => {
711+ addNode ( client . x , client . y , "scope" ) ;
712+ } }
713+ >
714+ New Scope{ " " }
715+ </ Button >
716+ </ Stack >
717+ </ Box >
718+ ) }
718719 </ Box >
719720 </ Box >
720721 ) ;
0 commit comments