// Reconnectable edges have a anchors around their handles to reconnect the edge. import { XYHandle, type Connection, EdgePosition } from '@xyflow/system'; import { EdgeAnchor } from '../Edges/EdgeAnchor'; import type { EdgeWrapperProps, Edge } from '../../types/edges'; import { useStoreApi } from '../../hooks/useStore'; type EdgeUpdateAnchorsProps = { edge: EdgeType; isReconnectable: boolean | 'source' | 'target'; reconnectRadius: EdgeWrapperProps['reconnectRadius']; sourceHandleId: Edge['sourceHandle']; targetHandleId: Edge['targetHandle']; onReconnect: EdgeWrapperProps['onReconnect']; onReconnectStart: EdgeWrapperProps['onReconnectStart']; onReconnectEnd: EdgeWrapperProps['onReconnectEnd']; setUpdateHover: (hover: boolean) => void; setReconnecting: (updating: boolean) => void; } & EdgePosition; export function EdgeUpdateAnchors({ isReconnectable, reconnectRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onReconnect, onReconnectStart, onReconnectEnd, setReconnecting, setUpdateHover, }: EdgeUpdateAnchorsProps) { const store = useStoreApi(); const handleEdgeUpdater = (event: React.MouseEvent, isSourceHandle: boolean) => { // avoid triggering edge updater if mouse btn is not left if (event.button !== 0) { return; } const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodeLookup, rfId: flowId, panBy, updateConnection, } = store.getState(); const nodeId = isSourceHandle ? edge.target : edge.source; const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null; const handleType = isSourceHandle ? 'target' : 'source'; const isTarget = isSourceHandle; setReconnecting(true); onReconnectStart?.(event, edge, handleType); const _onReconnectEnd = (evt: MouseEvent | TouchEvent) => { setReconnecting(false); onReconnectEnd?.(evt, edge, handleType); }; const onConnectEdge = (connection: Connection) => onReconnect?.(edge, connection); XYHandle.onPointerDown(event.nativeEvent, { autoPanOnConnect, connectionMode, connectionRadius, domNode, handleId, nodeId, nodeLookup, isTarget, edgeUpdaterType: handleType, lib, flowId, cancelConnection, panBy, isValidConnection, onConnect: onConnectEdge, onConnectStart, onConnectEnd, onReconnectEnd: _onReconnectEnd, updateConnection, getTransform: () => store.getState().transform, getConnectionStartHandle: () => store.getState().connectionStartHandle, }); }; const onReconnectSourceMouseDown = (event: React.MouseEvent): void => handleEdgeUpdater(event, true); const onReconnectTargetMouseDown = (event: React.MouseEvent): void => handleEdgeUpdater(event, false); const onReconnectMouseEnter = () => setUpdateHover(true); const onReconnectMouseOut = () => setUpdateHover(false); return ( <> {(isReconnectable === 'source' || isReconnectable === true) && ( )} {(isReconnectable === 'target' || isReconnectable === true) && ( )} ); }