react-super-mermaid 0.1.0 → 0.3.1
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/README.md +338 -165
- package/dist/index.cjs +579 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +579 -17
- package/dist/index.js.map +1 -1
- package/llms.txt +41 -0
- package/package.json +84 -83
package/dist/index.cjs
CHANGED
|
@@ -108,6 +108,7 @@ var RSM_CSS = `
|
|
|
108
108
|
--rsm-hover: #f3f4f6;
|
|
109
109
|
--rsm-surface: #ffffff;
|
|
110
110
|
--rsm-canvas-bg: transparent;
|
|
111
|
+
--rsm-grid-dot: rgba(0, 0, 0, 0.08);
|
|
111
112
|
--rsm-radius: 8px;
|
|
112
113
|
display: flex;
|
|
113
114
|
flex-direction: column;
|
|
@@ -245,7 +246,91 @@ var RSM_CSS = `
|
|
|
245
246
|
--rsm-accent: #60a5fa;
|
|
246
247
|
--rsm-hover: #1f2937;
|
|
247
248
|
--rsm-surface: #111827;
|
|
249
|
+
--rsm-grid-dot: rgba(255, 255, 255, 0.10);
|
|
248
250
|
}
|
|
251
|
+
|
|
252
|
+
/* \u2500\u2500 \u80CC\u666F\u6A21\u5F0F \u2500\u2500 \u900F\u660E(\u9810\u8A2D,\u8DDF\u96A8\u9801\u9762) / \u7D14\u8272(surface) / \u9EDE\u9663\u683C\u7DDA\u3002 */
|
|
253
|
+
.rsm-root.rsm-bg-solid .rsm-canvas { background: var(--rsm-surface); }
|
|
254
|
+
.rsm-root.rsm-bg-grid .rsm-canvas {
|
|
255
|
+
background-color: var(--rsm-surface);
|
|
256
|
+
background-image: radial-gradient(var(--rsm-grid-dot) 1px, transparent 1px);
|
|
257
|
+
background-size: 18px 18px;
|
|
258
|
+
background-position: -9px -9px;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* \u2500\u2500 \u5168\u87A2\u5E55\u8DF3\u7A97 \u2500\u2500 position:fixed \u8986\u84CB\u6574\u500B\u8996\u7A97,RWD \u53CB\u5584\u3002 */
|
|
262
|
+
.rsm-root.rsm-fullscreen {
|
|
263
|
+
position: fixed;
|
|
264
|
+
inset: 0;
|
|
265
|
+
width: 100vw;
|
|
266
|
+
width: 100dvw;
|
|
267
|
+
height: 100vh;
|
|
268
|
+
height: 100dvh;
|
|
269
|
+
max-width: 100vw;
|
|
270
|
+
max-height: 100dvh;
|
|
271
|
+
margin: 0;
|
|
272
|
+
z-index: 2147483000;
|
|
273
|
+
border: 0;
|
|
274
|
+
border-radius: 0;
|
|
275
|
+
animation: rsm-fs-in 0.16s ease-out;
|
|
276
|
+
}
|
|
277
|
+
@keyframes rsm-fs-in {
|
|
278
|
+
from { opacity: 0; }
|
|
279
|
+
to { opacity: 1; }
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* \u5168\u87A2\u5E55\u53F3\u4E0A\u89D2\u7684\u96E2\u958B\u9215(toolbar \u96B1\u85CF\u6642\u4E5F\u80FD\u95DC\u9589)\u3002 */
|
|
283
|
+
.rsm-fs-close {
|
|
284
|
+
position: absolute;
|
|
285
|
+
top: 10px;
|
|
286
|
+
right: 10px;
|
|
287
|
+
z-index: 5;
|
|
288
|
+
display: inline-flex;
|
|
289
|
+
align-items: center;
|
|
290
|
+
justify-content: center;
|
|
291
|
+
width: 34px;
|
|
292
|
+
height: 34px;
|
|
293
|
+
padding: 0;
|
|
294
|
+
font-size: 16px;
|
|
295
|
+
line-height: 1;
|
|
296
|
+
border: 1px solid var(--rsm-border);
|
|
297
|
+
border-radius: 8px;
|
|
298
|
+
background: var(--rsm-surface);
|
|
299
|
+
color: var(--rsm-fg);
|
|
300
|
+
cursor: pointer;
|
|
301
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
|
|
302
|
+
transition: background 0.12s ease, color 0.12s ease;
|
|
303
|
+
}
|
|
304
|
+
.rsm-fs-close:hover { background: var(--rsm-hover); }
|
|
305
|
+
|
|
306
|
+
/* \u2500\u2500 RWD \u2500\u2500 \u5C0F\u87A2\u5E55\u6536\u7DCA toolbar\u3001\u7E2E\u77ED\u641C\u5C0B\u6846,\u907F\u514D\u63DB\u884C\u64E0\u58D3\u756B\u5E03\u3002 */
|
|
307
|
+
@media (max-width: 640px) {
|
|
308
|
+
.rsm-toolbar { gap: 6px; padding: 6px 8px; }
|
|
309
|
+
.rsm-btn { padding: 4px 8px; font-size: 12px; }
|
|
310
|
+
.rsm-label { font-size: 11px; }
|
|
311
|
+
.rsm-select { padding: 3px 6px; font-size: 12px; }
|
|
312
|
+
.rsm-zoom > button { padding: 4px 8px; font-size: 12px; }
|
|
313
|
+
.rsm-input { flex-basis: 150px; }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* \u2500\u2500 \u6A19\u7C64\u5B57\u91CD(\u91CF\u6E2C\u968E\u6BB5\u5C31\u751F\u6548)\u2500\u2500
|
|
317
|
+
* boostLegibility \u5728\u300C\u6E32\u67D3\u5F8C\u300D\u624D\u628A\u6A19\u7C64\u5B57\u91CD\u52A0\u5230 600/700,\u4F46 mermaid \u662F\u5728\u300C\u6E32\u67D3\u4E2D\u300D
|
|
318
|
+
* \u91CF\u6E2C\u6587\u5B57\u5BEC\u5EA6\u4F86\u6C7A\u5B9A foreignObject / \u7BC0\u9EDE\u5916\u6846\u7684\u5927\u5C0F\u3002\u82E5\u53EA\u5728\u4E8B\u5F8C\u52A0\u7C97,\u7C97\u9AD4\u5B57\u6703\u6BD4\u5DF2\u91CF\u597D\u7684
|
|
319
|
+
* \u6846\u66F4\u5BEC \u2192 foreignObject \u628A\u5C3E\u5B57\u88C1\u6389(\u5FC3\u667A\u5716\u7BC0\u9EDE\u300Creact-super-mermaid\u300D\u5C3E\u5DF4\u7684 d \u4E0D\u898B\u5C31\u662F\u9019\u500B)\u3002
|
|
320
|
+
* \u89E3\u6CD5:\u628A\u540C\u6A23\u7684\u5B57\u91CD\u7528 CSS \u63D0\u524D\u5BA3\u544A,\u4E14\u300C\u4E0D\u300Dscope \u5728 .rsm-root \u4E4B\u4E0B,\u800C\u662F scope \u5728 mermaid
|
|
321
|
+
* \u7684\u6E32\u67D3 id(svg[id^="rsm-"])\u2014\u2014\u56E0\u70BA\u91CF\u6E2C\u6642\u90A3\u9846\u66AB\u6642\u7684 svg \u9084\u5728 <body> \u4E0B\u3001\u5C1A\u672A\u639B\u9032 .rsm-root\u3002
|
|
322
|
+
* \u9019\u6A23 mermaid \u91CF\u5230\u7684\u5C31\u662F\u7C97\u9AD4\u5BEC\u5EA6,\u6846\u6703\u525B\u597D\u5BB9\u7D0D,\u4E8B\u5F8C boostLegibility \u8A2D\u540C\u503C\u4E0D\u518D\u6490\u7834\u3002
|
|
323
|
+
* \u53EA scope \u6211\u5011\u81EA\u5DF1\u6E32\u67D3\u51FA\u7684 svg,\u6545\u4E0D\u6703\u6C61\u67D3 host \u9801\u9762\u5176\u5B83 mermaid\u3002 */
|
|
324
|
+
svg[id^="rsm-"] g.node text,
|
|
325
|
+
svg[id^="rsm-"] g.node tspan,
|
|
326
|
+
svg[id^="rsm-"] g.node .nodeLabel,
|
|
327
|
+
svg[id^="rsm-"] g.mindmap-node text,
|
|
328
|
+
svg[id^="rsm-"] g.mindmap-node .nodeLabel,
|
|
329
|
+
svg[id^="rsm-"] g[class*="timeline-node"] text,
|
|
330
|
+
svg[id^="rsm-"] text.actor { font-weight: 600 !important; }
|
|
331
|
+
svg[id^="rsm-"] .cluster-label text,
|
|
332
|
+
svg[id^="rsm-"] .cluster-label .nodeLabel,
|
|
333
|
+
svg[id^="rsm-"] text.pieTitleText { font-weight: 700 !important; }
|
|
249
334
|
`;
|
|
250
335
|
|
|
251
336
|
// src/core/ensure-styles.ts
|
|
@@ -282,16 +367,88 @@ var NODE_PALETTE = [
|
|
|
282
367
|
// violet
|
|
283
368
|
];
|
|
284
369
|
var CLUSTER_PALETTE = [
|
|
285
|
-
{ fill: "rgba(59, 130, 246, 0.
|
|
286
|
-
|
|
287
|
-
{ fill: "rgba(
|
|
288
|
-
|
|
289
|
-
{ fill: "rgba(
|
|
290
|
-
|
|
370
|
+
{ fill: "rgba(59, 130, 246, 0.16)", stroke: "#3B82F6" },
|
|
371
|
+
// blue
|
|
372
|
+
{ fill: "rgba(34, 197, 94, 0.16)", stroke: "#22C55E" },
|
|
373
|
+
// green
|
|
374
|
+
{ fill: "rgba(249, 115, 22, 0.16)", stroke: "#F97316" },
|
|
375
|
+
// orange
|
|
376
|
+
{ fill: "rgba(168, 85, 247, 0.16)", stroke: "#A855F7" },
|
|
377
|
+
// purple
|
|
378
|
+
{ fill: "rgba(239, 68, 68, 0.16)", stroke: "#EF4444" },
|
|
379
|
+
// red
|
|
380
|
+
{ fill: "rgba(6, 182, 212, 0.16)", stroke: "#06B6D4" },
|
|
381
|
+
// cyan
|
|
382
|
+
{ fill: "rgba(234, 179, 8, 0.16)", stroke: "#EAB308" },
|
|
383
|
+
// yellow
|
|
384
|
+
{ fill: "rgba(139, 92, 246, 0.16)", stroke: "#8B5CF6" }
|
|
385
|
+
// violet
|
|
386
|
+
];
|
|
387
|
+
var PIE_PALETTE = [
|
|
388
|
+
"#3B82F6",
|
|
389
|
+
// blue
|
|
390
|
+
"#22C55E",
|
|
391
|
+
// green
|
|
392
|
+
"#F59E0B",
|
|
393
|
+
// amber
|
|
394
|
+
"#A855F7",
|
|
395
|
+
// purple
|
|
396
|
+
"#EF4444",
|
|
397
|
+
// red
|
|
398
|
+
"#06B6D4",
|
|
399
|
+
// cyan
|
|
400
|
+
"#EC4899",
|
|
401
|
+
// pink
|
|
402
|
+
"#84CC16",
|
|
403
|
+
// lime
|
|
404
|
+
"#F97316",
|
|
405
|
+
// orange
|
|
406
|
+
"#14B8A6",
|
|
407
|
+
// teal
|
|
408
|
+
"#6366F1",
|
|
409
|
+
// indigo
|
|
410
|
+
"#EAB308"
|
|
411
|
+
// yellow
|
|
291
412
|
];
|
|
292
413
|
var NODE_TEXT = "#1F2937";
|
|
293
414
|
var SHADOW_FILTER_ID = "rsm-soft-shadow";
|
|
294
415
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
416
|
+
function resolveSvg(root) {
|
|
417
|
+
if (root instanceof Element && root.tagName.toLowerCase() === "svg") {
|
|
418
|
+
return root;
|
|
419
|
+
}
|
|
420
|
+
return root.querySelector("svg");
|
|
421
|
+
}
|
|
422
|
+
function canonColor(input) {
|
|
423
|
+
const s = (input || "").trim();
|
|
424
|
+
const hex = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(s);
|
|
425
|
+
if (hex) {
|
|
426
|
+
let h = hex[1];
|
|
427
|
+
if (h.length === 3) {
|
|
428
|
+
h = h.split("").map((c) => c + c).join("");
|
|
429
|
+
}
|
|
430
|
+
const n = parseInt(h, 16);
|
|
431
|
+
return `${n >> 16 & 255},${n >> 8 & 255},${n & 255}`;
|
|
432
|
+
}
|
|
433
|
+
const rgb = /rgba?\(([^)]+)\)/i.exec(s);
|
|
434
|
+
if (rgb) {
|
|
435
|
+
const p = rgb[1].split(",").map((x) => Math.round(parseFloat(x)));
|
|
436
|
+
return `${p[0]},${p[1]},${p[2]}`;
|
|
437
|
+
}
|
|
438
|
+
return s.toLowerCase();
|
|
439
|
+
}
|
|
440
|
+
function readableTextOn(color) {
|
|
441
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(color.trim());
|
|
442
|
+
if (!m) {
|
|
443
|
+
return "#FFFFFF";
|
|
444
|
+
}
|
|
445
|
+
const n = parseInt(m[1], 16);
|
|
446
|
+
const r = n >> 16 & 255;
|
|
447
|
+
const g = n >> 8 & 255;
|
|
448
|
+
const b = n & 255;
|
|
449
|
+
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
450
|
+
return lum > 0.62 ? "#1F2937" : "#FFFFFF";
|
|
451
|
+
}
|
|
295
452
|
function ensureShadowFilter(svg) {
|
|
296
453
|
if (svg.querySelector(`#${SHADOW_FILTER_ID}`)) {
|
|
297
454
|
return;
|
|
@@ -397,6 +554,17 @@ function styleEdgeLabels(svg) {
|
|
|
397
554
|
rect.setAttribute("ry", "4");
|
|
398
555
|
}
|
|
399
556
|
}
|
|
557
|
+
function styleLabelText(svg, dark) {
|
|
558
|
+
const color = dark ? "#E2E8F0" : NODE_TEXT;
|
|
559
|
+
for (const t of Array.from(
|
|
560
|
+
svg.querySelectorAll("text.messageText, .edgeLabel text, .edgeLabel tspan")
|
|
561
|
+
)) {
|
|
562
|
+
t.style.fill = color;
|
|
563
|
+
}
|
|
564
|
+
for (const t of Array.from(svg.querySelectorAll(".edgeLabel span, .edgeLabel p"))) {
|
|
565
|
+
t.style.color = color;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
400
568
|
function colorizeLegacyEr(svg) {
|
|
401
569
|
const erGroups = [];
|
|
402
570
|
for (const rect of Array.from(svg.querySelectorAll("rect.er.entityBox"))) {
|
|
@@ -508,12 +676,194 @@ function colorizeSequence(svg, dark) {
|
|
|
508
676
|
text.style.fill = dark ? "#E2E8F0" : NODE_TEXT;
|
|
509
677
|
}
|
|
510
678
|
}
|
|
679
|
+
function stylePie(svg, dark) {
|
|
680
|
+
const slices = Array.from(svg.querySelectorAll("path.pieCircle"));
|
|
681
|
+
const swatches = Array.from(svg.querySelectorAll("g.legend rect"));
|
|
682
|
+
if (slices.length === 0 && swatches.length === 0) {
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const remap = /* @__PURE__ */ new Map();
|
|
686
|
+
let next = 0;
|
|
687
|
+
const newColorFor = (old) => {
|
|
688
|
+
const key = canonColor(old) || `#slot-${next}`;
|
|
689
|
+
let c = remap.get(key);
|
|
690
|
+
if (!c) {
|
|
691
|
+
c = PIE_PALETTE[next % PIE_PALETTE.length];
|
|
692
|
+
remap.set(key, c);
|
|
693
|
+
next += 1;
|
|
694
|
+
}
|
|
695
|
+
return c;
|
|
696
|
+
};
|
|
697
|
+
for (const slice of slices) {
|
|
698
|
+
const old = slice.style.fill || slice.getAttribute("fill") || "";
|
|
699
|
+
const c = newColorFor(old);
|
|
700
|
+
slice.style.fill = c;
|
|
701
|
+
slice.style.opacity = "1";
|
|
702
|
+
slice.style.stroke = dark ? "#0F172A" : "#FFFFFF";
|
|
703
|
+
slice.style.strokeWidth = "2px";
|
|
704
|
+
slice.style.strokeLinejoin = "round";
|
|
705
|
+
}
|
|
706
|
+
for (const sw of swatches) {
|
|
707
|
+
const old = sw.style.fill || sw.getAttribute("fill") || "";
|
|
708
|
+
const c = newColorFor(old);
|
|
709
|
+
sw.style.fill = c;
|
|
710
|
+
sw.style.stroke = c;
|
|
711
|
+
sw.setAttribute("rx", "3");
|
|
712
|
+
sw.setAttribute("ry", "3");
|
|
713
|
+
}
|
|
714
|
+
Array.from(svg.querySelectorAll("text.slice")).forEach((label, i) => {
|
|
715
|
+
const slice = slices[i];
|
|
716
|
+
const c = slice ? slice.style.fill || PIE_PALETTE[0] : PIE_PALETTE[0];
|
|
717
|
+
label.style.fill = readableTextOn(c);
|
|
718
|
+
label.style.fontWeight = "600";
|
|
719
|
+
});
|
|
720
|
+
for (const title of Array.from(svg.querySelectorAll("text.pieTitleText"))) {
|
|
721
|
+
title.style.fontWeight = "700";
|
|
722
|
+
title.style.fill = dark ? "#E2E8F0" : "#1F2937";
|
|
723
|
+
}
|
|
724
|
+
for (const t of Array.from(svg.querySelectorAll("g.legend text"))) {
|
|
725
|
+
t.style.fill = dark ? "#E2E8F0" : "#1F2937";
|
|
726
|
+
}
|
|
727
|
+
for (const oc of Array.from(svg.querySelectorAll("circle.pieOuterCircle"))) {
|
|
728
|
+
oc.style.stroke = dark ? "#334155" : "#CBD5E1";
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
function styleGantt(svg, dark) {
|
|
732
|
+
const tasks = Array.from(svg.querySelectorAll("rect.task"));
|
|
733
|
+
if (tasks.length === 0) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
for (const task of tasks) {
|
|
737
|
+
const cls = task.getAttribute("class") ?? "";
|
|
738
|
+
if (/\b(done|active|crit|milestone)\d*\b/.test(cls)) {
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
const m = cls.match(/task(\d+)/);
|
|
742
|
+
if (!m) {
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
const entry = NODE_PALETTE[Number(m[1]) % NODE_PALETTE.length];
|
|
746
|
+
task.style.fill = entry.fill;
|
|
747
|
+
task.style.stroke = entry.stroke;
|
|
748
|
+
task.setAttribute("rx", "4");
|
|
749
|
+
task.setAttribute("ry", "4");
|
|
750
|
+
}
|
|
751
|
+
Array.from(svg.querySelectorAll("rect.section")).forEach((band) => {
|
|
752
|
+
const m = (band.getAttribute("class") ?? "").match(/section(\d+)/);
|
|
753
|
+
if (m) {
|
|
754
|
+
band.style.fill = CLUSTER_PALETTE[Number(m[1]) % CLUSTER_PALETTE.length].fill;
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
for (const inBar of Array.from(svg.querySelectorAll("text.taskText"))) {
|
|
758
|
+
if (!/Outside/.test(inBar.getAttribute("class") ?? "")) {
|
|
759
|
+
inBar.style.fill = NODE_TEXT;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
for (const tick of Array.from(svg.querySelectorAll("g.grid g.tick line"))) {
|
|
763
|
+
tick.style.stroke = dark ? "#334155" : "#E2E8F0";
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function styleTimeline(svg) {
|
|
767
|
+
const nodes = Array.from(svg.querySelectorAll('g[class*="timeline-node"]'));
|
|
768
|
+
nodes.forEach((node, i) => {
|
|
769
|
+
const m = (node.getAttribute("class") ?? "").match(/section-(-?\d+)/);
|
|
770
|
+
const section = m ? Number(m[1]) : i;
|
|
771
|
+
const entry = section < 0 ? NODE_PALETTE[7] : NODE_PALETTE[section % NODE_PALETTE.length];
|
|
772
|
+
const backgrounds = Array.from(node.querySelectorAll(".node-bkg"));
|
|
773
|
+
if (backgrounds.length > 0) {
|
|
774
|
+
for (const bkg of backgrounds) {
|
|
775
|
+
bkg.style.fill = entry.fill;
|
|
776
|
+
bkg.style.stroke = entry.stroke;
|
|
777
|
+
bkg.style.strokeWidth = "1.4px";
|
|
778
|
+
}
|
|
779
|
+
} else {
|
|
780
|
+
paintShapes(node, entry);
|
|
781
|
+
}
|
|
782
|
+
darkenNodeText(node);
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
function styleMindmap(svg) {
|
|
786
|
+
const nodes = Array.from(svg.querySelectorAll("g.mindmap-node"));
|
|
787
|
+
if (nodes.length === 0) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
for (const node of nodes) {
|
|
791
|
+
const m = (node.getAttribute("class") ?? "").match(/section-(-?\d+)/);
|
|
792
|
+
const section = m ? Number(m[1]) : 0;
|
|
793
|
+
const entry = section < 0 ? NODE_PALETTE[7] : NODE_PALETTE[section % NODE_PALETTE.length];
|
|
794
|
+
for (const shape of Array.from(
|
|
795
|
+
node.querySelectorAll("path, rect, circle, ellipse")
|
|
796
|
+
)) {
|
|
797
|
+
if (shape.closest("g.children")) {
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
800
|
+
shape.style.fill = entry.fill;
|
|
801
|
+
shape.style.stroke = entry.stroke;
|
|
802
|
+
shape.style.strokeWidth = "1.4px";
|
|
803
|
+
}
|
|
804
|
+
darkenNodeText(node);
|
|
805
|
+
}
|
|
806
|
+
for (const edge of Array.from(svg.querySelectorAll('path[class*="edge"]'))) {
|
|
807
|
+
const m = (edge.getAttribute("class") ?? "").match(/section-edge-(-?\d+)/);
|
|
808
|
+
if (m) {
|
|
809
|
+
const section = Number(m[1]);
|
|
810
|
+
const entry = section < 0 ? NODE_PALETTE[7] : NODE_PALETTE[section % NODE_PALETTE.length];
|
|
811
|
+
edge.style.stroke = entry.stroke;
|
|
812
|
+
edge.style.strokeWidth = "2px";
|
|
813
|
+
edge.style.opacity = "0.6";
|
|
814
|
+
edge.style.fill = "none";
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
function styleJourney(svg) {
|
|
819
|
+
const tasks = Array.from(
|
|
820
|
+
svg.querySelectorAll('circle[class*="task-type"], rect[class*="task-type"]')
|
|
821
|
+
);
|
|
822
|
+
tasks.forEach((shape) => {
|
|
823
|
+
const m = (shape.getAttribute("class") ?? "").match(/task-type-(\d+)/);
|
|
824
|
+
if (m) {
|
|
825
|
+
const entry = NODE_PALETTE[Number(m[1]) % NODE_PALETTE.length];
|
|
826
|
+
shape.style.fill = entry.fill;
|
|
827
|
+
shape.style.stroke = entry.stroke;
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
Array.from(svg.querySelectorAll('rect[class*="section-type"]')).forEach((rect) => {
|
|
831
|
+
const m = (rect.getAttribute("class") ?? "").match(/section-type-(\d+)/);
|
|
832
|
+
if (m) {
|
|
833
|
+
const entry = CLUSTER_PALETTE[Number(m[1]) % CLUSTER_PALETTE.length];
|
|
834
|
+
rect.style.fill = entry.fill;
|
|
835
|
+
rect.style.stroke = entry.stroke;
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
function boostLegibility(root) {
|
|
840
|
+
const svg = resolveSvg(root);
|
|
841
|
+
if (!svg) {
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
for (const el of Array.from(
|
|
845
|
+
svg.querySelectorAll(
|
|
846
|
+
'g.node text, g.node tspan, g.mindmap-node text, g[class*="timeline-node"] text, text.actor'
|
|
847
|
+
)
|
|
848
|
+
)) {
|
|
849
|
+
el.style.fontWeight = "600";
|
|
850
|
+
}
|
|
851
|
+
for (const el of Array.from(svg.querySelectorAll(".nodeLabel, g.node span, g.node p"))) {
|
|
852
|
+
el.style.fontWeight = "600";
|
|
853
|
+
}
|
|
854
|
+
for (const el of Array.from(svg.querySelectorAll("text"))) {
|
|
855
|
+
if (!el.style.fontWeight) {
|
|
856
|
+
el.style.fontWeight = "500";
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
511
860
|
function colorizeDiagram(root, opts = {}) {
|
|
512
|
-
const svg =
|
|
861
|
+
const svg = resolveSvg(root);
|
|
513
862
|
if (!svg) {
|
|
514
863
|
return;
|
|
515
864
|
}
|
|
516
865
|
ensureShadowFilter(svg);
|
|
866
|
+
const dark = opts.dark === true;
|
|
517
867
|
Array.from(svg.querySelectorAll("g.node")).forEach((node, i) => {
|
|
518
868
|
paintShapes(node, NODE_PALETTE[i % NODE_PALETTE.length]);
|
|
519
869
|
darkenNodeText(node);
|
|
@@ -523,14 +873,41 @@ function colorizeDiagram(root, opts = {}) {
|
|
|
523
873
|
for (const rect of Array.from(cluster.querySelectorAll(":scope > rect"))) {
|
|
524
874
|
rect.style.fill = entry.fill;
|
|
525
875
|
rect.style.stroke = entry.stroke;
|
|
526
|
-
rect.style.strokeWidth = "1.
|
|
876
|
+
rect.style.strokeWidth = "1.5px";
|
|
527
877
|
roundRect(rect, 10);
|
|
528
878
|
}
|
|
879
|
+
const label = cluster.querySelector(":scope > .cluster-label");
|
|
880
|
+
if (label) {
|
|
881
|
+
for (const el of Array.from(label.querySelectorAll("text, tspan"))) {
|
|
882
|
+
el.style.fill = entry.stroke;
|
|
883
|
+
el.style.fontWeight = "700";
|
|
884
|
+
}
|
|
885
|
+
for (const el of Array.from(label.querySelectorAll(".nodeLabel, span, p"))) {
|
|
886
|
+
el.style.color = entry.stroke;
|
|
887
|
+
el.style.fontWeight = "700";
|
|
888
|
+
}
|
|
889
|
+
for (const lr of Array.from(label.querySelectorAll("rect"))) {
|
|
890
|
+
lr.style.fill = entry.fill;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
529
893
|
});
|
|
530
894
|
colorizeLegacyEr(svg);
|
|
531
|
-
colorizeSequence(svg,
|
|
532
|
-
styleEdges(svg,
|
|
895
|
+
colorizeSequence(svg, dark);
|
|
896
|
+
styleEdges(svg, dark);
|
|
533
897
|
styleEdgeLabels(svg);
|
|
898
|
+
styleLabelText(svg, dark);
|
|
899
|
+
const kind = svg.getAttribute("aria-roledescription") ?? "";
|
|
900
|
+
if (kind === "pie" || kind === "pieChart") {
|
|
901
|
+
stylePie(svg, dark);
|
|
902
|
+
} else if (kind === "gantt") {
|
|
903
|
+
styleGantt(svg, dark);
|
|
904
|
+
} else if (kind === "timeline") {
|
|
905
|
+
styleTimeline(svg);
|
|
906
|
+
} else if (kind === "mindmap") {
|
|
907
|
+
styleMindmap(svg);
|
|
908
|
+
} else if (kind === "journey") {
|
|
909
|
+
styleJourney(svg);
|
|
910
|
+
}
|
|
534
911
|
}
|
|
535
912
|
|
|
536
913
|
// src/core/themes/sketch.ts
|
|
@@ -814,6 +1191,7 @@ function applyPostProcess(svg, postProcess, opts) {
|
|
|
814
1191
|
} else if (postProcess === "sketch") {
|
|
815
1192
|
sketchifyDiagram(svg, { dark: opts.dark, seed: opts.seed });
|
|
816
1193
|
}
|
|
1194
|
+
boostLegibility(svg);
|
|
817
1195
|
}
|
|
818
1196
|
async function renderDiagram(opts) {
|
|
819
1197
|
assertBrowser("renderDiagram");
|
|
@@ -1312,6 +1690,11 @@ function useMermaidViewer(opts) {
|
|
|
1312
1690
|
getSvg
|
|
1313
1691
|
};
|
|
1314
1692
|
}
|
|
1693
|
+
var BACKGROUND_LABELS = {
|
|
1694
|
+
transparent: { icon: "\u25A6", label: "\u900F\u660E" },
|
|
1695
|
+
solid: { icon: "\u25FB", label: "\u7D14\u8272" },
|
|
1696
|
+
grid: { icon: "\u229E", label: "\u683C\u7DDA" }
|
|
1697
|
+
};
|
|
1315
1698
|
var DEFAULT_THEME_OPTIONS = [
|
|
1316
1699
|
{ value: "colorful", label: "Colorful" },
|
|
1317
1700
|
{ value: "sketch", label: "Excalidraw" },
|
|
@@ -1335,6 +1718,20 @@ function Toolbar(props) {
|
|
|
1335
1718
|
}
|
|
1336
1719
|
)
|
|
1337
1720
|
] }),
|
|
1721
|
+
props.backgroundEnabled ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1722
|
+
"button",
|
|
1723
|
+
{
|
|
1724
|
+
type: "button",
|
|
1725
|
+
className: "rsm-btn",
|
|
1726
|
+
onClick: props.onCycleBackground,
|
|
1727
|
+
title: "\u5207\u63DB\u756B\u5E03\u80CC\u666F\uFF08\u900F\u660E / \u7D14\u8272 / \u683C\u7DDA\uFF0CB\uFF09",
|
|
1728
|
+
children: [
|
|
1729
|
+
BACKGROUND_LABELS[props.background].icon,
|
|
1730
|
+
" \u80CC\u666F\uFF1A",
|
|
1731
|
+
BACKGROUND_LABELS[props.background].label
|
|
1732
|
+
]
|
|
1733
|
+
}
|
|
1734
|
+
) : null,
|
|
1338
1735
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rsm-toolbar-spacer" }),
|
|
1339
1736
|
props.searchEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1340
1737
|
"button",
|
|
@@ -1388,9 +1785,21 @@ function Toolbar(props) {
|
|
|
1388
1785
|
),
|
|
1389
1786
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: props.onZoomIn, title: "\u653E\u5927\uFF08+\uFF09", children: "\uFF0B" }),
|
|
1390
1787
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: props.onReset, title: "\u7B26\u5408\u8996\u7A97\uFF080\uFF09", children: "\u2922" })
|
|
1391
|
-
] })
|
|
1788
|
+
] }),
|
|
1789
|
+
props.fullscreenEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1790
|
+
"button",
|
|
1791
|
+
{
|
|
1792
|
+
type: "button",
|
|
1793
|
+
className: "rsm-btn rsm-btn-fullscreen",
|
|
1794
|
+
"aria-pressed": props.fullscreen ? "true" : "false",
|
|
1795
|
+
onClick: props.onToggleFullscreen,
|
|
1796
|
+
title: props.fullscreen ? "\u96E2\u958B\u5168\u87A2\u5E55\uFF08Esc\uFF09" : "\u5168\u87A2\u5E55\u6AA2\u8996\uFF08F\uFF09",
|
|
1797
|
+
children: props.fullscreen ? "\u2715 \u96E2\u958B\u5168\u87A2\u5E55" : "\u26F6 \u5168\u87A2\u5E55"
|
|
1798
|
+
}
|
|
1799
|
+
) : null
|
|
1392
1800
|
] });
|
|
1393
1801
|
}
|
|
1802
|
+
var BACKGROUND_CYCLE = ["transparent", "solid", "grid"];
|
|
1394
1803
|
function usePrefersDark(explicit) {
|
|
1395
1804
|
const [autoDark, setAutoDark] = react.useState(false);
|
|
1396
1805
|
react.useEffect(() => {
|
|
@@ -1414,6 +1823,9 @@ var MermaidViewer = react.forwardRef(
|
|
|
1414
1823
|
panZoom = true,
|
|
1415
1824
|
search: searchEnabled = true,
|
|
1416
1825
|
exportable = true,
|
|
1826
|
+
background: backgroundEnabled = true,
|
|
1827
|
+
fullscreen: fullscreenEnabled = true,
|
|
1828
|
+
onFullscreenChange,
|
|
1417
1829
|
keyboard = true,
|
|
1418
1830
|
seed = 42,
|
|
1419
1831
|
fontUrl,
|
|
@@ -1437,6 +1849,15 @@ var MermaidViewer = react.forwardRef(
|
|
|
1437
1849
|
const [query, setQuery] = react.useState("");
|
|
1438
1850
|
const [matchInfo, setMatchInfo] = react.useState({ current: 0, total: 0 });
|
|
1439
1851
|
const [exporting, setExporting] = react.useState(false);
|
|
1852
|
+
const [background, setBackgroundState] = react.useState(
|
|
1853
|
+
props.backgroundMode ?? "transparent"
|
|
1854
|
+
);
|
|
1855
|
+
react.useEffect(() => {
|
|
1856
|
+
if (props.backgroundMode) {
|
|
1857
|
+
setBackgroundState(props.backgroundMode);
|
|
1858
|
+
}
|
|
1859
|
+
}, [props.backgroundMode]);
|
|
1860
|
+
const [isFullscreen, setIsFullscreen] = react.useState(false);
|
|
1440
1861
|
const rootRef = react.useRef(null);
|
|
1441
1862
|
const searchInputRef = react.useRef(null);
|
|
1442
1863
|
const vm = useMermaidViewer({
|
|
@@ -1499,6 +1920,85 @@ var MermaidViewer = react.forwardRef(
|
|
|
1499
1920
|
setExporting(false);
|
|
1500
1921
|
}
|
|
1501
1922
|
}, [vm, onError]);
|
|
1923
|
+
const cycleBackground = react.useCallback(() => {
|
|
1924
|
+
setBackgroundState((prev) => {
|
|
1925
|
+
const i = BACKGROUND_CYCLE.indexOf(prev);
|
|
1926
|
+
return BACKGROUND_CYCLE[(i + 1) % BACKGROUND_CYCLE.length];
|
|
1927
|
+
});
|
|
1928
|
+
}, []);
|
|
1929
|
+
const setBackground = react.useCallback((mode) => {
|
|
1930
|
+
setBackgroundState(mode);
|
|
1931
|
+
}, []);
|
|
1932
|
+
const enterFullscreen = react.useCallback(() => {
|
|
1933
|
+
setIsFullscreen((prev) => {
|
|
1934
|
+
if (!prev) {
|
|
1935
|
+
onFullscreenChange?.(true);
|
|
1936
|
+
}
|
|
1937
|
+
return true;
|
|
1938
|
+
});
|
|
1939
|
+
}, [onFullscreenChange]);
|
|
1940
|
+
const exitFullscreen = react.useCallback(() => {
|
|
1941
|
+
setIsFullscreen((prev) => {
|
|
1942
|
+
if (prev) {
|
|
1943
|
+
onFullscreenChange?.(false);
|
|
1944
|
+
}
|
|
1945
|
+
return false;
|
|
1946
|
+
});
|
|
1947
|
+
}, [onFullscreenChange]);
|
|
1948
|
+
const toggleFullscreen = react.useCallback(() => {
|
|
1949
|
+
setIsFullscreen((prev) => {
|
|
1950
|
+
onFullscreenChange?.(!prev);
|
|
1951
|
+
return !prev;
|
|
1952
|
+
});
|
|
1953
|
+
}, [onFullscreenChange]);
|
|
1954
|
+
react.useEffect(() => {
|
|
1955
|
+
if (!isFullscreen) {
|
|
1956
|
+
return void 0;
|
|
1957
|
+
}
|
|
1958
|
+
const body = typeof document !== "undefined" ? document.body : null;
|
|
1959
|
+
const prevOverflow = body?.style.overflow ?? "";
|
|
1960
|
+
if (body) {
|
|
1961
|
+
body.style.overflow = "hidden";
|
|
1962
|
+
}
|
|
1963
|
+
const onWinKey = (e) => {
|
|
1964
|
+
if (e.key === "Escape") {
|
|
1965
|
+
e.preventDefault();
|
|
1966
|
+
exitFullscreen();
|
|
1967
|
+
}
|
|
1968
|
+
};
|
|
1969
|
+
window.addEventListener("keydown", onWinKey);
|
|
1970
|
+
const fitId = window.setTimeout(() => vm.reset(), 60);
|
|
1971
|
+
let resizeId = 0;
|
|
1972
|
+
const onResize = () => {
|
|
1973
|
+
window.clearTimeout(resizeId);
|
|
1974
|
+
resizeId = window.setTimeout(() => vm.reset(), 150);
|
|
1975
|
+
};
|
|
1976
|
+
window.addEventListener("resize", onResize);
|
|
1977
|
+
window.addEventListener("orientationchange", onResize);
|
|
1978
|
+
rootRef.current?.focus();
|
|
1979
|
+
return () => {
|
|
1980
|
+
window.removeEventListener("keydown", onWinKey);
|
|
1981
|
+
window.removeEventListener("resize", onResize);
|
|
1982
|
+
window.removeEventListener("orientationchange", onResize);
|
|
1983
|
+
window.clearTimeout(fitId);
|
|
1984
|
+
window.clearTimeout(resizeId);
|
|
1985
|
+
if (body) {
|
|
1986
|
+
body.style.overflow = prevOverflow;
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
}, [isFullscreen, exitFullscreen]);
|
|
1990
|
+
const fsMountedRef = react.useRef(false);
|
|
1991
|
+
react.useEffect(() => {
|
|
1992
|
+
if (!fsMountedRef.current) {
|
|
1993
|
+
fsMountedRef.current = true;
|
|
1994
|
+
return void 0;
|
|
1995
|
+
}
|
|
1996
|
+
if (isFullscreen) {
|
|
1997
|
+
return void 0;
|
|
1998
|
+
}
|
|
1999
|
+
const id = window.setTimeout(() => vm.reset(), 60);
|
|
2000
|
+
return () => window.clearTimeout(id);
|
|
2001
|
+
}, [isFullscreen]);
|
|
1502
2002
|
react.useEffect(() => {
|
|
1503
2003
|
if (!keyboard) {
|
|
1504
2004
|
return void 0;
|
|
@@ -1524,6 +2024,11 @@ var MermaidViewer = react.forwardRef(
|
|
|
1524
2024
|
closeSearch();
|
|
1525
2025
|
return;
|
|
1526
2026
|
}
|
|
2027
|
+
if (e.key === "Escape" && isFullscreen) {
|
|
2028
|
+
e.preventDefault();
|
|
2029
|
+
exitFullscreen();
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
1527
2032
|
if (typing) {
|
|
1528
2033
|
return;
|
|
1529
2034
|
}
|
|
@@ -1537,11 +2042,29 @@ var MermaidViewer = react.forwardRef(
|
|
|
1537
2042
|
vm.actualSize();
|
|
1538
2043
|
} else if (e.key === "w" || e.key === "W") {
|
|
1539
2044
|
vm.fit();
|
|
2045
|
+
} else if (fullscreenEnabled && (e.key === "f" || e.key === "F")) {
|
|
2046
|
+
e.preventDefault();
|
|
2047
|
+
toggleFullscreen();
|
|
2048
|
+
} else if (backgroundEnabled && (e.key === "b" || e.key === "B")) {
|
|
2049
|
+
e.preventDefault();
|
|
2050
|
+
cycleBackground();
|
|
1540
2051
|
}
|
|
1541
2052
|
};
|
|
1542
2053
|
root.addEventListener("keydown", onKey);
|
|
1543
2054
|
return () => root.removeEventListener("keydown", onKey);
|
|
1544
|
-
}, [
|
|
2055
|
+
}, [
|
|
2056
|
+
keyboard,
|
|
2057
|
+
searchOpen,
|
|
2058
|
+
openSearch,
|
|
2059
|
+
closeSearch,
|
|
2060
|
+
vm,
|
|
2061
|
+
isFullscreen,
|
|
2062
|
+
exitFullscreen,
|
|
2063
|
+
toggleFullscreen,
|
|
2064
|
+
cycleBackground,
|
|
2065
|
+
fullscreenEnabled,
|
|
2066
|
+
backgroundEnabled
|
|
2067
|
+
]);
|
|
1545
2068
|
react.useImperativeHandle(
|
|
1546
2069
|
ref,
|
|
1547
2070
|
() => ({
|
|
@@ -1559,9 +2082,25 @@ var MermaidViewer = react.forwardRef(
|
|
|
1559
2082
|
exportPng: vm.exportPng,
|
|
1560
2083
|
downloadSvg: vm.downloadSvg,
|
|
1561
2084
|
downloadPng: vm.downloadPng,
|
|
1562
|
-
getSvg: vm.getSvg
|
|
2085
|
+
getSvg: vm.getSvg,
|
|
2086
|
+
enterFullscreen,
|
|
2087
|
+
exitFullscreen,
|
|
2088
|
+
toggleFullscreen,
|
|
2089
|
+
isFullscreen: () => isFullscreen,
|
|
2090
|
+
setBackground,
|
|
2091
|
+
cycleBackground,
|
|
2092
|
+
getBackground: () => background
|
|
1563
2093
|
}),
|
|
1564
|
-
[
|
|
2094
|
+
[
|
|
2095
|
+
vm,
|
|
2096
|
+
enterFullscreen,
|
|
2097
|
+
exitFullscreen,
|
|
2098
|
+
toggleFullscreen,
|
|
2099
|
+
isFullscreen,
|
|
2100
|
+
setBackground,
|
|
2101
|
+
cycleBackground,
|
|
2102
|
+
background
|
|
2103
|
+
]
|
|
1565
2104
|
);
|
|
1566
2105
|
let countText = "";
|
|
1567
2106
|
if (matchInfo.total > 0) {
|
|
@@ -1569,7 +2108,13 @@ var MermaidViewer = react.forwardRef(
|
|
|
1569
2108
|
} else if (query.trim()) {
|
|
1570
2109
|
countText = "0";
|
|
1571
2110
|
}
|
|
1572
|
-
const rootClassName = [
|
|
2111
|
+
const rootClassName = [
|
|
2112
|
+
"rsm-root",
|
|
2113
|
+
dark ? "rsm-dark" : "",
|
|
2114
|
+
`rsm-bg-${background}`,
|
|
2115
|
+
isFullscreen ? "rsm-fullscreen" : "",
|
|
2116
|
+
className ?? ""
|
|
2117
|
+
].filter(Boolean).join(" ");
|
|
1573
2118
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1574
2119
|
"div",
|
|
1575
2120
|
{
|
|
@@ -1595,7 +2140,13 @@ var MermaidViewer = react.forwardRef(
|
|
|
1595
2140
|
exportEnabled: exportable,
|
|
1596
2141
|
exporting,
|
|
1597
2142
|
onExportSvg: exportSvg,
|
|
1598
|
-
onExportPng: exportPng
|
|
2143
|
+
onExportPng: exportPng,
|
|
2144
|
+
backgroundEnabled,
|
|
2145
|
+
background,
|
|
2146
|
+
onCycleBackground: cycleBackground,
|
|
2147
|
+
fullscreenEnabled,
|
|
2148
|
+
fullscreen: isFullscreen,
|
|
2149
|
+
onToggleFullscreen: toggleFullscreen
|
|
1599
2150
|
}
|
|
1600
2151
|
) : null,
|
|
1601
2152
|
toolbar && searchEnabled && searchOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rsm-searchbar", children: [
|
|
@@ -1635,6 +2186,17 @@ var MermaidViewer = react.forwardRef(
|
|
|
1635
2186
|
"\u5716\u8868\u8F09\u5165\u5931\u6557\uFF1A",
|
|
1636
2187
|
vm.error
|
|
1637
2188
|
] }) : null,
|
|
2189
|
+
isFullscreen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2190
|
+
"button",
|
|
2191
|
+
{
|
|
2192
|
+
type: "button",
|
|
2193
|
+
className: "rsm-fs-close",
|
|
2194
|
+
onClick: exitFullscreen,
|
|
2195
|
+
title: "\u96E2\u958B\u5168\u87A2\u5E55\uFF08Esc\uFF09",
|
|
2196
|
+
"aria-label": "\u96E2\u958B\u5168\u87A2\u5E55",
|
|
2197
|
+
children: "\u2715"
|
|
2198
|
+
}
|
|
2199
|
+
) : null,
|
|
1638
2200
|
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: vm.stageRef, className: "rsm-stage" })
|
|
1639
2201
|
] })
|
|
1640
2202
|
]
|
|
@@ -1654,6 +2216,7 @@ exports.MermaidDiagram = MermaidDiagram;
|
|
|
1654
2216
|
exports.MermaidViewer = MermaidViewer;
|
|
1655
2217
|
exports.SKETCH_FONT = SKETCH_FONT;
|
|
1656
2218
|
exports.Toolbar = Toolbar;
|
|
2219
|
+
exports.boostLegibility = boostLegibility;
|
|
1657
2220
|
exports.colorizeDiagram = colorizeDiagram;
|
|
1658
2221
|
exports.downloadBlob = downloadBlob;
|
|
1659
2222
|
exports.ensureSketchFont = ensureSketchFont;
|