@elixpo/lixsketch 5.5.1 → 5.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/react/{AIRenderer-M4LMJ66J.js → AIRenderer-S2SKFJKT.js} +3 -3
  2. package/dist/react/{EventDispatcher-SRFH6LQZ.js → EventDispatcher-5FYHE47T.js} +2 -2
  3. package/dist/react/{GraphEngine-QE5B2PMR.js → GraphEngine-IHRVGUGG.js} +41 -19
  4. package/dist/react/GraphEngine-IHRVGUGG.js.map +7 -0
  5. package/dist/react/{MermaidFlowchartRenderer-4QBAZ5MB.js → MermaidFlowchartRenderer-A26B2SM3.js} +18 -6
  6. package/dist/react/MermaidFlowchartRenderer-A26B2SM3.js.map +7 -0
  7. package/dist/react/{MermaidSequenceRenderer-HPLHY5II.js → MermaidSequenceRenderer-OF4JK77D.js} +37 -12
  8. package/dist/react/MermaidSequenceRenderer-OF4JK77D.js.map +7 -0
  9. package/dist/react/{SketchEngine-YA4RG3KX.js → SketchEngine-R5RCQF3L.js} +5 -5
  10. package/dist/react/{chunk-JJCJNLNN.js → chunk-VRRJEOCH.js} +4 -3
  11. package/dist/react/{chunk-JJCJNLNN.js.map → chunk-VRRJEOCH.js.map} +2 -2
  12. package/dist/react/index.js +1 -1
  13. package/dist/react/{textTool-M7S6F3VC.js → textTool-7LMEIBF5.js} +2 -2
  14. package/package.json +1 -1
  15. package/src/core/GraphRenderer.js +48 -19
  16. package/src/core/MermaidFlowchartRenderer.js +19 -4
  17. package/src/core/MermaidSequenceRenderer.js +44 -9
  18. package/src/tools/textTool.js +21 -12
  19. package/dist/react/GraphEngine-QE5B2PMR.js.map +0 -7
  20. package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js.map +0 -7
  21. package/dist/react/MermaidSequenceRenderer-HPLHY5II.js.map +0 -7
  22. /package/dist/react/{AIRenderer-M4LMJ66J.js.map → AIRenderer-S2SKFJKT.js.map} +0 -0
  23. /package/dist/react/{EventDispatcher-SRFH6LQZ.js.map → EventDispatcher-5FYHE47T.js.map} +0 -0
  24. /package/dist/react/{SketchEngine-YA4RG3KX.js.map → SketchEngine-R5RCQF3L.js.map} +0 -0
  25. /package/dist/react/{textTool-M7S6F3VC.js.map → textTool-7LMEIBF5.js.map} +0 -0
