diff --git a/example/src/Edges/index.tsx b/example/src/Edges/index.tsx
index 35d6aaa4..48405154 100644
--- a/example/src/Edges/index.tsx
+++ b/example/src/Edges/index.tsx
@@ -9,7 +9,6 @@ import ReactFlow, {
MarkerType,
MiniMap,
Node,
- Position,
ReactFlowInstance,
useEdgesState,
useNodesState,
@@ -20,6 +19,11 @@ import CustomEdge2 from './CustomEdge2';
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
+const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
+const onEdgeDoubleClick = (_: MouseEvent, edge: Edge) => console.log('dblclick', edge);
+const onEdgeMouseEnter = (_: MouseEvent, edge: Edge) => console.log('enter', edge);
+const onEdgeMouseMove = (_: MouseEvent, edge: Edge) => console.log('move', edge);
+const onEdgeMouseLeave = (_: MouseEvent, edge: Edge) => console.log('leave', edge);
const initialNodes: Node[] = [
{ id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
@@ -131,6 +135,11 @@ const EdgesFlow = () => {
onInit={onInit}
snapToGrid={true}
edgeTypes={edgeTypes}
+ onEdgeClick={onEdgeClick}
+ onEdgeDoubleClick={onEdgeDoubleClick}
+ onEdgeMouseEnter={onEdgeMouseEnter}
+ onEdgeMouseMove={onEdgeMouseMove}
+ onEdgeMouseLeave={onEdgeMouseLeave}
>
diff --git a/src/components/Edges/utils.ts b/src/components/Edges/utils.ts
index eb4f5127..82ac7d7c 100644
--- a/src/components/Edges/utils.ts
+++ b/src/components/Edges/utils.ts
@@ -1,4 +1,7 @@
-import { MarkerType, Position } from '../../types';
+import { MouseEvent as ReactMouseEvent } from 'react';
+import { GetState } from 'zustand';
+
+import { Edge, MarkerType, Position, ReactFlowState } from '../../types';
export const getMarkerEnd = (markerType?: MarkerType, markerEndId?: string): string => {
if (typeof markerEndId !== 'undefined' && markerEndId) {
@@ -52,3 +55,16 @@ export const getCenter = ({
return [centerX, centerY, xOffset, yOffset];
};
+
+export function getMouseHandler(
+ id: string,
+ getState: GetState,
+ handler?: (event: ReactMouseEvent, edge: Edge) => void
+) {
+ return handler === undefined
+ ? handler
+ : (event: ReactMouseEvent) => {
+ const edge = getState().edges.find((e) => e.id === id)!;
+ handler(event, { ...edge });
+ };
+}
diff --git a/src/components/Edges/wrapEdge.tsx b/src/components/Edges/wrapEdge.tsx
index 47fb9c85..7f2a66b9 100644
--- a/src/components/Edges/wrapEdge.tsx
+++ b/src/components/Edges/wrapEdge.tsx
@@ -1,12 +1,13 @@
-import React, { memo, ComponentType, useCallback, useState, useMemo } from 'react';
+import React, { memo, ComponentType, useState, useMemo } from 'react';
import cc from 'classcat';
import shallow from 'zustand/shallow';
import { useStore, useStoreApi } from '../../store';
-import { Edge, EdgeProps, WrapEdgeProps, ReactFlowState, Connection } from '../../types';
+import { EdgeProps, WrapEdgeProps, ReactFlowState, Connection } from '../../types';
import { handleMouseDown } from '../../components/Handle/handler';
import { EdgeAnchor } from './EdgeAnchor';
import { getMarkerId } from '../../utils/graph';
+import { getMouseHandler } from './utils';
const selector = (s: ReactFlowState) => ({
addSelectedEdges: s.addSelectedEdges,
@@ -53,10 +54,78 @@ export default (EdgeComponent: ComponentType) => {
markerEnd,
markerStart,
}: WrapEdgeProps): JSX.Element | null => {
- const store = useStoreApi();
- const { addSelectedEdges, connectionMode } = useStore(selector, shallow);
-
const [updating, setUpdating] = useState(false);
+ const { addSelectedEdges, connectionMode } = useStore(selector, shallow);
+ const store = useStoreApi();
+
+ const onEdgeClick = (event: React.MouseEvent): void => {
+ const edge = store.getState().edges.find((e) => e.id === id)!;
+
+ if (elementsSelectable) {
+ store.setState({ nodesSelectionActive: false });
+ addSelectedEdges([id]);
+ }
+
+ onClick?.(event, edge);
+ };
+
+ const onEdgeDoubleClickHandler = getMouseHandler(id, store.getState, onEdgeDoubleClick);
+ const onEdgeContextMenu = getMouseHandler(id, store.getState, onContextMenu);
+ const onEdgeMouseEnter = getMouseHandler(id, store.getState, onMouseEnter);
+ const onEdgeMouseMove = getMouseHandler(id, store.getState, onMouseMove);
+ const onEdgeMouseLeave = getMouseHandler(id, store.getState, onMouseLeave);
+
+ const handleEdgeUpdater = (event: React.MouseEvent, isSourceHandle: boolean) => {
+ const nodeId = isSourceHandle ? target : source;
+ const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
+ const handleType = isSourceHandle ? 'target' : 'source';
+ const isValidConnection = () => true;
+ const isTarget = isSourceHandle;
+ const edge = store.getState().edges.find((e) => e.id === id)!;
+
+ onEdgeUpdateStart?.(event, edge, handleType);
+
+ const _onEdgeUpdate = onEdgeUpdateEnd
+ ? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edge, handleType)
+ : undefined;
+
+ const onConnectEdge = (connection: Connection) => {
+ const { edges } = store.getState();
+ const edge = edges.find((e) => e.id === id);
+
+ if (edge && onEdgeUpdate) {
+ onEdgeUpdate(edge, connection);
+ }
+ };
+
+ handleMouseDown(
+ event,
+ handleId,
+ nodeId,
+ store.setState,
+ onConnectEdge,
+ isTarget,
+ isValidConnection,
+ connectionMode,
+ handleType,
+ _onEdgeUpdate,
+ store.getState
+ );
+ };
+
+ const onEdgeUpdaterSourceMouseDown = (event: React.MouseEvent): void =>
+ handleEdgeUpdater(event, true);
+ const onEdgeUpdaterTargetMouseDown = (event: React.MouseEvent): void =>
+ handleEdgeUpdater(event, false);
+
+ const onEdgeUpdaterMouseEnter = () => setUpdating(true);
+ const onEdgeUpdaterMouseOut = () => setUpdating(false);
+ const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart)})`, [markerStart]);
+ const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd)})`, [markerEnd]);
+
+ if (hidden) {
+ return null;
+ }
const inactive = !elementsSelectable && !onClick;
const handleEdgeUpdate = typeof onEdgeUpdate !== 'undefined';
@@ -67,139 +136,6 @@ export default (EdgeComponent: ComponentType) => {
{ selected, animated, inactive, updating },
]);
- const edgeElement = useMemo(() => {
- const el: Edge = {
- id,
- source,
- target,
- type,
- };
-
- if (sourceHandleId) {
- el.sourceHandle = sourceHandleId;
- }
-
- if (targetHandleId) {
- el.targetHandle = targetHandleId;
- }
-
- if (typeof data !== 'undefined') {
- el.data = data;
- }
-
- return el;
- }, [id, source, target, type, sourceHandleId, targetHandleId, data]);
-
- const onEdgeClick = useCallback(
- (event: React.MouseEvent): void => {
- if (elementsSelectable) {
- store.setState({ nodesSelectionActive: false });
- addSelectedEdges([edgeElement.id]);
- }
-
- onClick?.(event, edgeElement);
- },
- [elementsSelectable, edgeElement, onClick]
- );
-
- const onEdgeDoubleClickHandler = useCallback(
- (event: React.MouseEvent) => {
- onEdgeDoubleClick?.(event, edgeElement);
- },
- [edgeElement, onEdgeDoubleClick]
- );
-
- const onEdgeContextMenu = useCallback(
- (event: React.MouseEvent): void => {
- onContextMenu?.(event, edgeElement);
- },
- [edgeElement, onContextMenu]
- );
-
- const onEdgeMouseEnter = useCallback(
- (event: React.MouseEvent): void => {
- onMouseEnter?.(event, edgeElement);
- },
- [edgeElement, onContextMenu]
- );
-
- const onEdgeMouseMove = useCallback(
- (event: React.MouseEvent): void => {
- onMouseMove?.(event, edgeElement);
- },
- [edgeElement, onContextMenu]
- );
-
- const onEdgeMouseLeave = useCallback(
- (event: React.MouseEvent): void => {
- onMouseLeave?.(event, edgeElement);
- },
- [edgeElement, onContextMenu]
- );
-
- const handleEdgeUpdater = useCallback(
- (event: React.MouseEvent, isSourceHandle: boolean) => {
- const nodeId = isSourceHandle ? target : source;
- const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
- const handleType = isSourceHandle ? 'target' : 'source';
- const isValidConnection = () => true;
- const isTarget = isSourceHandle;
-
- onEdgeUpdateStart?.(event, edgeElement, handleType);
-
- const _onEdgeUpdate = onEdgeUpdateEnd
- ? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edgeElement, handleType)
- : undefined;
-
- const onConnectEdge = (connection: Connection) => {
- const { edges } = store.getState();
- const edge = edges.find((e) => e.id === id);
-
- if (edge && onEdgeUpdate) {
- onEdgeUpdate(edge, connection);
- }
- };
-
- handleMouseDown(
- event,
- handleId,
- nodeId,
- store.setState,
- onConnectEdge,
- isTarget,
- isValidConnection,
- connectionMode,
- handleType,
- _onEdgeUpdate,
- store.getState
- );
- },
- [id, source, target, type, sourceHandleId, targetHandleId, edgeElement, onEdgeUpdate]
- );
-
- const onEdgeUpdaterSourceMouseDown = useCallback(
- (event: React.MouseEvent): void => {
- handleEdgeUpdater(event, true);
- },
- [id, source, sourceHandleId, handleEdgeUpdater]
- );
-
- const onEdgeUpdaterTargetMouseDown = useCallback(
- (event: React.MouseEvent): void => {
- handleEdgeUpdater(event, false);
- },
- [id, target, targetHandleId, handleEdgeUpdater]
- );
-
- const onEdgeUpdaterMouseEnter = useCallback(() => setUpdating(true), [setUpdating]);
- const onEdgeUpdaterMouseOut = useCallback(() => setUpdating(false), [setUpdating]);
- const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart)})`, [markerStart]);
- const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd)})`, [markerEnd]);
-
- if (hidden) {
- return null;
- }
-
return (