@ktrysmt/beautiful-mermaid 1.4.3 → 1.4.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- # beautiful-mermaid
3
+ # @ktrysmt/beautiful-mermaid
4
4
 
5
5
  **Render Mermaid diagrams as beautiful SVGs or ASCII art**
6
6
 
@@ -8,32 +8,23 @@ Ultra-fast, fully themeable, zero DOM dependencies. Built for the AI era.
8
8
 
9
9
  ![beautiful-mermaid sequence diagram example](hero.png)
10
10
 
11
- [![npm version](https://img.shields.io/npm/v/beautiful-mermaid.svg)](https://www.npmjs.com/package/beautiful-mermaid)
11
+ [![npm version](https://img.shields.io/npm/v/@ktrysmt/beautiful-mermaid.svg)](https://www.npmjs.com/package/@ktrysmt/beautiful-mermaid)
12
12
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
13
13
 
14
- [**Live Demo & Samples**](https://agents.craft.do/mermaid)
15
-
16
- **[→ Use it live in Craft Agents](https://agents.craft.do)**
17
-
18
14
  </div>
19
15
 
20
16
  ---
21
17
 
22
- ## Why We Built This
23
-
24
- Diagrams are essential for AI-assisted programming. When you're working with an AI coding assistant, being able to visualize data flows, state machines, and system architecture—directly in your terminal or chat interface—makes complex concepts instantly graspable.
25
-
26
- [Mermaid](https://mermaid.js.org/) is the de facto standard for text-based diagrams. It's brilliant. But the default renderer has problems:
27
-
28
- - **Aesthetics** — Might be personal preference, but wished they looked more professional
29
- - **Complex theming** — Customizing colors requires wrestling with CSS classes
30
- - **No terminal output** — Can't render to ASCII for CLI tools
31
- - **Heavy dependencies** — Pulls in a lot of code for simple diagrams
18
+ ## About This Fork
32
19
 
33
- We built `beautiful-mermaid` at [Craft](https://craft.do) to power diagrams in [Craft Agents](https://agents.craft.do). It's fast, beautiful, and works everywhere—from rich UIs to plain terminals.
20
+ This is a fork of [beautiful-mermaid](https://github.com/lukilabs/beautiful-mermaid), originally built by the team at [Craft](https://craft.do). This fork is independently maintained by [@ktrysmt](https://github.com/ktrysmt) with additional bug fixes and improvements including:
34
21
 
22
+ - CJK/Unicode label support for subgraphs
23
+ - Subgraph layout fixes (vertical stacking, containment, label width)
24
+ - Edge routing improvements
25
+ - Scoped npm package (`@ktrysmt/beautiful-mermaid`)
35
26
 
36
- The ASCII rendering engine is based on [mermaid-ascii](https://github.com/AlexanderGrooff/mermaid-ascii) by Alexander Grooff. We ported it from Go to TypeScript and extended it. Thank you Alexander for the excellent foundation! (And inspiration that this was possible.)
27
+ The ASCII rendering engine is based on [mermaid-ascii](https://github.com/AlexanderGrooff/mermaid-ascii) by Alexander Grooff, ported from Go to TypeScript. Thank you Alexander for the excellent foundation!
37
28
 
38
29
  ## Features
39
30
 
@@ -50,11 +41,11 @@ The ASCII rendering engine is based on [mermaid-ascii](https://github.com/Alexan
50
41
  ## Installation
51
42
 
52
43
  ```bash
53
- npm install beautiful-mermaid
44
+ npm install @ktrysmt/beautiful-mermaid
54
45
  # or
55
- bun add beautiful-mermaid
46
+ bun add @ktrysmt/beautiful-mermaid
56
47
  # or
57
- pnpm add beautiful-mermaid
48
+ pnpm add @ktrysmt/beautiful-mermaid
58
49
  ```
59
50
 
60
51
  ## Quick Start
@@ -62,7 +53,7 @@ pnpm add beautiful-mermaid
62
53
  ### SVG Output
63
54
 
64
55
  ```typescript
65
- import { renderMermaidSVG } from 'beautiful-mermaid'
56
+ import { renderMermaidSVG } from '@ktrysmt/beautiful-mermaid'
66
57
 
67
58
  const svg = renderMermaidSVG(`
68
59
  graph TD
@@ -79,7 +70,7 @@ Need async? Use `renderMermaidSVGAsync()` — same output, returns a `Promise<st
79
70
  ### ASCII Output
80
71
 
81
72
  ```typescript
82
- import { renderMermaidASCII } from 'beautiful-mermaid'
73
+ import { renderMermaidASCII } from '@ktrysmt/beautiful-mermaid'
83
74
 
84
75
  const ascii = renderMermaidASCII(`graph LR; A --> B --> C`)
85
76
  ```
@@ -99,7 +90,7 @@ const ascii = renderMermaidASCII(`graph LR; A --> B --> C`)
99
90
  Because rendering is synchronous, you can use `useMemo()` for zero-flash diagram rendering:
100
91
 
101
92
  ```tsx
102
- import { renderMermaidSVG } from 'beautiful-mermaid'
93
+ import { renderMermaidSVG } from '@ktrysmt/beautiful-mermaid'
103
94
 
104
95
  function MermaidDiagram({ code }: { code: string }) {
105
96
  const { svg, error } = React.useMemo(() => {
@@ -224,7 +215,7 @@ const svg = renderMermaidSVG(diagram, {
224
215
  | `one-dark` | Dark | `#282c34` | `#c678dd` |
225
216
 
226
217
  ```typescript
227
- import { renderMermaidSVG, THEMES } from 'beautiful-mermaid'
218
+ import { renderMermaidSVG, THEMES } from '@ktrysmt/beautiful-mermaid'
228
219
 
229
220
  const svg = renderMermaidSVG(diagram, THEMES['tokyo-night'])
230
221
  ```
@@ -259,7 +250,7 @@ Use **any VS Code theme** directly via Shiki integration. This gives you access
259
250
 
260
251
  ```typescript
261
252
  import { getSingletonHighlighter } from 'shiki'
262
- import { renderMermaidSVG, fromShikiTheme } from 'beautiful-mermaid'
253
+ import { renderMermaidSVG, fromShikiTheme } from '@ktrysmt/beautiful-mermaid'
263
254
 
264
255
  // Load any theme from Shiki's registry
265
256
  const highlighter = await getSingletonHighlighter({
@@ -437,7 +428,7 @@ The chart renderer follows a clean, minimal design philosophy inspired by Apple
437
428
  For terminal environments, CLI tools, or anywhere you need plain text, render to ASCII or Unicode box-drawing characters:
438
429
 
439
430
  ```typescript
440
- import { renderMermaidASCII } from 'beautiful-mermaid'
431
+ import { renderMermaidASCII } from '@ktrysmt/beautiful-mermaid'
441
432
 
442
433
  // Unicode mode (default) — prettier box drawing
443
434
  const unicode = renderMermaidASCII(`graph LR; A --> B`)
@@ -580,6 +571,6 @@ MIT — see [LICENSE](LICENSE) for details.
580
571
 
581
572
  <div align="center">
582
573
 
583
- Built with care by the team at [Craft](https://craft.do)
574
+ Originally built by the team at [Craft](https://craft.do). Fork maintained by [@ktrysmt](https://github.com/ktrysmt).
584
575
 
585
576
  </div>
package/dist/index.js CHANGED
@@ -2927,8 +2927,9 @@ function drawArrow(graph, edge) {
2927
2927
  return [empty, empty, empty, empty, empty, empty];
2928
2928
  }
2929
2929
  const labelCanvas = drawArrowLabel(graph, edge);
2930
- const [pathCanvas, linesDrawn, lineDirs] = drawPath(graph, edge.path, edge.style);
2931
- const boxStartCanvas = drawBoxStart(graph, edge.path, linesDrawn[0], edge.from.shape);
2930
+ const endCoordOverride = computeEndCoordOverride(graph, edge);
2931
+ const [pathCanvas, linesDrawn, lineDirs] = drawPath(graph, edge.path, edge.style, void 0, endCoordOverride);
2932
+ const boxStartCanvas = drawBoxStart(graph, edge.path, linesDrawn[0], edge.from);
2932
2933
  let arrowHeadEndCanvas;
2933
2934
  if (edge.hasArrowEnd) {
2934
2935
  arrowHeadEndCanvas = drawArrowHead(
@@ -2957,6 +2958,38 @@ function drawArrow(graph, edge) {
2957
2958
  const cornersCanvas = drawCorners(graph, edge.path);
2958
2959
  return [pathCanvas, boxStartCanvas, arrowHeadEndCanvas, arrowHeadStartCanvas, cornersCanvas, labelCanvas];
2959
2960
  }
2961
+ function computeEndCoordOverride(graph, edge) {
2962
+ if (edge.path.length < 2) return void 0;
2963
+ const lastPathCoord = edge.path[edge.path.length - 1];
2964
+ const prevPathCoord = edge.path[edge.path.length - 2];
2965
+ const dir = determineDirection(prevPathCoord, lastPathCoord);
2966
+ const defaultDC = gridToDrawingCoord(graph, lastPathCoord);
2967
+ const targetDC = edge.to.drawingCoord;
2968
+ const targetGC = edge.to.gridCoord;
2969
+ if (!targetDC || !targetGC) return void 0;
2970
+ let boxW = 0;
2971
+ for (let i = 0; i < 2; i++) boxW += graph.columnWidth.get(targetGC.x + i) ?? 0;
2972
+ let boxH = 0;
2973
+ for (let i = 0; i < 2; i++) boxH += graph.rowHeight.get(targetGC.y + i) ?? 0;
2974
+ if (dirEquals(dir, Left)) {
2975
+ const borderX = targetDC.x + boxW;
2976
+ if (borderX === defaultDC.x) return void 0;
2977
+ return { x: borderX, y: defaultDC.y };
2978
+ } else if (dirEquals(dir, Right)) {
2979
+ const borderX = targetDC.x;
2980
+ if (borderX === defaultDC.x) return void 0;
2981
+ return { x: borderX, y: defaultDC.y };
2982
+ } else if (dirEquals(dir, Up)) {
2983
+ const borderY = targetDC.y + boxH;
2984
+ if (borderY === defaultDC.y) return void 0;
2985
+ return { x: defaultDC.x, y: borderY };
2986
+ } else if (dirEquals(dir, Down)) {
2987
+ const borderY = targetDC.y;
2988
+ if (borderY === defaultDC.y) return void 0;
2989
+ return { x: defaultDC.x, y: borderY };
2990
+ }
2991
+ return void 0;
2992
+ }
2960
2993
  function reverseDirection(dir) {
2961
2994
  if (dirEquals(dir, Up)) return Down;
2962
2995
  if (dirEquals(dir, Down)) return Up;
@@ -2968,15 +3001,16 @@ function reverseDirection(dir) {
2968
3001
  if (dirEquals(dir, LowerRight)) return UpperLeft;
2969
3002
  return Middle;
2970
3003
  }
2971
- function drawPath(graph, path, style = "solid") {
3004
+ function drawPath(graph, path, style = "solid", startCoordOverride, endCoordOverride) {
2972
3005
  const canvas = copyCanvas(graph.canvas);
2973
3006
  let previousCoord = path[0];
2974
3007
  const linesDrawn = [];
2975
3008
  const lineDirs = [];
3009
+ const lastIdx = path.length - 1;
2976
3010
  for (let i = 1; i < path.length; i++) {
2977
3011
  const nextCoord = path[i];
2978
- const prevDC = gridToDrawingCoord(graph, previousCoord);
2979
- const nextDC = gridToDrawingCoord(graph, nextCoord);
3012
+ const prevDC = i === 1 && startCoordOverride ? startCoordOverride : gridToDrawingCoord(graph, previousCoord);
3013
+ const nextDC = i === lastIdx && endCoordOverride ? endCoordOverride : gridToDrawingCoord(graph, nextCoord);
2980
3014
  if (drawingCoordEquals(prevDC, nextDC)) {
2981
3015
  previousCoord = nextCoord;
2982
3016
  continue;
@@ -2990,18 +3024,45 @@ function drawPath(graph, path, style = "solid") {
2990
3024
  }
2991
3025
  return [canvas, linesDrawn, lineDirs];
2992
3026
  }
2993
- function drawBoxStart(graph, path, firstLine, sourceShape) {
3027
+ function drawBoxStart(graph, path, firstLine, sourceNode) {
2994
3028
  const canvas = copyCanvas(graph.canvas);
2995
3029
  if (graph.config.useAscii) return canvas;
2996
- if (sourceShape === "state-start" || sourceShape === "state-end") {
3030
+ if (sourceNode.shape === "state-start" || sourceNode.shape === "state-end") {
2997
3031
  return canvas;
2998
3032
  }
2999
3033
  const from = firstLine[0];
3000
3034
  const dir = determineDirection(path[0], path[1]);
3001
- if (dirEquals(dir, Up)) canvas[from.x][from.y + 1] = "\u2534";
3002
- else if (dirEquals(dir, Down)) canvas[from.x][from.y - 1] = "\u252C";
3003
- else if (dirEquals(dir, Left)) canvas[from.x + 1][from.y] = "\u2524";
3004
- else if (dirEquals(dir, Right)) canvas[from.x - 1][from.y] = "\u251C";
3035
+ const dc = sourceNode.drawingCoord;
3036
+ const gc = sourceNode.gridCoord;
3037
+ if (dirEquals(dir, Right)) {
3038
+ let boxW = 0;
3039
+ for (let i = 0; i < 2; i++) boxW += graph.columnWidth.get(gc.x + i) ?? 0;
3040
+ const borderX = dc.x + boxW;
3041
+ canvas[borderX][from.y] = "\u251C";
3042
+ for (let x = borderX + 1; x < from.x; x++) {
3043
+ canvas[x][from.y] = "\u2500";
3044
+ }
3045
+ } else if (dirEquals(dir, Left)) {
3046
+ const borderX = dc.x;
3047
+ canvas[borderX][from.y] = "\u2524";
3048
+ for (let x = from.x + 1; x < borderX; x++) {
3049
+ canvas[x][from.y] = "\u2500";
3050
+ }
3051
+ } else if (dirEquals(dir, Down)) {
3052
+ let boxH = 0;
3053
+ for (let i = 0; i < 2; i++) boxH += graph.rowHeight.get(gc.y + i) ?? 0;
3054
+ const borderY = dc.y + boxH;
3055
+ canvas[from.x][borderY] = "\u252C";
3056
+ for (let y = borderY + 1; y < from.y; y++) {
3057
+ canvas[from.x][y] = "\u2502";
3058
+ }
3059
+ } else if (dirEquals(dir, Up)) {
3060
+ const borderY = dc.y;
3061
+ canvas[from.x][borderY] = "\u2534";
3062
+ for (let y = from.y + 1; y < borderY; y++) {
3063
+ canvas[from.x][y] = "\u2502";
3064
+ }
3065
+ }
3005
3066
  return canvas;
3006
3067
  }
3007
3068
  function drawArrowHead(graph, lastLine, fallbackDir) {