astro-mermaid 1.0.3 → 1.1.0

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,47 +1,83 @@
1
1
  # astro-mermaid
2
2
 
3
- An Astro integration for rendering Mermaid diagrams with automatic theme switching and client-side rendering. This follows the mermaid integration in [cloudflare-docs](https://github.com/cloudflare/cloudflare-docs)
3
+ An Astro integration for rendering Mermaid diagrams with automatic theme switching, client-side rendering, and universal compatibility. Works seamlessly with both standalone Astro projects and documentation frameworks like Starlight.
4
+
5
+ ## Live Demos
6
+
7
+ | Demo Type | URL | Description |
8
+ |-----------|-----|-------------|
9
+ | **Starlight Integration** | [starlight-mermaid-demo.netlify.app](https://starlight-mermaid-demo.netlify.app/) | Full documentation site with Starlight |
10
+ | **Standalone Template** | [astro-mermaid-demo.netlify.app](https://astro-mermaid-demo.netlify.app/) | Pure Astro project template |
11
+
12
+ Both demos showcase:
13
+ - ✅ All diagram types with live examples
14
+ - ✅ Theme switching (light/dark modes)
15
+ - ✅ Icon pack integration
16
+ - ✅ Responsive design
17
+ - ✅ Content collections and direct `.astro` usage
18
+
4
19
 
5
20
  ## Features
6
21
 
7
- - 🎨 Automatic theme switching based on your site's theme
8
- - 🚀 Client-side rendering for optimal performance
9
- - 📝 Simple markdown syntax using code blocks
10
- - ⚡ Vite optimization for fast development
11
- - 🔧 Customizable mermaid configuration
12
- - 🎯 TypeScript support
13
- - 🔒 Privacy-focused with no external server dependencies
14
- - 🌐 Offline-capable rendering
15
- - Zero network latency for diagram generation
16
- - 📦 Conditional loading - mermaid.js only loads on pages with diagrams
17
- - 🎭 Smooth loading animations to prevent layout shifts
22
+ - 🎨 **Universal Theme Detection** - Works with both `html[data-theme]` and `body[data-theme]` attributes
23
+ - 🚀 **Dual Plugin System** - Remark + Rehype plugins for comprehensive markdown processing
24
+ - 📝 **Universal File Support** - Works with `.md`, `.mdx`, and `.astro` files
25
+ - ⚡ **Performance Optimized** - Conditional loading and client-side rendering
26
+ - 🔧 **Highly Configurable** - Full mermaid.js configuration support
27
+ - 🎯 **TypeScript Ready** - Complete type definitions included
28
+ - 🔒 **Privacy-Focused** - No external dependencies, fully offline-capable
29
+ - 📦 **Zero Configuration** - Works out of the box with sensible defaults
30
+ - 🎭 **Smooth UX** - Loading animations and layout shift prevention
31
+ - 🦌 **ELK Support** - Optionally works with the `elk` layout ([The Eclipse Layout Kernel](https://eclipse.dev/elk/))
18
32
 
19
- ## Installation
33
+ ## Quick Start
34
+
35
+ ### 1. Installation
20
36
 
21
37
  ```bash
22
38
  npm install astro-mermaid mermaid
23
39
  ```
24
40
 
25
- ## Usage
26
-
27
- Add the integration to your `astro.config.mjs`:
41
+ ### 2. Add to Astro Config
28
42
 
29
43
  ```js
44
+ // astro.config.mjs
30
45
  import { defineConfig } from 'astro/config';
31
46
  import mermaid from 'astro-mermaid';
32
47
 
33
48
  export default defineConfig({
34
49
  integrations: [
35
50
  mermaid({
36
- theme: 'forest'
51
+ theme: 'forest',
52
+ autoTheme: true
37
53
  })
38
54
  ]
39
55
  });
40
56
  ```
41
57
 
42
- ### Important: Integration Order
58
+ ### 3. Use in Markdown
59
+
60
+ ````markdown
61
+ ```mermaid
62
+ graph TD
63
+ A[Start] --> B[Process]
64
+ B --> C[End]
65
+ ```
66
+ ````
67
+
68
+ ### 4. (Optional) Use ELK layout
43
69
 
44
- When using with Starlight or other integrations that process markdown, make sure to place the mermaid integration **before** them:
70
+ To enable the `elk` layout in Mermaid diagrams, install the `@mermaid-js/layout-elk` package.
71
+
72
+ ```bash
73
+ npm install @mermaid-js/layout-elk
74
+ ```
75
+
76
+ Learn more about [Mermaid layouts](https://mermaid.js.org/config/layouts.html) or [The Eclipse Layout Kernel](https://eclipse.dev/elk/).
77
+
78
+ ## Integration Order (Important!)
79
+
80
+ When using with Starlight or other markdown-processing integrations, place mermaid **first**:
45
81
 
46
82
  ```js
47
83
  import { defineConfig } from 'astro/config';
@@ -50,7 +86,7 @@ import mermaid from 'astro-mermaid';
50
86
 
51
87
  export default defineConfig({
52
88
  integrations: [
53
- mermaid(), // Must come BEFORE starlight
89
+ mermaid(), // ⚠️ Must come BEFORE starlight
54
90
  starlight({
55
91
  title: 'My Docs'
56
92
  })
@@ -58,18 +94,6 @@ export default defineConfig({
58
94
  });
59
95
  ```
60
96
 
61
- Then use mermaid code blocks in your markdown files:
62
-
63
- ````markdown
64
- ```mermaid
65
- graph TD
66
- A[Start] --> B{Is it working?}
67
- B -->|Yes| C[Great!]
68
- B -->|No| D[Debug]
69
- D --> A
70
- ```
71
- ````
72
-
73
97
  ## Configuration
74
98
 
75
99
  ```js
@@ -192,14 +216,16 @@ All mermaid diagram types are supported:
192
216
  - Quadrant charts
193
217
  - And more!
194
218
 
195
- ## Demo
219
+ ## Version
220
+
221
+ **Current:** `v1.0.4` - Enhanced universal compatibility with dual plugin system
196
222
 
197
- Check out the [live demo](https://starlight-mermaid-demo.netlify.app/) built with Starlight.
223
+ See [changelog](https://github.com/joesaby/astro-mermaid/releases) for version history.
198
224
 
199
225
  ## Contributing
200
226
 
201
- Contributions are welcome! Please feel free to submit a Pull Request.
227
+ Contributions welcome! See our [demos](https://astro-mermaid-demo.netlify.app/) for examples.
202
228
 
203
229
  ## License
204
230
 
205
- MIT
231
+ MIT © [Jose Sebastian](https://github.com/joesaby)
@@ -1,5 +1,40 @@
1
- import { fileURLToPath } from 'node:url';
2
- import path from 'node:path';
1
+ import { resolve } from 'import-meta-resolve';
2
+
3
+ /**
4
+ * Remark plugin to transform mermaid code blocks at the markdown level
5
+ */
6
+ function remarkMermaidPlugin(options = {}) {
7
+ return async function transformer(tree, file) {
8
+ const { visit } = await import('unist-util-visit');
9
+
10
+ let mermaidCount = 0;
11
+
12
+ visit(tree, 'code', (node, index, parent) => {
13
+ if (node.lang === 'mermaid') {
14
+ mermaidCount++;
15
+
16
+ // Transform to html node with pre.mermaid
17
+ const htmlNode = {
18
+ type: 'html',
19
+ value: `<pre class="mermaid">${node.value}</pre>`
20
+ };
21
+
22
+ // Replace the code node with html node
23
+ if (parent && typeof index === 'number') {
24
+ parent.children[index] = htmlNode;
25
+ }
26
+
27
+ if (options.logger) {
28
+ options.logger.info(`Remark transformed mermaid block #${mermaidCount} in ${file.path || 'unknown file'}`);
29
+ }
30
+ }
31
+ });
32
+
33
+ if (mermaidCount > 0 && options.logger) {
34
+ options.logger.info(`Remark total mermaid blocks transformed: ${mermaidCount}`);
35
+ }
36
+ };
37
+ }
3
38
 
