@haklex/rich-renderer-mermaid 0.15.1 → 0.15.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.
@@ -1 +1 @@
1
- {"version":3,"file":"MermaidEditRenderer.d.ts","sourceRoot":"","sources":["../src/MermaidEditRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAiB1E,OAAO,KAAK,EAAe,EAAE,EAAE,MAAM,OAAO,CAAC;AAiU7C,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,oBAAoB,CA6DxD,CAAC"}
1
+ {"version":3,"file":"MermaidEditRenderer.d.ts","sourceRoot":"","sources":["../src/MermaidEditRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAiB1E,OAAO,KAAK,EAAe,EAAE,EAAE,MAAM,OAAO,CAAC;AAqT7C,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,oBAAoB,CAyDxD,CAAC"}
@@ -0,0 +1,148 @@
1
+ import { useColorScheme } from "@haklex/rich-editor/static";
2
+ import { useMemo } from "react";
3
+ import { renderMermaidSVG } from "beautiful-mermaid";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/styles.css.ts
6
+ var mermaidContainer = "_36yqie0";
7
+ var mermaidEditHint = "_36yqie1";
8
+ var zoomControls = "_36yqie2";
9
+ var zoomBtn = "_36yqie3";
10
+ var mermaidError = "_36yqie7";
11
+ var editorPopup = "_36yqie8";
12
+ var editorHeader = "_36yqie9";
13
+ var editorHeaderLeft = "_36yqiea";
14
+ var editorHeaderRight = "_36yqieb";
15
+ var editorSep = "_36yqiec";
16
+ var editorTitle = "_36yqied";
17
+ var editorTplBtn = "_36yqiee";
18
+ var editorViewToggle = "_36yqief";
19
+ var editorViewItem = "_36yqieg";
20
+ var editorViewItemActive = "_36yqieh";
21
+ var editorIconBtn = "_36yqiei";
22
+ var editorBody = "_36yqiej";
23
+ var editorPane = "_36yqiek";
24
+ var editorPaneHalf = "_36yqiel";
25
+ var editorPaneFull = "_36yqiem";
26
+ var editorPaneLabel = "_36yqien";
27
+ var editorPreviewPane = "_36yqieo";
28
+ var editorPreviewWrap = "_36yqiep";
29
+ var editorPreviewEmpty = "_36yqieq";
30
+ var editorPreviewErrorWrap = "_36yqier";
31
+ var editorPreviewErrorIcon = "_36yqies";
32
+ var editorPreviewErrorTitle = "_36yqiet";
33
+ var editorPreviewErrorMsg = "_36yqieu";
34
+ var codeEditor = "_36yqiev";
35
+ var codeGutter = "_36yqiew";
36
+ var codeGutterLine = "_36yqiex";
37
+ var codeArea = "_36yqiey";
38
+ var editorFooter = "_36yqiez";
39
+ var footerActions = "_36yqie13";
40
+ var footerBtnCancel = "_36yqie15 _36yqie14";
41
+ var footerBtnSave = "_36yqie16 _36yqie14";
42
+ //#endregion
43
+ //#region src/useMermaidRender.ts
44
+ var LIGHT_PALETTE = {
45
+ bg: "#ffffff",
46
+ fg: "#262626"
47
+ };
48
+ var DARK_PALETTE = {
49
+ bg: "#171717",
50
+ fg: "#fafafa"
51
+ };
52
+ function svgToDataUrl(svg) {
53
+ const bytes = new TextEncoder().encode(svg);
54
+ let binary = "";
55
+ for (const byte of bytes) binary += String.fromCodePoint(byte);
56
+ return `data:image/svg+xml;base64,${btoa(binary)}`;
57
+ }
58
+ function readDimensions(svg) {
59
+ const match = svg.match(/viewBox="\s*(?:[\d.-]+\s+){2}([\d.]+)\s+([\d.]+)/);
60
+ if (!match) return {};
61
+ return {
62
+ width: Number.parseFloat(match[1]),
63
+ height: Number.parseFloat(match[2])
64
+ };
65
+ }
66
+ function useMermaidRender(content, preferredColorScheme) {
67
+ const colorScheme = useColorScheme();
68
+ const effectiveColorScheme = preferredColorScheme ?? colorScheme;
69
+ return useMemo(() => {
70
+ if (!content) return {
71
+ loading: false,
72
+ error: "",
73
+ svg: "",
74
+ imgSrc: "",
75
+ width: void 0,
76
+ height: void 0
77
+ };
78
+ try {
79
+ const palette = effectiveColorScheme === "dark" ? DARK_PALETTE : LIGHT_PALETTE;
80
+ const svg = renderMermaidSVG(content, {
81
+ bg: palette.bg,
82
+ fg: palette.fg
83
+ });
84
+ const { width, height } = readDimensions(svg);
85
+ return {
86
+ loading: false,
87
+ error: "",
88
+ svg,
89
+ imgSrc: svgToDataUrl(svg),
90
+ width,
91
+ height
92
+ };
93
+ } catch (err) {
94
+ return {
95
+ loading: false,
96
+ error: err instanceof Error ? err.message : String(err),
97
+ svg: "",
98
+ imgSrc: "",
99
+ width: void 0,
100
+ height: void 0
101
+ };
102
+ }
103
+ }, [content, effectiveColorScheme]);
104
+ }
105
+ //#endregion
106
+ //#region src/estimate-height.ts
107
+ function estimateMermaidHeight(content) {
108
+ const lines = content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("%%"));
109
+ const first = (lines[0] ?? "").toLowerCase();
110
+ let h;
111
+ if (first.startsWith("sequencediagram")) h = lines.length * 50 + 60;
112
+ else if (first.startsWith("gantt")) h = lines.length * 36 + 80;
113
+ else if (first.startsWith("pie")) h = 320;
114
+ else if (first.startsWith("flowchart lr") || first.startsWith("graph lr") || first.startsWith("flowchart rl") || first.startsWith("graph rl")) h = lines.length * 30 + 100;
115
+ else if (first.startsWith("classdiagram")) h = lines.length * 40 + 100;
116
+ else if (first.startsWith("statediagram")) h = lines.length * 50 + 80;
117
+ else if (first.startsWith("erdiagram")) h = lines.length * 60 + 80;
118
+ else if (first.startsWith("journey")) h = lines.length * 40 + 80;
119
+ else if (first.startsWith("mindmap")) h = lines.length * 50 + 100;
120
+ else h = lines.length * 60 + 80;
121
+ return Math.min(Math.max(Math.round(h), 200), 800);
122
+ }
123
+ //#endregion
124
+ //#region src/MermaidRenderer.tsx
125
+ var MermaidRenderer = ({ content, colorScheme }) => {
126
+ const { error, imgSrc, width, height } = useMermaidRender(content, colorScheme);
127
+ const wrapperStyle = { minHeight: estimateMermaidHeight(content) };
128
+ if (!imgSrc) return /* @__PURE__ */ jsx("div", {
129
+ className: mermaidError,
130
+ style: wrapperStyle,
131
+ children: error || "Render failed"
132
+ });
133
+ return /* @__PURE__ */ jsx("div", {
134
+ className: mermaidContainer,
135
+ style: {
136
+ ...wrapperStyle,
137
+ cursor: "default"
138
+ },
139
+ children: /* @__PURE__ */ jsx("img", {
140
+ alt: "Mermaid diagram",
141
+ height,
142
+ src: imgSrc,
143
+ width
144
+ })
145
+ });
146
+ };
147
+ //#endregion
148
+ export { editorViewToggle as A, editorPreviewPane as C, editorTplBtn as D, editorTitle as E, mermaidEditHint as F, mermaidError as I, zoomBtn as L, footerBtnCancel as M, footerBtnSave as N, editorViewItem as O, mermaidContainer as P, zoomControls as R, editorPreviewErrorWrap as S, editorSep as T, editorPopup as _, codeGutter as a, editorPreviewErrorMsg as b, editorFooter as c, editorHeaderRight as d, editorIconBtn as f, editorPaneLabel as g, editorPaneHalf as h, codeEditor as i, footerActions as j, editorViewItemActive as k, editorHeader as l, editorPaneFull as m, useMermaidRender as n, codeGutterLine as o, editorPane as p, codeArea as r, editorBody as s, MermaidRenderer as t, editorHeaderLeft as u, editorPreviewEmpty as v, editorPreviewWrap as w, editorPreviewErrorTitle as x, editorPreviewErrorIcon as y };
@@ -1 +1 @@
1
- {"version":3,"file":"MermaidRenderer.d.ts","sourceRoot":"","sources":["../src/MermaidRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,GAAG;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE,CA8BpF,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"MermaidRenderer.d.ts","sourceRoot":"","sources":["../src/MermaidRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,GAAG;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE,CAqBpF,CAAC;AAEF,eAAe,eAAe,CAAC"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as editorViewToggle, D as editorTplBtn, E as editorTitle, I as mermaidError, L as mermaidLoading, M as footerBtnCancel, N as footerBtnSave, O as editorViewItem, P as mermaidContainer, R as zoomBtn, S as editorPreviewErrorWrap, T as editorSep, _ as editorPopup, a as codeGutter, b as editorPreviewErrorMsg, c as editorFooter, d as editorHeaderRight, f as editorIconBtn, i as codeEditor, j as footerActions, k as editorViewItemActive, l as editorHeader, n as useMermaidRender, o as codeGutterLine, r as codeArea, s as editorBody, t as MermaidRenderer, u as editorHeaderLeft, v as editorPreviewEmpty, w as editorPreviewWrap, x as editorPreviewErrorTitle, y as editorPreviewErrorIcon, z as zoomControls } from "./MermaidRenderer-DnxSrFxY.js";
1
+ import { A as editorViewToggle, D as editorTplBtn, E as editorTitle, I as mermaidError, L as zoomBtn, M as footerBtnCancel, N as footerBtnSave, O as editorViewItem, P as mermaidContainer, R as zoomControls, S as editorPreviewErrorWrap, T as editorSep, _ as editorPopup, a as codeGutter, b as editorPreviewErrorMsg, c as editorFooter, d as editorHeaderRight, f as editorIconBtn, i as codeEditor, j as footerActions, k as editorViewItemActive, l as editorHeader, n as useMermaidRender, o as codeGutterLine, r as codeArea, s as editorBody, t as MermaidRenderer, u as editorHeaderLeft, v as editorPreviewEmpty, w as editorPreviewWrap, x as editorPreviewErrorTitle, y as editorPreviewErrorIcon } from "./MermaidRenderer-BGh5KLUU.js";
2
2
  import { useColorScheme } from "@haklex/rich-editor/static";
3
3
  import { presentDialog, usePortalTheme } from "@haklex/rich-editor-ui";
4
4
  import { CircleAlert, Code2, Columns2, Copy, Download, Eye, FishSymbol, Maximize2, RotateCcw, X, ZoomIn, ZoomOut } from "lucide-react";
@@ -22,10 +22,6 @@ var TEMPLATES = [
22
22
  {
23
23
  label: "State",
24
24
  code: "stateDiagram-v2\n [*] --> Idle\n Idle --> Processing: Submit\n Processing --> Success: Complete\n Processing --> Error: Fail\n Error --> Idle: Retry\n Success --> [*]"
25
- },
26
- {
27
- label: "Git",
28
- code: "gitGraph\n commit\n branch develop\n checkout develop\n commit\n checkout main\n merge develop\n commit"
29
25
  }
30
26
  ];
31
27
  var MermaidLivePreview = ({ code, svgRef, colorScheme }) => {
@@ -34,7 +30,7 @@ var MermaidLivePreview = ({ code, svgRef, colorScheme }) => {
34
30
  const t = setTimeout(() => setDebounced(code), 300);
35
31
  return () => clearTimeout(t);
36
32
  }, [code]);
37
- const { loading, error, imgSrc, svg, width, height } = useMermaidRender(debounced, colorScheme);
33
+ const { error, imgSrc, svg, width, height } = useMermaidRender(debounced, colorScheme);
38
34
  useEffect(() => {
39
35
  svgRef.current = svg;
40
36
  }, [svg, svgRef]);
@@ -45,13 +41,6 @@ var MermaidLivePreview = ({ code, svgRef, colorScheme }) => {
45
41
  children: "Enter Mermaid code to see the preview"
46
42
  })
47
43
  });
48
- if (loading && !imgSrc) return /* @__PURE__ */ jsx("div", {
49
- className: editorPreviewWrap,
50
- children: /* @__PURE__ */ jsx("div", {
51
- className: mermaidLoading,
52
- children: "Rendering"
53
- })
54
- });
55
44
  if (error && !imgSrc) return /* @__PURE__ */ jsx("div", {
56
45
  className: editorPreviewWrap,
57
46
  children: /* @__PURE__ */ jsxs("div", {
@@ -312,7 +301,7 @@ var ZoomControls = () => {
312
301
  };
313
302
  var MermaidEditRenderer = ({ content, onContentChange }) => {
314
303
  const colorScheme = useColorScheme();
315
- const { loading, error, imgSrc, width, height } = useMermaidRender(content);
304
+ const { error, imgSrc, width, height } = useMermaidRender(content);
316
305
  const { className: portalClassName } = usePortalTheme();
317
306
  const handleClick = useCallback(() => {
318
307
  if (!onContentChange) return;
@@ -335,10 +324,6 @@ var MermaidEditRenderer = ({ content, onContentChange }) => {
335
324
  portalClassName,
336
325
  colorScheme
337
326
  ]);
338
- if (loading) return /* @__PURE__ */ jsx("div", {
339
- className: mermaidLoading,
340
- children: "Mermaid Loading"
341
- });
342
327
  if (!imgSrc) return /* @__PURE__ */ jsx("div", {
343
328
  className: mermaidError,
344
329
  children: error || "Render failed"
package/dist/static.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as MermaidRenderer } from "./MermaidRenderer-DnxSrFxY.js";
1
+ import { t as MermaidRenderer } from "./MermaidRenderer-BGh5KLUU.js";
2
2
  export { MermaidRenderer };
@@ -2,8 +2,8 @@ import { ColorScheme } from '@haklex/rich-editor/static';
2
2
  export declare function useMermaidRender(content: string, preferredColorScheme?: ColorScheme): {
3
3
  loading: boolean;
4
4
  error: string;
5
- imgSrc: string;
6
5
  svg: string;
6
+ imgSrc: string;
7
7
  width: number | undefined;
8
8
  height: number | undefined;
9
9
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useMermaidRender.d.ts","sourceRoot":"","sources":["../src/useMermaidRender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAO9D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,WAAW;;;;;;;EAyFnF"}
1
+ {"version":3,"file":"useMermaidRender.d.ts","sourceRoot":"","sources":["../src/useMermaidRender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAwB9D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,WAAW;;;;;WAWxD,MAAM,GAAG,SAAS;YACjB,MAAM,GAAG,SAAS;EA8B9C"}
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,2 @@
1
- export type { ThemeTokens } from './mermaid-theme';
2
- export { darkTheme, darkTokens, deriveTokens, lightTheme, lightTokens, } from './mermaid-theme';
3
- export { postProcessMermaidSvg } from './svg-post-process';
1
+ export {};
4
2
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EACL,SAAS,EACT,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haklex/rich-renderer-mermaid",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "Mermaid diagram renderer",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,7 +29,7 @@
29
29
  "dist"
30
30
  ],
31
31
  "dependencies": {
32
- "mermaid": "^11.15.0",
32
+ "beautiful-mermaid": "^1.1.3",
33
33
  "react-zoom-pan-pinch": "^4.0.3"
34
34
  },
35
35
  "devDependencies": {
@@ -47,9 +47,9 @@
47
47
  "lucide-react": "^1.0.0",
48
48
  "react": ">=19",
49
49
  "react-dom": ">=19",
50
- "@haklex/rich-editor": "0.15.1",
51
- "@haklex/rich-style-token": "0.15.1",
52
- "@haklex/rich-editor-ui": "0.15.1"
50
+ "@haklex/rich-editor": "0.15.2",
51
+ "@haklex/rich-editor-ui": "0.15.2",
52
+ "@haklex/rich-style-token": "0.15.2"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public"
@@ -1,614 +0,0 @@
1
- import { useColorScheme } from "@haklex/rich-editor/static";
2
- import { useEffect, useId, useState } from "react";
3
- import { jsx, jsxs } from "react/jsx-runtime";
4
- //#region src/styles.css.ts
5
- var mermaidContainer = "_36yqie0";
6
- var mermaidEditHint = "_36yqie1";
7
- var zoomControls = "_36yqie2";
8
- var zoomBtn = "_36yqie3";
9
- var mermaidLoading = "_36yqie4";
10
- var mermaidSpinner = "_36yqie6";
11
- var mermaidError = "_36yqie7";
12
- var editorPopup = "_36yqie8";
13
- var editorHeader = "_36yqie9";
14
- var editorHeaderLeft = "_36yqiea";
15
- var editorHeaderRight = "_36yqieb";
16
- var editorSep = "_36yqiec";
17
- var editorTitle = "_36yqied";
18
- var editorTplBtn = "_36yqiee";
19
- var editorViewToggle = "_36yqief";
20
- var editorViewItem = "_36yqieg";
21
- var editorViewItemActive = "_36yqieh";
22
- var editorIconBtn = "_36yqiei";
23
- var editorBody = "_36yqiej";
24
- var editorPane = "_36yqiek";
25
- var editorPaneHalf = "_36yqiel";
26
- var editorPaneFull = "_36yqiem";
27
- var editorPaneLabel = "_36yqien";
28
- var editorPreviewPane = "_36yqieo";
29
- var editorPreviewWrap = "_36yqiep";
30
- var editorPreviewEmpty = "_36yqieq";
31
- var editorPreviewErrorWrap = "_36yqier";
32
- var editorPreviewErrorIcon = "_36yqies";
33
- var editorPreviewErrorTitle = "_36yqiet";
34
- var editorPreviewErrorMsg = "_36yqieu";
35
- var codeEditor = "_36yqiev";
36
- var codeGutter = "_36yqiew";
37
- var codeGutterLine = "_36yqiex";
38
- var codeArea = "_36yqiey";
39
- var editorFooter = "_36yqiez";
40
- var footerActions = "_36yqie13";
41
- var footerBtnCancel = "_36yqie15 _36yqie14";
42
- var footerBtnSave = "_36yqie16 _36yqie14";
43
- //#endregion
44
- //#region src/mermaid-theme.ts
45
- var MIX = {
46
- text: 100,
47
- textSec: 60,
48
- textMuted: 40,
49
- textFaint: 25,
50
- line: 50,
51
- arrow: 85,
52
- nodeFill: 3,
53
- nodeStroke: 20,
54
- groupHeader: 5,
55
- innerStroke: 12
56
- };
57
- function parseHex(hex) {
58
- return [
59
- Number.parseInt(hex.slice(1, 3), 16),
60
- Number.parseInt(hex.slice(3, 5), 16),
61
- Number.parseInt(hex.slice(5, 7), 16)
62
- ];
63
- }
64
- function toHex(r, g, b) {
65
- const clamp = (v) => Math.round(Math.max(0, Math.min(255, v)));
66
- return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`;
67
- }
68
- function mix(fg, bg, percent) {
69
- const [fR, fG, fB] = parseHex(fg);
70
- const [bR, bG, bB] = parseHex(bg);
71
- const p = percent / 100;
72
- return toHex(fR * p + bR * (1 - p), fG * p + bG * (1 - p), fB * p + bB * (1 - p));
73
- }
74
- function deriveTokens(bg, fg) {
75
- return {
76
- bg,
77
- fg,
78
- line: mix(fg, bg, MIX.line),
79
- arrow: mix(fg, bg, MIX.arrow),
80
- nodeFill: mix(fg, bg, MIX.nodeFill),
81
- nodeStroke: mix(fg, bg, MIX.nodeStroke),
82
- groupHeader: mix(fg, bg, MIX.groupHeader),
83
- innerStroke: mix(fg, bg, MIX.innerStroke),
84
- textSec: mix(fg, bg, MIX.textSec),
85
- textMuted: mix(fg, bg, MIX.textMuted),
86
- textFaint: mix(fg, bg, MIX.textFaint)
87
- };
88
- }
89
- function buildTheme(bg, fg) {
90
- const t = deriveTokens(bg, fg);
91
- return {
92
- theme: "base",
93
- themeVariables: {
94
- background: t.bg,
95
- fontFamily: "system-ui, -apple-system, sans-serif",
96
- fontSize: "14px",
97
- primaryColor: t.nodeFill,
98
- primaryTextColor: t.fg,
99
- primaryBorderColor: t.nodeStroke,
100
- secondaryColor: t.nodeFill,
101
- secondaryTextColor: t.fg,
102
- secondaryBorderColor: t.innerStroke,
103
- tertiaryColor: t.groupHeader,
104
- tertiaryTextColor: t.fg,
105
- tertiaryBorderColor: t.innerStroke,
106
- noteBkgColor: t.nodeFill,
107
- noteTextColor: t.fg,
108
- noteBorderColor: t.innerStroke,
109
- lineColor: t.line,
110
- textColor: t.fg,
111
- mainBkg: t.nodeFill,
112
- nodeBorder: t.nodeStroke,
113
- nodeTextColor: t.fg,
114
- clusterBkg: t.bg,
115
- clusterBorder: t.nodeStroke,
116
- titleColor: t.fg,
117
- labelColor: t.fg,
118
- altBackground: t.nodeFill,
119
- fillType0: t.nodeFill,
120
- fillType1: t.groupHeader,
121
- fillType2: mix(fg, bg, 7),
122
- fillType3: t.innerStroke,
123
- fillType4: t.nodeStroke,
124
- fillType5: t.groupHeader,
125
- fillType6: t.nodeFill,
126
- fillType7: mix(fg, bg, 7),
127
- actorBkg: t.nodeFill,
128
- actorBorder: t.nodeStroke,
129
- actorTextColor: t.fg,
130
- actorLineColor: t.line,
131
- signalColor: t.fg,
132
- signalTextColor: t.fg,
133
- labelBoxBkgColor: t.nodeFill,
134
- labelBoxBorderColor: t.nodeStroke,
135
- labelTextColor: t.fg,
136
- loopTextColor: t.fg,
137
- activationBorderColor: t.line,
138
- activationBkgColor: t.innerStroke,
139
- sequenceNumberColor: t.bg,
140
- git0: t.fg,
141
- git1: t.line,
142
- git2: t.textMuted,
143
- git3: t.textFaint,
144
- git4: t.nodeStroke,
145
- git5: t.innerStroke,
146
- git6: t.groupHeader,
147
- git7: t.nodeFill,
148
- gitBranchLabel0: t.bg,
149
- gitBranchLabel1: t.bg,
150
- gitBranchLabel2: t.bg,
151
- gitBranchLabel3: t.fg,
152
- gitInv0: t.bg,
153
- pie1: t.fg,
154
- pie2: mix(fg, bg, 80),
155
- pie3: t.line,
156
- pie4: t.textMuted,
157
- pie5: t.nodeStroke,
158
- pie6: t.innerStroke,
159
- pie7: mix(fg, bg, 7),
160
- pie8: t.groupHeader,
161
- pie9: t.nodeFill,
162
- pie10: t.bg,
163
- pie11: t.textSec,
164
- pie12: t.arrow,
165
- pieTitleTextColor: t.fg,
166
- pieSectionTextColor: t.bg,
167
- pieLegendTextColor: t.fg,
168
- pieLegendTextSize: "14px",
169
- pieStrokeColor: t.bg,
170
- pieStrokeWidth: "2px",
171
- classText: t.fg,
172
- sectionBkgColor: t.nodeFill,
173
- altSectionBkgColor: t.groupHeader,
174
- sectionBkgColor2: mix(fg, bg, 7),
175
- taskBkgColor: t.innerStroke,
176
- taskTextColor: t.fg,
177
- taskTextLightColor: t.fg,
178
- taskTextOutsideColor: t.fg,
179
- activeTaskBkgColor: t.nodeStroke,
180
- activeTaskBorderColor: t.line,
181
- gridColor: t.innerStroke,
182
- doneTaskBkgColor: t.nodeStroke,
183
- doneTaskBorderColor: t.line,
184
- critBkgColor: t.fg,
185
- critBorderColor: t.fg,
186
- todayLineColor: t.fg,
187
- requirementBackground: t.nodeFill,
188
- requirementBorderColor: t.nodeStroke,
189
- requirementBorderSize: "1px",
190
- requirementTextColor: t.fg,
191
- relationColor: t.line,
192
- relationLabelBackground: t.bg,
193
- relationLabelColor: t.fg,
194
- edgeLabelBackground: t.bg,
195
- cScale0: t.nodeFill,
196
- cScale1: t.innerStroke,
197
- cScale2: t.nodeStroke,
198
- cScale3: t.textMuted,
199
- cScale4: t.line,
200
- cScale5: t.textSec,
201
- cScale6: mix(fg, bg, 70),
202
- cScale7: mix(fg, bg, 80),
203
- cScale8: t.arrow,
204
- cScale9: t.fg,
205
- cScaleLabel0: t.fg,
206
- cScaleLabel2: t.fg
207
- }
208
- };
209
- }
210
- var lightTheme = buildTheme("#ffffff", "#262626");
211
- var darkTheme = buildTheme("#171717", "#fafafa");
212
- var lightTokens = deriveTokens("#ffffff", "#262626");
213
- var darkTokens = deriveTokens("#171717", "#fafafa");
214
- //#endregion
215
- //#region src/svg-post-process.ts
216
- var CORNER_RADIUS = {
217
- node: 5,
218
- classNode: 4,
219
- entity: 5,
220
- subgraphOuter: 7,
221
- subgraphHeader: 6,
222
- actor: 6,
223
- activation: 4,
224
- diamond: 4
225
- };
226
- /**
227
- * Convert node <polygon> elements to <path> with rounded corners.
228
- * Handles diamonds (4pt), hexagons (6pt), asymmetric (5pt), etc.
229
- * Each corner is replaced by a quadratic bezier curve.
230
- */
231
- function roundNodePolygons(doc, radius) {
232
- const polygons = doc.querySelectorAll(".node > polygon, .node polygon");
233
- for (const polygon of polygons) {
234
- const points = polygon.points;
235
- if (points.numberOfItems < 3) continue;
236
- const pts = [];
237
- for (let i = 0; i < points.numberOfItems; i++) {
238
- const p = points.getItem(i);
239
- pts.push([p.x, p.y]);
240
- }
241
- const d = pts.map((pt, i) => {
242
- const prev = pts[(i + pts.length - 1) % pts.length];
243
- const next = pts[(i + 1) % pts.length];
244
- const dx1 = prev[0] - pt[0];
245
- const dy1 = prev[1] - pt[1];
246
- const len1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
247
- const dx2 = next[0] - pt[0];
248
- const dy2 = next[1] - pt[1];
249
- const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
250
- const r = Math.min(radius, len1 / 2, len2 / 2);
251
- const startX = pt[0] + dx1 / len1 * r;
252
- const startY = pt[1] + dy1 / len1 * r;
253
- const endX = pt[0] + dx2 / len2 * r;
254
- const endY = pt[1] + dy2 / len2 * r;
255
- return `${i === 0 ? "M" : "L"}${startX},${startY} Q${pt[0]},${pt[1]} ${endX},${endY}`;
256
- }).join(" ");
257
- const path = doc.createElementNS("http://www.w3.org/2000/svg", "path");
258
- path.setAttribute("d", `${d} Z`);
259
- for (const attr of Array.from(polygon.attributes)) if (attr.name !== "points") path.setAttribute(attr.name, attr.value);
260
- polygon.replaceWith(path);
261
- }
262
- }
263
- function applyCornerRounding(doc) {
264
- const applyRadius = (selector, radius) => {
265
- const rects = doc.querySelectorAll(selector);
266
- for (const rect of rects) {
267
- rect.setAttribute("rx", String(radius));
268
- rect.setAttribute("ry", String(radius));
269
- }
270
- };
271
- applyRadius(".node > rect", CORNER_RADIUS.node);
272
- applyRadius(".node > .basic", CORNER_RADIUS.node);
273
- applyRadius(".classGroup > rect", CORNER_RADIUS.classNode);
274
- applyRadius(".er > rect", CORNER_RADIUS.entity);
275
- applyRadius(".cluster > rect", CORNER_RADIUS.subgraphOuter);
276
- applyRadius(".actor", CORNER_RADIUS.actor);
277
- applyRadius(".activation0, .activation1, .activation2", CORNER_RADIUS.activation);
278
- roundNodePolygons(doc, CORNER_RADIUS.diamond);
279
- }
280
- function buildVisualCss(tokens) {
281
- return `
282
- /* beautiful-mermaid inspired visual overrides */
283
-
284
- /* Edge styling: rounded linecaps for clean connections */
285
- .edgePath path.path,
286
- .flowchart-link,
287
- line[class*="messageLine"] {
288
- stroke-linecap: round !important;
289
- stroke-linejoin: round !important;
290
- }
291
-
292
- /* Cluster/subgraph "soft" styling */
293
- .cluster > rect {
294
- fill: ${tokens.nodeFill} !important;
295
- fill-opacity: 0.96 !important;
296
- stroke: ${tokens.nodeStroke} !important;
297
- stroke-width: 1px !important;
298
- }
299
-
300
- /* Cluster title */
301
- .cluster text,
302
- .cluster .nodeLabel {
303
- fill: ${tokens.textSec} !important;
304
- }
305
-
306
- /* Node stroke consistency */
307
- .node rect,
308
- .node circle,
309
- .node ellipse,
310
- .node polygon,
311
- .node .basic {
312
- stroke: ${tokens.nodeStroke} !important;
313
- stroke-width: 1px !important;
314
- }
315
-
316
- /* Node fill */
317
- .node rect,
318
- .node .basic {
319
- fill: ${tokens.nodeFill} !important;
320
- }
321
-
322
- /* Edge label "subtle" styling */
323
- .edgeLabel rect,
324
- .labelBkg {
325
- rx: 5 !important;
326
- ry: 5 !important;
327
- fill: ${tokens.bg} !important;
328
- stroke: ${tokens.innerStroke} !important;
329
- stroke-width: 1px !important;
330
- }
331
-
332
- .edgeLabel text,
333
- .edgeLabel .edgeLabel {
334
- fill: ${tokens.textMuted} !important;
335
- }
336
-
337
- /* Arrow heads */
338
- marker path {
339
- fill: ${tokens.arrow} !important;
340
- stroke: ${tokens.arrow} !important;
341
- }
342
-
343
- /* Edge paths */
344
- .edgePath path.path {
345
- stroke: ${tokens.line} !important;
346
- stroke-width: 1px !important;
347
- }
348
-
349
- /* Sequence diagram refinements */
350
- .actor {
351
- fill: ${tokens.nodeFill} !important;
352
- stroke: ${tokens.nodeStroke} !important;
353
- stroke-width: 1px !important;
354
- }
355
-
356
- .messageLine0,
357
- .messageLine1 {
358
- stroke: ${tokens.line} !important;
359
- stroke-width: 1px !important;
360
- }
361
-
362
- .messageText {
363
- fill: ${tokens.fg} !important;
364
- }
365
-
366
- .loopLine {
367
- stroke: ${tokens.innerStroke} !important;
368
- stroke-width: 1px !important;
369
- }
370
-
371
- .labelBox {
372
- fill: ${tokens.nodeFill} !important;
373
- stroke: ${tokens.nodeStroke} !important;
374
- stroke-width: 1px !important;
375
- }
376
-
377
- .loopText tspan,
378
- .loopText {
379
- fill: ${tokens.textSec} !important;
380
- }
381
-
382
- /* Activation bars */
383
- .activation0,
384
- .activation1,
385
- .activation2 {
386
- fill: ${tokens.innerStroke} !important;
387
- stroke: ${tokens.line} !important;
388
- }
389
-
390
- /* Note styling */
391
- .note {
392
- fill: ${tokens.nodeFill} !important;
393
- stroke: ${tokens.innerStroke} !important;
394
- }
395
-
396
- .noteText {
397
- fill: ${tokens.fg} !important;
398
- }
399
-
400
- /* Inner divider lines */
401
- .divider {
402
- stroke: ${tokens.innerStroke} !important;
403
- stroke-width: 0.75px !important;
404
- }
405
-
406
- /* Class diagram */
407
- .classGroup rect {
408
- fill: ${tokens.nodeFill} !important;
409
- stroke: ${tokens.nodeStroke} !important;
410
- stroke-width: 1px !important;
411
- }
412
-
413
- .classGroup line {
414
- stroke: ${tokens.innerStroke} !important;
415
- stroke-width: 0.75px !important;
416
- }
417
-
418
- .classGroup text {
419
- fill: ${tokens.fg} !important;
420
- }
421
-
422
- .classLabel .box {
423
- fill: ${tokens.groupHeader} !important;
424
- stroke: ${tokens.nodeStroke} !important;
425
- }
426
-
427
- .relation {
428
- stroke: ${tokens.line} !important;
429
- stroke-width: 1px !important;
430
- }
431
-
432
- /* State diagram */
433
- .stateGroup rect,
434
- .statediagram-state rect {
435
- fill: ${tokens.nodeFill} !important;
436
- stroke: ${tokens.nodeStroke} !important;
437
- stroke-width: 1px !important;
438
- rx: 5 !important;
439
- ry: 5 !important;
440
- }
441
-
442
- .stateGroup text {
443
- fill: ${tokens.fg} !important;
444
- }
445
-
446
- /* Git graph */
447
- .commit-id text {
448
- fill: ${tokens.textMuted} !important;
449
- }
450
-
451
- `;
452
- }
453
- function postProcessMermaidSvg(svg, tokens) {
454
- const normalizedSvg = svg.replaceAll(/<br\s*>/gi, "<br/>");
455
- const doc = new DOMParser().parseFromString(normalizedSvg, "image/svg+xml");
456
- if (doc.querySelector("parsererror")) return normalizedSvg;
457
- const root = doc.documentElement;
458
- if (!root || root.tagName.toLowerCase() !== "svg") return normalizedSvg;
459
- applyCornerRounding(doc);
460
- const viewBox = root.getAttribute("viewBox");
461
- if (viewBox) {
462
- const parts = viewBox.split(/\s+/).map(Number);
463
- if (parts.length === 4 && parts[2] > 0 && parts[3] > 0) {
464
- root.setAttribute("width", String(parts[2]));
465
- root.setAttribute("height", String(parts[3]));
466
- }
467
- }
468
- root.querySelector("style[data-visual-overrides]")?.remove();
469
- const styleEl = doc.createElementNS("http://www.w3.org/2000/svg", "style");
470
- styleEl.dataset.visualOverrides = "";
471
- styleEl.textContent = buildVisualCss(tokens);
472
- if (root.firstChild) root.insertBefore(styleEl, root.firstChild);
473
- else root.append(styleEl);
474
- return new XMLSerializer().serializeToString(root);
475
- }
476
- //#endregion
477
- //#region src/useMermaidRender.ts
478
- function useMermaidRender(content, preferredColorScheme) {
479
- const [loading, setLoading] = useState(true);
480
- const [error, setError] = useState("");
481
- const [svg, setSvg] = useState("");
482
- const [width, setWidth] = useState();
483
- const [height, setHeight] = useState();
484
- const colorScheme = useColorScheme();
485
- const effectiveColorScheme = preferredColorScheme ?? colorScheme;
486
- const id = useId().split(":").join("");
487
- useEffect(() => {
488
- if (!content) return;
489
- setError("");
490
- setLoading(true);
491
- let cancelled = false;
492
- import("mermaid").then(async (mo) => {
493
- const mermaid = mo.default;
494
- const themeConfig = effectiveColorScheme === "dark" ? darkTheme : lightTheme;
495
- const tokens = effectiveColorScheme === "dark" ? darkTokens : lightTokens;
496
- mermaid.initialize({
497
- startOnLoad: false,
498
- theme: themeConfig.theme,
499
- themeVariables: themeConfig.themeVariables,
500
- darkMode: effectiveColorScheme === "dark",
501
- flowchart: {
502
- htmlLabels: true,
503
- curve: "basis",
504
- padding: 20,
505
- nodeSpacing: 24,
506
- rankSpacing: 48
507
- },
508
- sequence: {
509
- actorMargin: 80,
510
- messageMargin: 40
511
- },
512
- gantt: {
513
- titleTopMargin: 16,
514
- barHeight: 24,
515
- barGap: 6
516
- }
517
- });
518
- let result;
519
- try {
520
- result = await mermaid.render(`mermaid-${id}`, content);
521
- } catch (err) {
522
- document.getElementById(`dmermaid-${id}`)?.remove();
523
- if (err instanceof Error) setError(err.message);
524
- setSvg("");
525
- setWidth(void 0);
526
- setHeight(void 0);
527
- }
528
- if (cancelled) return;
529
- if (result) {
530
- const processedSvg = postProcessMermaidSvg(result.svg, tokens);
531
- setSvg(processedSvg);
532
- const match = processedSvg.match(/viewBox="[^"]*\s([\d.]+)\s([\d.]+)"/);
533
- if (match?.[1] && match?.[2]) {
534
- setWidth(Number.parseInt(match[1]));
535
- setHeight(Number.parseInt(match[2]));
536
- }
537
- setError("");
538
- }
539
- setLoading(false);
540
- });
541
- return () => {
542
- cancelled = true;
543
- };
544
- }, [
545
- id,
546
- content,
547
- effectiveColorScheme
548
- ]);
549
- let imgSrc = "";
550
- if (svg) {
551
- const data = new TextEncoder().encode(svg);
552
- imgSrc = `data:image/svg+xml;base64,${btoa(String.fromCodePoint(...new Uint8Array(data)))}`;
553
- }
554
- return {
555
- loading,
556
- error,
557
- imgSrc,
558
- svg,
559
- width,
560
- height
561
- };
562
- }
563
- //#endregion
564
- //#region src/estimate-height.ts
565
- function estimateMermaidHeight(content) {
566
- const lines = content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("%%"));
567
- const first = (lines[0] ?? "").toLowerCase();
568
- let h;
569
- if (first.startsWith("sequencediagram")) h = lines.length * 50 + 60;
570
- else if (first.startsWith("gantt")) h = lines.length * 36 + 80;
571
- else if (first.startsWith("pie")) h = 320;
572
- else if (first.startsWith("flowchart lr") || first.startsWith("graph lr") || first.startsWith("flowchart rl") || first.startsWith("graph rl")) h = lines.length * 30 + 100;
573
- else if (first.startsWith("classdiagram")) h = lines.length * 40 + 100;
574
- else if (first.startsWith("statediagram")) h = lines.length * 50 + 80;
575
- else if (first.startsWith("erdiagram")) h = lines.length * 60 + 80;
576
- else if (first.startsWith("journey")) h = lines.length * 40 + 80;
577
- else if (first.startsWith("mindmap")) h = lines.length * 50 + 100;
578
- else h = lines.length * 60 + 80;
579
- return Math.min(Math.max(Math.round(h), 200), 800);
580
- }
581
- //#endregion
582
- //#region src/MermaidRenderer.tsx
583
- var MermaidRenderer = ({ content, colorScheme }) => {
584
- const { loading, error, imgSrc, width, height } = useMermaidRender(content, colorScheme);
585
- const wrapperStyle = { minHeight: estimateMermaidHeight(content) };
586
- if (loading) return /* @__PURE__ */ jsxs("div", {
587
- className: mermaidLoading,
588
- style: wrapperStyle,
589
- children: [/* @__PURE__ */ jsx("span", {
590
- "aria-hidden": "true",
591
- className: mermaidSpinner
592
- }), /* @__PURE__ */ jsx("span", { children: "Rendering diagram…" })]
593
- });
594
- if (!imgSrc) return /* @__PURE__ */ jsx("div", {
595
- className: mermaidError,
596
- style: wrapperStyle,
597
- children: error || "Render failed"
598
- });
599
- return /* @__PURE__ */ jsx("div", {
600
- className: mermaidContainer,
601
- style: {
602
- ...wrapperStyle,
603
- cursor: "default"
604
- },
605
- children: /* @__PURE__ */ jsx("img", {
606
- alt: "Mermaid diagram",
607
- height,
608
- src: imgSrc,
609
- width
610
- })
611
- });
612
- };
613
- //#endregion
614
- export { editorViewToggle as A, editorPreviewPane as C, editorTplBtn as D, editorTitle as E, mermaidEditHint as F, mermaidError as I, mermaidLoading as L, footerBtnCancel as M, footerBtnSave as N, editorViewItem as O, mermaidContainer as P, zoomBtn as R, editorPreviewErrorWrap as S, editorSep as T, editorPopup as _, codeGutter as a, editorPreviewErrorMsg as b, editorFooter as c, editorHeaderRight as d, editorIconBtn as f, editorPaneLabel as g, editorPaneHalf as h, codeEditor as i, footerActions as j, editorViewItemActive as k, editorHeader as l, editorPaneFull as m, useMermaidRender as n, codeGutterLine as o, editorPane as p, codeArea as r, editorBody as s, MermaidRenderer as t, editorHeaderLeft as u, editorPreviewEmpty as v, editorPreviewWrap as w, editorPreviewErrorTitle as x, editorPreviewErrorIcon as y, zoomControls as z };
@@ -1,34 +0,0 @@
1
- /**
2
- * Mermaid theme system inspired by beautiful-mermaid (lukilabs/beautiful-mermaid).
3
- *
4
- * Architecture:
5
- * - Two base colors: bg (background) + fg (foreground)
6
- * - All derived colors computed via color-mix ratios from bg + fg
7
- * - Produces a coherent mono hierarchy on any bg/fg combination
8
- *
9
- * @see https://github.com/lukilabs/beautiful-mermaid/blob/main/src/theme.ts
10
- */
11
- interface MermaidThemeConfig {
12
- theme: 'base';
13
- themeVariables: Record<string, string>;
14
- }
15
- export interface ThemeTokens {
16
- arrow: string;
17
- bg: string;
18
- fg: string;
19
- groupHeader: string;
20
- innerStroke: string;
21
- line: string;
22
- nodeFill: string;
23
- nodeStroke: string;
24
- textFaint: string;
25
- textMuted: string;
26
- textSec: string;
27
- }
28
- export declare function deriveTokens(bg: string, fg: string): ThemeTokens;
29
- export declare const lightTheme: MermaidThemeConfig;
30
- export declare const darkTheme: MermaidThemeConfig;
31
- export declare const lightTokens: ThemeTokens;
32
- export declare const darkTokens: ThemeTokens;
33
- export {};
34
- //# sourceMappingURL=mermaid-theme.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mermaid-theme.d.ts","sourceRoot":"","sources":["../src/mermaid-theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAoCD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAchE;AAqJD,eAAO,MAAM,UAAU,oBAAmC,CAAC;AAG3D,eAAO,MAAM,SAAS,oBAAmC,CAAC;AAE1D,eAAO,MAAM,WAAW,aAAqC,CAAC;AAC9D,eAAO,MAAM,UAAU,aAAqC,CAAC"}
@@ -1,3 +0,0 @@
1
- import { ThemeTokens } from './mermaid-theme';
2
- export declare function postProcessMermaidSvg(svg: string, tokens: ThemeTokens): string;
3
- //# sourceMappingURL=svg-post-process.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"svg-post-process.d.ts","sourceRoot":"","sources":["../src/svg-post-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAmRnD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,CAmD9E"}