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