feat(connection): add start and stop props closes #380
This commit is contained in:
@@ -88,6 +88,8 @@ const BasicFlow = () => <ReactFlow elements={elements} />;
|
||||
- `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
|
||||
|
||||
@@ -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 = () => (
|
||||
<>
|
||||
<div>Only connectable with B</div>
|
||||
@@ -47,6 +51,8 @@ const HorizontalFlow = () => {
|
||||
onLoad={onLoad}
|
||||
className="validationflow"
|
||||
nodeTypes={nodeTypes}
|
||||
onConnectStart={onConnectStart}
|
||||
onConnectStop={onConnectStop}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
Connection,
|
||||
ConnectionLineType,
|
||||
FlowTransform,
|
||||
OnConnectStartFunc,
|
||||
} from '../../types';
|
||||
|
||||
import '../../style.css';
|
||||
@@ -42,6 +43,8 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, '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}
|
||||
|
||||
@@ -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<StoreModel, OnConnectFunc>;
|
||||
setOnConnectStart: Action<StoreModel, OnConnectStartFunc>;
|
||||
setOnConnectStop: Action<StoreModel, OnConnectStopFunc>;
|
||||
|
||||
setElements: Action<StoreModel, Elements>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user