import React, { useContext, useMemo, memo } from 'react' import { BaseEdge, getBezierPath, type EdgeProps, } from '@xyflow/react' import { ConnectionPathContext } from '@/lib/graph/flowContext' import { getConnectionStatus, CONNECTION_STATUS_CLASS } from '@/lib/graph/connectionStatus' const EDGE_STROKE_WIDTH = 2 const DOT_MARKER_R = 1.5 const EMPTY_PATH_NODE_IDS = new Set() function AnimatedEdgeInner({ id, source, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, label: labelProp, interactionWidth, target, data, }: EdgeProps) { const ctx = useContext(ConnectionPathContext) const pathNodeIds = ctx?.connectionPathNodeIds ?? EMPTY_PATH_NODE_IDS const pausedSegmentNodeIds = ctx?.connectionPathPausedSegmentNodeIds ?? EMPTY_PATH_NODE_IDS const activeSegmentNodeIds = ctx?.connectionPathActiveSegmentNodeIds ?? EMPTY_PATH_NODE_IDS const errorTargetNodeIds = useMemo( () => new Set(ctx?.connectionPathErrorNodeIds ?? []), [ctx?.connectionPathErrorNodeIds] ) const label = labelProp ?? (data as { connectionLabel?: string } | undefined)?.connectionLabel const connectionStatus = useMemo( () => getConnectionStatus({ source, target, pathNodeIds, pausedSegmentNodeIds, activeSegmentNodeIds, errorTargetNodeIds, }), [ source, target, pathNodeIds, pausedSegmentNodeIds, activeSegmentNodeIds, errorTargetNodeIds, ] ) const statusClass = CONNECTION_STATUS_CLASS[connectionStatus] const [edgePath, edgeLabelX, edgeLabelY] = getBezierPath({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, }) const startId = `animated-edge-dot-start-${id}` const endId = `animated-edge-dot-end-${id}` return ( <> {label != null && ( {label} )} ) } function edgePropsAreEqual(prev: EdgeProps, next: EdgeProps): boolean { return ( prev.id === next.id && prev.source === next.source && prev.target === next.target && prev.sourceX === next.sourceX && prev.sourceY === next.sourceY && prev.targetX === next.targetX && prev.targetY === next.targetY && prev.sourcePosition === next.sourcePosition && prev.targetPosition === next.targetPosition && prev.style === next.style && prev.label === next.label && (prev.data as { connectionLabel?: string } | undefined)?.connectionLabel === (next.data as { connectionLabel?: string } | undefined)?.connectionLabel ) } export const AnimatedEdge = memo(AnimatedEdgeInner, edgePropsAreEqual)