{
  "name": "JourneyGraph",
  "package": "@magicblocksai/ui",
  "file": "packages/ui/src/components/JourneyGraph.tsx",
  "chapterTag": "20 Explainability",
  "chapter": "20-explainability.html",
  "sectionId": "journey-graph",
  "elName": "Five-step reasoning trace",
  "demoUrl": "https://brand.magicblocks.ai/components/20-explainability#journey-graph",
  "hasLiveDemo": false,
  "description": "Journey graph — agent reasoning visualisation. A node-and-edge SVG\ndiagram where each node is a step in an agent's reasoning trace\n(decision / tool / retrieval / response) and each edge carries an\noutcome label. Nodes are click-selectable; the selected node carries\nan accent ring and exposes its detail (latency / cost / output\npreview) in a side panel that the consumer slots via the `detail`\nrender prop.",
  "useClient": true,
  "interactivity": "interactive",
  "namedExports": [
    {
      "name": "JourneyGraph",
      "isPrincipal": true,
      "isType": false
    },
    {
      "name": "JourneyGraphProps",
      "isPrincipal": false,
      "isType": true
    },
    {
      "name": "JourneyGraphNode",
      "isPrincipal": false,
      "isType": true
    },
    {
      "name": "JourneyGraphNodeKind",
      "isPrincipal": false,
      "isType": false
    },
    {
      "name": "JourneyGraphEdge",
      "isPrincipal": false,
      "isType": false
    }
  ],
  "importStatement": "import { JourneyGraph } from \"@magicblocksai/ui\";",
  "props": [
    {
      "name": "nodes",
      "optional": false,
      "type": "JourneyGraphNode[]",
      "doc": "Nodes — consumer supplies explicit x / y; the kit does not compute layout."
    },
    {
      "name": "edges",
      "optional": false,
      "type": "JourneyGraphEdge[]",
      "doc": "Edges connecting nodes by id."
    },
    {
      "name": "selectedNodeId",
      "optional": true,
      "type": "string",
      "doc": "Controlled selected node id. Pair with `onSelectedNodeChange`."
    },
    {
      "name": "defaultSelectedNodeId",
      "optional": true,
      "type": "string",
      "doc": "Uncontrolled initial selection."
    },
    {
      "name": "onSelectedNodeChange",
      "optional": true,
      "type": "(id: string | undefined) => void",
      "doc": "Fires whenever selection changes."
    },
    {
      "name": "viewBox",
      "optional": true,
      "type": "string",
      "doc": "SVG viewBox. Defaults to `\"0 0 600 320\"`."
    },
    {
      "name": "detail",
      "optional": true,
      "type": "(node: JourneyGraphNode | undefined) => React.ReactNode",
      "doc": "Render-prop for the side-panel detail. When supplied, the component renders a two-column grid (SVG + detail). When omitted, the SVG takes the full width. Called with the currently selected node, or `undefined` when no node is selected OR when `selectedNodeId` references a node id that doesn't exist in `nodes`. Return `null` to hide the side panel entirely."
    },
    {
      "name": "className",
      "optional": true,
      "type": "string",
      "doc": "Class merged via `cn()`. Caller wins over defaults."
    }
  ],
  "classesUsed": [
    "journey-graph",
    "journey-graph-edge",
    "journey-graph-edge-hit",
    "journey-graph-edge-label",
    "journey-graph-svg",
    "journey-node",
    "journey-node-label",
    "journey-node-shape"
  ],
  "examples": {
    "react": "<JourneyGraph\n  nodes={[\n    { id: \"n1\", kind: \"decision\", label: \"Should I look this up?\", x: 80,  y: 120 },\n    { id: \"n2\", kind: \"retrieval\", label: \"KB search\",             x: 240, y: 80  },\n    { id: \"n3\", kind: \"tool\",      label: \"CRM.getDeal\",           x: 240, y: 200,\n      meta: { latencyMs: 142, costUsd: 0.002, outputPreview: \"deal{…}\" } },\n    { id: \"n4\", kind: \"decision\", label: \"Both have answers?\",     x: 400, y: 140 },\n    { id: \"n5\", kind: \"response\", label: \"Compose reply\",          x: 540, y: 140 },\n  ]}\n  edges={[\n    { from: \"n1\", to: \"n2\", label: \"KB likely\" },\n    { from: \"n1\", to: \"n3\", label: \"Account data\" },\n    { from: \"n2\", to: \"n4\", label: \"found\" },\n    { from: \"n3\", to: \"n4\", label: \"found\" },\n    { from: \"n4\", to: \"n5\" },\n  ]}\n  defaultSelectedNodeId=\"n3\"\n  detail={(node) => node ? <aside>…</aside> : null}\n/>",
    "html": "<div class=\"journey-graph\" data-detail=\"true\"><svg class=\"journey-graph-svg\" viewBox=\"0 0 600 320\" role=\"img\" aria-label=\"Agent reasoning graph\"><g class=\"journey-graph-edge-group\" role=\"img\" aria-label=\"Taken when the question matches a knowledge-base topic\" tabindex=\"0\"><title>Taken when the question matches a knowledge-base topic</title><line class=\"journey-graph-edge-hit\" x1=\"80\" y1=\"120\" x2=\"240\" y2=\"80\"></line><line class=\"journey-graph-edge\" x1=\"80\" y1=\"120\" x2=\"240\" y2=\"80\"></line><text class=\"journey-graph-edge-label\" x=\"160\" y=\"94\">KB likely</text></g><g class=\"journey-graph-edge-group\"><line class=\"journey-graph-edge\" x1=\"80\" y1=\"120\" x2=\"240\" y2=\"200\"></line><text class=\"journey-graph-edge-label\" x=\"160\" y=\"154\">Account data</text></g><g class=\"journey-graph-edge-group\"><line class=\"journey-graph-edge\" x1=\"240\" y1=\"80\" x2=\"400\" y2=\"140\"></line><text class=\"journey-graph-edge-label\" x=\"320\" y=\"104\">found</text></g><g class=\"journey-graph-edge-group\"><line class=\"journey-graph-edge\" x1=\"240\" y1=\"200\" x2=\"400\" y2=\"140\"></line><text class=\"journey-graph-edge-label\" x=\"320\" y=\"164\">found</text></g><g class=\"journey-graph-edge-group\"><line class=\"journey-graph-edge\" x1=\"400\" y1=\"140\" x2=\"540\" y2=\"140\"></line></g><g class=\"journey-node\" data-kind=\"decision\" tabindex=\"0\" role=\"button\" aria-label=\"Should I look this up?\" aria-selected=\"false\"><polygon class=\"journey-node-shape\" points=\"80,100 120,120 80,140 40,120\"></polygon><text class=\"journey-node-label\" x=\"80\" y=\"124\">Should I look this up?</text></g><g class=\"journey-node\" data-kind=\"retrieval\" tabindex=\"0\" role=\"button\" aria-label=\"KB search: &quot;renewal&quot;\" aria-selected=\"false\"><rect class=\"journey-node-shape\" x=\"200\" y=\"60\" width=\"80\" height=\"40\" rx=\"12\" ry=\"12\"></rect><text class=\"journey-node-label\" x=\"240\" y=\"84\">KB search: &quot;renewal&quot;</text></g><g class=\"journey-node\" data-kind=\"tool\" tabindex=\"0\" role=\"button\" aria-label=\"CRM.getDeal\" aria-selected=\"true\"><rect class=\"journey-node-shape\" x=\"200\" y=\"180\" width=\"80\" height=\"40\"></rect><text class=\"journey-node-label\" x=\"240\" y=\"204\">CRM.getDeal</text></g><g class=\"journey-node\" data-kind=\"decision\" tabindex=\"0\" role=\"button\" aria-label=\"Both have answers?\" aria-selected=\"false\"><polygon class=\"journey-node-shape\" points=\"400,120 440,140 400,160 360,140\"></polygon><text class=\"journey-node-label\" x=\"400\" y=\"144\">Both have answers?</text></g><g class=\"journey-node\" data-kind=\"response\" tabindex=\"0\" role=\"button\" aria-label=\"Compose reply\" aria-selected=\"false\"><circle class=\"journey-node-shape\" cx=\"540\" cy=\"140\" r=\"20\"></circle><text class=\"journey-node-label\" x=\"540\" y=\"144\">Compose reply</text></g></svg><aside class=\"journey-graph-detail\"><h4 class=\"journey-graph-detail-title\">CRM.getDeal</h4><div class=\"journey-graph-detail-badges\"><span class=\"journey-graph-detail-badge\">142 ms</span><span class=\"journey-graph-detail-badge\">$0.002</span></div><pre class=\"journey-graph-detail-output\">deal{id, value, stage, owner}</pre></aside></div>",
    "css": ".journey-graph {\n  display: grid;\n  grid-template-columns: 1fr 240px;\n  gap: var(--s-4);\n  background: var(--bg-paper);\n  border: 1px solid var(--hair);\n  border-radius: var(--r-md);\n  padding: var(--s-4);\n}\n\n.journey-graph-edge { stroke: var(--hair); stroke-width: 1.2; fill: none; }\n\n.journey-graph-edge-hit { stroke: transparent; stroke-width: 14; fill: none; }\n\n.journey-graph-edge-label {\n  font: 500 11px/1 var(--f-mono);\n  fill: var(--fg-dim);\n  text-anchor: middle;\n}\n\n.journey-graph-svg { width: 100%; height: auto; max-height: 360px; }\n\n.journey-node { cursor: pointer; outline: none; }\n\n.journey-node-label {\n  font: 500 12px/1.2 var(--f-body);\n  fill: var(--fg);\n  text-anchor: middle;\n  pointer-events: none;\n}\n\n.journey-node-shape {\n  fill: var(--bg-paper);\n  stroke: var(--hair);\n  stroke-width: 1.5;\n  transition: stroke 0.15s ease, stroke-width 0.15s ease, filter 0.15s ease;\n}"
  }
}
