// Reconnectable edges have a anchors around their handles to reconnect the edge. import { XYHandle, type Connection, EdgePosition, FinalConnectionState, HandleType } 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']; onReconnect: EdgeWrapperProps['onReconnect']; onReconnectStart: EdgeWrapperProps['onReconnectStart']; onReconnectEnd: EdgeWrapperProps['onReconnectEnd']; setUpdateHover: (hover: boolean) => void; setReconnecting: (updating: boolean) => void; } & EdgePosition; export function EdgeUpdateAnchors({ isReconnectable, reconnectRadius, edge, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onReconnect, onReconnectStart, onReconnectEnd, setReconnecting, setUpdateHover, }: EdgeUpdateAnchorsProps) { const store = useStoreApi(); const handleEdgeUpdater = ( event: React.MouseEvent, oppositeHandle: { nodeId: string; id: string | null; type: HandleType } ) => { // 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 isTarget = oppositeHandle.type === 'target'; setReconnecting(true); onReconnectStart?.(event, edge, oppositeHandle.type); const _onReconnectEnd = (evt: MouseEvent | TouchEvent, connectionState: FinalConnectionState) => { setReconnecting(false); onReconnectEnd?.(evt, edge, oppositeHandle.type, connectionState); }; const onConnectEdge = (connection: Connection) => onReconnect?.(edge, connection); XYHandle.onPointerDown(event.nativeEvent, { autoPanOnConnect, connectionMode, connectionRadius, domNode, handleId: oppositeHandle.id, nodeId: oppositeHandle.nodeId, nodeLookup, isTarget, edgeUpdaterType: oppositeHandle.type, lib, flowId, cancelConnection, panBy, isValidConnection, onConnect: onConnectEdge, onConnectStart, onConnectEnd, onReconnectEnd: _onReconnectEnd, updateConnection, getTransform: () => store.getState().transform, getFromHandle: () => store.getState().connection.fromHandle, }); }; const onReconnectSourceMouseDown = (event: React.MouseEvent): void => handleEdgeUpdater(event, { nodeId: edge.target, id: edge.targetHandle ?? null, type: 'target' }); const onReconnectTargetMouseDown = (event: React.MouseEvent): void => handleEdgeUpdater(event, { nodeId: edge.source, id: edge.sourceHandle ?? null, type: 'source' }); const onReconnectMouseEnter = () => setUpdateHover(true); const onReconnectMouseOut = () => setUpdateHover(false); return ( <> {(isReconnectable === true || isReconnectable === 'source') && ( )} {(isReconnectable === true || isReconnectable === 'target') && ( )} ); }