diff --git a/README.md b/README.md
index e2ca976a..bfdc0ce8 100644
--- a/README.md
+++ b/README.md
@@ -88,6 +88,8 @@ const BasicFlow = () => ;
- `onNodeMouseLeave(evt: MouseEvent, node: Node)`: node mouse leave
- `onNodeContextMenu(evt: MouseEvent, node: Node)`: node context menu
- `onConnect({ source, target })`: called when user connects two nodes
+- `onConnectStart({ nodeId, handleType })`: called when user starts to drag connection line
+- `onConnectStop()`: called when user stops to drag connection line
- `onLoad(reactFlowInstance)`: called after flow is initialized
- `onMove()`: called when user is panning or zooming
- `onMoveStart()`: called when user starts panning or zooming
diff --git a/example/src/Validation/index.js b/example/src/Validation/index.js
index fb82a320..48cbeafa 100644
--- a/example/src/Validation/index.js
+++ b/example/src/Validation/index.js
@@ -15,6 +15,10 @@ const isValidConnection = (connection) => connection.target === 'B';
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
+const onConnectStart = ({ nodeId, handleType }) => console.log('on connect start', { nodeId, handleType });
+
+const onConnectStop = () => console.log('on connect stop');
+
const CustomInput = () => (
<>
Only connectable with B
@@ -47,6 +51,8 @@ const HorizontalFlow = () => {
onLoad={onLoad}
className="validationflow"
nodeTypes={nodeTypes}
+ onConnectStart={onConnectStart}
+ onConnectStop={onConnectStop}
/>
);
};
diff --git a/src/components/Handle/BaseHandle.tsx b/src/components/Handle/BaseHandle.tsx
index 706aca81..3eebae64 100644
--- a/src/components/Handle/BaseHandle.tsx
+++ b/src/components/Handle/BaseHandle.tsx
@@ -1,7 +1,17 @@
import React, { memo, MouseEvent as ReactMouseEvent, CSSProperties } from 'react';
import cc from 'classcat';
-import { HandleType, ElementId, Position, XYPosition, OnConnectFunc, Connection, SetConnectionId } from '../../types';
+import {
+ HandleType,
+ ElementId,
+ Position,
+ XYPosition,
+ OnConnectFunc,
+ OnConnectStartFunc,
+ OnConnectStopFunc,
+ Connection,
+ SetConnectionId,
+} from '../../types';
type ValidConnectionFunc = (connection: Connection) => boolean;
type SetSourceIdFunc = (params: SetConnectionId) => void;
@@ -10,6 +20,8 @@ interface BaseHandleProps {
type: HandleType;
nodeId: ElementId;
onConnect: OnConnectFunc;
+ onConnectStart?: OnConnectStartFunc;
+ onConnectStop?: OnConnectStopFunc;
position: Position;
setConnectionNodeId: SetSourceIdFunc;
setPosition: (pos: XYPosition) => void;
@@ -33,7 +45,9 @@ function onMouseDown(
setPosition: (pos: XYPosition) => void,
onConnect: OnConnectFunc,
isTarget: boolean,
- isValidConnection: ValidConnectionFunc
+ isValidConnection: ValidConnectionFunc,
+ onConnectStart?: OnConnectStartFunc,
+ onConnectStop?: OnConnectStopFunc
): void {
const reactFlowNode = document.querySelector('.react-flow');
@@ -41,6 +55,7 @@ function onMouseDown(
return;
}
+ const handleType = isTarget ? 'target' : 'source';
const containerBounds = reactFlowNode.getBoundingClientRect();
let recentHoveredHandle: Element;
@@ -48,7 +63,11 @@ function onMouseDown(
x: evt.clientX - containerBounds.left,
y: evt.clientY - containerBounds.top,
});
- setConnectionNodeId({ connectionNodeId: nodeId, connectionHandleType: isTarget ? 'target' : 'source' });
+ setConnectionNodeId({ connectionNodeId: nodeId, connectionHandleType: handleType });
+
+ if (onConnectStart) {
+ onConnectStart({ nodeId, handleType });
+ }
function resetRecentHandle(): void {
if (!recentHoveredHandle) {
@@ -115,13 +134,17 @@ function onMouseDown(
function onMouseUp(evt: MouseEvent) {
const { connection, isValid } = checkElementBelowIsValid(evt);
- if (isValid) {
+ if (isValid && onConnect) {
onConnect(connection);
}
resetRecentHandle();
setConnectionNodeId({ connectionNodeId: null, connectionHandleType: null });
+ if (onConnectStop) {
+ onConnectStop();
+ }
+
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
@@ -134,6 +157,8 @@ const BaseHandle = ({
type,
nodeId,
onConnect,
+ onConnectStart,
+ onConnectStop,
position,
setConnectionNodeId,
setPosition,
@@ -162,7 +187,17 @@ const BaseHandle = ({
data-handlepos={position}
className={handleClasses}
onMouseDown={(evt) =>
- onMouseDown(evt, nodeIdWithHandleId, setConnectionNodeId, setPosition, onConnect, isTarget, isValidConnection)
+ onMouseDown(
+ evt,
+ nodeIdWithHandleId,
+ setConnectionNodeId,
+ setPosition,
+ onConnect,
+ isTarget,
+ isValidConnection,
+ onConnectStart,
+ onConnectStop
+ )
}
{...rest}
/>
diff --git a/src/components/Handle/index.tsx b/src/components/Handle/index.tsx
index f181183e..cba3d67b 100644
--- a/src/components/Handle/index.tsx
+++ b/src/components/Handle/index.tsx
@@ -10,20 +10,27 @@ import { HandleProps, ElementId, Position, Connection } from '../../types';
const Handle = ({
type = 'source',
position = Position.Top,
- onConnect = () => {},
isValidConnection = () => true,
isConnectable = true,
style,
className,
id,
+ onConnect,
}: HandleProps) => {
const nodeId = useContext(NodeIdContext) as ElementId;
const setPosition = useStoreActions((a) => a.setConnectionPosition);
const setConnectionNodeId = useStoreActions((a) => a.setConnectionNodeId);
const onConnectAction = useStoreState((s) => s.onConnect);
+ const onConnectStart = useStoreState((s) => s.onConnectStart);
+ const onConnectStop = useStoreState((s) => s.onConnectStop);
const onConnectExtended = (params: Connection) => {
- onConnectAction(params);
- onConnect(params);
+ if (onConnectAction) {
+ onConnectAction(params);
+ }
+
+ if (onConnect) {
+ onConnect(params);
+ }
};
const handleClasses = cc([className, { connectable: isConnectable }]);
@@ -35,6 +42,8 @@ const Handle = ({
setPosition={setPosition}
setConnectionNodeId={setConnectionNodeId}
onConnect={onConnectExtended}
+ onConnectStart={onConnectStart}
+ onConnectStop={onConnectStop}
type={type}
position={position}
isValidConnection={isValidConnection}
diff --git a/src/container/GraphView/index.tsx b/src/container/GraphView/index.tsx
index 1d598c71..9ebd9767 100644
--- a/src/container/GraphView/index.tsx
+++ b/src/container/GraphView/index.tsx
@@ -22,6 +22,7 @@ import {
Connection,
ConnectionLineType,
FlowTransform,
+ OnConnectStartFunc,
} from '../../types';
export interface GraphViewProps {
@@ -35,6 +36,8 @@ export interface GraphViewProps {
onNodeDragStart?: (node: Node) => void;
onNodeDragStop?: (node: Node) => void;
onConnect?: (connection: Connection | Edge) => void;
+ onConnectStart?: OnConnectStartFunc;
+ onConnectStop?: () => void;
onLoad?: OnLoadFunc;
onMove?: (flowTransform?: FlowTransform) => void;
onMoveStart?: (flowTransform?: FlowTransform) => void;
@@ -85,6 +88,8 @@ const GraphView = ({
deleteKeyCode,
elements,
onConnect,
+ onConnectStart,
+ onConnectStop,
snapToGrid,
snapGrid,
onlyRenderVisibleNodes,
@@ -112,6 +117,8 @@ const GraphView = ({
const updateSize = useStoreActions((actions) => actions.updateSize);
const setNodesSelection = useStoreActions((actions) => actions.setNodesSelection);
const setOnConnect = useStoreActions((a) => a.setOnConnect);
+ const setOnConnectStart = useStoreActions((a) => a.setOnConnectStart);
+ const setOnConnectStop = useStoreActions((a) => a.setOnConnectStop);
const setSnapGrid = useStoreActions((actions) => actions.setSnapGrid);
const setNodesDraggable = useStoreActions((actions) => actions.setNodesDraggable);
const setNodesConnectable = useStoreActions((actions) => actions.setNodesConnectable);
@@ -210,6 +217,18 @@ const GraphView = ({
}
}, [onConnect]);
+ useEffect(() => {
+ if (onConnectStart) {
+ setOnConnectStart(onConnectStart);
+ }
+ }, [onConnectStart]);
+
+ useEffect(() => {
+ if (onConnectStop) {
+ setOnConnectStop(onConnectStop);
+ }
+ }, [onConnectStop]);
+
useEffect(() => {
setSnapGrid({ snapToGrid, snapGrid });
}, [snapToGrid]);
diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx
index 44882aa7..8e383073 100644
--- a/src/container/ReactFlow/index.tsx
+++ b/src/container/ReactFlow/index.tsx
@@ -27,6 +27,7 @@ import {
Connection,
ConnectionLineType,
FlowTransform,
+ OnConnectStartFunc,
} from '../../types';
import '../../style.css';
@@ -42,6 +43,8 @@ export interface ReactFlowProps extends Omit, 'on
onNodeDragStart?: (node: Node) => void;
onNodeDragStop?: (node: Node) => void;
onConnect?: (connection: Edge | Connection) => void;
+ onConnectStart?: OnConnectStartFunc;
+ onConnectStop?: () => void;
onLoad?: OnLoadFunc;
onMove?: (flowTransform?: FlowTransform) => void;
onMoveStart?: (flowTransform?: FlowTransform) => void;
@@ -86,6 +89,8 @@ const ReactFlow = ({
onMoveEnd,
onElementsRemove,
onConnect,
+ onConnectStart,
+ onConnectStop,
onNodeMouseEnter,
onNodeMouseMove,
onNodeMouseLeave,
@@ -143,6 +148,8 @@ const ReactFlow = ({
deleteKeyCode={deleteKeyCode}
elements={elements}
onConnect={onConnect}
+ onConnectStart={onConnectStart}
+ onConnectStop={onConnectStop}
snapToGrid={snapToGrid}
snapGrid={snapGrid}
onlyRenderVisibleNodes={onlyRenderVisibleNodes}
diff --git a/src/store/index.ts b/src/store/index.ts
index cf710ab2..be995188 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -18,6 +18,8 @@ import {
Dimensions,
XYPosition,
OnConnectFunc,
+ OnConnectStartFunc,
+ OnConnectStopFunc,
SelectionRect,
HandleType,
SetConnectionId,
@@ -87,9 +89,13 @@ export interface StoreModel {
reactFlowVersion: string;
- onConnect: OnConnectFunc;
+ onConnect?: OnConnectFunc;
+ onConnectStart?: OnConnectStartFunc;
+ onConnectStop?: OnConnectStopFunc;
setOnConnect: Action;
+ setOnConnectStart: Action;
+ setOnConnectStop: Action;
setElements: Action;
@@ -177,11 +183,15 @@ export const storeModel: StoreModel = {
reactFlowVersion: typeof __REACT_FLOW_VERSION__ !== 'undefined' ? __REACT_FLOW_VERSION__ : '-',
- onConnect: () => {},
-
setOnConnect: action((state, onConnect) => {
state.onConnect = onConnect;
}),
+ setOnConnectStart: action((state, onConnectStart) => {
+ state.onConnectStart = onConnectStart;
+ }),
+ setOnConnectStop: action((state, onConnectStop) => {
+ state.onConnectStop = onConnectStop;
+ }),
setElements: action((state, elements) => {
state.elements = elements;
diff --git a/src/types/index.ts b/src/types/index.ts
index fc1124a0..c1ac6057 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -198,6 +198,12 @@ export enum ConnectionLineType {
}
export type OnConnectFunc = (connection: Connection) => void;
+export type OnConnectStartParams = {
+ nodeId: ElementId | null;
+ handleType: HandleType | null;
+};
+export type OnConnectStartFunc = (params: OnConnectStartParams) => void;
+export type OnConnectStopFunc = () => void;
export type SetConnectionId = {
connectionNodeId: ElementId | null;