diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index b2d81d37..9297562c 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -1,10 +1,11 @@ import React, { useEffect, useState, CSSProperties } from 'react'; import cx from 'classnames'; -import { ElementId, Node, Transform, HandleElement, Position, ConnectionLineType } from '../../types'; +import { ElementId, Node, Transform, HandleElement, Position, ConnectionLineType, HandleType } from '../../types'; interface ConnectionLineProps { - connectionSourceId: ElementId; + connectionNodeId: ElementId; + connectionHandleType: HandleType; connectionPositionX: number; connectionPositionY: number; connectionLineType: ConnectionLineType; @@ -16,7 +17,8 @@ interface ConnectionLineProps { } export default ({ - connectionSourceId, + connectionNodeId, + connectionHandleType, connectionLineStyle, connectionPositionX, connectionPositionY, @@ -27,8 +29,8 @@ export default ({ isInteractive, }: ConnectionLineProps) => { const [sourceNode, setSourceNode] = useState(null); - const hasHandleId = connectionSourceId.includes('__'); - const sourceIdSplitted = connectionSourceId.split('__'); + const hasHandleId = connectionNodeId.includes('__'); + const sourceIdSplitted = connectionNodeId.split('__'); const nodeId = sourceIdSplitted[0]; const handleId = hasHandleId ? sourceIdSplitted[1] : null; @@ -42,14 +44,10 @@ export default ({ } const connectionLineClasses: string = cx('react-flow__connection', className); - const hasSource = sourceNode.__rg.handleBounds.source !== null; - - // output nodes don't have source handles so we need to use the target one - const handleKey = hasSource ? 'source' : 'target'; const sourceHandle = handleId - ? sourceNode.__rg.handleBounds[handleKey].find((d: HandleElement) => d.id === handleId) - : sourceNode.__rg.handleBounds[handleKey][0]; + ? sourceNode.__rg.handleBounds[connectionHandleType].find((d: HandleElement) => d.id === handleId) + : sourceNode.__rg.handleBounds[connectionHandleType][0]; const sourceHandleX = sourceHandle ? sourceHandle.x + sourceHandle.width / 2 : sourceNode.__rg.width / 2; const sourceHandleY = sourceHandle ? sourceHandle.y + sourceHandle.height / 2 : sourceNode.__rg.height; const sourceX = sourceNode.__rg.position.x + sourceHandleX; diff --git a/src/components/Handle/BaseHandle.tsx b/src/components/Handle/BaseHandle.tsx index 61772853..87537d98 100644 --- a/src/components/Handle/BaseHandle.tsx +++ b/src/components/Handle/BaseHandle.tsx @@ -1,17 +1,17 @@ import React, { memo, MouseEvent as ReactMouseEvent, CSSProperties } from 'react'; import cx from 'classnames'; -import { HandleType, ElementId, Position, XYPosition, OnConnectFunc, Connection } from '../../types'; +import { HandleType, ElementId, Position, XYPosition, OnConnectFunc, Connection, SetConnectionId } from '../../types'; type ValidConnectionFunc = (connection: Connection) => boolean; -type SetSourceIdFunc = (nodeId: ElementId | null) => void; +type SetSourceIdFunc = (params: SetConnectionId) => void; interface BaseHandleProps { type: HandleType; nodeId: ElementId; onConnect: OnConnectFunc; position: Position; - setSourceId: SetSourceIdFunc; + setConnectionNodeId: SetSourceIdFunc; setPosition: (pos: XYPosition) => void; isValidConnection: ValidConnectionFunc; id?: ElementId | boolean; @@ -29,8 +29,8 @@ type Result = { function onMouseDown( evt: ReactMouseEvent, nodeId: ElementId, - setSourceId: SetSourceIdFunc, - setPosition: (pos: XYPosition) => any, + setConnectionNodeId: SetSourceIdFunc, + setPosition: (pos: XYPosition) => void, onConnect: OnConnectFunc, isTarget: boolean, isValidConnection: ValidConnectionFunc @@ -48,7 +48,7 @@ function onMouseDown( x: evt.clientX - containerBounds.left, y: evt.clientY - containerBounds.top, }); - setSourceId(nodeId); + setConnectionNodeId({ connectionNodeId: nodeId, connectionHandleType: isTarget ? 'target' : 'source' }); function resetRecentHandle(): void { if (!recentHoveredHandle) { @@ -120,7 +120,7 @@ function onMouseDown( } resetRecentHandle(); - setSourceId(null); + setConnectionNodeId({ connectionNodeId: null, connectionHandleType: null }); document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); @@ -136,7 +136,7 @@ const BaseHandle = memo( nodeId, onConnect, position, - setSourceId, + setConnectionNodeId, setPosition, className, id = false, @@ -157,7 +157,7 @@ const BaseHandle = memo( data-handlepos={position} className={handleClasses} onMouseDown={(evt) => - onMouseDown(evt, nodeIdWithHandleId, setSourceId, setPosition, onConnect, isTarget, isValidConnection) + onMouseDown(evt, nodeIdWithHandleId, setConnectionNodeId, setPosition, onConnect, isTarget, isValidConnection) } {...rest} /> diff --git a/src/components/Handle/index.tsx b/src/components/Handle/index.tsx index 56a544c0..31e0832e 100644 --- a/src/components/Handle/index.tsx +++ b/src/components/Handle/index.tsx @@ -18,7 +18,7 @@ const Handle = memo( }: HandleProps) => { const nodeId = useContext(NodeIdContext) as ElementId; const setPosition = useStoreActions((a) => a.setConnectionPosition); - const setSourceId = useStoreActions((a) => a.setConnectionSourceId); + const setConnectionNodeId = useStoreActions((a) => a.setConnectionNodeId); const onConnectAction = useStoreState((s) => s.onConnect); const onConnectExtended = (params: Connection) => { onConnectAction(params); @@ -29,7 +29,7 @@ const Handle = memo( { const [tX, tY, tScale] = useStoreState((s) => s.transform); const edges = useStoreState((s) => s.edges); const nodes = useStoreState((s) => s.nodes); - const connectionSourceId = useStoreState((s) => s.connectionSourceId); + const connectionNodeId = useStoreState((s) => s.connectionNodeId); + const connectionHandleType = useStoreState((s) => s.connectionHandleType); const connectionPosition = useStoreState((s) => s.connectionPosition); const selectedElements = useStoreState((s) => s.selectedElements); const isInteractive = useStoreState((s) => s.isInteractive); @@ -202,15 +203,17 @@ const EdgeRenderer = memo((props: EdgeRendererProps) => { } const transformStyle = `translate(${tX},${tY}) scale(${tScale})`; + const renderConnectionLine = connectionNodeId && connectionHandleType; return ( {edges.map((e: Edge) => renderEdge(e, props, nodes, selectedElements, isInteractive))} - {connectionSourceId && ( + {renderConnectionLine && ( ; - setConnectionSourceId: Action; + setConnectionNodeId: Action; setInteractive: Action; @@ -140,7 +143,8 @@ const storeModel: StoreModel = { height: 0, draw: false, }, - connectionSourceId: null, + connectionNodeId: null, + connectionHandleType: 'source', connectionPosition: { x: 0, y: 0 }, snapGrid: [16, 16], @@ -330,8 +334,9 @@ const storeModel: StoreModel = { state.connectionPosition = position; }), - setConnectionSourceId: action((state, sourceId) => { - state.connectionSourceId = sourceId; + setConnectionNodeId: action((state, { connectionNodeId, connectionHandleType }) => { + state.connectionNodeId = connectionNodeId; + state.connectionHandleType = connectionHandleType; }), setSnapGrid: action((state, { snapToGrid, snapGrid }) => { diff --git a/src/types/index.ts b/src/types/index.ts index 8a29f12b..0a0ca976 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -160,6 +160,11 @@ export enum ConnectionLineType { export type OnConnectFunc = (connection: Connection) => void; +export type SetConnectionId = { + connectionNodeId: ElementId | null; + connectionHandleType: HandleType | null; +}; + export interface HandleElement extends XYPosition, Dimensions { id?: ElementId | null; position: Position;