4
39
  /**
5
40
  * Rehype plugin to transform mermaid code blocks
@@ -9,9 +44,9 @@ function rehypeMermaidPlugin(options = {}) {
9
44
  return async function transformer(tree, file) {
10
45
  const { visit } = await import('unist-util-visit');
11
46
  const { toString } = await import('mdast-util-to-string');
12
-
47
+
13
48
  let mermaidCount = 0;
14
-
49
+
15
50
  visit(tree, 'element', (node, index, parent) => {
16
51
  // Look for <pre><code class="language-mermaid">
17
52
  if (
@@ -21,40 +56,52 @@ function rehypeMermaidPlugin(options = {}) {
21
56
  ) {
22
57
  const codeNode = node.children[0];
23
58
  const className = codeNode.properties?.className;
24
-
59
+
25
60
  if (Array.isArray(className) && className.includes('language-mermaid')) {
26
61
  mermaidCount++;
27
62
  // Get the mermaid diagram content
28
63
  const diagramContent = toString(codeNode);
29
-
64
+
30
65
  // Transform to <pre class="mermaid">
31
66
  node.properties = {
32
67
  ...node.properties,
33
68
  className: ['mermaid']
34
69
  };
35
-
70
+
36
71
  node.children = [{
37
72
  type: 'text',
38
73
  value: diagramContent
39
74
  }];
40
-
75
+
41
76
  if (options.logger) {
42
- options.logger.info(`Transformed mermaid block #${mermaidCount} in ${file.path || 'unknown file'}`);
77
+ options.logger.info(`Rehype transformed mermaid block #${mermaidCount} in ${file.path || 'unknown file'}`);
43
78
  }
44
79
  }
45
80
  }
46
81
  });
47
-
82
+
48
83
  if (mermaidCount > 0 && options.logger) {
49
- options.logger.info(`Total mermaid blocks transformed: ${mermaidCount}`);
84
+ options.logger.info(`Rehype total mermaid blocks transformed: ${mermaidCount}`);
50
85
  }
51
86
  };
52
87
  }
53
88
 
89
+ /** Detect if optional peer dependency `@mermaid-js/layout-elk` is available. */
90
+ async function isElkInstalled(logger, consumerRoot) {
91
+ try {
92
+ resolve('@mermaid-js/layout-elk', `${consumerRoot.href}package.json`);
93
+ logger.info('Enabling ELK support');
94
+ return true;
95
+ } catch {
96
+ logger.info('Skipping ELK support');
97
+ return false;
98
+ }
99
+ }
100
+
54
101
  /**
55
102
  * Astro integration for rendering Mermaid diagrams
56
103
  * Supports automatic theme switching and client-side rendering
57
- *
104
+ *
58
105
  * @param {Object} options - Configuration options
59
106
  * @param {string} [options.theme='default'] - Default theme ('default', 'dark', 'forest', 'neutral')
60
107
  * @param {boolean} [options.autoTheme=true] - Enable automatic theme switching based on data-theme attribute
@@ -78,9 +125,22 @@ export default function astroMermaid(options = {}) {
78
125
  // Log existing rehype plugins
79
126
  logger.info('Existing rehype plugins:', config.markdown?.rehypePlugins?.length || 0);
80
127
 
81
- // Update markdown config to use our rehype plugin
128
+ // Always include mermaid.
129
+ const viteOptimizeDepsInclude = ['mermaid'];
130
+
131
+ // Conditionally include ELK
132
+ const useElk = await isElkInstalled(logger, config.root);
133
+ if (useElk) {
134
+ viteOptimizeDepsInclude.push('@mermaid-js/layout-elk');
135
+ }
136
+
137
+ // Update markdown config to use both remark and rehype plugins
82
138
  updateConfig({
83
139
  markdown: {
140
+ remarkPlugins: [
141
+ ...(config.markdown?.remarkPlugins || []),
142
+ [remarkMermaidPlugin, { logger }]
143
+ ],
84
144
  rehypePlugins: [
85
145
  ...(config.markdown?.rehypePlugins || []),
86
146
  [rehypeMermaidPlugin, { logger }]
@@ -88,7 +148,7 @@ export default function astroMermaid(options = {}) {
88
148
  },
89
149
  vite: {
90
150
  optimizeDeps: {
91
- include: ['mermaid']
151
+ include: viteOptimizeDepsInclude
92
152
  }
93
153
  }
94
154
  });
@@ -122,6 +182,16 @@ if (hasMermaidDiagrams()) {
122
182
  }));
123
183
  await mermaid.registerIconPacks(packs);
124
184
  }
185
+
186
+ // Register ELK layouts if the optional peer is available at build-time
187
+ ${useElk ? `
188
+ const elkModule = await import("@mermaid-js/layout-elk").catch(() => null);
189
+ if (elkModule?.default) {
190
+ console.log("[astro-mermaid] Registering elk layouts");
191
+ mermaid.registerLayoutLoaders(elkModule.default);
192
+ }
193
+ ` : ``}
194
+
125
195
  // Mermaid configuration
126
196
  const defaultConfig = ${JSON.stringify({
127
197
  startOnLoad: false,
@@ -146,13 +216,16 @@ if (hasMermaidDiagrams()) {
146
216
  return;
147
217
  }
148
218
 
149
- // Get current theme
219
+ // Get current theme from multiple sources
150
220
  let currentTheme = defaultConfig.theme;
151
221
 
152
222
  if (${autoTheme}) {
153
- const dataTheme = document.documentElement.getAttribute('data-theme');
223
+ // Check both html and body for data-theme attribute
224
+ const htmlTheme = document.documentElement.getAttribute('data-theme');
225
+ const bodyTheme = document.body.getAttribute('data-theme');
226
+ const dataTheme = htmlTheme || bodyTheme;
154
227
  currentTheme = themeMap[dataTheme] || defaultConfig.theme;
155
- console.log('[astro-mermaid] Using theme:', currentTheme);
228
+ console.log('[astro-mermaid] Using theme:', currentTheme, 'from', htmlTheme ? 'html' : 'body');
156
229
  }
157
230
 
158
231
  // Configure mermaid with gitGraph support
@@ -221,10 +294,15 @@ if (hasMermaidDiagrams()) {
221
294
  }
222
295
  });
223
296
 
297
+ // Observe both html and body for data-theme changes
224
298
  observer.observe(document.documentElement, {
225
299
  attributes: true,
226
300
  attributeFilter: ['data-theme']
227
301
  });
302
+ observer.observe(document.body, {
303
+ attributes: true,
304
+ attributeFilter: ['data-theme']
305
+ });
228
306
  }
229
307
 
230
308
  // Handle view transitions (for Astro View Transitions API)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-mermaid",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "An Astro integration for rendering Mermaid diagrams with automatic theme switching and client-side rendering",
5
5
  "type": "module",
6
6
  "main": "./astro-mermaid-integration.js",
@@ -29,10 +29,17 @@
29
29
  "author": "Jose Sebastian",
30
30
  "license": "MIT",
31
31
  "peerDependencies": {
32
+ "@mermaid-js/layout-elk": "^0.2.0",
32
33
  "astro": "^4.0.0 || ^5.0.0",
33
34
  "mermaid": "^10.0.0 || ^11.0.0"
34
35
  },
36
+ "peerDependenciesMeta": {
37
+ "@mermaid-js/layout-elk": {
38
+ "optional": true
39
+ }
40
+ },
35
41
  "dependencies": {
42
+ "import-meta-resolve": "^4.2.0",
36
43
  "mdast-util-to-string": "^4.0.0",
37
44
  "unist-util-visit": "^5.0.0"
38
45
  },
@@ -44,7 +51,7 @@
44
51
  },
45
52
  "repository": {
46
53
  "type": "git",
47
- "url": "https://github.com/joesaby/astro-mermaid.git"
54
+ "url": "git+https://github.com/joesaby/astro-mermaid.git"
48
55
  },
49
56
  "homepage": "https://github.com/joesaby/astro-mermaid#readme",
50
57
  "bugs": {