@@ -1032,14 +1032,14 @@ function initAIRenderer() {
1032
1032
  async function loadSequenceRenderer() {
1033
1033
  if (_seqParser) return;
1034
1034
  const mod = await import("./MermaidSequenceParser-UKG2NSZY.js");
1035
- const rend = await import("./MermaidSequenceRenderer-HPLHY5II.js");
1035
+ const rend = await import("./MermaidSequenceRenderer-OF4JK77D.js");
1036
1036
  _seqParser = mod.parseSequenceDiagram;
1037
1037
  _seqPreview = rend.renderSequencePreviewSVG;
1038
1038
  _seqCanvas = rend.renderSequenceOnCanvas;
1039
1039
  }
1040
1040
  async function loadFlowchartRenderer() {
1041
1041
  if (_fcPreview) return;
1042
- const mod = await import("./MermaidFlowchartRenderer-4QBAZ5MB.js");
1042
+ const mod = await import("./MermaidFlowchartRenderer-A26B2SM3.js");
1043
1043
  _fcPreview = mod.renderFlowchartPreviewSVG;
1044
1044
  _fcCanvas = mod.renderFlowchartOnCanvas;
1045
1045
  }
@@ -1102,4 +1102,4 @@ export {
1102
1102
  parseMermaid,
1103
1103
  renderAIDiagram
1104
1104
  };
1105
- //# sourceMappingURL=AIRenderer-M4LMJ66J.js.map
1105
+ //# sourceMappingURL=AIRenderer-S2SKFJKT.js.map
@@ -4,7 +4,7 @@ import {
4
4
  handleTextMouseDown,
5
5
  handleTextMouseMove,
6
6
  handleTextMouseUp
7
- } from "./chunk-JJCJNLNN.js";
7
+ } from "./chunk-VRRJEOCH.js";
8
8
  import {
9
9
  handleCodeMouseDown,
10
10
  handleCodeMouseMove,
@@ -460,4 +460,4 @@ export {
460
460
  handleMainMouseUp,
461
461
  initEventDispatcher
462
462
  };
463
- //# sourceMappingURL=EventDispatcher-SRFH6LQZ.js.map
463
+ //# sourceMappingURL=EventDispatcher-5FYHE47T.js.map
@@ -17,6 +17,27 @@ var GRAPH_COLORS = [
17
17
  "#E91E63",
18
18
  "#00BCD4"
19
19
  ];
20
+ function graphThemeTokens() {
21
+ const isDark = typeof document !== "undefined" && document.body && document.body.classList.contains("theme-dark");
22
+ if (isDark) {
23
+ return {
24
+ outerBg: "#0d1117",
25
+ plotBg: "#111822",
26
+ gridStroke: "rgba(255,255,255,0.06)",
27
+ axisStroke: "rgba(255,255,255,0.25)",
28
+ borderStroke: "rgba(255,255,255,0.1)",
29
+ tickLabel: "#8b949e"
30
+ };
31
+ }
32
+ return {
33
+ outerBg: "#fbfaf6",
34
+ plotBg: "#ffffff",
35
+ gridStroke: "rgba(60,60,80,0.08)",
36
+ axisStroke: "rgba(60,60,80,0.35)",
37
+ borderStroke: "rgba(60,60,80,0.16)",
38
+ tickLabel: "#62627a"
39
+ };
40
+ }
20
41
  function niceInterval(range) {
21
42
  const rough = range / 8;
22
43
  const mag = Math.pow(10, Math.floor(Math.log10(rough)));
@@ -46,8 +67,9 @@ function renderGraphSVG(equations, settings) {
46
67
  const toSvgX = (x) => pad.left + (x - xMin) / xRange * plotW;
47
68
  const toSvgY = (y) => pad.top + (yMax - y) / yRange * plotH;
48
69
  let svg = "";
49
- svg += `<rect x="0" y="0" width="${width}" height="${height}" fill="#0d1117" rx="8" />`;
50
- svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="#111822" />`;
70
+ const tk = graphThemeTokens();
71
+ svg += `<rect x="0" y="0" width="${width}" height="${height}" fill="${tk.outerBg}" rx="8" />`;
72
+ svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="${tk.plotBg}" />`;
51
73
  const xTick = niceInterval(xRange);
52
74
  const yTick = niceInterval(yRange);
53
75
  const xStart = Math.ceil(xMin / xTick) * xTick;
@@ -55,30 +77,30 @@ function renderGraphSVG(equations, settings) {
55
77
  const sx = toSvgX(x);
56
78
  if (sx < pad.left || sx > pad.left + plotW) continue;
57
79
  if (showGrid) {
58
- svg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="rgba(255,255,255,0.06)" stroke-width="0.5" />`;
80
+ svg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
59
81
  }
60
82
  const label = Math.abs(x) < 1e-10 ? "0" : Number.isInteger(x) ? x : x.toFixed(1);
61
- svg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="#8b949e" font-size="10" font-family="lixCode, monospace">${label}</text>`;
83
+ svg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
62
84
  }
63
85
  const yStart = Math.ceil(yMin / yTick) * yTick;
64
86
  for (let y = yStart; y <= yMax; y += yTick) {
65
87
  const sy = toSvgY(y);
66
88
  if (sy < pad.top || sy > pad.top + plotH) continue;
67
89
  if (showGrid) {
68
- svg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="rgba(255,255,255,0.06)" stroke-width="0.5" />`;
90
+ svg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
69
91
  }
70
92
  const label = Math.abs(y) < 1e-10 ? "0" : Number.isInteger(y) ? y : y.toFixed(1);
71
- svg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="#8b949e" font-size="10" font-family="lixCode, monospace">${label}</text>`;
93
+ svg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
72
94
  }
73
95
  if (xMin <= 0 && xMax >= 0) {
74
96
  const ax = toSvgX(0);
75
- svg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="rgba(255,255,255,0.25)" stroke-width="1" />`;
97
+ svg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="${tk.axisStroke}" stroke-width="1" />`;
76
98
  }
77
99
  if (yMin <= 0 && yMax >= 0) {
78
100
  const ay = toSvgY(0);
79
- svg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="rgba(255,255,255,0.25)" stroke-width="1" />`;
101
+ svg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="${tk.axisStroke}" stroke-width="1" />`;
80
102
  }
81
- svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="1" />`;
103
+ svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="${tk.borderStroke}" stroke-width="1" />`;
82
104
  const samplesPerPixel = 2;
83
105
  const totalSamples = plotW * samplesPerPixel;
84
106
  const dx = xRange / totalSamples;
@@ -160,35 +182,35 @@ function renderGraphSVG(equations, settings) {
160
182
  legendY += 18;
161
183
  });
162
184
  let cleanSvg = "";
163
- cleanSvg += `<rect x="0" y="0" width="${width}" height="${height}" fill="#0d1117" rx="8" />`;
164
- cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="#111822" />`;
185
+ cleanSvg += `<rect x="0" y="0" width="${width}" height="${height}" fill="${tk.outerBg}" rx="8" />`;
186
+ cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="${tk.plotBg}" />`;
165
187
  for (let x = xStart; x <= xMax; x += xTick) {
166
188
  const sx = toSvgX(x);
167
189
  if (sx < pad.left || sx > pad.left + plotW) continue;
168
190
  if (showGrid) {
169
- cleanSvg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="rgba(255,255,255,0.06)" stroke-width="0.5" />`;
191
+ cleanSvg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
170
192
  }
171
193
  const label = Math.abs(x) < 1e-10 ? "0" : Number.isInteger(x) ? x : x.toFixed(1);
172
- cleanSvg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="#8b949e" font-size="10" font-family="lixCode, monospace">${label}</text>`;
194
+ cleanSvg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
173
195
  }
174
196
  for (let y = yStart; y <= yMax; y += yTick) {
175
197
  const sy = toSvgY(y);
176
198
  if (sy < pad.top || sy > pad.top + plotH) continue;
177
199
  if (showGrid) {
178
- cleanSvg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="rgba(255,255,255,0.06)" stroke-width="0.5" />`;
200
+ cleanSvg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
179
201
  }
180
202
  const label = Math.abs(y) < 1e-10 ? "0" : Number.isInteger(y) ? y : y.toFixed(1);
181
- cleanSvg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="#8b949e" font-size="10" font-family="lixCode, monospace">${label}</text>`;
203
+ cleanSvg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
182
204
  }
183
205
  if (xMin <= 0 && xMax >= 0) {
184
206
  const ax = toSvgX(0);
185
- cleanSvg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="rgba(255,255,255,0.25)" stroke-width="1" />`;
207
+ cleanSvg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="${tk.axisStroke}" stroke-width="1" />`;
186
208
  }
187
209
  if (yMin <= 0 && yMax >= 0) {
188
210
  const ay = toSvgY(0);
189
- cleanSvg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="rgba(255,255,255,0.25)" stroke-width="1" />`;
211
+ cleanSvg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="${tk.axisStroke}" stroke-width="1" />`;
190
212
  }
191
- cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="1" />`;
213
+ cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="${tk.borderStroke}" stroke-width="1" />`;
192
214
  cleanSvg += `<g clip-path="url(#${clipId})">${curves}</g>`;
193
215
  cleanSvg += legend;
194
216
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${defs}${cleanSvg}</svg>`;
@@ -337,4 +359,4 @@ function initGraphEngine() {
337
359
  export {
338
360
  initGraphEngine
339
361
  };
340
- //# sourceMappingURL=GraphEngine-QE5B2PMR.js.map
362
+ //# sourceMappingURL=GraphEngine-IHRVGUGG.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/GraphRenderer.js", "../../src/core/GraphEngine.js"],
4
+ "sourcesContent": ["/* eslint-disable */\n/**\n * GraphRenderer - Renders mathematical equations as SVG graphs.\n * Produces axes, grid, tick labels, and equation curves.\n */\n\nimport { parseExpression } from './GraphMathParser.js';\n\nconst GRAPH_COLORS = [\n '#4A90D9', '#E74C3C', '#2ECC71', '#F39C12', '#9B59B6',\n '#1ABC9C', '#E67E22', '#3498DB', '#E91E63', '#00BCD4',\n];\n\n// Issue #38 follow-up: theme-aware graph chrome. Light mode flips every\n// hardcoded `rgba(255,255,255,X)` token (designed for dark canvas) to a\n// matching `rgba(60,60,80,X)` so the grid, axes, plot border, and tick\n// labels stay readable on the warm off-white canvas. The equation\n// curves themselves keep their colours from GRAPH_COLORS.\nfunction graphThemeTokens() {\n const isDark = typeof document !== 'undefined'\n && document.body\n && document.body.classList.contains('theme-dark');\n if (isDark) {\n return {\n outerBg: '#0d1117',\n plotBg: '#111822',\n gridStroke:'rgba(255,255,255,0.06)',\n axisStroke:'rgba(255,255,255,0.25)',\n borderStroke:'rgba(255,255,255,0.1)',\n tickLabel: '#8b949e',\n };\n }\n return {\n outerBg: '#fbfaf6',\n plotBg: '#ffffff',\n gridStroke:'rgba(60,60,80,0.08)',\n axisStroke:'rgba(60,60,80,0.35)',\n borderStroke:'rgba(60,60,80,0.16)',\n tickLabel: '#62627a',\n };\n}\n\n/**\n * Calculate nice tick intervals for a given range.\n */\nfunction niceInterval(range) {\n const rough = range / 8;\n const mag = Math.pow(10, Math.floor(Math.log10(rough)));\n const residual = rough / mag;\n let nice;\n if (residual <= 1.5) nice = 1;\n else if (residual <= 3) nice = 2;\n else if (residual <= 7) nice = 5;\n else nice = 10;\n return nice * mag;\n}\n\n/**\n * Render graph as SVG markup string.\n * @param {Array} equations - [{expression: string, color: string}]\n * @param {Object} settings - {xMin, xMax, yMin, yMax, showGrid, width, height}\n * @returns {string} SVG markup\n */\nexport function renderGraphSVG(equations, settings) {\n const {\n xMin = -10, xMax = 10,\n yMin = -10, yMax = 10,\n showGrid = true,\n width = 600, height = 400,\n } = settings || {};\n\n const pad = { top: 20, right: 20, bottom: 35, left: 45 };\n const plotW = width - pad.left - pad.right;\n const plotH = height - pad.top - pad.bottom;\n const xRange = xMax - xMin || 1;\n const yRange = yMax - yMin || 1;\n\n // Coordinate transforms\n const toSvgX = (x) => pad.left + ((x - xMin) / xRange) * plotW;\n const toSvgY = (y) => pad.top + ((yMax - y) / yRange) * plotH;\n\n let svg = '';\n const tk = graphThemeTokens();\n\n // Background\n svg += `<rect x=\"0\" y=\"0\" width=\"${width}\" height=\"${height}\" fill=\"${tk.outerBg}\" rx=\"8\" />`;\n svg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"${tk.plotBg}\" />`;\n\n // Grid & ticks\n const xTick = niceInterval(xRange);\n const yTick = niceInterval(yRange);\n\n // Vertical grid lines + x labels\n const xStart = Math.ceil(xMin / xTick) * xTick;\n for (let x = xStart; x <= xMax; x += xTick) {\n const sx = toSvgX(x);\n if (sx < pad.left || sx > pad.left + plotW) continue;\n if (showGrid) {\n svg += `<line x1=\"${sx}\" y1=\"${pad.top}\" x2=\"${sx}\" y2=\"${pad.top + plotH}\" stroke=\"${tk.gridStroke}\" stroke-width=\"0.5\" />`;\n }\n const label = Math.abs(x) < 1e-10 ? '0' : (Number.isInteger(x) ? x : x.toFixed(1));\n svg += `<text x=\"${sx}\" y=\"${pad.top + plotH + 16}\" text-anchor=\"middle\" fill=\"${tk.tickLabel}\" font-size=\"10\" font-family=\"lixCode, monospace\">${label}</text>`;\n }\n\n // Horizontal grid lines + y labels\n const yStart = Math.ceil(yMin / yTick) * yTick;\n for (let y = yStart; y <= yMax; y += yTick) {\n const sy = toSvgY(y);\n if (sy < pad.top || sy > pad.top + plotH) continue;\n if (showGrid) {\n svg += `<line x1=\"${pad.left}\" y1=\"${sy}\" x2=\"${pad.left + plotW}\" y2=\"${sy}\" stroke=\"${tk.gridStroke}\" stroke-width=\"0.5\" />`;\n }\n const label = Math.abs(y) < 1e-10 ? '0' : (Number.isInteger(y) ? y : y.toFixed(1));\n svg += `<text x=\"${pad.left - 8}\" y=\"${sy + 3}\" text-anchor=\"end\" fill=\"${tk.tickLabel}\" font-size=\"10\" font-family=\"lixCode, monospace\">${label}</text>`;\n }\n\n // Axes\n if (xMin <= 0 && xMax >= 0) {\n const ax = toSvgX(0);\n svg += `<line x1=\"${ax}\" y1=\"${pad.top}\" x2=\"${ax}\" y2=\"${pad.top + plotH}\" stroke=\"${tk.axisStroke}\" stroke-width=\"1\" />`;\n }\n if (yMin <= 0 && yMax >= 0) {\n const ay = toSvgY(0);\n svg += `<line x1=\"${pad.left}\" y1=\"${ay}\" x2=\"${pad.left + plotW}\" y2=\"${ay}\" stroke=\"${tk.axisStroke}\" stroke-width=\"1\" />`;\n }\n\n // Plot border\n svg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"none\" stroke=\"${tk.borderStroke}\" stroke-width=\"1\" />`;\n\n // Equations\n const samplesPerPixel = 2;\n const totalSamples = plotW * samplesPerPixel;\n const dx = xRange / totalSamples;\n\n equations.forEach((eq, eqIdx) => {\n if (!eq.expression || !eq.expression.trim()) return;\n\n const fn = parseExpression(eq.expression);\n if (!fn) return;\n\n const color = eq.color || GRAPH_COLORS[eqIdx % GRAPH_COLORS.length];\n let pathData = '';\n let drawing = false;\n\n for (let i = 0; i <= totalSamples; i++) {\n const x = xMin + i * dx;\n let y;\n try { y = fn(x); } catch { y = NaN; }\n\n if (!isFinite(y) || isNaN(y) || y < yMin - yRange * 5 || y > yMax + yRange * 5) {\n drawing = false;\n continue;\n }\n\n // Clamp to plot area for rendering\n const clampedY = Math.max(yMin - yRange * 0.5, Math.min(yMax + yRange * 0.5, y));\n const sx = toSvgX(x);\n const sy = toSvgY(clampedY);\n\n if (!drawing) {\n pathData += `M ${sx.toFixed(1)} ${sy.toFixed(1)} `;\n drawing = true;\n } else {\n pathData += `L ${sx.toFixed(1)} ${sy.toFixed(1)} `;\n }\n }\n\n if (pathData) {\n svg += `<path d=\"${pathData.trim()}\" fill=\"none\" stroke=\"${color}\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />`;\n }\n });\n\n // Clip path for plot area\n const clipId = 'graph-clip-' + Date.now();\n const defs = `<defs><clipPath id=\"${clipId}\"><rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" /></clipPath></defs>`;\n\n // Re-wrap: curves should be clipped\n // Rebuild with clip group\n let curves = '';\n equations.forEach((eq, eqIdx) => {\n if (!eq.expression || !eq.expression.trim()) return;\n const fn = parseExpression(eq.expression);\n if (!fn) return;\n\n const color = eq.color || GRAPH_COLORS[eqIdx % GRAPH_COLORS.length];\n let pathData = '';\n let drawing = false;\n\n for (let i = 0; i <= totalSamples; i++) {\n const x = xMin + i * dx;\n let y;\n try { y = fn(x); } catch { y = NaN; }\n\n if (!isFinite(y) || isNaN(y)) { drawing = false; continue; }\n\n const sx = toSvgX(x);\n const sy = toSvgY(y);\n\n if (!drawing) {\n pathData += `M ${sx.toFixed(1)} ${sy.toFixed(1)} `;\n drawing = true;\n } else {\n pathData += `L ${sx.toFixed(1)} ${sy.toFixed(1)} `;\n }\n }\n\n if (pathData) {\n curves += `<path d=\"${pathData.trim()}\" fill=\"none\" stroke=\"${color}\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />`;\n }\n });\n\n // Equation legend\n let legendY = pad.top + 12;\n let legend = '';\n equations.forEach((eq, eqIdx) => {\n if (!eq.expression || !eq.expression.trim()) return;\n const color = eq.color || GRAPH_COLORS[eqIdx % GRAPH_COLORS.length];\n legend += `<circle cx=\"${pad.left + 12}\" cy=\"${legendY}\" r=\"4\" fill=\"${color}\" />`;\n legend += `<text x=\"${pad.left + 22}\" y=\"${legendY + 3}\" fill=\"${color}\" font-size=\"11\" font-family=\"lixCode, monospace\">${escapeXml(eq.expression)}</text>`;\n legendY += 18;\n });\n\n // Remove the non-clipped curves from svg (we added them above for building)\n // Rebuild cleanly\n let cleanSvg = '';\n cleanSvg += `<rect x=\"0\" y=\"0\" width=\"${width}\" height=\"${height}\" fill=\"${tk.outerBg}\" rx=\"8\" />`;\n cleanSvg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"${tk.plotBg}\" />`;\n\n // Grid + ticks (re-add)\n for (let x = xStart; x <= xMax; x += xTick) {\n const sx = toSvgX(x);\n if (sx < pad.left || sx > pad.left + plotW) continue;\n if (showGrid) {\n cleanSvg += `<line x1=\"${sx}\" y1=\"${pad.top}\" x2=\"${sx}\" y2=\"${pad.top + plotH}\" stroke=\"${tk.gridStroke}\" stroke-width=\"0.5\" />`;\n }\n const label = Math.abs(x) < 1e-10 ? '0' : (Number.isInteger(x) ? x : x.toFixed(1));\n cleanSvg += `<text x=\"${sx}\" y=\"${pad.top + plotH + 16}\" text-anchor=\"middle\" fill=\"${tk.tickLabel}\" font-size=\"10\" font-family=\"lixCode, monospace\">${label}</text>`;\n }\n for (let y = yStart; y <= yMax; y += yTick) {\n const sy = toSvgY(y);\n if (sy < pad.top || sy > pad.top + plotH) continue;\n if (showGrid) {\n cleanSvg += `<line x1=\"${pad.left}\" y1=\"${sy}\" x2=\"${pad.left + plotW}\" y2=\"${sy}\" stroke=\"${tk.gridStroke}\" stroke-width=\"0.5\" />`;\n }\n const label = Math.abs(y) < 1e-10 ? '0' : (Number.isInteger(y) ? y : y.toFixed(1));\n cleanSvg += `<text x=\"${pad.left - 8}\" y=\"${sy + 3}\" text-anchor=\"end\" fill=\"${tk.tickLabel}\" font-size=\"10\" font-family=\"lixCode, monospace\">${label}</text>`;\n }\n // Axes\n if (xMin <= 0 && xMax >= 0) {\n const ax = toSvgX(0);\n cleanSvg += `<line x1=\"${ax}\" y1=\"${pad.top}\" x2=\"${ax}\" y2=\"${pad.top + plotH}\" stroke=\"${tk.axisStroke}\" stroke-width=\"1\" />`;\n }\n if (yMin <= 0 && yMax >= 0) {\n const ay = toSvgY(0);\n cleanSvg += `<line x1=\"${pad.left}\" y1=\"${ay}\" x2=\"${pad.left + plotW}\" y2=\"${ay}\" stroke=\"${tk.axisStroke}\" stroke-width=\"1\" />`;\n }\n // Plot border\n cleanSvg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"none\" stroke=\"${tk.borderStroke}\" stroke-width=\"1\" />`;\n\n // Clipped curves\n cleanSvg += `<g clip-path=\"url(#${clipId})\">${curves}</g>`;\n\n // Legend\n cleanSvg += legend;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">${defs}${cleanSvg}</svg>`;\n}\n\n/**\n * Generate a preview SVG for the modal.\n */\nexport function renderGraphPreviewSVG(equations, settings) {\n return renderGraphSVG(equations, {\n ...settings,\n width: 520,\n height: 380,\n });\n}\n\nfunction escapeXml(str) {\n return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\nexport { GRAPH_COLORS };\n", "/* eslint-disable */\n/**\n * GraphEngine - Bridge between graph rendering and the sketch canvas.\n * Creates Frames containing rendered graph SVG elements.\n */\n\nimport { parseExpression, isValidExpression } from './GraphMathParser.js';\nimport { renderGraphSVG, renderGraphPreviewSVG, GRAPH_COLORS } from './GraphRenderer.js';\n\nconst NS = 'http://www.w3.org/2000/svg';\nconst GRAPH_WIDTH = 600;\nconst GRAPH_HEIGHT = 420;\n\n/**\n * Place a graph on the canvas inside a Frame.\n */\nfunction renderGraphOnCanvas(equations, settings) {\n if (!equations || equations.length === 0) return false;\n if (!window.svg || !window.Frame) {\n console.error('[GraphEngine] Engine not initialized');\n return false;\n }\n\n // Generate full-size SVG\n const svgMarkup = renderGraphSVG(equations, {\n ...settings,\n width: GRAPH_WIDTH,\n height: GRAPH_HEIGHT,\n });\n if (!svgMarkup) return false;\n\n // Viewport center\n const vb = window.currentViewBox || { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight };\n const vcx = vb.x + vb.width / 2;\n const vcy = vb.y + vb.height / 2;\n\n const frameW = GRAPH_WIDTH + 40;\n const frameH = GRAPH_HEIGHT + 40;\n const frameX = vcx - frameW / 2;\n const frameY = vcy - frameH / 2;\n\n // Build title from equations\n const eqLabels = equations\n .filter(eq => eq.expression && eq.expression.trim())\n .map(eq => eq.expression.trim())\n .slice(0, 3);\n const title = eqLabels.length > 0\n ? 'Graph: ' + eqLabels.join(', ')\n : 'Graph';\n\n // Phase 5 (issue #22): no wrapper frame. The graph is conceptually a\n // single rendering \u2014 axes, grid, curves all interlocked \u2014 so we don't\n // split it into per-curve shapes. Instead the graph becomes ONE\n // first-class shape on the canvas: a `graphShape` that implements the\n // shape API the engine relies on (contains / selectShape / etc.) so\n // it can be selected, dragged, attached to by arrows, picked up by\n // the rect-drag \u2014 exactly like a user-drawn shape.\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(svgMarkup, 'image/svg+xml');\n const svgEl = doc.querySelector('svg');\n if (!svgEl) return false;\n\n const graphGroup = document.createElementNS(NS, 'g');\n graphGroup.setAttribute('data-type', 'graph-group');\n graphGroup.setAttribute('transform', `translate(${frameX + 20}, ${frameY + 20})`);\n\n // Copy defs (clip paths)\n const defs = svgEl.querySelector('defs');\n if (defs) {\n const defsClone = defs.cloneNode(true);\n window.svg.querySelector('defs')?.appendChild(defsClone.firstChild) ||\n window.svg.insertBefore(defsClone, window.svg.firstChild);\n }\n\n while (svgEl.childNodes.length > 0) {\n const child = svgEl.childNodes[0];\n if (child.nodeName === 'defs') { svgEl.removeChild(child); continue; }\n graphGroup.appendChild(child);\n }\n window.svg.appendChild(graphGroup);\n\n const graphShape = {\n shapeName: 'graph', // first-class shapeName\n shapeID: `graph-${Date.now().toString(36)}-${Math.floor(Math.random() * 10000)}`,\n group: graphGroup,\n element: graphGroup,\n x: frameX + 20,\n y: frameY + 20,\n width: GRAPH_WIDTH,\n height: GRAPH_HEIGHT,\n rotation: 0,\n isSelected: false,\n _selectionRect: null,\n _graphData: {\n equations: equations.map(eq => ({ expression: eq.expression, color: eq.color })),\n settings: { ...settings },\n },\n\n // \u2500\u2500 Shape API the engine relies on \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n contains(px, py) {\n return px >= this.x && px <= this.x + this.width\n && py >= this.y && py <= this.y + this.height;\n },\n move(dx, dy) {\n this.x += dx; this.y += dy;\n this.group.setAttribute('transform', `translate(${this.x}, ${this.y})`);\n this._updateSelectionRect();\n },\n selectShape() {\n this.isSelected = true;\n if (this._selectionRect) return;\n const r = document.createElementNS(NS, 'rect');\n r.setAttribute('fill', 'none');\n r.setAttribute('stroke', '#9b7bf7');\n r.setAttribute('stroke-width', '1.5');\n r.setAttribute('stroke-dasharray', '4 3');\n r.setAttribute('pointer-events', 'none');\n window.svg.appendChild(r);\n this._selectionRect = r;\n this._updateSelectionRect();\n },\n removeSelection() {\n this.isSelected = false;\n if (this._selectionRect && this._selectionRect.parentNode) {\n this._selectionRect.parentNode.removeChild(this._selectionRect);\n }\n this._selectionRect = null;\n },\n _updateSelectionRect() {\n if (!this._selectionRect) return;\n const pad = 4;\n this._selectionRect.setAttribute('x', this.x - pad);\n this._selectionRect.setAttribute('y', this.y - pad);\n this._selectionRect.setAttribute('width', this.width + pad * 2);\n this._selectionRect.setAttribute('height', this.height + pad * 2);\n },\n updateAttachedArrows() {\n if (typeof window.updateAttachedArrows === 'function') {\n window.updateAttachedArrows(this);\n }\n },\n };\n\n window.shapes.push(graphShape);\n if (window.pushCreateAction) window.pushCreateAction(graphShape);\n\n // Auto-select so the user sees something landed.\n window.currentShape = graphShape;\n graphShape.selectShape();\n } catch (err) {\n console.error('[GraphEngine] SVG insertion failed:', err);\n return false;\n }\n\n return true;\n}\n\n/**\n * Initialize the graph engine \u2014 expose bridge functions on window.\n */\nexport function initGraphEngine() {\n window.__graphPreview = (equations, settings) => {\n return renderGraphPreviewSVG(equations, settings);\n };\n window.__graphRenderer = renderGraphOnCanvas;\n window.__graphParser = (expr) => {\n const fn = parseExpression(expr);\n return fn ? true : false;\n };\n window.__graphValidate = isValidExpression;\n window.__graphColors = GRAPH_COLORS;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -6,6 +6,16 @@ var NODE_H = 50;
6
6
  var SIDE_MARGIN = 50;
7
7
  var TOP_MARGIN = 40;
8
8
  var FONT_FAMILY = "lixFont, sans-serif";
9
+ function isThemeDark() {
10
+ if (typeof document === "undefined") return true;
11
+ return !!(document.body && document.body.classList.contains("theme-dark"));
12
+ }
13
+ function nodeStrokeColor() {
14
+ return isThemeDark() ? "#fff" : "#1a1a2e";
15
+ }
16
+ function edgeStrokeColor() {
17
+ return isThemeDark() ? "#888" : "#444";
18
+ }
9
19
  var THEME = {
10
20
  bg: "#1e1e28",
11
21
  nodeBg: "transparent",
@@ -296,7 +306,7 @@ function renderFlowchartOnCanvas(diagram) {
296
306
  const vcy = vb.y + vb.height / 2;
297
307
  const ox = vcx - dw / 2 - minX;
298
308
  const oy = vcy - dh / 2 - minY;
299
- const PADDING = 40;
309
+ const PADDING = 90;
300
310
  const frameTitle = diagram.title || "Mermaid diagram";
301
311
  const frame = new window.Frame(
302
312
  vcx - dw / 2 - PADDING,
@@ -323,12 +333,13 @@ function renderFlowchartOnCanvas(diagram) {
323
333
  const cx = nx + nw / 2;
324
334
  const cy = ny + nh / 2;
325
335
  const opts = {
326
- stroke: n.stroke || "#fff",
336
+ stroke: n.stroke || nodeStrokeColor(),
327
337
  strokeWidth: n.strokeWidth ?? 1.5,
328
338
  fill: n.fill || "transparent",
329
339
  fillStyle: n.fill && n.fill !== "transparent" ? "solid" : "none",
330
340
  roughness: 1,
331
- label: n.label || ""
341
+ label: n.label || "",
342
+ labelColor: n.labelColor || nodeStrokeColor()
332
343
  };
333
344
  let shape = null;
334
345
  try {
@@ -365,11 +376,12 @@ function renderFlowchartOnCanvas(diagram) {
365
376
  const isThick = style === "thick";
366
377
  const isDotted = style === "dotted";
367
378
  const opts = {
368
- stroke: e.stroke || "#fff",
379
+ stroke: e.stroke || edgeStrokeColor(),
369
380
  strokeWidth: isThick ? 3 : 1.5,
370
381
  roughness: 1,
371
382
  strokeDasharray: isDotted ? "5 3" : "",
372
- label: e.label || ""
383
+ label: e.label || "",
384
+ labelColor: e.labelColor || edgeStrokeColor()
373
385
  };
374
386
  let connector = null;
375
387
  try {
@@ -409,4 +421,4 @@ export {
409
421
  renderFlowchartPreviewSVG,
410
422
  renderFlowchartSVG
411
423
  };
412
- //# sourceMappingURL=MermaidFlowchartRenderer-4QBAZ5MB.js.map
424
+ //# sourceMappingURL=MermaidFlowchartRenderer-A26B2SM3.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/MermaidFlowchartRenderer.js"],
4
+ "sourcesContent": ["/* eslint-disable */\n/**\n * MermaidFlowchartRenderer - Renders parsed flowchart diagrams as high-quality SVG.\n *\n * One renderer for both preview and canvas \u2014 ensures they always match.\n * Supports: rectangle [], rounded rectangle (), circle (()), diamond/rhombus {},\n * directed/undirected edges with labels, subgraphs, all directions (TD/TB/LR/RL/BT).\n *\n * Dark theme matching the app aesthetic.\n */\n\n// Layout constants\nconst NODE_W = 150;\nconst NODE_H = 50;\nconst H_SPACING = 200;\nconst V_SPACING = 120;\nconst SIDE_MARGIN = 50;\nconst TOP_MARGIN = 40;\nconst FONT_FAMILY = 'lixFont, sans-serif';\n\n// Issue #38 follow-up: theme-aware stroke / fill. Resolved at draw time\n// so a single render call uses whichever palette is active.\nfunction isThemeDark() {\n if (typeof document === 'undefined') return true;\n return !!(document.body && document.body.classList.contains('theme-dark'));\n}\nfunction nodeStrokeColor() { return isThemeDark() ? '#fff' : '#1a1a2e'; }\nfunction edgeStrokeColor() { return isThemeDark() ? '#888' : '#444'; }\n\n// Theme colors (dark theme \u2014 used by the SVG-string preview path only)\nconst THEME = {\n bg: '#1e1e28',\n nodeBg: 'transparent',\n nodeStroke: '#9090c0',\n nodeText: '#e0e0e0',\n edgeStroke: '#888',\n edgeText: '#a0a0b0',\n subgraphBg: 'rgba(80,80,120,0.08)',\n subgraphBorder: '#555',\n subgraphLabel: '#888',\n};\n\nfunction escapeXml(str) {\n return String(str)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nfunction measureText(text, fontSize) {\n return text.length * fontSize * 0.55;\n}\n\n/**\n * Render a parsed flowchart diagram to SVG markup.\n *\n * @param {Object} diagram - Parsed from parseMermaid()\n * @param {Object} opts - { width?, height?, fitToContent? }\n * @returns {string} SVG markup string\n */\nexport function renderFlowchartSVG(diagram, opts = {}) {\n if (!diagram || !diagram.nodes || diagram.nodes.length === 0) return '';\n\n const nodes = diagram.nodes;\n const edges = diagram.edges || [];\n const subgraphs = diagram.subgraphs || [];\n const direction = diagram.direction || 'TD';\n\n // Compute bounds of laid-out nodes\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n nodes.forEach(n => {\n const nw = n.width || NODE_W;\n const nh = n.height || NODE_H;\n minX = Math.min(minX, n.x);\n minY = Math.min(minY, n.y);\n maxX = Math.max(maxX, n.x + nw);\n maxY = Math.max(maxY, n.y + nh);\n });\n\n const dw = maxX - minX || 1;\n const dh = maxY - minY || 1;\n\n // If fitToContent or explicit size, scale to fit\n const targetW = opts.width || dw + SIDE_MARGIN * 2;\n const targetH = opts.height || dh + TOP_MARGIN * 2;\n\n let scale, offX, offY;\n if (opts.width || opts.height) {\n const pad = 40;\n scale = Math.min(\n (targetW - pad * 2) / dw,\n (targetH - pad * 2) / dh,\n 1.8\n );\n offX = (targetW - dw * scale) / 2 - minX * scale;\n offY = (targetH - dh * scale) / 2 - minY * scale;\n } else {\n scale = 1;\n offX = SIDE_MARGIN - minX;\n offY = TOP_MARGIN - minY;\n }\n\n const totalWidth = opts.width || Math.round(dw * scale + SIDE_MARGIN * 2);\n const totalHeight = opts.height || Math.round(dh * scale + TOP_MARGIN * 2);\n\n // Build node lookup for edge rendering\n const nodeById = new Map();\n nodes.forEach(n => {\n const nw = (n.width || NODE_W) * scale;\n const nh = (n.height || NODE_H) * scale;\n const nx = n.x * scale + offX;\n const ny = n.y * scale + offY;\n nodeById.set(n.id, {\n x: nx, y: ny, w: nw, h: nh,\n cx: nx + nw / 2, cy: ny + nh / 2,\n type: n.type, label: n.label,\n fill: n.fill, stroke: n.stroke, strokeWidth: n.strokeWidth,\n });\n });\n\n let svg = '';\n const defs = [];\n\n // Arrow markers (normal, dotted, thick)\n defs.push(`<marker id=\"fc-arrow\" markerWidth=\"10\" markerHeight=\"7\" refX=\"9\" refY=\"3.5\" orient=\"auto\">\n <path d=\"M1,1 L9,3.5 L1,6\" fill=\"none\" stroke=\"${THEME.edgeStroke}\" stroke-width=\"1.5\" stroke-linejoin=\"round\" />\n </marker>`);\n defs.push(`<marker id=\"fc-arrow-thick\" markerWidth=\"12\" markerHeight=\"9\" refX=\"11\" refY=\"4.5\" orient=\"auto\">\n <path d=\"M1,1 L11,4.5 L1,8\" fill=\"none\" stroke=\"${THEME.edgeStroke}\" stroke-width=\"2\" stroke-linejoin=\"round\" />\n </marker>`);\n\n // Background\n svg += `<rect x=\"0\" y=\"0\" width=\"${totalWidth}\" height=\"${totalHeight}\" fill=\"${THEME.bg}\" rx=\"8\" />`;\n\n // --- Subgraphs (rendered first, behind everything) ---\n for (const sg of subgraphs) {\n if (!sg.nodes || sg.nodes.length === 0) continue;\n\n let sgMinX = Infinity, sgMinY = Infinity, sgMaxX = -Infinity, sgMaxY = -Infinity;\n let hasNodes = false;\n for (const nid of sg.nodes) {\n const nd = nodeById.get(nid);\n if (!nd) continue;\n hasNodes = true;\n sgMinX = Math.min(sgMinX, nd.x);\n sgMinY = Math.min(sgMinY, nd.y);\n sgMaxX = Math.max(sgMaxX, nd.x + nd.w);\n sgMaxY = Math.max(sgMaxY, nd.y + nd.h);\n }\n if (!hasNodes) continue;\n\n const sgPad = 20 * scale;\n const sgX = sgMinX - sgPad;\n const sgY = sgMinY - sgPad - 16 * scale;\n const sgW = (sgMaxX - sgMinX) + sgPad * 2;\n const sgH = (sgMaxY - sgMinY) + sgPad * 2 + 16 * scale;\n\n svg += `<g data-fc-type=\"subgraph\" data-fc-id=\"${escapeXml(sg.id)}\">`;\n svg += `<rect x=\"${sgX}\" y=\"${sgY}\" width=\"${sgW}\" height=\"${sgH}\" rx=\"6\" fill=\"${THEME.subgraphBg}\" stroke=\"${THEME.subgraphBorder}\" stroke-width=\"1\" stroke-dasharray=\"4 2\" />`;\n if (sg.label) {\n svg += `<text x=\"${sgX + 8}\" y=\"${sgY + 14}\" fill=\"${THEME.subgraphLabel}\" font-size=\"${Math.max(9, 11 * scale)}\" font-family=\"${FONT_FAMILY}\">${escapeXml(sg.label)}</text>`;\n }\n svg += `</g>`;\n }\n\n // --- Edges ---\n edges.forEach(e => {\n const f = nodeById.get(e.from);\n const t = nodeById.get(e.to);\n if (!f || !t) return;\n\n const directed = e.directed !== false;\n const edgeStyle = e.style || 'normal';\n let strokeW, dashArr, markerRef;\n if (edgeStyle === 'thick') {\n strokeW = 3;\n dashArr = '';\n markerRef = directed ? ' marker-end=\"url(#fc-arrow-thick)\"' : '';\n } else if (edgeStyle === 'dotted') {\n strokeW = 1.5;\n dashArr = ' stroke-dasharray=\"5 3\"';\n markerRef = directed ? ' marker-end=\"url(#fc-arrow)\"' : '';\n } else {\n strokeW = 1.5;\n dashArr = '';\n markerRef = directed ? ' marker-end=\"url(#fc-arrow)\"' : '';\n }\n const eStroke = e.stroke || THEME.edgeStroke;\n\n // Compute connection points\n const sp = getEdgePoint(f, t);\n const ep = getEdgePoint(t, f);\n\n // Determine if we should curve\n const dx = t.cx - f.cx;\n const dy = t.cy - f.cy;\n const dist = Math.sqrt(dx * dx + dy * dy);\n let mx = (sp.x + ep.x) / 2;\n let my = (sp.y + ep.y) / 2;\n\n svg += `<g data-fc-type=\"edge\" data-fc-from=\"${escapeXml(e.from)}\" data-fc-to=\"${escapeXml(e.to)}\">`;\n\n if (dist > 0 && Math.abs(dy) > 15 && Math.abs(dx) > 15) {\n // Curved edge\n const perpX = -dy / dist;\n const perpY = dx / dist;\n const curveAmt = dist * 0.12;\n const cpx = mx + perpX * curveAmt;\n const cpy = my + perpY * curveAmt;\n mx = 0.25 * sp.x + 0.5 * cpx + 0.25 * ep.x;\n my = 0.25 * sp.y + 0.5 * cpy + 0.25 * ep.y;\n svg += `<path d=\"M ${sp.x} ${sp.y} Q ${cpx} ${cpy} ${ep.x} ${ep.y}\" fill=\"none\" stroke=\"${eStroke}\" stroke-width=\"${strokeW}\"${dashArr}${markerRef} />`;\n } else {\n svg += `<line x1=\"${sp.x}\" y1=\"${sp.y}\" x2=\"${ep.x}\" y2=\"${ep.y}\" stroke=\"${eStroke}\" stroke-width=\"${strokeW}\"${dashArr}${markerRef} />`;\n }\n\n // Edge label (supports multi-line via \\n)\n if (e.label) {\n const labelFontSize = Math.max(8, 10 * scale);\n const labelLines = e.label.split('\\n');\n const maxLineW = Math.max(...labelLines.map(l => measureText(l, labelFontSize)));\n const labelW = maxLineW + 12;\n const labelH = labelLines.length * (labelFontSize + 3) + 6;\n svg += `<rect x=\"${mx - labelW / 2}\" y=\"${my - labelH / 2}\" width=\"${labelW}\" height=\"${labelH}\" rx=\"3\" fill=\"${THEME.bg}\" opacity=\"0.85\" />`;\n if (labelLines.length === 1) {\n svg += `<text x=\"${mx}\" y=\"${my + 1}\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"${THEME.edgeText}\" font-size=\"${labelFontSize}\" font-family=\"${FONT_FAMILY}\">${escapeXml(e.label)}</text>`;\n } else {\n const startY = my - ((labelLines.length - 1) * (labelFontSize + 3)) / 2;\n svg += `<text x=\"${mx}\" text-anchor=\"middle\" fill=\"${THEME.edgeText}\" font-size=\"${labelFontSize}\" font-family=\"${FONT_FAMILY}\">`;\n labelLines.forEach((ln, idx) => {\n svg += `<tspan x=\"${mx}\" dy=\"${idx === 0 ? 0 : labelFontSize + 3}\" y=\"${idx === 0 ? startY : ''}\">${escapeXml(ln)}</tspan>`;\n });\n svg += `</text>`;\n }\n }\n\n svg += `</g>`;\n });\n\n // --- Nodes ---\n nodes.forEach(n => {\n const d = nodeById.get(n.id);\n if (!d) return;\n\n const nStroke = n.stroke || THEME.nodeStroke;\n const nFill = n.fill || THEME.nodeBg;\n const nStrokeWidth = n.strokeWidth || 1.8;\n const fontSize = Math.max(9, Math.min(13, 12 * scale));\n\n svg += `<g data-fc-type=\"node\" data-fc-id=\"${escapeXml(n.id)}\">`;\n\n if (n.type === 'circle') {\n const r = Math.min(d.w, d.h) / 2;\n svg += `<circle cx=\"${d.cx}\" cy=\"${d.cy}\" r=\"${r}\" fill=\"${nFill}\" stroke=\"${nStroke}\" stroke-width=\"${nStrokeWidth}\" />`;\n } else if (n.type === 'diamond') {\n const hw = d.w / 2 * 0.85;\n const hh = d.h / 2 * 0.85;\n svg += `<polygon points=\"${d.cx},${d.cy - hh} ${d.cx + hw},${d.cy} ${d.cx},${d.cy + hh} ${d.cx - hw},${d.cy}\" fill=\"${nFill}\" stroke=\"${nStroke}\" stroke-width=\"${nStrokeWidth}\" />`;\n } else if (n.type === 'asymmetric') {\n // Flag/asymmetric shape: pointed left, flat right\n const notchX = d.x + 15 * scale;\n svg += `<polygon points=\"${d.x},${d.y} ${d.x + d.w},${d.y} ${d.x + d.w},${d.y + d.h} ${d.x},${d.y + d.h} ${notchX},${d.cy}\" fill=\"${nFill}\" stroke=\"${nStroke}\" stroke-width=\"${nStrokeWidth}\" />`;\n } else if (n.type === 'roundrect') {\n svg += `<rect x=\"${d.x}\" y=\"${d.y}\" width=\"${d.w}\" height=\"${d.h}\" rx=\"${12 * scale}\" fill=\"${nFill}\" stroke=\"${nStroke}\" stroke-width=\"${nStrokeWidth}\" />`;\n } else {\n svg += `<rect x=\"${d.x}\" y=\"${d.y}\" width=\"${d.w}\" height=\"${d.h}\" rx=\"${3 * scale}\" fill=\"${nFill}\" stroke=\"${nStroke}\" stroke-width=\"${nStrokeWidth}\" />`;\n }\n\n // Node label (supports multi-line via \\n)\n if (n.label) {\n let labelFill = nFill && nFill !== 'transparent' && nFill !== THEME.nodeBg ? getContrastColor(nFill) : nStroke;\n if (isColorTooDark(labelFill)) labelFill = '#d0d0d0';\n\n const labelLines = n.label.split('\\n');\n if (labelLines.length === 1) {\n svg += `<text x=\"${d.cx}\" y=\"${d.cy}\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"${labelFill}\" font-size=\"${fontSize}\" font-family=\"${FONT_FAMILY}\" font-weight=\"500\">${escapeXml(n.label)}</text>`;\n } else {\n const lineH = fontSize + 3;\n const startY = d.cy - ((labelLines.length - 1) * lineH) / 2;\n svg += `<text text-anchor=\"middle\" fill=\"${labelFill}\" font-size=\"${fontSize}\" font-family=\"${FONT_FAMILY}\" font-weight=\"500\">`;\n labelLines.forEach((ln, idx) => {\n svg += `<tspan x=\"${d.cx}\" y=\"${startY + idx * lineH}\">${escapeXml(ln)}</tspan>`;\n });\n svg += `</text>`;\n }\n }\n\n svg += `</g>`;\n });\n\n // Build final SVG\n const defsStr = defs.length > 0 ? `<defs>${defs.join('')}</defs>` : '';\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${totalWidth}\" height=\"${totalHeight}\" viewBox=\"0 0 ${totalWidth} ${totalHeight}\">${defsStr}${svg}</svg>`;\n}\n\n/**\n * Get the connection point on a node's boundary toward another node.\n */\nfunction getEdgePoint(node, target) {\n const dx = target.cx - node.cx;\n const dy = target.cy - node.cy;\n\n if (node.type === 'circle') {\n const r = Math.min(node.w, node.h) / 2;\n const dist = Math.sqrt(dx * dx + dy * dy) || 1;\n return { x: node.cx + (dx / dist) * r, y: node.cy + (dy / dist) * r };\n }\n\n if (node.type === 'diamond') {\n // Diamond edge intersection\n const hw = node.w / 2 * 0.85;\n const hh = node.h / 2 * 0.85;\n const adx = Math.abs(dx) || 0.001;\n const ady = Math.abs(dy) || 0.001;\n const t = Math.min(hw / adx, hh / ady);\n return { x: node.cx + dx * t * 0.95, y: node.cy + dy * t * 0.95 };\n }\n\n // Rectangle / rounded rect / asymmetric - exit from edges\n const hw = node.w / 2;\n const hh = node.h / 2;\n\n if (Math.abs(dx) < 0.001 || Math.abs(dy) * hw > Math.abs(dx) * hh) {\n if (dy > 0) return { x: node.cx, y: node.y + node.h };\n return { x: node.cx, y: node.y };\n }\n if (dx > 0) return { x: node.x + node.w, y: node.cy };\n return { x: node.x, y: node.cy };\n}\n\nfunction isColorTooDark(hex) {\n if (!hex || hex === 'transparent' || hex === 'none') return false;\n const rgb = parseColor(hex);\n if (!rgb) return false;\n return (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) < 80;\n}\n\nfunction parseColor(hex) {\n if (!hex || hex === 'transparent' || hex === 'none') return null;\n let c = hex.replace('#', '');\n // Support 3-char shorthand (#9f6 \u2192 #99ff66)\n if (c.length === 3) c = c[0] + c[0] + c[1] + c[1] + c[2] + c[2];\n if (c.length < 6) return null;\n return {\n r: parseInt(c.substring(0, 2), 16),\n g: parseInt(c.substring(2, 4), 16),\n b: parseInt(c.substring(4, 6), 16),\n };\n}\n\nfunction getLuminance(hex) {\n const rgb = parseColor(hex);\n if (!rgb) return 0;\n return 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;\n}\n\nfunction getContrastColor(bgHex) {\n // Pick dark or light text based on background luminance\n return getLuminance(bgHex) > 140 ? '#1a1a2e' : '#f0f0f0';\n}\n\n/**\n * Generate preview SVG for the modal.\n */\nexport function renderFlowchartPreviewSVG(diagram) {\n return renderFlowchartSVG(diagram, { width: 600, height: 450 });\n}\n\n/**\n * Render a flowchart diagram onto the canvas as a real engine `Frame`\n * containing independent shapes \u2014 Rectangle nodes (with embedded labels)\n * joined by Arrow edges. Each child is fully independent for click /\n * drag / resize / colour-change, exactly like a user-drawn shape; the\n * Frame's `_diagramType` marker means deleting it pulls every child with\n * it (so the diagram behaves as one logical unit when you're done with\n * it) \u2014 see Frame.destroy().\n *\n * Issue #34 bug #3 (follow-up to #22 phase 5): drops the shared `groupId`\n * glue that made selecting one shape select the whole diagram; the Frame\n * is the explicit container instead.\n */\nexport function renderFlowchartOnCanvas(diagram) {\n if (!diagram || !diagram.nodes || diagram.nodes.length === 0) return false;\n if (!window.svg || !window.Rectangle || !window.Frame) {\n console.error('[FlowchartRenderer] Engine not initialized');\n return false;\n }\n\n const nodes = diagram.nodes;\n const edges = diagram.edges || [];\n\n // Diagram bounds (in the renderer's natural coordinate space)\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n nodes.forEach((n) => {\n const nw = n.width || 140;\n const nh = n.height || 60;\n minX = Math.min(minX, n.x);\n minY = Math.min(minY, n.y);\n maxX = Math.max(maxX, n.x + nw);\n maxY = Math.max(maxY, n.y + nh);\n });\n const dw = (maxX - minX) || 1;\n const dh = (maxY - minY) || 1;\n\n // Center on the current viewport\n const vb = window.currentViewBox || { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight };\n const vcx = vb.x + vb.width / 2;\n const vcy = vb.y + vb.height / 2;\n const ox = vcx - dw / 2 - minX;\n const oy = vcy - dh / 2 - minY;\n\n // \u2500\u2500 Wrapper frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Created up-front so we can call addShapeToFrame as each child is\n // built. _diagramType marks it so Frame.destroy() takes the children\n // along on delete (issue #34 bug #3).\n //\n // PADDING bumped from 40 \u2192 90 so edge labels, rotated diamond nodes,\n // and arrow heads near the diagram boundary stay inside the frame\n // instead of getting clipped at the corners.\n const PADDING = 90;\n const frameTitle = diagram.title || 'Mermaid diagram';\n const frame = new window.Frame(\n vcx - dw / 2 - PADDING,\n vcy - dh / 2 - PADDING,\n dw + PADDING * 2,\n dh + PADDING * 2,\n {\n stroke: '#888',\n strokeWidth: 1,\n fill: 'transparent',\n opacity: 0.7,\n frameName: frameTitle,\n }\n );\n frame._diagramType = 'mermaid-flowchart';\n window.shapes.push(frame);\n if (window.pushCreateAction) window.pushCreateAction(frame);\n\n const nodeMap = new Map(); // id \u2192 shape\n\n // \u2500\u2500 Nodes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n for (const n of nodes) {\n const nw = n.width || 140;\n const nh = n.height || 60;\n const nx = n.x + ox;\n const ny = n.y + oy;\n const cx = nx + nw / 2;\n const cy = ny + nh / 2;\n\n const opts = {\n stroke: n.stroke || nodeStrokeColor(),\n strokeWidth: n.strokeWidth ?? 1.5,\n fill: n.fill || 'transparent',\n fillStyle: n.fill && n.fill !== 'transparent' ? 'solid' : 'none',\n roughness: 1,\n label: n.label || '',\n labelColor: n.labelColor || nodeStrokeColor(),\n };\n\n let shape = null;\n try {\n if (n.type === 'circle' && window.Circle) {\n shape = new window.Circle(cx, cy, nw / 2, nh / 2, opts);\n } else if (n.type === 'diamond') {\n const sz = Math.max(nw, nh) * 0.75;\n shape = new window.Rectangle(cx - sz / 2, cy - sz / 2, sz, sz, opts);\n shape.rotation = 45;\n if (typeof shape.draw === 'function') shape.draw();\n } else if (n.type === 'roundrect') {\n shape = new window.Rectangle(nx, ny, nw, nh, { ...opts, cornerRadius: Math.min(nw, nh) * 0.2 });\n } else {\n shape = new window.Rectangle(nx, ny, nw, nh, opts);\n }\n } catch (err) {\n console.warn('[FlowchartRenderer] Node creation failed:', n.id, err);\n continue;\n }\n if (!shape) continue;\n\n window.shapes.push(shape);\n if (window.pushCreateAction) window.pushCreateAction(shape);\n frame.addShapeToFrame(shape);\n\n nodeMap.set(n.id, { shape, x: nx, y: ny, width: nw, height: nh, centerX: cx, centerY: cy });\n }\n\n // \u2500\u2500 Edges \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n for (const e of edges) {\n const fromNode = nodeMap.get(e.from);\n const toNode = nodeMap.get(e.to);\n if (!fromNode || !toNode) continue;\n\n // Connect from the source center to the target center \u2014 autoAttach\n // will snap each endpoint to the appropriate edge of the shape.\n const sp = { x: fromNode.centerX, y: fromNode.centerY };\n const ep = { x: toNode.centerX, y: toNode.centerY };\n\n const directed = e.directed !== false;\n const style = e.style || 'normal';\n const isThick = style === 'thick';\n const isDotted = style === 'dotted';\n\n const opts = {\n stroke: e.stroke || edgeStrokeColor(),\n strokeWidth: isThick ? 3 : 1.5,\n roughness: 1,\n strokeDasharray: isDotted ? '5 3' : '',\n label: e.label || '',\n labelColor: e.labelColor || edgeStrokeColor(),\n };\n\n let connector = null;\n try {\n if (directed && window.Arrow) {\n connector = new window.Arrow(sp, ep, opts);\n } else if (window.Line) {\n connector = new window.Line(sp, ep, opts);\n } else if (window.Arrow) {\n connector = new window.Arrow(sp, ep, opts);\n }\n } catch (err) {\n console.warn('[FlowchartRenderer] Edge creation failed:', e, err);\n continue;\n }\n if (!connector) continue;\n\n window.shapes.push(connector);\n if (window.pushCreateAction) window.pushCreateAction(connector);\n frame.addShapeToFrame(connector);\n\n // Wire arrow endpoints into the source/target shapes so moving a\n // node drags its connections along. window.__autoAttach is set up\n // by AIRenderer.initAIRenderer() during engine init.\n if (directed && connector.shapeName === 'arrow' && typeof window.__autoAttach === 'function') {\n try {\n window.__autoAttach(connector, fromNode.shape, true, sp);\n window.__autoAttach(connector, toNode.shape, false, ep);\n } catch (err) {\n console.warn('[FlowchartRenderer] autoAttach failed:', err);\n }\n }\n }\n\n // Select the first node so the user has feedback that something\n // landed. Selecting a child (not the frame) reinforces the\n // \"independent shapes inside a frame\" model.\n const first = nodeMap.values().next().value;\n if (first) {\n window.currentShape = first.shape;\n if (typeof first.shape.selectShape === 'function') first.shape.selectShape();\n }\n\n return true;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["hw", "hh"]
7
+ }
@@ -14,6 +14,27 @@ var TOP_MARGIN = 30;
14
14
  var BOTTOM_MARGIN = 30;
15
15
  var SIDE_MARGIN = 40;
16
16
  var FONT_FAMILY = "lixFont, sans-serif";
17
+ function themeColors() {
18
+ const isDark = typeof document !== "undefined" && document.body && document.body.classList.contains("theme-dark");
19
+ if (isDark) return THEME;
20
+ return {
21
+ bg: "#fbfaf6",
22
+ participantBg: "#ffffff",
23
+ participantBorder: "#9c9c9c",
24
+ participantText: "#38384e",
25
+ lifeline: "#b0b0b8",
26
+ messageLine: "#62627a",
27
+ messageDash: "#888",
28
+ messageText: "#38384e",
29
+ noteBg: "#fffce0",
30
+ noteBorder: "#c0b870",
31
+ noteText: "#5e5230",
32
+ blockBg: "rgba(80,80,120,0.08)",
33
+ blockBorder: "#9c9c9c",
34
+ blockLabel: "#62627a",
35
+ crossColor: "#c2483a"
36
+ };
37
+ }
17
38
  var THEME = {
18
39
  bg: "#1e1e28",
19
40
  participantBg: "#232329",
@@ -272,7 +293,8 @@ function renderSequenceOnCanvas(diagram) {
272
293
  console.error("[SequenceRenderer] window.Frame missing \u2014 cannot wrap diagram");
273
294
  return false;
274
295
  }
275
- const PADDING = 24;
296
+ const PADDING = 60;
297
+ const TK = themeColors();
276
298
  const frameTitle = diagram.title || "Sequence diagram";
277
299
  const frame = new window.Frame(
278
300
  ox - PADDING,
@@ -280,7 +302,7 @@ function renderSequenceOnCanvas(diagram) {
280
302
  totalWidth + PADDING * 2,
281
303
  totalHeight + PADDING * 2,
282
304
  {
283
- stroke: "#888",
305
+ stroke: TK.blockBorder,
284
306
  strokeWidth: 1,
285
307
  fill: "transparent",
286
308
  opacity: 0.7,
@@ -299,12 +321,13 @@ function renderSequenceOnCanvas(diagram) {
299
321
  const bx = cx - PARTICIPANT_W / 2;
300
322
  try {
301
323
  const topBox = new window.Rectangle(bx, TOP_MARGIN + oy, PARTICIPANT_W, PARTICIPANT_H, {
302
- stroke: THEME.participantBorder,
324
+ stroke: TK.participantBorder,
303
325
  strokeWidth: 1.5,
304
- fill: THEME.participantBg,
326
+ fill: TK.participantBg,
305
327
  fillStyle: "solid",
306
328
  roughness: 1,
307
- label: p.name
329
+ label: p.name,
330
+ labelColor: TK.participantText
308
331
  });
309
332
  window.shapes.push(topBox);
310
333
  if (window.pushCreateAction) window.pushCreateAction(topBox);
@@ -314,7 +337,7 @@ function renderSequenceOnCanvas(diagram) {
314
337
  { x: cx, y: topBoxBottom + oy },
315
338
  { x: cx, y: bottomBoxTop + oy },
316
339
  {
317
- stroke: THEME.lifeline,
340
+ stroke: TK.lifeline,
318
341
  strokeWidth: 1,
319
342
  strokeDasharray: "6 4",
320
343
  roughness: 0
@@ -325,12 +348,13 @@ function renderSequenceOnCanvas(diagram) {
325
348
  frame.addShapeToFrame(lifeline);
326
349
  created.push(lifeline);
327
350
  const bottomBox = new window.Rectangle(bx, bottomBoxTop + oy, PARTICIPANT_W, PARTICIPANT_H, {
328
- stroke: THEME.participantBorder,
351
+ stroke: TK.participantBorder,
329
352
  strokeWidth: 1.5,
330
- fill: THEME.participantBg,
353
+ fill: TK.participantBg,
331
354
  fillStyle: "solid",
332
355
  roughness: 1,
333
- label: p.name
356
+ label: p.name,
357
+ labelColor: TK.participantText
334
358
  });
335
359
  window.shapes.push(bottomBox);
336
360
  if (window.pushCreateAction) window.pushCreateAction(bottomBox);
@@ -352,11 +376,12 @@ function renderSequenceOnCanvas(diagram) {
352
376
  const labelText = m.number ? `${m.number}. ${m.text}` : m.text;
353
377
  const isCross = !!m.cross && m.arrowHead === "cross";
354
378
  const opts = {
355
- stroke: THEME.messageLine,
379
+ stroke: TK.messageLine,
356
380
  strokeWidth: 1.5,
357
381
  roughness: 0,
358
382
  strokeDasharray: m.solid ? "" : "6 4",
359
- label: labelText || ""
383
+ label: labelText || "",
384
+ labelColor: TK.messageText
360
385
  };
361
386
  try {
362
387
  const sp = { x: fromCx, y };
@@ -384,4 +409,4 @@ export {
384
409
  renderSequencePreviewSVG,
385
410
  renderSequenceSVG
386
411
  };
387
- //# sourceMappingURL=MermaidSequenceRenderer-HPLHY5II.js.map
412
+ //# sourceMappingURL=MermaidSequenceRenderer-OF4JK77D.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/MermaidSequenceRenderer.js"],
4
+ "sourcesContent": ["/* eslint-disable */\n/**\n * MermaidSequenceRenderer - Renders parsed sequence diagrams as high-quality SVG.\n *\n * One renderer for both preview and canvas \u2014 ensures they always match.\n * The canvas renderer inserts the SVG into a frame; elements inside are\n * individually editable (each participant box, message label, note, etc.\n * is its own SVG group with data attributes for the editor).\n *\n * Design follows the reference image: dark theme, clean lines,\n * participant boxes at top and bottom, dashed lifelines, arrow styles.\n */\n\nimport { parseSequenceDiagram } from './MermaidSequenceParser.js';\n\n// Layout constants\nconst PARTICIPANT_W = 100;\nconst PARTICIPANT_H = 36;\nconst PARTICIPANT_GAP = 140;\nconst MSG_ROW_HEIGHT = 50;\nconst NOTE_PAD = 10;\nconst NOTE_MAX_W = 160;\nconst TOP_MARGIN = 30;\nconst BOTTOM_MARGIN = 30;\nconst SIDE_MARGIN = 40;\nconst FONT_FAMILY = 'lixFont, sans-serif';\nconst CODE_FONT = 'lixCode, monospace';\n\n// Issue #38 follow-up: theme-aware palette. The on-canvas renderer reads\n// `themeColors()` at draw time so a single render call gets whichever\n// palette is active. The dark THEME object below is kept for the SVG-\n// string preview path (`renderSequenceSVG`), which is rendered inside\n// the modal's preview pane.\nfunction themeColors() {\n const isDark = typeof document !== 'undefined'\n && document.body\n && document.body.classList.contains('theme-dark');\n if (isDark) return THEME;\n return {\n bg: '#fbfaf6',\n participantBg: '#ffffff',\n participantBorder: '#9c9c9c',\n participantText: '#38384e',\n lifeline: '#b0b0b8',\n messageLine: '#62627a',\n messageDash: '#888',\n messageText: '#38384e',\n noteBg: '#fffce0',\n noteBorder: '#c0b870',\n noteText: '#5e5230',\n blockBg: 'rgba(80,80,120,0.08)',\n blockBorder: '#9c9c9c',\n blockLabel: '#62627a',\n crossColor: '#c2483a',\n };\n}\n\n// Theme colors (dark theme \u2014 preview/SVG-string path).\nconst THEME = {\n bg: '#1e1e28',\n participantBg: '#232329',\n participantBorder: '#555',\n participantText: '#e8e8ee',\n lifeline: '#444',\n messageLine: '#888',\n messageDash: '#666',\n messageText: '#e0e0e0',\n noteBg: '#3a3520',\n noteBorder: '#665e30',\n noteText: '#d4c870',\n blockBg: 'rgba(80,80,120,0.12)',\n blockBorder: '#555',\n blockLabel: '#a0a0b0',\n crossColor: '#e74c3c',\n};\n\nfunction escapeXml(str) {\n return String(str)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n/**\n * Measure approximate text width (since we can't use DOM measurement in pure SVG generation).\n * Uses a rough character-width heuristic.\n */\nfunction measureText(text, fontSize) {\n const avgCharWidth = fontSize * 0.55;\n return text.length * avgCharWidth;\n}\n\n/**\n * Word-wrap text into lines that fit within maxWidth.\n */\nfunction wrapText(text, fontSize, maxWidth) {\n // Handle <br/> tags\n const segments = text.split(/<br\\s*\\/?>/i);\n const lines = [];\n for (const segment of segments) {\n const words = segment.split(/\\s+/);\n let currentLine = '';\n for (const word of words) {\n const testLine = currentLine ? currentLine + ' ' + word : word;\n if (measureText(testLine, fontSize) > maxWidth && currentLine) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n currentLine = testLine;\n }\n }\n if (currentLine) lines.push(currentLine);\n }\n return lines.length > 0 ? lines : [''];\n}\n\n/**\n * Render a parsed sequence diagram to SVG markup.\n *\n * @param {Object} diagram - Parsed from parseSequenceDiagram()\n * @param {Object} opts - { width?, fitToContent? }\n * @returns {string} SVG markup string\n */\nexport function renderSequenceSVG(diagram, opts = {}) {\n if (!diagram || diagram.type !== 'sequenceDiagram') return '';\n\n const participants = diagram.participants;\n const messages = diagram.messages;\n const notes = diagram.notes;\n const blocks = diagram.blocks || [];\n\n const pCount = participants.length;\n if (pCount === 0) return '';\n\n // Build participant index map\n const pIndex = new Map();\n participants.forEach((p, i) => pIndex.set(p.name, i));\n\n // Calculate total width\n const contentWidth = (pCount - 1) * PARTICIPANT_GAP + PARTICIPANT_W;\n const totalWidth = opts.width || Math.max(contentWidth + SIDE_MARGIN * 2, 400);\n const startX = (totalWidth - contentWidth) / 2;\n\n // Participant X centers\n const pCenters = participants.map((_, i) => startX + i * PARTICIPANT_GAP + PARTICIPANT_W / 2);\n\n // Pre-calculate note heights to account for row expansion\n const noteAtMsg = new Map(); // msgIndex -> [{note, height}]\n for (const note of notes) {\n const fontSize = 11;\n const lines = wrapText(note.text, fontSize, NOTE_MAX_W - NOTE_PAD * 2);\n const h = lines.length * (fontSize + 4) + NOTE_PAD * 2;\n if (!noteAtMsg.has(note.atMessage)) noteAtMsg.set(note.atMessage, []);\n noteAtMsg.get(note.atMessage).push({ ...note, lines, height: h });\n }\n\n // Calculate message Y positions (accounting for notes that expand rows)\n const topBoxBottom = TOP_MARGIN + PARTICIPANT_H;\n let currentY = topBoxBottom + 30; // gap after top participant boxes\n\n const msgYPositions = [];\n for (let mi = 0; mi < messages.length; mi++) {\n // Check if notes appear before this message\n const notesBefore = noteAtMsg.get(mi);\n if (notesBefore) {\n const maxNoteH = Math.max(...notesBefore.map(n => n.height));\n currentY += maxNoteH + 10;\n }\n msgYPositions.push(currentY);\n currentY += MSG_ROW_HEIGHT;\n }\n\n // Notes after last message\n const notesAfterLast = noteAtMsg.get(messages.length);\n if (notesAfterLast) {\n const maxNoteH = Math.max(...notesAfterLast.map(n => n.height));\n currentY += maxNoteH + 10;\n }\n\n const bottomBoxTop = currentY + 20;\n const totalHeight = bottomBoxTop + PARTICIPANT_H + BOTTOM_MARGIN;\n\n // Start building SVG\n let svg = '';\n const defs = [];\n\n // Arrow markers\n defs.push(`<marker id=\"seq-arrow-open\" markerWidth=\"10\" markerHeight=\"7\" refX=\"9\" refY=\"3.5\" orient=\"auto\">\n <polyline points=\"1,1 9,3.5 1,6\" fill=\"none\" stroke=\"${THEME.messageLine}\" stroke-width=\"1.5\" stroke-linejoin=\"round\" />\n </marker>`);\n defs.push(`<marker id=\"seq-arrow-filled\" markerWidth=\"10\" markerHeight=\"7\" refX=\"9\" refY=\"3.5\" orient=\"auto\">\n <polygon points=\"1,1 9,3.5 1,6\" fill=\"${THEME.messageLine}\" stroke=\"none\" />\n </marker>`);\n\n // Background\n svg += `<rect x=\"0\" y=\"0\" width=\"${totalWidth}\" height=\"${totalHeight}\" fill=\"${THEME.bg}\" rx=\"8\" />`;\n\n // Title\n if (diagram.title) {\n svg += `<text x=\"${totalWidth / 2}\" y=\"${TOP_MARGIN - 8}\" text-anchor=\"middle\" fill=\"${THEME.participantText}\" font-size=\"14\" font-family=\"${FONT_FAMILY}\" font-weight=\"600\">${escapeXml(diagram.title)}</text>`;\n }\n\n // --- Lifelines (dashed vertical lines) ---\n for (let pi = 0; pi < pCount; pi++) {\n const cx = pCenters[pi];\n svg += `<line x1=\"${cx}\" y1=\"${topBoxBottom}\" x2=\"${cx}\" y2=\"${bottomBoxTop}\" stroke=\"${THEME.lifeline}\" stroke-width=\"1\" stroke-dasharray=\"6 4\" />`;\n }\n\n // --- Participant boxes (top) ---\n for (let pi = 0; pi < pCount; pi++) {\n const cx = pCenters[pi];\n const bx = cx - PARTICIPANT_W / 2;\n const by = TOP_MARGIN;\n svg += `<g data-seq-type=\"participant\" data-seq-id=\"${escapeXml(participants[pi].name)}\" data-seq-pos=\"top\">`;\n svg += `<rect x=\"${bx}\" y=\"${by}\" width=\"${PARTICIPANT_W}\" height=\"${PARTICIPANT_H}\" rx=\"4\" fill=\"${THEME.participantBg}\" stroke=\"${THEME.participantBorder}\" stroke-width=\"1.5\" />`;\n svg += `<text x=\"${cx}\" y=\"${by + PARTICIPANT_H / 2 + 1}\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"${THEME.participantText}\" font-size=\"13\" font-family=\"${FONT_FAMILY}\">${escapeXml(participants[pi].name)}</text>`;\n svg += `</g>`;\n }\n\n // --- Participant boxes (bottom) ---\n for (let pi = 0; pi < pCount; pi++) {\n const cx = pCenters[pi];\n const bx = cx - PARTICIPANT_W / 2;\n const by = bottomBoxTop;\n svg += `<g data-seq-type=\"participant\" data-seq-id=\"${escapeXml(participants[pi].name)}\" data-seq-pos=\"bottom\">`;\n svg += `<rect x=\"${bx}\" y=\"${by}\" width=\"${PARTICIPANT_W}\" height=\"${PARTICIPANT_H}\" rx=\"4\" fill=\"${THEME.participantBg}\" stroke=\"${THEME.participantBorder}\" stroke-width=\"1.5\" />`;\n svg += `<text x=\"${cx}\" y=\"${by + PARTICIPANT_H / 2 + 1}\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"${THEME.participantText}\" font-size=\"13\" font-family=\"${FONT_FAMILY}\">${escapeXml(participants[pi].name)}</text>`;\n svg += `</g>`;\n }\n\n // --- Blocks (alt/loop/opt etc.) ---\n for (const block of blocks) {\n const startY = block.startMsg < msgYPositions.length\n ? msgYPositions[block.startMsg] - 20\n : topBoxBottom + 20;\n const endY = block.endMsg <= msgYPositions.length\n ? (block.endMsg < msgYPositions.length ? msgYPositions[block.endMsg] - 10 : currentY)\n : currentY;\n\n const blockX = startX - 15;\n const blockW = contentWidth + 30;\n\n svg += `<g data-seq-type=\"block\" data-block-type=\"${block.type}\">`;\n svg += `<rect x=\"${blockX}\" y=\"${startY}\" width=\"${blockW}\" height=\"${endY - startY}\" rx=\"4\" fill=\"${THEME.blockBg}\" stroke=\"${THEME.blockBorder}\" stroke-width=\"1\" stroke-dasharray=\"4 2\" />`;\n // Type label in top-left corner\n svg += `<rect x=\"${blockX}\" y=\"${startY}\" width=\"${measureText(block.type, 10) + 12}\" height=\"18\" rx=\"3\" fill=\"${THEME.blockBorder}\" />`;\n svg += `<text x=\"${blockX + 6}\" y=\"${startY + 12}\" fill=\"${THEME.bg}\" font-size=\"10\" font-family=\"${FONT_FAMILY}\" font-weight=\"600\">${escapeXml(block.type)}</text>`;\n // Condition label\n if (block.label) {\n svg += `<text x=\"${blockX + measureText(block.type, 10) + 20}\" y=\"${startY + 12}\" fill=\"${THEME.blockLabel}\" font-size=\"10\" font-family=\"${FONT_FAMILY}\" font-style=\"italic\">[${escapeXml(block.label)}]</text>`;\n }\n\n // Section dividers (else sections)\n for (let si = 1; si < block.sections.length; si++) {\n const section = block.sections[si];\n const secY = section.startMsg < msgYPositions.length\n ? msgYPositions[section.startMsg] - 15\n : endY - 10;\n svg += `<line x1=\"${blockX}\" y1=\"${secY}\" x2=\"${blockX + blockW}\" y2=\"${secY}\" stroke=\"${THEME.blockBorder}\" stroke-width=\"1\" stroke-dasharray=\"4 2\" />`;\n if (section.label) {\n svg += `<text x=\"${blockX + 8}\" y=\"${secY + 13}\" fill=\"${THEME.blockLabel}\" font-size=\"10\" font-family=\"${FONT_FAMILY}\" font-style=\"italic\">[${escapeXml(section.label)}]</text>`;\n }\n }\n svg += `</g>`;\n }\n\n // --- Messages ---\n for (let mi = 0; mi < messages.length; mi++) {\n const msg = messages[mi];\n const y = msgYPositions[mi];\n const fromIdx = pIndex.get(msg.from);\n const toIdx = pIndex.get(msg.to);\n if (fromIdx === undefined || toIdx === undefined) continue;\n\n const fromX = pCenters[fromIdx];\n const toX = pCenters[toIdx];\n const isSelf = fromIdx === toIdx;\n\n svg += `<g data-seq-type=\"message\" data-seq-idx=\"${mi}\">`;\n\n if (isSelf) {\n // Self-message: loop arrow to the right\n const loopW = 40;\n const loopH = 25;\n const dash = msg.solid ? '' : ` stroke-dasharray=\"6 3\"`;\n svg += `<path d=\"M ${fromX} ${y} L ${fromX + loopW} ${y} L ${fromX + loopW} ${y + loopH} L ${fromX + 4} ${y + loopH}\" fill=\"none\" stroke=\"${THEME.messageLine}\" stroke-width=\"1.5\"${dash} marker-end=\"url(#seq-arrow-open)\" />`;\n if (msg.text) {\n svg += `<text x=\"${fromX + loopW + 6}\" y=\"${y + loopH / 2 + 1}\" dominant-baseline=\"central\" fill=\"${THEME.messageText}\" font-size=\"12\" font-family=\"${FONT_FAMILY}\">${escapeXml(msg.text)}</text>`;\n }\n } else {\n const isLeft = toX < fromX;\n const lineEndX = isLeft ? toX + 4 : toX - 4;\n const dash = msg.solid ? '' : ` stroke-dasharray=\"6 3\"`;\n\n // Arrow line\n const markerId = msg.arrowHead === 'filled' ? 'seq-arrow-filled' : 'seq-arrow-open';\n\n if (msg.cross) {\n // Cross at end (lost message)\n svg += `<line x1=\"${fromX}\" y1=\"${y}\" x2=\"${lineEndX}\" y2=\"${y}\" stroke=\"${THEME.messageLine}\" stroke-width=\"1.5\"${dash} />`;\n // X mark\n const xSize = 6;\n svg += `<line x1=\"${toX - xSize}\" y1=\"${y - xSize}\" x2=\"${toX + xSize}\" y2=\"${y + xSize}\" stroke=\"${THEME.crossColor}\" stroke-width=\"2\" />`;\n svg += `<line x1=\"${toX + xSize}\" y1=\"${y - xSize}\" x2=\"${toX - xSize}\" y2=\"${y + xSize}\" stroke=\"${THEME.crossColor}\" stroke-width=\"2\" />`;\n } else {\n svg += `<line x1=\"${fromX}\" y1=\"${y}\" x2=\"${lineEndX}\" y2=\"${y}\" stroke=\"${THEME.messageLine}\" stroke-width=\"1.5\"${dash} marker-end=\"url(#${markerId})\" />`;\n }\n\n // Message text (centered above the line)\n if (msg.text) {\n const midX = (fromX + toX) / 2;\n const textContent = msg.number ? `${msg.number}. ${msg.text}` : msg.text;\n svg += `<text x=\"${midX}\" y=\"${y - 8}\" text-anchor=\"middle\" fill=\"${THEME.messageText}\" font-size=\"12\" font-family=\"${FONT_FAMILY}\">${escapeXml(textContent)}</text>`;\n }\n }\n\n svg += `</g>`;\n }\n\n // --- Notes ---\n for (const [msgIdx, noteGroup] of noteAtMsg.entries()) {\n const baseY = msgIdx < msgYPositions.length\n ? msgYPositions[msgIdx] - 15\n : (msgIdx > 0 ? msgYPositions[msgIdx - 1] + MSG_ROW_HEIGHT - 15 : topBoxBottom + 30);\n\n for (const note of noteGroup) {\n const targetIdxs = note.targets.map(t => pIndex.get(t)).filter(i => i !== undefined);\n if (targetIdxs.length === 0) continue;\n\n const fontSize = 11;\n const lineH = fontSize + 4;\n const noteH = note.lines.length * lineH + NOTE_PAD * 2;\n const noteW = Math.min(\n NOTE_MAX_W,\n Math.max(...note.lines.map(l => measureText(l, fontSize))) + NOTE_PAD * 2 + 10\n );\n\n let noteX;\n if (note.position === 'left of') {\n const px = pCenters[targetIdxs[0]];\n noteX = px - PARTICIPANT_W / 2 - noteW - 8;\n } else if (note.position === 'right of') {\n const px = pCenters[targetIdxs[0]];\n noteX = px + PARTICIPANT_W / 2 + 8;\n } else {\n // 'over' - center between targets\n if (targetIdxs.length >= 2) {\n const minP = Math.min(...targetIdxs);\n const maxP = Math.max(...targetIdxs);\n const center = (pCenters[minP] + pCenters[maxP]) / 2;\n noteX = center - noteW / 2;\n } else {\n noteX = pCenters[targetIdxs[0]] - noteW / 2;\n }\n }\n\n const noteY = baseY - noteH;\n\n svg += `<g data-seq-type=\"note\">`;\n svg += `<rect x=\"${noteX}\" y=\"${noteY}\" width=\"${noteW}\" height=\"${noteH}\" rx=\"3\" fill=\"${THEME.noteBg}\" stroke=\"${THEME.noteBorder}\" stroke-width=\"1\" />`;\n // Render wrapped text lines\n note.lines.forEach((line, li) => {\n svg += `<text x=\"${noteX + NOTE_PAD}\" y=\"${noteY + NOTE_PAD + li * lineH + fontSize}\" fill=\"${THEME.noteText}\" font-size=\"${fontSize}\" font-family=\"${FONT_FAMILY}\">${escapeXml(line)}</text>`;\n });\n svg += `</g>`;\n }\n }\n\n // Build final SVG\n const defsStr = defs.length > 0 ? `<defs>${defs.join('')}</defs>` : '';\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${totalWidth}\" height=\"${totalHeight}\" viewBox=\"0 0 ${totalWidth} ${totalHeight}\">${defsStr}${svg}</svg>`;\n}\n\n/**\n * Generate preview SVG for the modal (fixed width).\n */\nexport function renderSequencePreviewSVG(diagram) {\n return renderSequenceSVG(diagram, { width: 620 });\n}\n\n/**\n * Parse raw mermaid source and render sequence SVG.\n * Returns SVG string or empty string if not a sequence diagram.\n */\nexport function parseAndRenderSequence(src) {\n const diagram = parseSequenceDiagram(src);\n if (!diagram) return '';\n return renderSequenceSVG(diagram);\n}\n\n/**\n * Render a sequence diagram onto the canvas as a real engine `Frame`\n * containing independent shapes \u2014 top + bottom participant boxes,\n * dashed lifelines, and a real Arrow (or Line for `--x`/`-x`) per\n * message. Each child is fully independent for click / drag / resize;\n * the Frame's `_diagramType` marker makes Frame.destroy() pull the\n * children along on delete, so the diagram still behaves as one\n * logical unit when discarded.\n *\n * Issue #34 bug #3 (follow-up to #24 per-actor split): drops the shared\n * `groupId` glue so clicking one shape selects only that shape.\n *\n * Notes and block-frames (alt/opt/loop) are skipped for now \u2014 they'd\n * either need their own shape types or a richer label model. Self-\n * messages are also skipped (would need a curved arrow).\n */\nexport function renderSequenceOnCanvas(diagram) {\n if (!diagram || diagram.type !== 'sequenceDiagram') return false;\n if (!window.svg || !window.Rectangle || !window.Line || !window.Arrow) {\n console.error('[SequenceRenderer] Engine not initialized (Rectangle / Line / Arrow missing)');\n return false;\n }\n\n const participants = diagram.participants || [];\n const messages = diagram.messages || [];\n if (participants.length === 0) return false;\n\n // Mirror the layout math from renderSequenceSVG so the canvas layout\n // matches the modal preview.\n const pCount = participants.length;\n const contentWidth = (pCount - 1) * PARTICIPANT_GAP + PARTICIPANT_W;\n const totalWidth = Math.max(contentWidth + SIDE_MARGIN * 2, 400);\n const startX = (totalWidth - contentWidth) / 2;\n const pCenters = participants.map((_, i) => startX + i * PARTICIPANT_GAP + PARTICIPANT_W / 2);\n\n const topBoxBottom = TOP_MARGIN + PARTICIPANT_H;\n const msgYPositions = [];\n let currentY = topBoxBottom + 30;\n for (let mi = 0; mi < messages.length; mi++) {\n msgYPositions.push(currentY);\n currentY += MSG_ROW_HEIGHT;\n }\n const bottomBoxTop = currentY + 20;\n const totalHeight = bottomBoxTop + PARTICIPANT_H + BOTTOM_MARGIN;\n\n // Centre the diagram on the current viewport so the user sees it\n // right where they invoked the renderer.\n const vb = window.currentViewBox || { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight };\n const ox = vb.x + vb.width / 2 - totalWidth / 2;\n const oy = vb.y + vb.height / 2 - totalHeight / 2;\n\n // \u2500\u2500 Wrapper frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Issue #34 bug #3: drop the shared groupId glue. Each child is\n // independent for click / drag / resize. The Frame's `_diagramType`\n // marker makes Frame.destroy() pull the children along on delete,\n // so the diagram still behaves as one logical unit when discarded.\n if (!window.Frame) {\n console.error('[SequenceRenderer] window.Frame missing \u2014 cannot wrap diagram');\n return false;\n }\n // Padding bumped 24 \u2192 60 so participant labels + message text near\n // the frame's edges stay inside on the new wider light canvas.\n const PADDING = 60;\n const TK = themeColors();\n const frameTitle = diagram.title || 'Sequence diagram';\n const frame = new window.Frame(\n ox - PADDING,\n oy - PADDING,\n totalWidth + PADDING * 2,\n totalHeight + PADDING * 2,\n {\n stroke: TK.blockBorder,\n strokeWidth: 1,\n fill: 'transparent',\n opacity: 0.7,\n frameName: frameTitle,\n }\n );\n frame._diagramType = 'mermaid-sequence';\n window.shapes.push(frame);\n if (window.pushCreateAction) window.pushCreateAction(frame);\n\n const created = [];\n\n // \u2500\u2500 Participants: top box + lifeline (and bottom box) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const pIndex = new Map();\n for (let pi = 0; pi < pCount; pi++) {\n const p = participants[pi];\n pIndex.set(p.name, pi);\n const cx = pCenters[pi] + ox;\n const bx = cx - PARTICIPANT_W / 2;\n\n try {\n // Top participant box\n const topBox = new window.Rectangle(bx, TOP_MARGIN + oy, PARTICIPANT_W, PARTICIPANT_H, {\n stroke: TK.participantBorder,\n strokeWidth: 1.5,\n fill: TK.participantBg,\n fillStyle: 'solid',\n roughness: 1,\n label: p.name,\n labelColor: TK.participantText,\n });\n window.shapes.push(topBox);\n if (window.pushCreateAction) window.pushCreateAction(topBox);\n frame.addShapeToFrame(topBox);\n created.push(topBox);\n\n // Lifeline (dashed vertical line spanning the diagram height)\n const lifeline = new window.Line(\n { x: cx, y: topBoxBottom + oy },\n { x: cx, y: bottomBoxTop + oy },\n {\n stroke: TK.lifeline,\n strokeWidth: 1,\n strokeDasharray: '6 4',\n roughness: 0,\n }\n );\n window.shapes.push(lifeline);\n if (window.pushCreateAction) window.pushCreateAction(lifeline);\n frame.addShapeToFrame(lifeline);\n created.push(lifeline);\n\n // Bottom participant box (mirrors top \u2014 Mermaid convention)\n const bottomBox = new window.Rectangle(bx, bottomBoxTop + oy, PARTICIPANT_W, PARTICIPANT_H, {\n stroke: TK.participantBorder,\n strokeWidth: 1.5,\n fill: TK.participantBg,\n fillStyle: 'solid',\n roughness: 1,\n label: p.name,\n labelColor: TK.participantText,\n });\n window.shapes.push(bottomBox);\n if (window.pushCreateAction) window.pushCreateAction(bottomBox);\n frame.addShapeToFrame(bottomBox);\n created.push(bottomBox);\n } catch (err) {\n console.warn('[SequenceRenderer] Participant creation failed:', p.name, err);\n }\n }\n\n // \u2500\u2500 Messages: arrow (or line for --x style) per row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n for (let mi = 0; mi < messages.length; mi++) {\n const m = messages[mi];\n const fromI = pIndex.get(m.from);\n const toI = pIndex.get(m.to);\n if (fromI == null || toI == null) continue;\n if (fromI === toI) continue; // skip self-messages (v1 limitation)\n\n const fromCx = pCenters[fromI] + ox;\n const toCx = pCenters[toI] + ox;\n const y = msgYPositions[mi] + oy;\n\n const labelText = m.number ? `${m.number}. ${m.text}` : m.text;\n\n // Solid vs dashed (sync vs async response). `cross` style (-x)\n // would render as a line with an X at the head \u2014 fall back to a\n // line for that, arrow otherwise.\n const isCross = !!m.cross && m.arrowHead === 'cross';\n const opts = {\n stroke: TK.messageLine,\n strokeWidth: 1.5,\n roughness: 0,\n strokeDasharray: m.solid ? '' : '6 4',\n label: labelText || '',\n labelColor: TK.messageText,\n };\n\n try {\n const sp = { x: fromCx, y };\n const ep = { x: toCx, y };\n const connector = isCross\n ? new window.Line(sp, ep, opts)\n : new window.Arrow(sp, ep, opts);\n window.shapes.push(connector);\n if (window.pushCreateAction) window.pushCreateAction(connector);\n frame.addShapeToFrame(connector);\n created.push(connector);\n } catch (err) {\n console.warn('[SequenceRenderer] Message creation failed:', m, err);\n }\n }\n\n // Auto-select the first node so the user has feedback that the\n // diagram landed. Selecting a child (not the frame) reinforces the\n // \"independent shapes inside a frame\" model from issue #34 bug #3.\n const first = created[0];\n if (first) {\n window.currentShape = first;\n if (typeof first.selectShape === 'function') first.selectShape();\n }\n\n console.log(`[SequenceRenderer] Done: ${pCount} participants, ${messages.length} messages`);\n return true;\n}\n\n"],
5
+ "mappings": ";;;;;;AAgBA,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AACxB,IAAM,iBAAiB;AACvB,IAAM,WAAW;AACjB,IAAM,aAAa;AACnB,IAAM,aAAa;AACnB,IAAM,gBAAgB;AACtB,IAAM,cAAc;AACpB,IAAM,cAAc;AAQpB,SAAS,cAAc;AACnB,QAAM,SAAS,OAAO,aAAa,eAC5B,SAAS,QACT,SAAS,KAAK,UAAU,SAAS,YAAY;AACpD,MAAI,OAAQ,QAAO;AACnB,SAAO;AAAA,IACH,IAAI;AAAA,IACJ,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,SAAS;AAAA,IACT,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,YAAY;AAAA,EAChB;AACJ;AAGA,IAAM,QAAQ;AAAA,EACV,IAAI;AAAA,EACJ,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,SAAS;AAAA,EACT,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,YAAY;AAChB;AAEA,SAAS,UAAU,KAAK;AACpB,SAAO,OAAO,GAAG,EACZ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ;AAC/B;AAMA,SAAS,YAAY,MAAM,UAAU;AACjC,QAAM,eAAe,WAAW;AAChC,SAAO,KAAK,SAAS;AACzB;AAKA,SAAS,SAAS,MAAM,UAAU,UAAU;AAExC,QAAM,WAAW,KAAK,MAAM,aAAa;AACzC,QAAM,QAAQ,CAAC;AACf,aAAW,WAAW,UAAU;AAC5B,UAAM,QAAQ,QAAQ,MAAM,KAAK;AACjC,QAAI,cAAc;AAClB,eAAW,QAAQ,OAAO;AACtB,YAAM,WAAW,cAAc,cAAc,MAAM,OAAO;AAC1D,UAAI,YAAY,UAAU,QAAQ,IAAI,YAAY,aAAa;AAC3D,cAAM,KAAK,WAAW;AACtB,sBAAc;AAAA,MAClB,OAAO;AACH,sBAAc;AAAA,MAClB;AAAA,IACJ;AACA,QAAI,YAAa,OAAM,KAAK,WAAW;AAAA,EAC3C;AACA,SAAO,MAAM,SAAS,IAAI,QAAQ,CAAC,EAAE;AACzC;AASO,SAAS,kBAAkB,SAAS,OAAO,CAAC,GAAG;AAClD,MAAI,CAAC,WAAW,QAAQ,SAAS,kBAAmB,QAAO;AAE3D,QAAM,eAAe,QAAQ;AAC7B,QAAM,WAAW,QAAQ;AACzB,QAAM,QAAQ,QAAQ;AACtB,QAAM,SAAS,QAAQ,UAAU,CAAC;AAElC,QAAM,SAAS,aAAa;AAC5B,MAAI,WAAW,EAAG,QAAO;AAGzB,QAAM,SAAS,oBAAI,IAAI;AACvB,eAAa,QAAQ,CAAC,GAAG,MAAM,OAAO,IAAI,EAAE,MAAM,CAAC,CAAC;AAGpD,QAAM,gBAAgB,SAAS,KAAK,kBAAkB;AACtD,QAAM,aAAa,KAAK,SAAS,KAAK,IAAI,eAAe,cAAc,GAAG,GAAG;AAC7E,QAAM,UAAU,aAAa,gBAAgB;AAG7C,QAAM,WAAW,aAAa,IAAI,CAAC,GAAG,MAAM,SAAS,IAAI,kBAAkB,gBAAgB,CAAC;AAG5F,QAAM,YAAY,oBAAI,IAAI;AAC1B,aAAW,QAAQ,OAAO;AACtB,UAAM,WAAW;AACjB,UAAM,QAAQ,SAAS,KAAK,MAAM,UAAU,aAAa,WAAW,CAAC;AACrE,UAAM,IAAI,MAAM,UAAU,WAAW,KAAK,WAAW;AACrD,QAAI,CAAC,UAAU,IAAI,KAAK,SAAS,EAAG,WAAU,IAAI,KAAK,WAAW,CAAC,CAAC;AACpE,cAAU,IAAI,KAAK,SAAS,EAAE,KAAK,EAAE,GAAG,MAAM,OAAO,QAAQ,EAAE,CAAC;AAAA,EACpE;AAGA,QAAM,eAAe,aAAa;AAClC,MAAI,WAAW,eAAe;AAE9B,QAAM,gBAAgB,CAAC;AACvB,WAAS,KAAK,GAAG,KAAK,SAAS,QAAQ,MAAM;AAEzC,UAAM,cAAc,UAAU,IAAI,EAAE;AACpC,QAAI,aAAa;AACb,YAAM,WAAW,KAAK,IAAI,GAAG,YAAY,IAAI,OAAK,EAAE,MAAM,CAAC;AAC3D,kBAAY,WAAW;AAAA,IAC3B;AACA,kBAAc,KAAK,QAAQ;AAC3B,gBAAY;AAAA,EAChB;AAGA,QAAM,iBAAiB,UAAU,IAAI,SAAS,MAAM;AACpD,MAAI,gBAAgB;AAChB,UAAM,WAAW,KAAK,IAAI,GAAG,eAAe,IAAI,OAAK,EAAE,MAAM,CAAC;AAC9D,gBAAY,WAAW;AAAA,EAC3B;AAEA,QAAM,eAAe,WAAW;AAChC,QAAM,cAAc,eAAe,gBAAgB;AAGnD,MAAI,MAAM;AACV,QAAM,OAAO,CAAC;AAGd,OAAK,KAAK;AAAA,6DAC+C,MAAM,WAAW;AAAA,cAChE;AACV,OAAK,KAAK;AAAA,8CACgC,MAAM,WAAW;AAAA,cACjD;AAGV,SAAO,4BAA4B,UAAU,aAAa,WAAW,WAAW,MAAM,EAAE;AAGxF,MAAI,QAAQ,OAAO;AACf,WAAO,YAAY,aAAa,CAAC,QAAQ,aAAa,CAAC,gCAAgC,MAAM,eAAe,iCAAiC,WAAW,uBAAuB,UAAU,QAAQ,KAAK,CAAC;AAAA,EAC3M;AAGA,WAAS,KAAK,GAAG,KAAK,QAAQ,MAAM;AAChC,UAAM,KAAK,SAAS,EAAE;AACtB,WAAO,aAAa,EAAE,SAAS,YAAY,SAAS,EAAE,SAAS,YAAY,aAAa,MAAM,QAAQ;AAAA,EAC1G;AAGA,WAAS,KAAK,GAAG,KAAK,QAAQ,MAAM;AAChC,UAAM,KAAK,SAAS,EAAE;AACtB,UAAM,KAAK,KAAK,gBAAgB;AAChC,UAAM,KAAK;AACX,WAAO,+CAA+C,UAAU,aAAa,EAAE,EAAE,IAAI,CAAC;AACtF,WAAO,YAAY,EAAE,QAAQ,EAAE,YAAY,aAAa,aAAa,aAAa,kBAAkB,MAAM,aAAa,aAAa,MAAM,iBAAiB;AAC3J,WAAO,YAAY,EAAE,QAAQ,KAAK,gBAAgB,IAAI,CAAC,4DAA4D,MAAM,eAAe,iCAAiC,WAAW,KAAK,UAAU,aAAa,EAAE,EAAE,IAAI,CAAC;AACzN,WAAO;AAAA,EACX;AAGA,WAAS,KAAK,GAAG,KAAK,QAAQ,MAAM;AAChC,UAAM,KAAK,SAAS,EAAE;AACtB,UAAM,KAAK,KAAK,gBAAgB;AAChC,UAAM,KAAK;AACX,WAAO,+CAA+C,UAAU,aAAa,EAAE,EAAE,IAAI,CAAC;AACtF,WAAO,YAAY,EAAE,QAAQ,EAAE,YAAY,aAAa,aAAa,aAAa,kBAAkB,MAAM,aAAa,aAAa,MAAM,iBAAiB;AAC3J,WAAO,YAAY,EAAE,QAAQ,KAAK,gBAAgB,IAAI,CAAC,4DAA4D,MAAM,eAAe,iCAAiC,WAAW,KAAK,UAAU,aAAa,EAAE,EAAE,IAAI,CAAC;AACzN,WAAO;AAAA,EACX;AAGA,aAAW,SAAS,QAAQ;AACxB,UAAM,SAAS,MAAM,WAAW,cAAc,SACxC,cAAc,MAAM,QAAQ,IAAI,KAChC,eAAe;AACrB,UAAM,OAAO,MAAM,UAAU,cAAc,SACpC,MAAM,SAAS,cAAc,SAAS,cAAc,MAAM,MAAM,IAAI,KAAK,WAC1E;AAEN,UAAM,SAAS,SAAS;AACxB,UAAM,SAAS,eAAe;AAE9B,WAAO,6CAA6C,MAAM,IAAI;AAC9D,WAAO,YAAY,MAAM,QAAQ,MAAM,YAAY,MAAM,aAAa,OAAO,MAAM,kBAAkB,MAAM,OAAO,aAAa,MAAM,WAAW;AAEhJ,WAAO,YAAY,MAAM,QAAQ,MAAM,YAAY,YAAY,MAAM,MAAM,EAAE,IAAI,EAAE,8BAA8B,MAAM,WAAW;AAClI,WAAO,YAAY,SAAS,CAAC,QAAQ,SAAS,EAAE,WAAW,MAAM,EAAE,iCAAiC,WAAW,uBAAuB,UAAU,MAAM,IAAI,CAAC;AAE3J,QAAI,MAAM,OAAO;AACb,aAAO,YAAY,SAAS,YAAY,MAAM,MAAM,EAAE,IAAI,EAAE,QAAQ,SAAS,EAAE,WAAW,MAAM,UAAU,iCAAiC,WAAW,0BAA0B,UAAU,MAAM,KAAK,CAAC;AAAA,IAC1M;AAGA,aAAS,KAAK,GAAG,KAAK,MAAM,SAAS,QAAQ,MAAM;AAC/C,YAAM,UAAU,MAAM,SAAS,EAAE;AACjC,YAAM,OAAO,QAAQ,WAAW,cAAc,SACxC,cAAc,QAAQ,QAAQ,IAAI,KAClC,OAAO;AACb,aAAO,aAAa,MAAM,SAAS,IAAI,SAAS,SAAS,MAAM,SAAS,IAAI,aAAa,MAAM,WAAW;AAC1G,UAAI,QAAQ,OAAO;AACf,eAAO,YAAY,SAAS,CAAC,QAAQ,OAAO,EAAE,WAAW,MAAM,UAAU,iCAAiC,WAAW,0BAA0B,UAAU,QAAQ,KAAK,CAAC;AAAA,MAC3K;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAGA,WAAS,KAAK,GAAG,KAAK,SAAS,QAAQ,MAAM;AACzC,UAAM,MAAM,SAAS,EAAE;AACvB,UAAM,IAAI,cAAc,EAAE;AAC1B,UAAM,UAAU,OAAO,IAAI,IAAI,IAAI;AACnC,UAAM,QAAQ,OAAO,IAAI,IAAI,EAAE;AAC/B,QAAI,YAAY,UAAa,UAAU,OAAW;AAElD,UAAM,QAAQ,SAAS,OAAO;AAC9B,UAAM,MAAM,SAAS,KAAK;AAC1B,UAAM,SAAS,YAAY;AAE3B,WAAO,4CAA4C,EAAE;AAErD,QAAI,QAAQ;AAER,YAAM,QAAQ;AACd,YAAM,QAAQ;AACd,YAAM,OAAO,IAAI,QAAQ,KAAK;AAC9B,aAAO,cAAc,KAAK,IAAI,CAAC,MAAM,QAAQ,KAAK,IAAI,CAAC,MAAM,QAAQ,KAAK,IAAI,IAAI,KAAK,MAAM,QAAQ,CAAC,IAAI,IAAI,KAAK,yBAAyB,MAAM,WAAW,uBAAuB,IAAI;AACxL,UAAI,IAAI,MAAM;AACV,eAAO,YAAY,QAAQ,QAAQ,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC,uCAAuC,MAAM,WAAW,iCAAiC,WAAW,KAAK,UAAU,IAAI,IAAI,CAAC;AAAA,MAC7L;AAAA,IACJ,OAAO;AACH,YAAM,SAAS,MAAM;AACrB,YAAM,WAAW,SAAS,MAAM,IAAI,MAAM;AAC1C,YAAM,OAAO,IAAI,QAAQ,KAAK;AAG9B,YAAM,WAAW,IAAI,cAAc,WAAW,qBAAqB;AAEnE,UAAI,IAAI,OAAO;AAEX,eAAO,aAAa,KAAK,SAAS,CAAC,SAAS,QAAQ,SAAS,CAAC,aAAa,MAAM,WAAW,uBAAuB,IAAI;AAEvH,cAAM,QAAQ;AACd,eAAO,aAAa,MAAM,KAAK,SAAS,IAAI,KAAK,SAAS,MAAM,KAAK,SAAS,IAAI,KAAK,aAAa,MAAM,UAAU;AACpH,eAAO,aAAa,MAAM,KAAK,SAAS,IAAI,KAAK,SAAS,MAAM,KAAK,SAAS,IAAI,KAAK,aAAa,MAAM,UAAU;AAAA,MACxH,OAAO;AACH,eAAO,aAAa,KAAK,SAAS,CAAC,SAAS,QAAQ,SAAS,CAAC,aAAa,MAAM,WAAW,uBAAuB,IAAI,qBAAqB,QAAQ;AAAA,MACxJ;AAGA,UAAI,IAAI,MAAM;AACV,cAAM,QAAQ,QAAQ,OAAO;AAC7B,cAAM,cAAc,IAAI,SAAS,GAAG,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,IAAI;AACpE,eAAO,YAAY,IAAI,QAAQ,IAAI,CAAC,gCAAgC,MAAM,WAAW,iCAAiC,WAAW,KAAK,UAAU,WAAW,CAAC;AAAA,MAChK;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AAGA,aAAW,CAAC,QAAQ,SAAS,KAAK,UAAU,QAAQ,GAAG;AACnD,UAAM,QAAQ,SAAS,cAAc,SAC/B,cAAc,MAAM,IAAI,KACvB,SAAS,IAAI,cAAc,SAAS,CAAC,IAAI,iBAAiB,KAAK,eAAe;AAErF,eAAW,QAAQ,WAAW;AAC1B,YAAM,aAAa,KAAK,QAAQ,IAAI,OAAK,OAAO,IAAI,CAAC,CAAC,EAAE,OAAO,OAAK,MAAM,MAAS;AACnF,UAAI,WAAW,WAAW,EAAG;AAE7B,YAAM,WAAW;AACjB,YAAM,QAAQ,WAAW;AACzB,YAAM,QAAQ,KAAK,MAAM,SAAS,QAAQ,WAAW;AACrD,YAAM,QAAQ,KAAK;AAAA,QACf;AAAA,QACA,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,OAAK,YAAY,GAAG,QAAQ,CAAC,CAAC,IAAI,WAAW,IAAI;AAAA,MAChF;AAEA,UAAI;AACJ,UAAI,KAAK,aAAa,WAAW;AAC7B,cAAM,KAAK,SAAS,WAAW,CAAC,CAAC;AACjC,gBAAQ,KAAK,gBAAgB,IAAI,QAAQ;AAAA,MAC7C,WAAW,KAAK,aAAa,YAAY;AACrC,cAAM,KAAK,SAAS,WAAW,CAAC,CAAC;AACjC,gBAAQ,KAAK,gBAAgB,IAAI;AAAA,MACrC,OAAO;AAEH,YAAI,WAAW,UAAU,GAAG;AACxB,gBAAM,OAAO,KAAK,IAAI,GAAG,UAAU;AACnC,gBAAM,OAAO,KAAK,IAAI,GAAG,UAAU;AACnC,gBAAM,UAAU,SAAS,IAAI,IAAI,SAAS,IAAI,KAAK;AACnD,kBAAQ,SAAS,QAAQ;AAAA,QAC7B,OAAO;AACH,kBAAQ,SAAS,WAAW,CAAC,CAAC,IAAI,QAAQ;AAAA,QAC9C;AAAA,MACJ;AAEA,YAAM,QAAQ,QAAQ;AAEtB,aAAO;AACP,aAAO,YAAY,KAAK,QAAQ,KAAK,YAAY,KAAK,aAAa,KAAK,kBAAkB,MAAM,MAAM,aAAa,MAAM,UAAU;AAEnI,WAAK,MAAM,QAAQ,CAAC,MAAM,OAAO;AAC7B,eAAO,YAAY,QAAQ,QAAQ,QAAQ,QAAQ,WAAW,KAAK,QAAQ,QAAQ,WAAW,MAAM,QAAQ,gBAAgB,QAAQ,kBAAkB,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,MACzL,CAAC;AACD,aAAO;AAAA,IACX;AAAA,EACJ;AAGA,QAAM,UAAU,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC,YAAY;AACpE,SAAO,kDAAkD,UAAU,aAAa,WAAW,kBAAkB,UAAU,IAAI,WAAW,KAAK,OAAO,GAAG,GAAG;AAC5J;AAKO,SAAS,yBAAyB,SAAS;AAC9C,SAAO,kBAAkB,SAAS,EAAE,OAAO,IAAI,CAAC;AACpD;AAMO,SAAS,uBAAuB,KAAK;AACxC,QAAM,UAAU,qBAAqB,GAAG;AACxC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,kBAAkB,OAAO;AACpC;AAkBO,SAAS,uBAAuB,SAAS;AAC5C,MAAI,CAAC,WAAW,QAAQ,SAAS,kBAAmB,QAAO;AAC3D,MAAI,CAAC,OAAO,OAAO,CAAC,OAAO,aAAa,CAAC,OAAO,QAAQ,CAAC,OAAO,OAAO;AACnE,YAAQ,MAAM,8EAA8E;AAC5F,WAAO;AAAA,EACX;AAEA,QAAM,eAAe,QAAQ,gBAAgB,CAAC;AAC9C,QAAM,WAAW,QAAQ,YAAY,CAAC;AACtC,MAAI,aAAa,WAAW,EAAG,QAAO;AAItC,QAAM,SAAS,aAAa;AAC5B,QAAM,gBAAgB,SAAS,KAAK,kBAAkB;AACtD,QAAM,aAAa,KAAK,IAAI,eAAe,cAAc,GAAG,GAAG;AAC/D,QAAM,UAAU,aAAa,gBAAgB;AAC7C,QAAM,WAAW,aAAa,IAAI,CAAC,GAAG,MAAM,SAAS,IAAI,kBAAkB,gBAAgB,CAAC;AAE5F,QAAM,eAAe,aAAa;AAClC,QAAM,gBAAgB,CAAC;AACvB,MAAI,WAAW,eAAe;AAC9B,WAAS,KAAK,GAAG,KAAK,SAAS,QAAQ,MAAM;AACzC,kBAAc,KAAK,QAAQ;AAC3B,gBAAY;AAAA,EAChB;AACA,QAAM,eAAe,WAAW;AAChC,QAAM,cAAc,eAAe,gBAAgB;AAInD,QAAM,KAAK,OAAO,kBAAkB,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,OAAO,YAAY,QAAQ,OAAO,YAAY;AACvG,QAAM,KAAK,GAAG,IAAI,GAAG,QAAQ,IAAI,aAAa;AAC9C,QAAM,KAAK,GAAG,IAAI,GAAG,SAAS,IAAI,cAAc;AAOhD,MAAI,CAAC,OAAO,OAAO;AACf,YAAQ,MAAM,oEAA+D;AAC7E,WAAO;AAAA,EACX;AAGA,QAAM,UAAU;AAChB,QAAM,KAAK,YAAY;AACvB,QAAM,aAAa,QAAQ,SAAS;AACpC,QAAM,QAAQ,IAAI,OAAO;AAAA,IACrB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,aAAa,UAAU;AAAA,IACvB,cAAc,UAAU;AAAA,IACxB;AAAA,MACI,QAAQ,GAAG;AAAA,MACX,aAAa;AAAA,MACb,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW;AAAA,IACf;AAAA,EACJ;AACA,QAAM,eAAe;AACrB,SAAO,OAAO,KAAK,KAAK;AACxB,MAAI,OAAO,iBAAkB,QAAO,iBAAiB,KAAK;AAE1D,QAAM,UAAU,CAAC;AAGjB,QAAM,SAAS,oBAAI,IAAI;AACvB,WAAS,KAAK,GAAG,KAAK,QAAQ,MAAM;AAChC,UAAM,IAAI,aAAa,EAAE;AACzB,WAAO,IAAI,EAAE,MAAM,EAAE;AACrB,UAAM,KAAK,SAAS,EAAE,IAAI;AAC1B,UAAM,KAAK,KAAK,gBAAgB;AAEhC,QAAI;AAEA,YAAM,SAAS,IAAI,OAAO,UAAU,IAAI,aAAa,IAAI,eAAe,eAAe;AAAA,QACnF,QAAQ,GAAG;AAAA,QACX,aAAa;AAAA,QACb,MAAM,GAAG;AAAA,QACT,WAAW;AAAA,QACX,WAAW;AAAA,QACX,OAAO,EAAE;AAAA,QACT,YAAY,GAAG;AAAA,MACnB,CAAC;AACD,aAAO,OAAO,KAAK,MAAM;AACzB,UAAI,OAAO,iBAAkB,QAAO,iBAAiB,MAAM;AAC3D,YAAM,gBAAgB,MAAM;AAC5B,cAAQ,KAAK,MAAM;AAGnB,YAAM,WAAW,IAAI,OAAO;AAAA,QACxB,EAAE,GAAG,IAAI,GAAG,eAAe,GAAG;AAAA,QAC9B,EAAE,GAAG,IAAI,GAAG,eAAe,GAAG;AAAA,QAC9B;AAAA,UACI,QAAQ,GAAG;AAAA,UACX,aAAa;AAAA,UACb,iBAAiB;AAAA,UACjB,WAAW;AAAA,QACf;AAAA,MACJ;AACA,aAAO,OAAO,KAAK,QAAQ;AAC3B,UAAI,OAAO,iBAAkB,QAAO,iBAAiB,QAAQ;AAC7D,YAAM,gBAAgB,QAAQ;AAC9B,cAAQ,KAAK,QAAQ;AAGrB,YAAM,YAAY,IAAI,OAAO,UAAU,IAAI,eAAe,IAAI,eAAe,eAAe;AAAA,QACxF,QAAQ,GAAG;AAAA,QACX,aAAa;AAAA,QACb,MAAM,GAAG;AAAA,QACT,WAAW;AAAA,QACX,WAAW;AAAA,QACX,OAAO,EAAE;AAAA,QACT,YAAY,GAAG;AAAA,MACnB,CAAC;AACD,aAAO,OAAO,KAAK,SAAS;AAC5B,UAAI,OAAO,iBAAkB,QAAO,iBAAiB,SAAS;AAC9D,YAAM,gBAAgB,SAAS;AAC/B,cAAQ,KAAK,SAAS;AAAA,IAC1B,SAAS,KAAK;AACV,cAAQ,KAAK,mDAAmD,EAAE,MAAM,GAAG;AAAA,IAC/E;AAAA,EACJ;AAGA,WAAS,KAAK,GAAG,KAAK,SAAS,QAAQ,MAAM;AACzC,UAAM,IAAI,SAAS,EAAE;AACrB,UAAM,QAAQ,OAAO,IAAI,EAAE,IAAI;AAC/B,UAAM,MAAM,OAAO,IAAI,EAAE,EAAE;AAC3B,QAAI,SAAS,QAAQ,OAAO,KAAM;AAClC,QAAI,UAAU,IAAK;AAEnB,UAAM,SAAS,SAAS,KAAK,IAAI;AACjC,UAAM,OAAO,SAAS,GAAG,IAAI;AAC7B,UAAM,IAAI,cAAc,EAAE,IAAI;AAE9B,UAAM,YAAY,EAAE,SAAS,GAAG,EAAE,MAAM,KAAK,EAAE,IAAI,KAAK,EAAE;AAK1D,UAAM,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,cAAc;AAC7C,UAAM,OAAO;AAAA,MACT,QAAQ,GAAG;AAAA,MACX,aAAa;AAAA,MACb,WAAW;AAAA,MACX,iBAAiB,EAAE,QAAQ,KAAK;AAAA,MAChC,OAAO,aAAa;AAAA,MACpB,YAAY,GAAG;AAAA,IACnB;AAEA,QAAI;AACA,YAAM,KAAK,EAAE,GAAG,QAAQ,EAAE;AAC1B,YAAM,KAAK,EAAE,GAAG,MAAM,EAAE;AACxB,YAAM,YAAY,UACZ,IAAI,OAAO,KAAK,IAAI,IAAI,IAAI,IAC5B,IAAI,OAAO,MAAM,IAAI,IAAI,IAAI;AACnC,aAAO,OAAO,KAAK,SAAS;AAC5B,UAAI,OAAO,iBAAkB,QAAO,iBAAiB,SAAS;AAC9D,YAAM,gBAAgB,SAAS;AAC/B,cAAQ,KAAK,SAAS;AAAA,IAC1B,SAAS,KAAK;AACV,cAAQ,KAAK,+CAA+C,GAAG,GAAG;AAAA,IACtE;AAAA,EACJ;AAKA,QAAM,QAAQ,QAAQ,CAAC;AACvB,MAAI,OAAO;AACP,WAAO,eAAe;AACtB,QAAI,OAAO,MAAM,gBAAgB,WAAY,OAAM,YAAY;AAAA,EACnE;AAEA,UAAQ,IAAI,4BAA4B,MAAM,kBAAkB,SAAS,MAAM,WAAW;AAC1F,SAAO;AACX;",
6
+ "names": []
7
+ }