50 lines
1.3 KiB
TypeScript
50 lines
1.3 KiB
TypeScript
import { BaseEdge, type EdgeProps } from "@xyflow/react";
|
|
import { memo } from "react";
|
|
|
|
export type LivingEdgeData = {
|
|
relation?: "depends_on" | "routes_to" | "review";
|
|
signal?: boolean;
|
|
selected?: boolean;
|
|
route?: { x: number; y: number }[];
|
|
};
|
|
|
|
function LivingEdgeView({
|
|
sourceX,
|
|
sourceY,
|
|
targetX,
|
|
targetY,
|
|
markerEnd,
|
|
data,
|
|
}: EdgeProps) {
|
|
const edgeData = (data ?? {}) as LivingEdgeData;
|
|
const route = edgeData.route?.filter(
|
|
(point) => Number.isFinite(point.x) && Number.isFinite(point.y),
|
|
);
|
|
const path =
|
|
route && route.length >= 2
|
|
? route
|
|
.map((point, index) => `${index === 0 ? "M" : "L"}${point.x} ${point.y}`)
|
|
.join(" ")
|
|
: `M${sourceX} ${sourceY} L${targetX} ${targetY}`;
|
|
const relation = edgeData.relation ?? "depends_on";
|
|
const classes = [
|
|
"living-edge-path",
|
|
`living-edge-${relation}`,
|
|
edgeData.selected ? "is-selected" : "",
|
|
edgeData.signal ? "has-signal" : "",
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ");
|
|
|
|
return (
|
|
<g className="living-edge" aria-hidden="true">
|
|
<BaseEdge path={path} markerEnd={markerEnd} className={classes} />
|
|
{edgeData.signal && (
|
|
<path d={path} className="living-edge-signal" markerEnd={markerEnd} />
|
|
)}
|
|
</g>
|
|
);
|
|
}
|
|
|
|
export const LivingEdge = memo(LivingEdgeView);
|