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 | 8x 8x 56x 56x 56x 56x | 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>
)}
</>
);
}
|