import React, { memo, ComponentType, useCallback, useState, useMemo } from 'react'; import cc from 'classcat'; import { useStoreActions, useStoreState } from '../../store/hooks'; import { Edge, EdgeProps, WrapEdgeProps } from '../../types'; import { onMouseDown } from '../../components/Handle/handler'; import { EdgeAnchor } from './EdgeAnchor'; export default (EdgeComponent: ComponentType) => { const EdgeWrapper = ({ id, className, type, data, onClick, onEdgeDoubleClick, selected, animated, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, arrowHeadType, source, target, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, elementsSelectable, markerEndId, isHidden, sourceHandleId, targetHandleId, handleEdgeUpdate, onConnectEdge, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, edgeUpdaterRadius, }: WrapEdgeProps): JSX.Element | null => { const addSelectedElements = useStoreActions((actions) => actions.addSelectedElements); const setConnectionNodeId = useStoreActions((actions) => actions.setConnectionNodeId); const unsetNodesSelection = useStoreActions((actions) => actions.unsetNodesSelection); const setPosition = useStoreActions((actions) => actions.setConnectionPosition); const connectionMode = useStoreState((state) => state.connectionMode); const [updating, setUpdating] = useState(false); const inactive = !elementsSelectable && !onClick; const edgeClasses = cc([ 'react-flow__edge', `react-flow__edge-${type}`, className, { 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) { unsetNodesSelection(); addSelectedElements(edgeElement); } onClick?.(event, edgeElement); }, [elementsSelectable, edgeElement, onClick] ); 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; const isValidConnection = () => true; const isTarget = isSourceHandle; onMouseDown( event, handleId, nodeId, setConnectionNodeId, setPosition, onConnectEdge, isTarget, isValidConnection, connectionMode ); }, [id, source, target, type, sourceHandleId, targetHandleId, setConnectionNodeId, setPosition] ); 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 onEdgeDoubleClickHandler = useCallback((event: React.MouseEvent) => { onEdgeDoubleClick?.(event, edgeElement) }, [edgeElement, onEdgeDoubleClick]) if (isHidden) { return null; } return ( {handleEdgeUpdate && ( )} {handleEdgeUpdate && ( )} ); }; EdgeWrapper.displayName = 'EdgeWrapper'; return memo(EdgeWrapper); };