@ktrysmt/beautiful-mermaid 1.1.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/LICENSE +21 -0
- package/README.md +585 -0
- package/dist/index.d.ts +312 -0
- package/dist/index.js +9312 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/__tests__/ascii-edge-styles.test.ts +134 -0
- package/src/__tests__/ascii-multiline.test.ts +175 -0
- package/src/__tests__/ascii.test.ts +251 -0
- package/src/__tests__/class-arrow-directions.test.ts +414 -0
- package/src/__tests__/class-integration.test.ts +115 -0
- package/src/__tests__/class-parser.test.ts +238 -0
- package/src/__tests__/edge-approach-direction.test.ts +296 -0
- package/src/__tests__/er-integration.test.ts +432 -0
- package/src/__tests__/er-parser.test.ts +187 -0
- package/src/__tests__/integration.test.ts +518 -0
- package/src/__tests__/layout-disconnected.test.ts +391 -0
- package/src/__tests__/linkstyle.test.ts +98 -0
- package/src/__tests__/multiline-labels.test.ts +845 -0
- package/src/__tests__/parser.test.ts +861 -0
- package/src/__tests__/pathfinder.test.ts +132 -0
- package/src/__tests__/renderer.test.ts +544 -0
- package/src/__tests__/sequence-integration.test.ts +118 -0
- package/src/__tests__/sequence-layout.test.ts +747 -0
- package/src/__tests__/sequence-parser.test.ts +233 -0
- package/src/__tests__/styles.test.ts +182 -0
- package/src/__tests__/testdata/ascii/ampersand_lhs.txt +18 -0
- package/src/__tests__/testdata/ascii/ampersand_lhs_and_rhs.txt +18 -0
- package/src/__tests__/testdata/ascii/ampersand_rhs.txt +18 -0
- package/src/__tests__/testdata/ascii/ampersand_td_fanin.txt +18 -0
- package/src/__tests__/testdata/ascii/ampersand_td_fanout.txt +18 -0
- package/src/__tests__/testdata/ascii/ampersand_without_edge.txt +18 -0
- package/src/__tests__/testdata/ascii/back_reference_from_child.txt +10 -0
- package/src/__tests__/testdata/ascii/backlink_from_bottom.txt +22 -0
- package/src/__tests__/testdata/ascii/backlink_from_top.txt +22 -0
- package/src/__tests__/testdata/ascii/backlink_with_short_y_padding.txt +20 -0
- package/src/__tests__/testdata/ascii/cls_all_relationships.txt +17 -0
- package/src/__tests__/testdata/ascii/cls_annotation.txt +31 -0
- package/src/__tests__/testdata/ascii/cls_association.txt +14 -0
- package/src/__tests__/testdata/ascii/cls_basic.txt +15 -0
- package/src/__tests__/testdata/ascii/cls_dependency.txt +14 -0
- package/src/__tests__/testdata/ascii/cls_inheritance.txt +22 -0
- package/src/__tests__/testdata/ascii/cls_methods.txt +21 -0
- package/src/__tests__/testdata/ascii/comments.txt +23 -0
- package/src/__tests__/testdata/ascii/custom_padding.txt +10 -0
- package/src/__tests__/testdata/ascii/duplicate_labels.txt +19 -0
- package/src/__tests__/testdata/ascii/er_attributes.txt +19 -0
- package/src/__tests__/testdata/ascii/er_basic.txt +8 -0
- package/src/__tests__/testdata/ascii/er_identifying.txt +16 -0
- package/src/__tests__/testdata/ascii/flowchart_tb_simple.txt +29 -0
- package/src/__tests__/testdata/ascii/graph_bt_direction.txt +28 -0
- package/src/__tests__/testdata/ascii/graph_tb_direction.txt +26 -0
- package/src/__tests__/testdata/ascii/nested_subgraphs_with_labels.txt +36 -0
- package/src/__tests__/testdata/ascii/preserve_order_of_definition.txt +23 -0
- package/src/__tests__/testdata/ascii/self_reference.txt +10 -0
- package/src/__tests__/testdata/ascii/self_reference_with_edge.txt +10 -0
- package/src/__tests__/testdata/ascii/seq_basic.txt +17 -0
- package/src/__tests__/testdata/ascii/seq_multiple_messages.txt +25 -0
- package/src/__tests__/testdata/ascii/seq_self_message.txt +18 -0
- package/src/__tests__/testdata/ascii/single_node.txt +8 -0
- package/src/__tests__/testdata/ascii/single_node_longer_name.txt +8 -0
- package/src/__tests__/testdata/ascii/subgraph_complex_mixed.txt +38 -0
- package/src/__tests__/testdata/ascii/subgraph_complex_nested.txt +49 -0
- package/src/__tests__/testdata/ascii/subgraph_direction_override.txt +37 -0
- package/src/__tests__/testdata/ascii/subgraph_empty.txt +10 -0
- package/src/__tests__/testdata/ascii/subgraph_mixed_nodes.txt +20 -0
- package/src/__tests__/testdata/ascii/subgraph_mixed_nodes_td.txt +48 -0
- package/src/__tests__/testdata/ascii/subgraph_multiple_edges.txt +32 -0
- package/src/__tests__/testdata/ascii/subgraph_multiple_nodes.txt +16 -0
- package/src/__tests__/testdata/ascii/subgraph_nested.txt +24 -0
- package/src/__tests__/testdata/ascii/subgraph_nested_with_external.txt +30 -0
- package/src/__tests__/testdata/ascii/subgraph_node_outside_lr.txt +17 -0
- package/src/__tests__/testdata/ascii/subgraph_single_node.txt +16 -0
- package/src/__tests__/testdata/ascii/subgraph_td_direction.txt +26 -0
- package/src/__tests__/testdata/ascii/subgraph_td_multiple.txt +44 -0
- package/src/__tests__/testdata/ascii/subgraph_td_multiple_paddingy.txt +42 -0
- package/src/__tests__/testdata/ascii/subgraph_three_levels_nested.txt +32 -0
- package/src/__tests__/testdata/ascii/subgraph_three_separate.txt +24 -0
- package/src/__tests__/testdata/ascii/subgraph_two_separate.txt +20 -0
- package/src/__tests__/testdata/ascii/subgraph_with_labels.txt +20 -0
- package/src/__tests__/testdata/ascii/three_nodes.txt +9 -0
- package/src/__tests__/testdata/ascii/three_nodes_single_line.txt +8 -0
- package/src/__tests__/testdata/ascii/two_layer_single_graph.txt +19 -0
- package/src/__tests__/testdata/ascii/two_layer_single_graph_longer_names.txt +19 -0
- package/src/__tests__/testdata/ascii/two_nodes_linked.txt +8 -0
- package/src/__tests__/testdata/ascii/two_nodes_longer_names.txt +8 -0
- package/src/__tests__/testdata/ascii/two_root_nodes.txt +19 -0
- package/src/__tests__/testdata/ascii/two_root_nodes_longer_names.txt +19 -0
- package/src/__tests__/testdata/ascii/two_single_root_nodes.txt +19 -0
- package/src/__tests__/testdata/unicode/ampersand_lhs.txt +18 -0
- package/src/__tests__/testdata/unicode/ampersand_lhs_and_rhs.txt +18 -0
- package/src/__tests__/testdata/unicode/ampersand_rhs.txt +18 -0
- package/src/__tests__/testdata/unicode/ampersand_without_edge.txt +18 -0
- package/src/__tests__/testdata/unicode/back_reference_from_child.txt +10 -0
- package/src/__tests__/testdata/unicode/backlink_from_bottom.txt +22 -0
- package/src/__tests__/testdata/unicode/backlink_from_top.txt +22 -0
- package/src/__tests__/testdata/unicode/cls_all_relationships.txt +17 -0
- package/src/__tests__/testdata/unicode/cls_annotation.txt +31 -0
- package/src/__tests__/testdata/unicode/cls_association.txt +14 -0
- package/src/__tests__/testdata/unicode/cls_basic.txt +15 -0
- package/src/__tests__/testdata/unicode/cls_dependency.txt +14 -0
- package/src/__tests__/testdata/unicode/cls_inheritance.txt +22 -0
- package/src/__tests__/testdata/unicode/cls_methods.txt +21 -0
- package/src/__tests__/testdata/unicode/comments.txt +23 -0
- package/src/__tests__/testdata/unicode/duplicate_labels.txt +19 -0
- package/src/__tests__/testdata/unicode/er_attributes.txt +19 -0
- package/src/__tests__/testdata/unicode/er_basic.txt +8 -0
- package/src/__tests__/testdata/unicode/er_identifying.txt +16 -0
- package/src/__tests__/testdata/unicode/graph_bt_direction.txt +28 -0
- package/src/__tests__/testdata/unicode/preserve_order_of_definition.txt +23 -0
- package/src/__tests__/testdata/unicode/self_reference.txt +10 -0
- package/src/__tests__/testdata/unicode/self_reference_with_edge.txt +10 -0
- package/src/__tests__/testdata/unicode/seq_basic.txt +17 -0
- package/src/__tests__/testdata/unicode/seq_multiple_messages.txt +25 -0
- package/src/__tests__/testdata/unicode/seq_self_message.txt +18 -0
- package/src/__tests__/testdata/unicode/single_node.txt +8 -0
- package/src/__tests__/testdata/unicode/single_node_longer_name.txt +8 -0
- package/src/__tests__/testdata/unicode/three_nodes.txt +9 -0
- package/src/__tests__/testdata/unicode/three_nodes_single_line.txt +8 -0
- package/src/__tests__/testdata/unicode/two_layer_single_graph.txt +19 -0
- package/src/__tests__/testdata/unicode/two_layer_single_graph_longer_names.txt +19 -0
- package/src/__tests__/testdata/unicode/two_nodes_linked.txt +8 -0
- package/src/__tests__/testdata/unicode/two_nodes_longer_names.txt +8 -0
- package/src/__tests__/testdata/unicode/two_root_nodes.txt +19 -0
- package/src/__tests__/testdata/unicode/two_root_nodes_longer_names.txt +19 -0
- package/src/__tests__/testdata/unicode/two_single_root_nodes.txt +19 -0
- package/src/__tests__/text-metrics.test.ts +256 -0
- package/src/__tests__/xychart-ascii.test.ts +310 -0
- package/src/__tests__/xychart-integration.test.ts +137 -0
- package/src/ascii/ansi.ts +447 -0
- package/src/ascii/canvas.ts +431 -0
- package/src/ascii/class-diagram.ts +697 -0
- package/src/ascii/converter.ts +271 -0
- package/src/ascii/draw.ts +1373 -0
- package/src/ascii/edge-bundling.ts +328 -0
- package/src/ascii/edge-routing.ts +296 -0
- package/src/ascii/er-diagram.ts +435 -0
- package/src/ascii/grid.ts +596 -0
- package/src/ascii/index.ts +171 -0
- package/src/ascii/multiline-utils.ts +77 -0
- package/src/ascii/pathfinder.ts +227 -0
- package/src/ascii/sequence.ts +451 -0
- package/src/ascii/shapes/circle.ts +27 -0
- package/src/ascii/shapes/corners.ts +127 -0
- package/src/ascii/shapes/diamond.ts +27 -0
- package/src/ascii/shapes/hexagon.ts +27 -0
- package/src/ascii/shapes/index.ts +101 -0
- package/src/ascii/shapes/rectangle.ts +173 -0
- package/src/ascii/shapes/rounded.ts +27 -0
- package/src/ascii/shapes/special.ts +293 -0
- package/src/ascii/shapes/stadium.ts +112 -0
- package/src/ascii/shapes/state.ts +192 -0
- package/src/ascii/shapes/types.ts +73 -0
- package/src/ascii/types.ts +273 -0
- package/src/ascii/validate.ts +120 -0
- package/src/ascii/xychart.ts +863 -0
- package/src/browser.ts +24 -0
- package/src/class/layout.ts +211 -0
- package/src/class/parser.ts +290 -0
- package/src/class/renderer.ts +397 -0
- package/src/class/types.ts +121 -0
- package/src/elk-instance.ts +113 -0
- package/src/er/layout.ts +161 -0
- package/src/er/parser.ts +181 -0
- package/src/er/renderer.ts +420 -0
- package/src/er/types.ts +91 -0
- package/src/index.ts +177 -0
- package/src/layout-engine.ts +1421 -0
- package/src/layout.ts +8 -0
- package/src/multiline-utils.ts +219 -0
- package/src/parser.ts +645 -0
- package/src/renderer.ts +603 -0
- package/src/sequence/layout.ts +410 -0
- package/src/sequence/parser.ts +207 -0
- package/src/sequence/renderer.ts +346 -0
- package/src/sequence/types.ts +146 -0
- package/src/shape-clipping.ts +179 -0
- package/src/styles.ts +96 -0
- package/src/text-metrics.ts +246 -0
- package/src/theme.ts +304 -0
- package/src/types.ts +164 -0
- package/src/xychart/colors.ts +140 -0
- package/src/xychart/layout.ts +440 -0
- package/src/xychart/parser.ts +115 -0
- package/src/xychart/renderer.ts +549 -0
- package/src/xychart/types.ts +150 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Craft Docs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# beautiful-mermaid
|
|
4
|
+
|
|
5
|
+
**Render Mermaid diagrams as beautiful SVGs or ASCII art**
|
|
6
|
+
|
|
7
|
+
Ultra-fast, fully themeable, zero DOM dependencies. Built for the AI era.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/beautiful-mermaid)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
[**Live Demo & Samples**](https://agents.craft.do/mermaid)
|
|
15
|
+
|
|
16
|
+
**[→ Use it live in Craft Agents](https://agents.craft.do)**
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
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
|
|
32
|
+
|
|
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.
|
|
34
|
+
|
|
35
|
+
|
|
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.)
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **6 diagram types** — Flowcharts, State, Sequence, Class, ER, and XY Charts (bar, line, combined)
|
|
41
|
+
- **Dual output** — SVG for rich UIs, ASCII/Unicode for terminals
|
|
42
|
+
- **Synchronous rendering** — No async, no flash. Works with React `useMemo()`
|
|
43
|
+
- **15 built-in themes** — And dead simple to add your own
|
|
44
|
+
- **Full Shiki compatibility** — Use any VS Code theme directly
|
|
45
|
+
- **Live theme switching** — CSS custom properties, no re-render needed
|
|
46
|
+
- **Mono mode** — Beautiful diagrams from just 2 colors
|
|
47
|
+
- **Zero DOM dependencies** — Pure TypeScript, works everywhere
|
|
48
|
+
- **Ultra-fast** — Renders 100+ diagrams in under 500ms
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install beautiful-mermaid
|
|
54
|
+
# or
|
|
55
|
+
bun add beautiful-mermaid
|
|
56
|
+
# or
|
|
57
|
+
pnpm add beautiful-mermaid
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
### SVG Output
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { renderMermaidSVG } from 'beautiful-mermaid'
|
|
66
|
+
|
|
67
|
+
const svg = renderMermaidSVG(`
|
|
68
|
+
graph TD
|
|
69
|
+
A[Start] --> B{Decision}
|
|
70
|
+
B -->|Yes| C[Action]
|
|
71
|
+
B -->|No| D[End]
|
|
72
|
+
`)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Rendering is **fully synchronous** — no `await`, no promises. The ELK.js layout engine runs synchronously via a FakeWorker bypass, so you get your SVG string instantly.
|
|
76
|
+
|
|
77
|
+
Need async? Use `renderMermaidSVGAsync()` — same output, returns a `Promise<string>`.
|
|
78
|
+
|
|
79
|
+
### ASCII Output
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { renderMermaidASCII } from 'beautiful-mermaid'
|
|
83
|
+
|
|
84
|
+
const ascii = renderMermaidASCII(`graph LR; A --> B --> C`)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
┌───┐ ┌───┐ ┌───┐
|
|
89
|
+
│ │ │ │ │ │
|
|
90
|
+
│ A │────►│ B │────►│ C │
|
|
91
|
+
│ │ │ │ │ │
|
|
92
|
+
└───┘ └───┘ └───┘
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## React Integration
|
|
98
|
+
|
|
99
|
+
Because rendering is synchronous, you can use `useMemo()` for zero-flash diagram rendering:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { renderMermaidSVG } from 'beautiful-mermaid'
|
|
103
|
+
|
|
104
|
+
function MermaidDiagram({ code }: { code: string }) {
|
|
105
|
+
const { svg, error } = React.useMemo(() => {
|
|
106
|
+
try {
|
|
107
|
+
return {
|
|
108
|
+
svg: renderMermaidSVG(code, {
|
|
109
|
+
bg: 'var(--background)',
|
|
110
|
+
fg: 'var(--foreground)',
|
|
111
|
+
transparent: true,
|
|
112
|
+
}),
|
|
113
|
+
error: null,
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
return { svg: null, error: err instanceof Error ? err : new Error(String(err)) }
|
|
117
|
+
}
|
|
118
|
+
}, [code])
|
|
119
|
+
|
|
120
|
+
if (error) return <pre>{error.message}</pre>
|
|
121
|
+
return <div dangerouslySetInnerHTML={{ __html: svg! }} />
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Why this works well:**
|
|
126
|
+
- **No flash** — SVG is computed synchronously during render, not in a useEffect
|
|
127
|
+
- **CSS variables** — Pass `var(--background)` etc. instead of hex colors. The SVG inherits from your app's CSS, so theme switches apply instantly without re-rendering
|
|
128
|
+
- **Memoized** — Only re-renders when `code` changes
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Theming
|
|
133
|
+
|
|
134
|
+
The theming system is the heart of `beautiful-mermaid`. It's designed to be both powerful and dead simple.
|
|
135
|
+
|
|
136
|
+
### The Two-Color Foundation
|
|
137
|
+
|
|
138
|
+
Every diagram needs just two colors: **background** (`bg`) and **foreground** (`fg`). That's it. From these two colors, the entire diagram is derived using `color-mix()`:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const svg = renderMermaidSVG(diagram, {
|
|
142
|
+
bg: '#1a1b26', // Background
|
|
143
|
+
fg: '#a9b1d6', // Foreground
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This is **Mono Mode**—a coherent, beautiful diagram from just two colors. The system automatically derives:
|
|
148
|
+
|
|
149
|
+
| Element | Derivation |
|
|
150
|
+
|---------|------------|
|
|
151
|
+
| Text | `--fg` at 100% |
|
|
152
|
+
| Secondary text | `--fg` at 60% into `--bg` |
|
|
153
|
+
| Edge labels | `--fg` at 40% into `--bg` |
|
|
154
|
+
| Faint text | `--fg` at 25% into `--bg` |
|
|
155
|
+
| Connectors | `--fg` at 50% into `--bg` |
|
|
156
|
+
| Arrow heads | `--fg` at 85% into `--bg` |
|
|
157
|
+
| Node fill | `--fg` at 3% into `--bg` |
|
|
158
|
+
| Group header | `--fg` at 5% into `--bg` |
|
|
159
|
+
| Inner strokes | `--fg` at 12% into `--bg` |
|
|
160
|
+
| Node stroke | `--fg` at 20% into `--bg` |
|
|
161
|
+
|
|
162
|
+
### Enriched Mode
|
|
163
|
+
|
|
164
|
+
For richer themes, you can provide optional "enrichment" colors that override specific derivations:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const svg = renderMermaidSVG(diagram, {
|
|
168
|
+
bg: '#1a1b26',
|
|
169
|
+
fg: '#a9b1d6',
|
|
170
|
+
// Optional enrichment:
|
|
171
|
+
line: '#3d59a1', // Edge/connector color
|
|
172
|
+
accent: '#7aa2f7', // Arrow heads, highlights
|
|
173
|
+
muted: '#565f89', // Secondary text, labels
|
|
174
|
+
surface: '#292e42', // Node fill tint
|
|
175
|
+
border: '#3d59a1', // Node stroke
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
If an enrichment color isn't provided, it falls back to the `color-mix()` derivation. This means you can provide just the colors you care about.
|
|
180
|
+
|
|
181
|
+
### CSS Custom Properties = Live Switching
|
|
182
|
+
|
|
183
|
+
All colors are CSS custom properties on the `<svg>` element. This means you can switch themes instantly without re-rendering:
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
// Switch theme by updating CSS variables
|
|
187
|
+
svg.style.setProperty('--bg', '#282a36')
|
|
188
|
+
svg.style.setProperty('--fg', '#f8f8f2')
|
|
189
|
+
// The entire diagram updates immediately
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
For React apps, pass CSS variable references instead of hex values:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
const svg = renderMermaidSVG(diagram, {
|
|
196
|
+
bg: 'var(--background)',
|
|
197
|
+
fg: 'var(--foreground)',
|
|
198
|
+
accent: 'var(--accent)',
|
|
199
|
+
transparent: true,
|
|
200
|
+
})
|
|
201
|
+
// Theme switches apply automatically via CSS cascade — no re-render needed
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Built-in Themes
|
|
205
|
+
|
|
206
|
+
15 carefully curated themes ship out of the box:
|
|
207
|
+
|
|
208
|
+
| Theme | Type | Background | Accent |
|
|
209
|
+
|-------|------|------------|--------|
|
|
210
|
+
| `zinc-light` | Light | `#FFFFFF` | Derived |
|
|
211
|
+
| `zinc-dark` | Dark | `#18181B` | Derived |
|
|
212
|
+
| `tokyo-night` | Dark | `#1a1b26` | `#7aa2f7` |
|
|
213
|
+
| `tokyo-night-storm` | Dark | `#24283b` | `#7aa2f7` |
|
|
214
|
+
| `tokyo-night-light` | Light | `#d5d6db` | `#34548a` |
|
|
215
|
+
| `catppuccin-mocha` | Dark | `#1e1e2e` | `#cba6f7` |
|
|
216
|
+
| `catppuccin-latte` | Light | `#eff1f5` | `#8839ef` |
|
|
217
|
+
| `nord` | Dark | `#2e3440` | `#88c0d0` |
|
|
218
|
+
| `nord-light` | Light | `#eceff4` | `#5e81ac` |
|
|
219
|
+
| `dracula` | Dark | `#282a36` | `#bd93f9` |
|
|
220
|
+
| `github-light` | Light | `#ffffff` | `#0969da` |
|
|
221
|
+
| `github-dark` | Dark | `#0d1117` | `#4493f8` |
|
|
222
|
+
| `solarized-light` | Light | `#fdf6e3` | `#268bd2` |
|
|
223
|
+
| `solarized-dark` | Dark | `#002b36` | `#268bd2` |
|
|
224
|
+
| `one-dark` | Dark | `#282c34` | `#c678dd` |
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { renderMermaidSVG, THEMES } from 'beautiful-mermaid'
|
|
228
|
+
|
|
229
|
+
const svg = renderMermaidSVG(diagram, THEMES['tokyo-night'])
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Adding Your Own Theme
|
|
233
|
+
|
|
234
|
+
Creating a theme is trivial. At minimum, just provide `bg` and `fg`:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const myTheme = {
|
|
238
|
+
bg: '#0f0f0f',
|
|
239
|
+
fg: '#e0e0e0',
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const svg = renderMermaidSVG(diagram, myTheme)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Want richer colors? Add any of the optional enrichments:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const myRichTheme = {
|
|
249
|
+
bg: '#0f0f0f',
|
|
250
|
+
fg: '#e0e0e0',
|
|
251
|
+
accent: '#ff6b6b', // Pop of color for arrows
|
|
252
|
+
muted: '#666666', // Subdued labels
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Full Shiki Compatibility
|
|
257
|
+
|
|
258
|
+
Use **any VS Code theme** directly via Shiki integration. This gives you access to hundreds of community themes:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { getSingletonHighlighter } from 'shiki'
|
|
262
|
+
import { renderMermaidSVG, fromShikiTheme } from 'beautiful-mermaid'
|
|
263
|
+
|
|
264
|
+
// Load any theme from Shiki's registry
|
|
265
|
+
const highlighter = await getSingletonHighlighter({
|
|
266
|
+
themes: ['vitesse-dark', 'rose-pine', 'material-theme-darker']
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
// Extract diagram colors from the theme
|
|
270
|
+
const colors = fromShikiTheme(highlighter.getTheme('vitesse-dark'))
|
|
271
|
+
|
|
272
|
+
const svg = renderMermaidSVG(diagram, colors)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
The `fromShikiTheme()` function intelligently maps VS Code editor colors to diagram roles:
|
|
276
|
+
|
|
277
|
+
| Editor Color | Diagram Role |
|
|
278
|
+
|--------------|--------------|
|
|
279
|
+
| `editor.background` | `bg` |
|
|
280
|
+
| `editor.foreground` | `fg` |
|
|
281
|
+
| `editorLineNumber.foreground` | `line` |
|
|
282
|
+
| `focusBorder` / keyword token | `accent` |
|
|
283
|
+
| comment token | `muted` |
|
|
284
|
+
| `editor.selectionBackground` | `surface` |
|
|
285
|
+
| `editorWidget.border` | `border` |
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Supported Diagrams
|
|
290
|
+
|
|
291
|
+
### Flowcharts
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
graph TD
|
|
295
|
+
A[Start] --> B{Decision}
|
|
296
|
+
B -->|Yes| C[Process]
|
|
297
|
+
B -->|No| D[End]
|
|
298
|
+
C --> D
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
All directions supported: `TD` (top-down), `LR` (left-right), `BT` (bottom-top), `RL` (right-left).
|
|
302
|
+
|
|
303
|
+
### State Diagrams
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
stateDiagram-v2
|
|
307
|
+
[*] --> Idle
|
|
308
|
+
Idle --> Processing: start
|
|
309
|
+
Processing --> Complete: done
|
|
310
|
+
Complete --> [*]
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Sequence Diagrams
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
sequenceDiagram
|
|
317
|
+
Alice->>Bob: Hello Bob!
|
|
318
|
+
Bob-->>Alice: Hi Alice!
|
|
319
|
+
Alice->>Bob: How are you?
|
|
320
|
+
Bob-->>Alice: Great, thanks!
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Class Diagrams
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
classDiagram
|
|
327
|
+
Animal <|-- Duck
|
|
328
|
+
Animal <|-- Fish
|
|
329
|
+
Animal: +int age
|
|
330
|
+
Animal: +String gender
|
|
331
|
+
Animal: +isMammal() bool
|
|
332
|
+
Duck: +String beakColor
|
|
333
|
+
Duck: +swim()
|
|
334
|
+
Duck: +quack()
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### ER Diagrams
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
erDiagram
|
|
341
|
+
CUSTOMER ||--o{ ORDER : places
|
|
342
|
+
ORDER ||--|{ LINE_ITEM : contains
|
|
343
|
+
PRODUCT ||--o{ LINE_ITEM : "is in"
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Inline Edge Styling
|
|
347
|
+
|
|
348
|
+
Use `linkStyle` to override edge colors and stroke widths — just like [Mermaid's linkStyle](https://mermaid.js.org/syntax/flowchart.html#styling-links):
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
graph TD
|
|
352
|
+
A --> B --> C
|
|
353
|
+
linkStyle 0 stroke:#ff0000,stroke-width:2px
|
|
354
|
+
linkStyle default stroke:#888888
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
| Syntax | Effect |
|
|
358
|
+
| ------------------------------- | -------------------------------------- |
|
|
359
|
+
| `linkStyle 0 stroke:#f00` | Style a single edge by index (0-based) |
|
|
360
|
+
| `linkStyle 0,2 stroke:#f00` | Style multiple edges at once |
|
|
361
|
+
| `linkStyle default stroke:#888` | Default style applied to all edges |
|
|
362
|
+
|
|
363
|
+
Index-specific styles override the default. Supported properties: `stroke`, `stroke-width`.
|
|
364
|
+
|
|
365
|
+
Works in both flowcharts and state diagrams.
|
|
366
|
+
|
|
367
|
+
### XY Charts
|
|
368
|
+
|
|
369
|
+
Bar charts, line charts, and combinations — using Mermaid's `xychart-beta` syntax.
|
|
370
|
+
|
|
371
|
+
**Bar chart:**
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
xychart-beta
|
|
375
|
+
title "Monthly Revenue"
|
|
376
|
+
x-axis [Jan, Feb, Mar, Apr, May, Jun]
|
|
377
|
+
y-axis "Revenue ($K)" 0 --> 500
|
|
378
|
+
bar [180, 250, 310, 280, 350, 420]
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Line chart:**
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
xychart-beta
|
|
385
|
+
title "User Growth"
|
|
386
|
+
x-axis [Jan, Feb, Mar, Apr, May, Jun]
|
|
387
|
+
line [1200, 1800, 2500, 3100, 3800, 4500]
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Combined bar + line:**
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
xychart-beta
|
|
394
|
+
title "Sales with Trend"
|
|
395
|
+
x-axis [Jan, Feb, Mar, Apr, May, Jun]
|
|
396
|
+
bar [300, 380, 280, 450, 350, 520]
|
|
397
|
+
line [300, 330, 320, 353, 352, 395]
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Horizontal orientation:**
|
|
401
|
+
|
|
402
|
+
```
|
|
403
|
+
xychart-beta horizontal
|
|
404
|
+
title "Language Popularity"
|
|
405
|
+
x-axis [Python, JavaScript, Java, Go, Rust]
|
|
406
|
+
bar [30, 25, 20, 12, 8]
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Axis configuration:**
|
|
410
|
+
|
|
411
|
+
- Categorical x-axis: `x-axis [A, B, C]`
|
|
412
|
+
- Numeric x-axis range: `x-axis 0 --> 100`
|
|
413
|
+
- Axis titles: `x-axis "Category" [A, B, C]`
|
|
414
|
+
- Y-axis range: `y-axis "Score" 0 --> 100`
|
|
415
|
+
|
|
416
|
+
**Multi-series:** Add multiple `bar` and/or `line` declarations. Each series gets a distinct color from a monochromatic palette derived from the theme's accent color.
|
|
417
|
+
|
|
418
|
+
### XY Chart Styling
|
|
419
|
+
|
|
420
|
+
The chart renderer follows a clean, minimal design philosophy inspired by Apple and Craft:
|
|
421
|
+
|
|
422
|
+
- **Dot grid** — A subtle dot pattern fills the plot area instead of traditional solid grid lines
|
|
423
|
+
- **Rounded bars** — All bar corners are rounded for a modern, polished look
|
|
424
|
+
- **Smooth curves** — Line series use natural cubic spline interpolation, producing mathematically smooth curves through all data points (not straight segments or staircase steps)
|
|
425
|
+
- **Floating labels** — No visible axis lines or tick marks; labels float freely for a clutter-free aesthetic
|
|
426
|
+
- **Drop-shadow lines** — Each line series has a subtle shadow beneath it for depth
|
|
427
|
+
- **Monochromatic palette** — Series 0 uses the theme's accent color; additional series get darker/lighter shades of the same hue with subtle hue drift, adapting automatically to light or dark backgrounds
|
|
428
|
+
- **Interactive tooltips** — When rendered with `interactive: true`, hovering over bars or data points shows value tooltips. Multi-line tooltips appear when multiple series share an x-position
|
|
429
|
+
- **Sparse line dots** — Lines with 12 or fewer data points show data point dots by default for readability
|
|
430
|
+
- **Full theme support** — All 15 built-in themes (and custom themes) apply to charts. The accent color drives the entire series color palette
|
|
431
|
+
- **Live theme switching** — Chart series colors are CSS custom properties (`--xychart-color-N`), so theme changes apply instantly without re-rendering
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## ASCII Output
|
|
436
|
+
|
|
437
|
+
For terminal environments, CLI tools, or anywhere you need plain text, render to ASCII or Unicode box-drawing characters:
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
import { renderMermaidASCII } from 'beautiful-mermaid'
|
|
441
|
+
|
|
442
|
+
// Unicode mode (default) — prettier box drawing
|
|
443
|
+
const unicode = renderMermaidASCII(`graph LR; A --> B`)
|
|
444
|
+
|
|
445
|
+
// Pure ASCII mode — maximum compatibility
|
|
446
|
+
const ascii = renderMermaidASCII(`graph LR; A --> B`, { useAscii: true })
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Unicode output:**
|
|
450
|
+
```
|
|
451
|
+
┌───┐ ┌───┐
|
|
452
|
+
│ │ │ │
|
|
453
|
+
│ A │────►│ B │
|
|
454
|
+
│ │ │ │
|
|
455
|
+
└───┘ └───┘
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**ASCII output:**
|
|
459
|
+
```
|
|
460
|
+
+---+ +---+
|
|
461
|
+
| | | |
|
|
462
|
+
| A |---->| B |
|
|
463
|
+
| | | |
|
|
464
|
+
+---+ +---+
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### ASCII Options
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
renderMermaidASCII(diagram, {
|
|
471
|
+
useAscii: false, // true = ASCII, false = Unicode (default)
|
|
472
|
+
paddingX: 5, // Horizontal spacing between nodes
|
|
473
|
+
paddingY: 5, // Vertical spacing between nodes
|
|
474
|
+
boxBorderPadding: 1, // Padding inside node boxes
|
|
475
|
+
colorMode: 'auto', // 'none' | 'auto' | 'ansi16' | 'ansi256' | 'truecolor' | 'html'
|
|
476
|
+
theme: { ... }, // Partial<AsciiTheme> — override default colors
|
|
477
|
+
})
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### ASCII XY Charts
|
|
481
|
+
|
|
482
|
+
XY charts render to ASCII with dedicated chart-drawing characters:
|
|
483
|
+
|
|
484
|
+
- **Bar charts** — `█` blocks (Unicode) or `#` (ASCII mode)
|
|
485
|
+
- **Line charts** — Staircase routing with rounded corners: `╭╮╰╯│─` (Unicode) or `+|-` (ASCII)
|
|
486
|
+
- **Multi-series** — Each series gets a distinct ANSI color from the theme's accent palette
|
|
487
|
+
- **Legends** — Automatically shown when multiple series are present
|
|
488
|
+
- **Horizontal charts** — Fully supported with categories on the y-axis
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## API Reference
|
|
493
|
+
|
|
494
|
+
### `renderMermaidSVG(text, options?): string`
|
|
495
|
+
|
|
496
|
+
Render a Mermaid diagram to SVG. Synchronous. Auto-detects diagram type.
|
|
497
|
+
|
|
498
|
+
**Parameters:**
|
|
499
|
+
- `text` — Mermaid source code
|
|
500
|
+
- `options` — Optional `RenderOptions` object
|
|
501
|
+
|
|
502
|
+
**RenderOptions:**
|
|
503
|
+
|
|
504
|
+
| Option | Type | Default | Description |
|
|
505
|
+
|--------|------|---------|-------------|
|
|
506
|
+
| `bg` | `string` | `#FFFFFF` | Background color (or CSS variable) |
|
|
507
|
+
| `fg` | `string` | `#27272A` | Foreground color (or CSS variable) |
|
|
508
|
+
| `line` | `string?` | — | Edge/connector color |
|
|
509
|
+
| `accent` | `string?` | — | Arrow heads, highlights |
|
|
510
|
+
| `muted` | `string?` | — | Secondary text, labels |
|
|
511
|
+
| `surface` | `string?` | — | Node fill tint |
|
|
512
|
+
| `border` | `string?` | — | Node stroke color |
|
|
513
|
+
| `font` | `string` | `Inter` | Font family |
|
|
514
|
+
| `transparent` | `boolean` | `false` | Render with transparent background |
|
|
515
|
+
| `padding` | `number` | `40` | Canvas padding in px |
|
|
516
|
+
| `nodeSpacing` | `number` | `24` | Horizontal spacing between sibling nodes |
|
|
517
|
+
| `layerSpacing` | `number` | `40` | Vertical spacing between layers |
|
|
518
|
+
| `componentSpacing` | `number` | `24` | Spacing between disconnected components |
|
|
519
|
+
| `thoroughness` | `number` | `3` | Crossing minimization trials (1-7, higher = better but slower) |
|
|
520
|
+
| `interactive` | `boolean` | `false` | Enable hover tooltips on XY chart bars and data points |
|
|
521
|
+
|
|
522
|
+
**XY Charts:** Diagrams starting with `xychart-beta` are auto-detected — no separate function needed. The `accent` color option drives the chart series color palette.
|
|
523
|
+
|
|
524
|
+
### `renderMermaidSVGAsync(text, options?): Promise<string>`
|
|
525
|
+
|
|
526
|
+
Async version of `renderMermaidSVG()`. Same output, returns a `Promise<string>`. Useful in async server handlers or data loaders.
|
|
527
|
+
|
|
528
|
+
### `renderMermaidASCII(text, options?): string`
|
|
529
|
+
|
|
530
|
+
Render a Mermaid diagram to ASCII/Unicode text. Synchronous.
|
|
531
|
+
|
|
532
|
+
**AsciiRenderOptions:**
|
|
533
|
+
|
|
534
|
+
| Option | Type | Default | Description |
|
|
535
|
+
|--------|------|---------|-------------|
|
|
536
|
+
| `useAscii` | `boolean` | `false` | Use ASCII instead of Unicode |
|
|
537
|
+
| `paddingX` | `number` | `5` | Horizontal node spacing |
|
|
538
|
+
| `paddingY` | `number` | `5` | Vertical node spacing |
|
|
539
|
+
| `boxBorderPadding` | `number` | `1` | Inner box padding |
|
|
540
|
+
| `colorMode` | `string` | `'auto'` | `'none'`, `'auto'`, `'ansi16'`, `'ansi256'`, `'truecolor'`, or `'html'` |
|
|
541
|
+
| `theme` | `Partial<AsciiTheme>` | — | Override default colors for ASCII output |
|
|
542
|
+
|
|
543
|
+
### `parseMermaid(text): MermaidGraph`
|
|
544
|
+
|
|
545
|
+
Parse Mermaid source into a structured graph object (for custom processing).
|
|
546
|
+
|
|
547
|
+
### `fromShikiTheme(theme): DiagramColors`
|
|
548
|
+
|
|
549
|
+
Extract diagram colors from a Shiki theme object.
|
|
550
|
+
|
|
551
|
+
### `THEMES: Record<string, DiagramColors>`
|
|
552
|
+
|
|
553
|
+
Object containing all 15 built-in themes.
|
|
554
|
+
|
|
555
|
+
### `DEFAULTS: { bg: string, fg: string }`
|
|
556
|
+
|
|
557
|
+
Default colors (`#FFFFFF` / `#27272A`).
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Attribution
|
|
562
|
+
|
|
563
|
+
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 with:
|
|
564
|
+
|
|
565
|
+
- Sequence diagram support
|
|
566
|
+
- Class diagram support
|
|
567
|
+
- ER diagram support
|
|
568
|
+
- Unicode box-drawing characters
|
|
569
|
+
- Configurable spacing and padding
|
|
570
|
+
|
|
571
|
+
Thank you Alexander for the excellent foundation!
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## License
|
|
576
|
+
|
|
577
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
<div align="center">
|
|
582
|
+
|
|
583
|
+
Built with care by the team at [Craft](https://craft.do)
|
|
584
|
+
|
|
585
|
+
</div>
|