@@ -356,6 +356,9 @@ const WorkflowContent = React.memo(() => {
356356 /** Stores source node/handle info when a connection drag starts for drop-on-block detection. */
357357 const connectionSourceRef = useRef < { nodeId : string ; handleId : string } | null > ( null )
358358
359+ /** Tracks whether onConnect successfully handled the connection (ReactFlow pattern). */
360+ const connectionCompletedRef = useRef ( false )
361+
359362 /** Stores start positions for multi-node drag undo/redo recording. */
360363 const multiNodeDragStartRef = useRef < Map < string , { x : number ; y : number ; parentId ?: string } > > (
361364 new Map ( )
@@ -2214,7 +2217,8 @@ const WorkflowContent = React.memo(() => {
22142217 )
22152218
22162219 /**
2217- * Captures the source handle when a connection drag starts
2220+ * Captures the source handle when a connection drag starts.
2221+ * Resets connectionCompletedRef to track if onConnect handles this connection.
22182222 */
22192223 const onConnectStart = useCallback ( ( _event : any , params : any ) => {
22202224 const handleId : string | undefined = params ?. handleId
@@ -2223,6 +2227,7 @@ const WorkflowContent = React.memo(() => {
22232227 nodeId : params ?. nodeId ,
22242228 handleId : params ?. handleId ,
22252229 }
2230+ connectionCompletedRef . current = false
22262231 } , [ ] )
22272232
22282233 /** Handles new edge connections with container boundary validation. */
@@ -2283,6 +2288,7 @@ const WorkflowContent = React.memo(() => {
22832288 isInsideContainer : true ,
22842289 } ,
22852290 } )
2291+ connectionCompletedRef . current = true
22862292 return
22872293 }
22882294
@@ -2311,6 +2317,7 @@ const WorkflowContent = React.memo(() => {
23112317 }
23122318 : undefined ,
23132319 } )
2320+ connectionCompletedRef . current = true
23142321 }
23152322 } ,
23162323 [ addEdge , getNodes , blocks ]
@@ -2319,8 +2326,9 @@ const WorkflowContent = React.memo(() => {
23192326 /**
23202327 * Handles connection drag end. Detects if the edge was dropped over a block
23212328 * and automatically creates a connection to that block's target handle.
2322- * Only creates a connection if ReactFlow didn't already handle it (e.g., when
2323- * dropping on the block body instead of a handle).
2329+ *
2330+ * Uses connectionCompletedRef to check if onConnect already handled this connection
2331+ * (ReactFlow pattern for distinguishing handle-to-handle vs handle-to-body drops).
23242332 */
23252333 const onConnectEnd = useCallback (
23262334 ( event : MouseEvent | TouchEvent ) => {
@@ -2332,6 +2340,12 @@ const WorkflowContent = React.memo(() => {
23322340 return
23332341 }
23342342
2343+ // If onConnect already handled this connection, skip (handle-to-handle case)
2344+ if ( connectionCompletedRef . current ) {
2345+ connectionSourceRef . current = null
2346+ return
2347+ }
2348+
23352349 // Get cursor position in flow coordinates
23362350 const clientPos = 'changedTouches' in event ? event . changedTouches [ 0 ] : event
23372351 const flowPosition = screenToFlowPosition ( {
@@ -2342,25 +2356,14 @@ const WorkflowContent = React.memo(() => {
23422356 // Find node under cursor
23432357 const targetNode = findNodeAtPosition ( flowPosition )
23442358
2345- // Create connection if valid target found AND edge doesn't already exist
2346- // ReactFlow's onConnect fires first when dropping on a handle, so we check
2347- // if that connection already exists to avoid creating duplicates.
2348- // IMPORTANT: We must read directly from the store (not React state) because
2349- // the store update from ReactFlow's onConnect may not have triggered a
2350- // React re-render yet when this callback runs (typically 1-2ms later).
2359+ // Create connection if valid target found (handle-to-body case)
23512360 if ( targetNode && targetNode . id !== source . nodeId ) {
2352- const currentEdges = useWorkflowStore . getState ( ) . edges
2353- const edgeAlreadyExists = currentEdges . some (
2354- ( e ) => e . source === source . nodeId && e . target === targetNode . id
2355- )
2356- if ( ! edgeAlreadyExists ) {
2357- onConnect ( {
2358- source : source . nodeId ,
2359- sourceHandle : source . handleId ,
2360- target : targetNode . id ,
2361- targetHandle : 'target' ,
2362- } )
2363- }
2361+ onConnect ( {
2362+ source : source . nodeId ,
2363+ sourceHandle : source . handleId ,
2364+ target : targetNode . id ,
2365+ targetHandle : 'target' ,
2366+ } )
23642367 }
23652368
23662369 connectionSourceRef . current = null
0 commit comments