@elixpo/lixsketch 5.5.0 → 5.5.2
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.
- package/dist/react/{AIRenderer-M4LMJ66J.js → AIRenderer-S2SKFJKT.js} +3 -3
- package/dist/react/{GraphEngine-QE5B2PMR.js → GraphEngine-IHRVGUGG.js} +41 -19
- package/dist/react/GraphEngine-IHRVGUGG.js.map +7 -0
- package/dist/react/{MermaidFlowchartRenderer-4QBAZ5MB.js → MermaidFlowchartRenderer-A26B2SM3.js} +18 -6
- package/dist/react/MermaidFlowchartRenderer-A26B2SM3.js.map +7 -0
- package/dist/react/{MermaidSequenceRenderer-HPLHY5II.js → MermaidSequenceRenderer-OF4JK77D.js} +37 -12
- package/dist/react/MermaidSequenceRenderer-OF4JK77D.js.map +7 -0
- package/dist/react/{SketchEngine-YA4RG3KX.js → SketchEngine-4WSPTHZ3.js} +3 -3
- package/dist/react/index.js +10 -3
- package/dist/react/index.js.map +2 -2
- package/package.json +1 -1
- package/src/core/GraphRenderer.js +48 -19
- package/src/core/MermaidFlowchartRenderer.js +19 -4
- package/src/core/MermaidSequenceRenderer.js +44 -9
- package/src/react/components/AppMenu.jsx +11 -4
- package/dist/react/GraphEngine-QE5B2PMR.js.map +0 -7
- package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js.map +0 -7
- package/dist/react/MermaidSequenceRenderer-HPLHY5II.js.map +0 -7
- /package/dist/react/{AIRenderer-M4LMJ66J.js.map → AIRenderer-S2SKFJKT.js.map} +0 -0
- /package/dist/react/{SketchEngine-YA4RG3KX.js.map → SketchEngine-4WSPTHZ3.js.map} +0 -0
package/package.json
CHANGED
|
@@ -11,6 +11,35 @@ const GRAPH_COLORS = [
|
|
|
11
11
|
'#1ABC9C', '#E67E22', '#3498DB', '#E91E63', '#00BCD4',
|
|
12
12
|
];
|
|
13
13
|
|
|
14
|
+
// Issue #38 follow-up: theme-aware graph chrome. Light mode flips every
|
|
15
|
+
// hardcoded `rgba(255,255,255,X)` token (designed for dark canvas) to a
|
|
16
|
+
// matching `rgba(60,60,80,X)` so the grid, axes, plot border, and tick
|
|
17
|
+
// labels stay readable on the warm off-white canvas. The equation
|
|
18
|
+
// curves themselves keep their colours from GRAPH_COLORS.
|
|
19
|
+
function graphThemeTokens() {
|
|
20
|
+
const isDark = typeof document !== 'undefined'
|
|
21
|
+
&& document.body
|
|
22
|
+
&& document.body.classList.contains('theme-dark');
|
|
23
|
+
if (isDark) {
|
|
24
|
+
return {
|
|
25
|
+
outerBg: '#0d1117',
|
|
26
|
+
plotBg: '#111822',
|
|
27
|
+
gridStroke:'rgba(255,255,255,0.06)',
|
|
28
|
+
axisStroke:'rgba(255,255,255,0.25)',
|
|
29
|
+
borderStroke:'rgba(255,255,255,0.1)',
|
|
30
|
+
tickLabel: '#8b949e',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
outerBg: '#fbfaf6',
|
|
35
|
+
plotBg: '#ffffff',
|
|
36
|
+
gridStroke:'rgba(60,60,80,0.08)',
|
|
37
|
+
axisStroke:'rgba(60,60,80,0.35)',
|
|
38
|
+
borderStroke:'rgba(60,60,80,0.16)',
|
|
39
|
+
tickLabel: '#62627a',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
14
43
|
/**
|
|
15
44
|
* Calculate nice tick intervals for a given range.
|
|
16
45
|
*/
|
|
@@ -51,10 +80,11 @@ export function renderGraphSVG(equations, settings) {
|
|
|
51
80
|
const toSvgY = (y) => pad.top + ((yMax - y) / yRange) * plotH;
|
|
52
81
|
|
|
53
82
|
let svg = '';
|
|
83
|
+
const tk = graphThemeTokens();
|
|
54
84
|
|
|
55
85
|
// Background
|
|
56
|
-
svg += `<rect x="0" y="0" width="${width}" height="${height}" fill="
|
|
57
|
-
svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="
|
|
86
|
+
svg += `<rect x="0" y="0" width="${width}" height="${height}" fill="${tk.outerBg}" rx="8" />`;
|
|
87
|
+
svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="${tk.plotBg}" />`;
|
|
58
88
|
|
|
59
89
|
// Grid & ticks
|
|
60
90
|
const xTick = niceInterval(xRange);
|
|
@@ -66,11 +96,10 @@ export function renderGraphSVG(equations, settings) {
|
|
|
66
96
|
const sx = toSvgX(x);
|
|
67
97
|
if (sx < pad.left || sx > pad.left + plotW) continue;
|
|
68
98
|
if (showGrid) {
|
|
69
|
-
svg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="
|
|
99
|
+
svg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
|
|
70
100
|
}
|
|
71
|
-
// Tick label
|
|
72
101
|
const label = Math.abs(x) < 1e-10 ? '0' : (Number.isInteger(x) ? x : x.toFixed(1));
|
|
73
|
-
svg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="
|
|
102
|
+
svg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
|
|
74
103
|
}
|
|
75
104
|
|
|
76
105
|
// Horizontal grid lines + y labels
|
|
@@ -79,24 +108,24 @@ export function renderGraphSVG(equations, settings) {
|
|
|
79
108
|
const sy = toSvgY(y);
|
|
80
109
|
if (sy < pad.top || sy > pad.top + plotH) continue;
|
|
81
110
|
if (showGrid) {
|
|
82
|
-
svg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="
|
|
111
|
+
svg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
|
|
83
112
|
}
|
|
84
113
|
const label = Math.abs(y) < 1e-10 ? '0' : (Number.isInteger(y) ? y : y.toFixed(1));
|
|
85
|
-
svg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="
|
|
114
|
+
svg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
|
|
86
115
|
}
|
|
87
116
|
|
|
88
117
|
// Axes
|
|
89
118
|
if (xMin <= 0 && xMax >= 0) {
|
|
90
119
|
const ax = toSvgX(0);
|
|
91
|
-
svg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="
|
|
120
|
+
svg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="${tk.axisStroke}" stroke-width="1" />`;
|
|
92
121
|
}
|
|
93
122
|
if (yMin <= 0 && yMax >= 0) {
|
|
94
123
|
const ay = toSvgY(0);
|
|
95
|
-
svg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="
|
|
124
|
+
svg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="${tk.axisStroke}" stroke-width="1" />`;
|
|
96
125
|
}
|
|
97
126
|
|
|
98
127
|
// Plot border
|
|
99
|
-
svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="
|
|
128
|
+
svg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="${tk.borderStroke}" stroke-width="1" />`;
|
|
100
129
|
|
|
101
130
|
// Equations
|
|
102
131
|
const samplesPerPixel = 2;
|
|
@@ -194,39 +223,39 @@ export function renderGraphSVG(equations, settings) {
|
|
|
194
223
|
// Remove the non-clipped curves from svg (we added them above for building)
|
|
195
224
|
// Rebuild cleanly
|
|
196
225
|
let cleanSvg = '';
|
|
197
|
-
cleanSvg += `<rect x="0" y="0" width="${width}" height="${height}" fill="
|
|
198
|
-
cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="
|
|
226
|
+
cleanSvg += `<rect x="0" y="0" width="${width}" height="${height}" fill="${tk.outerBg}" rx="8" />`;
|
|
227
|
+
cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="${tk.plotBg}" />`;
|
|
199
228
|
|
|
200
229
|
// Grid + ticks (re-add)
|
|
201
230
|
for (let x = xStart; x <= xMax; x += xTick) {
|
|
202
231
|
const sx = toSvgX(x);
|
|
203
232
|
if (sx < pad.left || sx > pad.left + plotW) continue;
|
|
204
233
|
if (showGrid) {
|
|
205
|
-
cleanSvg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="
|
|
234
|
+
cleanSvg += `<line x1="${sx}" y1="${pad.top}" x2="${sx}" y2="${pad.top + plotH}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
|
|
206
235
|
}
|
|
207
236
|
const label = Math.abs(x) < 1e-10 ? '0' : (Number.isInteger(x) ? x : x.toFixed(1));
|
|
208
|
-
cleanSvg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="
|
|
237
|
+
cleanSvg += `<text x="${sx}" y="${pad.top + plotH + 16}" text-anchor="middle" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
|
|
209
238
|
}
|
|
210
239
|
for (let y = yStart; y <= yMax; y += yTick) {
|
|
211
240
|
const sy = toSvgY(y);
|
|
212
241
|
if (sy < pad.top || sy > pad.top + plotH) continue;
|
|
213
242
|
if (showGrid) {
|
|
214
|
-
cleanSvg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="
|
|
243
|
+
cleanSvg += `<line x1="${pad.left}" y1="${sy}" x2="${pad.left + plotW}" y2="${sy}" stroke="${tk.gridStroke}" stroke-width="0.5" />`;
|
|
215
244
|
}
|
|
216
245
|
const label = Math.abs(y) < 1e-10 ? '0' : (Number.isInteger(y) ? y : y.toFixed(1));
|
|
217
|
-
cleanSvg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="
|
|
246
|
+
cleanSvg += `<text x="${pad.left - 8}" y="${sy + 3}" text-anchor="end" fill="${tk.tickLabel}" font-size="10" font-family="lixCode, monospace">${label}</text>`;
|
|
218
247
|
}
|
|
219
248
|
// Axes
|
|
220
249
|
if (xMin <= 0 && xMax >= 0) {
|
|
221
250
|
const ax = toSvgX(0);
|
|
222
|
-
cleanSvg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="
|
|
251
|
+
cleanSvg += `<line x1="${ax}" y1="${pad.top}" x2="${ax}" y2="${pad.top + plotH}" stroke="${tk.axisStroke}" stroke-width="1" />`;
|
|
223
252
|
}
|
|
224
253
|
if (yMin <= 0 && yMax >= 0) {
|
|
225
254
|
const ay = toSvgY(0);
|
|
226
|
-
cleanSvg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="
|
|
255
|
+
cleanSvg += `<line x1="${pad.left}" y1="${ay}" x2="${pad.left + plotW}" y2="${ay}" stroke="${tk.axisStroke}" stroke-width="1" />`;
|
|
227
256
|
}
|
|
228
257
|
// Plot border
|
|
229
|
-
cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="
|
|
258
|
+
cleanSvg += `<rect x="${pad.left}" y="${pad.top}" width="${plotW}" height="${plotH}" fill="none" stroke="${tk.borderStroke}" stroke-width="1" />`;
|
|
230
259
|
|
|
231
260
|
// Clipped curves
|
|
232
261
|
cleanSvg += `<g clip-path="url(#${clipId})">${curves}</g>`;
|
|
@@ -18,7 +18,16 @@ const SIDE_MARGIN = 50;
|
|
|
18
18
|
const TOP_MARGIN = 40;
|
|
19
19
|
const FONT_FAMILY = 'lixFont, sans-serif';
|
|
20
20
|
|
|
21
|
-
//
|
|
21
|
+
// Issue #38 follow-up: theme-aware stroke / fill. Resolved at draw time
|
|
22
|
+
// so a single render call uses whichever palette is active.
|
|
23
|
+
function isThemeDark() {
|
|
24
|
+
if (typeof document === 'undefined') return true;
|
|
25
|
+
return !!(document.body && document.body.classList.contains('theme-dark'));
|
|
26
|
+
}
|
|
27
|
+
function nodeStrokeColor() { return isThemeDark() ? '#fff' : '#1a1a2e'; }
|
|
28
|
+
function edgeStrokeColor() { return isThemeDark() ? '#888' : '#444'; }
|
|
29
|
+
|
|
30
|
+
// Theme colors (dark theme — used by the SVG-string preview path only)
|
|
22
31
|
const THEME = {
|
|
23
32
|
bg: '#1e1e28',
|
|
24
33
|
nodeBg: 'transparent',
|
|
@@ -405,7 +414,11 @@ export function renderFlowchartOnCanvas(diagram) {
|
|
|
405
414
|
// Created up-front so we can call addShapeToFrame as each child is
|
|
406
415
|
// built. _diagramType marks it so Frame.destroy() takes the children
|
|
407
416
|
// along on delete (issue #34 bug #3).
|
|
408
|
-
|
|
417
|
+
//
|
|
418
|
+
// PADDING bumped from 40 → 90 so edge labels, rotated diamond nodes,
|
|
419
|
+
// and arrow heads near the diagram boundary stay inside the frame
|
|
420
|
+
// instead of getting clipped at the corners.
|
|
421
|
+
const PADDING = 90;
|
|
409
422
|
const frameTitle = diagram.title || 'Mermaid diagram';
|
|
410
423
|
const frame = new window.Frame(
|
|
411
424
|
vcx - dw / 2 - PADDING,
|
|
@@ -436,12 +449,13 @@ export function renderFlowchartOnCanvas(diagram) {
|
|
|
436
449
|
const cy = ny + nh / 2;
|
|
437
450
|
|
|
438
451
|
const opts = {
|
|
439
|
-
stroke: n.stroke ||
|
|
452
|
+
stroke: n.stroke || nodeStrokeColor(),
|
|
440
453
|
strokeWidth: n.strokeWidth ?? 1.5,
|
|
441
454
|
fill: n.fill || 'transparent',
|
|
442
455
|
fillStyle: n.fill && n.fill !== 'transparent' ? 'solid' : 'none',
|
|
443
456
|
roughness: 1,
|
|
444
457
|
label: n.label || '',
|
|
458
|
+
labelColor: n.labelColor || nodeStrokeColor(),
|
|
445
459
|
};
|
|
446
460
|
|
|
447
461
|
let shape = null;
|
|
@@ -488,11 +502,12 @@ export function renderFlowchartOnCanvas(diagram) {
|
|
|
488
502
|
const isDotted = style === 'dotted';
|
|
489
503
|
|
|
490
504
|
const opts = {
|
|
491
|
-
stroke: e.stroke ||
|
|
505
|
+
stroke: e.stroke || edgeStrokeColor(),
|
|
492
506
|
strokeWidth: isThick ? 3 : 1.5,
|
|
493
507
|
roughness: 1,
|
|
494
508
|
strokeDasharray: isDotted ? '5 3' : '',
|
|
495
509
|
label: e.label || '',
|
|
510
|
+
labelColor: e.labelColor || edgeStrokeColor(),
|
|
496
511
|
};
|
|
497
512
|
|
|
498
513
|
let connector = null;
|
|
@@ -26,7 +26,36 @@ const SIDE_MARGIN = 40;
|
|
|
26
26
|
const FONT_FAMILY = 'lixFont, sans-serif';
|
|
27
27
|
const CODE_FONT = 'lixCode, monospace';
|
|
28
28
|
|
|
29
|
-
//
|
|
29
|
+
// Issue #38 follow-up: theme-aware palette. The on-canvas renderer reads
|
|
30
|
+
// `themeColors()` at draw time so a single render call gets whichever
|
|
31
|
+
// palette is active. The dark THEME object below is kept for the SVG-
|
|
32
|
+
// string preview path (`renderSequenceSVG`), which is rendered inside
|
|
33
|
+
// the modal's preview pane.
|
|
34
|
+
function themeColors() {
|
|
35
|
+
const isDark = typeof document !== 'undefined'
|
|
36
|
+
&& document.body
|
|
37
|
+
&& document.body.classList.contains('theme-dark');
|
|
38
|
+
if (isDark) return THEME;
|
|
39
|
+
return {
|
|
40
|
+
bg: '#fbfaf6',
|
|
41
|
+
participantBg: '#ffffff',
|
|
42
|
+
participantBorder: '#9c9c9c',
|
|
43
|
+
participantText: '#38384e',
|
|
44
|
+
lifeline: '#b0b0b8',
|
|
45
|
+
messageLine: '#62627a',
|
|
46
|
+
messageDash: '#888',
|
|
47
|
+
messageText: '#38384e',
|
|
48
|
+
noteBg: '#fffce0',
|
|
49
|
+
noteBorder: '#c0b870',
|
|
50
|
+
noteText: '#5e5230',
|
|
51
|
+
blockBg: 'rgba(80,80,120,0.08)',
|
|
52
|
+
blockBorder: '#9c9c9c',
|
|
53
|
+
blockLabel: '#62627a',
|
|
54
|
+
crossColor: '#c2483a',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Theme colors (dark theme — preview/SVG-string path).
|
|
30
59
|
const THEME = {
|
|
31
60
|
bg: '#1e1e28',
|
|
32
61
|
participantBg: '#232329',
|
|
@@ -420,7 +449,10 @@ export function renderSequenceOnCanvas(diagram) {
|
|
|
420
449
|
console.error('[SequenceRenderer] window.Frame missing — cannot wrap diagram');
|
|
421
450
|
return false;
|
|
422
451
|
}
|
|
423
|
-
|
|
452
|
+
// Padding bumped 24 → 60 so participant labels + message text near
|
|
453
|
+
// the frame's edges stay inside on the new wider light canvas.
|
|
454
|
+
const PADDING = 60;
|
|
455
|
+
const TK = themeColors();
|
|
424
456
|
const frameTitle = diagram.title || 'Sequence diagram';
|
|
425
457
|
const frame = new window.Frame(
|
|
426
458
|
ox - PADDING,
|
|
@@ -428,7 +460,7 @@ export function renderSequenceOnCanvas(diagram) {
|
|
|
428
460
|
totalWidth + PADDING * 2,
|
|
429
461
|
totalHeight + PADDING * 2,
|
|
430
462
|
{
|
|
431
|
-
stroke:
|
|
463
|
+
stroke: TK.blockBorder,
|
|
432
464
|
strokeWidth: 1,
|
|
433
465
|
fill: 'transparent',
|
|
434
466
|
opacity: 0.7,
|
|
@@ -452,12 +484,13 @@ export function renderSequenceOnCanvas(diagram) {
|
|
|
452
484
|
try {
|
|
453
485
|
// Top participant box
|
|
454
486
|
const topBox = new window.Rectangle(bx, TOP_MARGIN + oy, PARTICIPANT_W, PARTICIPANT_H, {
|
|
455
|
-
stroke:
|
|
487
|
+
stroke: TK.participantBorder,
|
|
456
488
|
strokeWidth: 1.5,
|
|
457
|
-
fill:
|
|
489
|
+
fill: TK.participantBg,
|
|
458
490
|
fillStyle: 'solid',
|
|
459
491
|
roughness: 1,
|
|
460
492
|
label: p.name,
|
|
493
|
+
labelColor: TK.participantText,
|
|
461
494
|
});
|
|
462
495
|
window.shapes.push(topBox);
|
|
463
496
|
if (window.pushCreateAction) window.pushCreateAction(topBox);
|
|
@@ -469,7 +502,7 @@ export function renderSequenceOnCanvas(diagram) {
|
|
|
469
502
|
{ x: cx, y: topBoxBottom + oy },
|
|
470
503
|
{ x: cx, y: bottomBoxTop + oy },
|
|
471
504
|
{
|
|
472
|
-
stroke:
|
|
505
|
+
stroke: TK.lifeline,
|
|
473
506
|
strokeWidth: 1,
|
|
474
507
|
strokeDasharray: '6 4',
|
|
475
508
|
roughness: 0,
|
|
@@ -482,12 +515,13 @@ export function renderSequenceOnCanvas(diagram) {
|
|
|
482
515
|
|
|
483
516
|
// Bottom participant box (mirrors top — Mermaid convention)
|
|
484
517
|
const bottomBox = new window.Rectangle(bx, bottomBoxTop + oy, PARTICIPANT_W, PARTICIPANT_H, {
|
|
485
|
-
stroke:
|
|
518
|
+
stroke: TK.participantBorder,
|
|
486
519
|
strokeWidth: 1.5,
|
|
487
|
-
fill:
|
|
520
|
+
fill: TK.participantBg,
|
|
488
521
|
fillStyle: 'solid',
|
|
489
522
|
roughness: 1,
|
|
490
523
|
label: p.name,
|
|
524
|
+
labelColor: TK.participantText,
|
|
491
525
|
});
|
|
492
526
|
window.shapes.push(bottomBox);
|
|
493
527
|
if (window.pushCreateAction) window.pushCreateAction(bottomBox);
|
|
@@ -517,11 +551,12 @@ export function renderSequenceOnCanvas(diagram) {
|
|
|
517
551
|
// line for that, arrow otherwise.
|
|
518
552
|
const isCross = !!m.cross && m.arrowHead === 'cross';
|
|
519
553
|
const opts = {
|
|
520
|
-
stroke:
|
|
554
|
+
stroke: TK.messageLine,
|
|
521
555
|
strokeWidth: 1.5,
|
|
522
556
|
roughness: 0,
|
|
523
557
|
strokeDasharray: m.solid ? '' : '6 4',
|
|
524
558
|
label: labelText || '',
|
|
559
|
+
labelColor: TK.messageText,
|
|
525
560
|
};
|
|
526
561
|
|
|
527
562
|
try {
|
|
@@ -8,15 +8,22 @@ import { triggerCloudSync } from '../hooks/inertStores'
|
|
|
8
8
|
import { triggerDocCloudSync, persistLayoutMode } from '../hooks/inertStores'
|
|
9
9
|
import { useTranslation } from '../hooks/useTranslation'
|
|
10
10
|
|
|
11
|
-
// Issue #38
|
|
12
|
-
//
|
|
13
|
-
const
|
|
11
|
+
// Issue #38 follow-up: theme-paired swatches. The menu picks the
|
|
12
|
+
// matching list at render time based on the active theme.
|
|
13
|
+
const CANVAS_BACKGROUNDS_LIGHT = [
|
|
14
14
|
{ color: '#ffffff', label: 'menu.canvasBg.white' },
|
|
15
15
|
{ color: '#faf9f5', label: 'menu.canvasBg.cream' },
|
|
16
16
|
{ color: '#f5f3ed', label: 'menu.canvasBg.paper' },
|
|
17
17
|
{ color: '#f0f5fb', label: 'menu.canvasBg.skyTint' },
|
|
18
18
|
{ color: '#f0f5ef', label: 'menu.canvasBg.sageTint' },
|
|
19
19
|
]
|
|
20
|
+
const CANVAS_BACKGROUNDS_DARK = [
|
|
21
|
+
{ color: '#000000', label: 'menu.canvasBg.black' },
|
|
22
|
+
{ color: '#161718', label: 'menu.canvasBg.darkGray' },
|
|
23
|
+
{ color: '#13171C', label: 'menu.canvasBg.blueBlack' },
|
|
24
|
+
{ color: '#181605', label: 'menu.canvasBg.darkYellow' },
|
|
25
|
+
{ color: '#1B1615', label: 'menu.canvasBg.darkBrown' },
|
|
26
|
+
]
|
|
20
27
|
|
|
21
28
|
export default function AppMenu() {
|
|
22
29
|
const { t, language } = useTranslation()
|
|
@@ -454,7 +461,7 @@ export default function AppMenu() {
|
|
|
454
461
|
{t('menu.canvasBackground')}
|
|
455
462
|
</p>
|
|
456
463
|
<div className="flex items-center gap-1.5">
|
|
457
|
-
{
|
|
464
|
+
{(theme === 'dark' ? CANVAS_BACKGROUNDS_DARK : CANVAS_BACKGROUNDS_LIGHT).map((bg) => (
|
|
458
465
|
<button
|
|
459
466
|
key={bg.color}
|
|
460
467
|
onClick={() => setCanvasBackground(bg.color)}
|
|
@@ -1,7 +0,0 @@
|
|
|
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/**\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\n // Background\n svg += `<rect x=\"0\" y=\"0\" width=\"${width}\" height=\"${height}\" fill=\"#0d1117\" rx=\"8\" />`;\n svg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"#111822\" />`;\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=\"rgba(255,255,255,0.06)\" stroke-width=\"0.5\" />`;\n }\n // Tick label\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=\"#8b949e\" 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=\"rgba(255,255,255,0.06)\" 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=\"#8b949e\" 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=\"rgba(255,255,255,0.25)\" 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=\"rgba(255,255,255,0.25)\" stroke-width=\"1\" />`;\n }\n\n // Plot border\n svg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"none\" stroke=\"rgba(255,255,255,0.1)\" 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=\"#0d1117\" rx=\"8\" />`;\n cleanSvg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"#111822\" />`;\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=\"rgba(255,255,255,0.06)\" 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=\"#8b949e\" 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=\"rgba(255,255,255,0.06)\" 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=\"#8b949e\" 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=\"rgba(255,255,255,0.25)\" 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=\"rgba(255,255,255,0.25)\" stroke-width=\"1\" />`;\n }\n // Plot border\n cleanSvg += `<rect x=\"${pad.left}\" y=\"${pad.top}\" width=\"${plotW}\" height=\"${plotH}\" fill=\"none\" stroke=\"rgba(255,255,255,0.1)\" 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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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// Theme colors (dark theme)\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, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\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 const PADDING = 40;\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 || '#fff',\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 };\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 || '#fff',\n strokeWidth: isThick ? 3 : 1.5,\n roughness: 1,\n strokeDasharray: isDotted ? '5 3' : '',\n label: e.label || '',\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
|
-
}
|