Created
November 7, 2024 18:13
-
-
Save misiek08/6a63eeec587cbce7021166492c7cc230 to your computer and use it in GitHub Desktop.
ReactFlow add node when edge dropped nowhere, like UE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState, useCallback, useRef } from 'react'; | |
import { | |
ReactFlow, | |
addEdge, | |
MiniMap, | |
Controls, | |
Background, | |
useNodesState, | |
useEdgesState, | |
useReactFlow, | |
ReactFlowProvider, | |
} from '@xyflow/react'; | |
import '@xyflow/react/dist/style.css'; | |
const initialNodes = [ | |
{ id: '1', position: { x: 250, y: 0 }, data: { label: 'Node 1' } }, | |
]; | |
const compatibleNodes = [ | |
{ id: 'comp1', data: { label: 'Compatible Node 1' }, type: 'default' }, | |
{ id: 'comp2', data: { label: 'Compatible Node 2' }, type: 'default' }, | |
]; | |
const FlowWithSuggestionsInner = () => { | |
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); | |
const [edges, setEdges, onEdgesChange] = useEdgesState([]); | |
const [suggestedNodes, setSuggestedNodes] = useState([]); | |
const [showSuggestions, setShowSuggestions] = useState(false); | |
const [newEdgePosition, setNewEdgePosition] = useState(null); | |
const popupRef = useRef(null); | |
const { screenToFlowPosition } = useReactFlow(); // Jest w kontekście ReactFlowProvider | |
const onConnect = useCallback( | |
(params) => { | |
setEdges((eds) => addEdge(params, eds)); | |
}, | |
[setEdges] | |
); | |
const onMouseDown = (event) => { | |
if (!popupRef.current.contains(event.target)) { | |
setShowSuggestions(false); | |
} | |
}; | |
const onConnectEnd = (event) => { | |
if (!event.target.closest('.react-flow__node')) { | |
const canvasPosition = screenToFlowPosition({ | |
x: event.clientX, | |
y: event.clientY, | |
}); | |
setSuggestedNodes(compatibleNodes); | |
setShowSuggestions(true); | |
setNewEdgePosition({ | |
node: canvasPosition, | |
mouse: { x: event.clientX, y: event.clientY }, | |
}); | |
} | |
}; | |
const addCompatibleNode = (nodeTemplate) => { | |
if (!newEdgePosition) return; | |
const newNodeId = (nodes.length + 1).toString(); | |
const newNode = { | |
...nodeTemplate, | |
id: newNodeId, | |
position: { x: newEdgePosition.node.x, y: newEdgePosition.node.y }, | |
}; | |
setNodes((nds) => [...nds, newNode]); | |
setEdges((eds) => | |
addEdge({ id: `e${newNodeId}`, source: '1', target: newNodeId }, eds) | |
); | |
setShowSuggestions(false); | |
setNewEdgePosition(null); | |
}; | |
return ( | |
<ReactFlow | |
nodes={nodes} | |
edges={edges} | |
onNodesChange={onNodesChange} | |
onEdgesChange={onEdgesChange} | |
onMouseDownCapture={onMouseDown} | |
onConnect={onConnect} | |
onConnectEnd={onConnectEnd} | |
onMouse | |
fitView | |
> | |
<MiniMap /> | |
<Controls /> | |
<Background /> | |
{showSuggestions && ( | |
<div | |
ref={popupRef} | |
className="suggestion-popup" | |
style={{ | |
position: 'absolute', | |
left: newEdgePosition?.mouse.x || 0, | |
top: newEdgePosition?.mouse.y || 0, | |
background: 'white', | |
padding: '10px', | |
border: '1px solid black', | |
borderRadius: '5px', | |
zIndex: 10, | |
}} | |
> | |
<h4>Select compatible node:</h4> | |
{suggestedNodes.map((node) => ( | |
<button key={node.id} onClick={() => addCompatibleNode(node)}> | |
{node.data.label} | |
</button> | |
))} | |
</div> | |
)} | |
</ReactFlow> | |
); | |
}; | |
// Główny komponent otaczający ReactFlowProvider | |
const FlowWithSuggestions = () => ( | |
<div style={{ width: '100%', height: '100%' }}> | |
<ReactFlowProvider> | |
{' '} | |
{/* ReactFlowProvider jako główny komponent */} | |
<FlowWithSuggestionsInner /> | |
</ReactFlowProvider> | |
</div> | |
); | |
export default FlowWithSuggestions; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment