Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import { BaseEdge, getSmoothStepPath, type EdgeProps } from "@xyflow/react"; import type { JSX } from "react"; import type { CoordEdgeData } from "./coordinationGraphModel.js"; import styles from "./CoordinationGraph.module.scss"; /** Duration of a single message-dot traversal. */ const DOT_DURATION: string = "0.7s"; /** Radius of the message dot (pixels). */ const DOT_RADIUS: number = 3; /** * Custom React Flow edge for the Coordination graph. Renders the same smoothstep * path as Phase A (via {@link BaseEdge}) and, when a new message arrives on the * edge's stream, fires a one-shot dot that travels source -> target. * * The dot is keyed on `data.pulseSeq` (the stream's latest message seq): when the * seq advances, the keyed `<circle>` remounts and the SMIL animation replays. The * dot rests at `opacity: 0` (base) with non-frozen SMIL, so it leaves no artifact * once the traversal completes. */ export function MessageDotEdge(props: EdgeProps): JSX.Element { const { sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, markerStart, markerEnd, style, data, } = props; const [edgePath] = getSmoothStepPath({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, }); const pulseSeq = (data as CoordEdgeData | undefined)?.pulseSeq; return ( <> <BaseEdge path={edgePath} markerStart={markerStart} markerEnd={markerEnd} style={style} /> {pulseSeq !== undefined && ( <circle key={pulseSeq} r={DOT_RADIUS} opacity={0} className={styles.messageDot} data-testid="coordination-message-dot" > <animateMotion dur={DOT_DURATION} repeatCount="1" path={edgePath} /> <animate attributeName="opacity" dur={DOT_DURATION} repeatCount="1" values="0;1;1;0" keyTimes="0;0.1;0.85;1" /> </circle> )} </> ); } |