Files
wehub-resource-sync e7738de6d2
CI / Deep Native Runtime Cases (1/6) (push) Has been skipped
CI / Native Preflight (push) Failing after 1s
CI / Native Runtime Cases (1/2) (push) Failing after 0s
CI / Native Runtime Cases (2/2) (push) Failing after 1s
CI / Native Metadata Reports (push) Failing after 0s
CI / Native Direct Backend Artifacts (push) Failing after 0s
CI / Native Sanitizer Smoke (push) Failing after 1s
CI / Command Contract Snapshots (push) Failing after 1s
CI / Deep Conformance Suite (push) Has been skipped
CI / Graph Build Perf (push) Failing after 1s
CI / Deep Native Preflight (push) Has been skipped
CI / Deep Native Runtime Cases (2/6) (push) Has been skipped
CI / Deep Native Runtime Cases (3/6) (push) Has been skipped
CI / Conformance Suite (push) Failing after 1s
CI / Workspace Checks (push) Failing after 0s
CI / Deep Native Runtime Cases (5/6) (push) Has been skipped
CI / Deep Native Runtime Cases (6/6) (push) Has been skipped
CI / Deep Native Runtime Cases (4/6) (push) Has been skipped
CI / Deep Graph Build Perf (push) Has been skipped
chore: import upstream snapshot with attribution
2026-07-13 12:29:30 +08:00

173 lines
5.4 KiB
TypeScript

type FlowTone = "graph" | "text" | "compiler" | "human";
type FlowNodeSpec = {
id: string;
label: string;
x: number;
y: number;
tone?: FlowTone;
};
type FlowEdgeSpec = {
id?: string;
source: string;
target: string;
label?: string;
};
export type FlowChartSpec = {
type: "flow";
title?: string;
height?: number;
nodes: FlowNodeSpec[];
edges: FlowEdgeSpec[];
};
// x/y in the spec are the top-left of each node, in px.
const NODE_W = 224;
const NODE_H = 72;
const PAD = 80;
const TONE_CLASS: Record<FlowTone, string> = {
// faint, "old" loop
text: "border border-border bg-bg text-muted",
// the enforcer: strong inverted
compiler: "bg-fg text-bg",
// the good path: clean and present
graph: "border border-fg/40 bg-surface text-fg",
// human review
human: "border border-border bg-surface-muted text-fg",
};
export function FlowChart({ spec }: { spec: FlowChartSpec }) {
const byId = new Map(spec.nodes.map((n) => [n.id, n]));
const maxX = Math.max(0, ...spec.nodes.map((n) => n.x));
const maxY = Math.max(0, ...spec.nodes.map((n) => n.y));
const width = PAD * 2 + maxX + NODE_W;
const height = Math.max(spec.height ?? 0, PAD * 2 + maxY + NODE_H);
const cx = (n: FlowNodeSpec) => PAD + n.x + NODE_W / 2;
const topY = (n: FlowNodeSpec) => PAD + n.y;
const bottomY = (n: FlowNodeSpec) => PAD + n.y + NODE_H;
const edges = spec.edges
.map((edge, i) => {
const s = byId.get(edge.source);
const t = byId.get(edge.target);
if (!s || !t) return null;
const loopBack = t.y <= s.y;
let path: string;
let labelX: number;
let labelY: number;
if (loopBack) {
const leftEdge = Math.min(PAD + s.x, PAD + t.x);
const sy = PAD + s.y + NODE_H / 2;
const ty = PAD + t.y + NODE_H / 2;
const bulge = leftEdge - 40;
path = `M ${leftEdge} ${sy} C ${bulge} ${sy}, ${bulge} ${ty}, ${leftEdge} ${ty}`;
labelX = bulge;
labelY = (sy + ty) / 2;
} else {
const sx = cx(s);
const sy = bottomY(s);
const tx = cx(t);
const ty = topY(t);
const mid = (sy + ty) / 2;
path = `M ${sx} ${sy} C ${sx} ${mid}, ${tx} ${mid}, ${tx} ${ty}`;
labelX = (sx + tx) / 2;
labelY = mid;
}
return {
key: edge.id ?? `${edge.source}-${edge.target}-${i}`,
path,
label: edge.label,
labelX,
labelY,
};
})
.filter((e): e is NonNullable<typeof e> => e !== null);
// Only show a connection dot where an edge actually attaches. Normal edges
// attach to the source's bottom and the target's top; loop-backs attach to
// the side, so they do not light up a top/bottom dot.
const topConn = new Set<string>();
const bottomConn = new Set<string>();
for (const edge of spec.edges) {
const s = byId.get(edge.source);
const t = byId.get(edge.target);
if (!s || !t || t.y <= s.y) continue;
bottomConn.add(s.id);
topConn.add(t.id);
}
const stroke = "color-mix(in srgb, var(--color-fg) 28%, transparent)";
const dot = "color-mix(in srgb, var(--color-fg) 40%, transparent)";
return (
<div className="not-prose my-6 overflow-hidden rounded-2xl border border-border bg-bg">
{spec.title ? (
<div className="border-b border-border px-5 py-3.5 font-mono text-xs font-medium text-muted">
{spec.title}
</div>
) : null}
<div
className="overflow-hidden p-2"
style={{
backgroundImage: "radial-gradient(var(--color-border) 1px, transparent 1px)",
backgroundSize: "22px 22px",
backgroundPosition: "-1px -1px",
}}
>
{/* Scales down to fit the column; never upscales past its natural size. */}
<svg
viewBox={`0 0 ${width} ${height}`}
className="mx-auto block h-auto w-full"
style={{ maxWidth: width }}
role="img"
aria-label={spec.title ?? "diagram"}
>
{edges.map((e) => (
<path key={e.key} d={e.path} fill="none" stroke={stroke} strokeWidth={1.5} />
))}
{spec.nodes.map((n) => (
<g key={`dots-${n.id}`} fill={dot}>
{topConn.has(n.id) && <circle cx={cx(n)} cy={topY(n)} r={3} />}
{bottomConn.has(n.id) && <circle cx={cx(n)} cy={bottomY(n)} r={3} />}
</g>
))}
{edges
.filter((e) => e.label)
.map((e) => (
<foreignObject
key={`label-${e.key}`}
x={e.labelX - 40}
y={e.labelY - 12}
width={80}
height={24}
>
<div className="flex h-full w-full items-center justify-center">
<span className="rounded border border-border bg-bg px-1.5 py-0.5 font-mono text-[0.6875rem] text-muted">
{e.label}
</span>
</div>
</foreignObject>
))}
{spec.nodes.map((n) => (
<foreignObject key={n.id} x={PAD + n.x} y={PAD + n.y} width={NODE_W} height={NODE_H}>
<div
className={`flex h-full w-full items-center justify-center rounded-xl px-4 text-center text-[0.875rem] font-medium leading-snug ${
TONE_CLASS[n.tone ?? "text"]
}`}
>
{n.label}
</div>
</foreignObject>
))}
</svg>
</div>
</div>
);
}