Skip to content

Commit a60a1fc

Browse files
aadamgoughaadamgoughicecrasher321
authored
improvement(edges): drag edge over block (#2596)
* drag edge over block * fix minor stale closure --------- Co-authored-by: aadamgough <[email protected]> Co-authored-by: Vikhyath Mondreti <[email protected]>
1 parent 298546d commit a60a1fc

File tree

1 file changed

+73
-8
lines changed
  • apps/sim/app/workspace/[workspaceId]/w/[workflowId]

1 file changed

+73
-8
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ const WorkflowContent = React.memo(() => {
248248
}))
249249
)
250250

251+
/** Stores source node/handle info when a connection drag starts for drop-on-block detection. */
252+
const connectionSourceRef = useRef<{ nodeId: string; handleId: string } | null>(null)
253+
251254
/** Re-applies diff markers when blocks change after socket rehydration. */
252255
const blocksRef = useRef(blocks)
253256
useEffect(() => {
@@ -1702,20 +1705,43 @@ const WorkflowContent = React.memo(() => {
17021705
[removeEdge]
17031706
)
17041707

1708+
/**
1709+
* Finds a node at a given flow position for drop-on-block connection.
1710+
* Skips subflow containers as they have their own connection logic.
1711+
*/
1712+
const findNodeAtPosition = useCallback(
1713+
(position: { x: number; y: number }) => {
1714+
const nodes = getNodes()
1715+
1716+
return nodes.find((node) => {
1717+
// Skip subflow containers for drop targets
1718+
if (node.type === 'subflowNode') return false
1719+
1720+
const absPos = getNodeAbsolutePosition(node.id)
1721+
const dims = getBlockDimensions(node.id)
1722+
1723+
return (
1724+
position.x >= absPos.x &&
1725+
position.x <= absPos.x + dims.width &&
1726+
position.y >= absPos.y &&
1727+
position.y <= absPos.y + dims.height
1728+
)
1729+
})
1730+
},
1731+
[getNodes, getNodeAbsolutePosition, getBlockDimensions]
1732+
)
1733+
17051734
/**
17061735
* Captures the source handle when a connection drag starts
17071736
*/
17081737
const onConnectStart = useCallback((_event: any, params: any) => {
17091738
const handleId: string | undefined = params?.handleId
17101739
// Treat explicit error handle (id === 'error') as error connection
17111740
setIsErrorConnectionDrag(handleId === 'error')
1712-
}, [])
1713-
1714-
/**
1715-
* Resets the source handle when connection drag ends
1716-
*/
1717-
const onConnectEnd = useCallback(() => {
1718-
setIsErrorConnectionDrag(false)
1741+
connectionSourceRef.current = {
1742+
nodeId: params?.nodeId,
1743+
handleId: params?.handleId,
1744+
}
17191745
}, [])
17201746

17211747
/** Handles new edge connections with container boundary validation. */
@@ -1806,7 +1832,46 @@ const WorkflowContent = React.memo(() => {
18061832
})
18071833
}
18081834
},
1809-
[addEdge, getNodes]
1835+
[addEdge, getNodes, blocks]
1836+
)
1837+
1838+
/**
1839+
* Handles connection drag end. Detects if the edge was dropped over a block
1840+
* and automatically creates a connection to that block's target handle.
1841+
*/
1842+
const onConnectEnd = useCallback(
1843+
(event: MouseEvent | TouchEvent) => {
1844+
setIsErrorConnectionDrag(false)
1845+
1846+
const source = connectionSourceRef.current
1847+
if (!source?.nodeId) {
1848+
connectionSourceRef.current = null
1849+
return
1850+
}
1851+
1852+
// Get cursor position in flow coordinates
1853+
const clientPos = 'changedTouches' in event ? event.changedTouches[0] : event
1854+
const flowPosition = screenToFlowPosition({
1855+
x: clientPos.clientX,
1856+
y: clientPos.clientY,
1857+
})
1858+
1859+
// Find node under cursor
1860+
const targetNode = findNodeAtPosition(flowPosition)
1861+
1862+
// Create connection if valid target found
1863+
if (targetNode && targetNode.id !== source.nodeId) {
1864+
onConnect({
1865+
source: source.nodeId,
1866+
sourceHandle: source.handleId,
1867+
target: targetNode.id,
1868+
targetHandle: 'target',
1869+
})
1870+
}
1871+
1872+
connectionSourceRef.current = null
1873+
},
1874+
[screenToFlowPosition, findNodeAtPosition, onConnect]
18101875
)
18111876

18121877
/** Handles node drag to detect container intersections and update highlighting. */

0 commit comments

Comments
 (0)