remark-mind-elixir 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # remark-mind-elixir
2
+
3
+ A [remark](https://github.com/remarkjs/remark) plugin for embedding interactive [Mind Elixir](https://mind-elixir.com/) mind maps in Markdown.
4
+
5
+ It lets you define mind maps using YAML inside `elixir-mind` fenced code blocks and transforms them into interactive Mind Elixir maps.
6
+
7
+ ## Features
8
+
9
+ * 📝 Define mind maps directly in Markdown
10
+ * 🌳 YAML-based mind map structure
11
+ * ⚙️ Optional YAML configuration
12
+ * ⚡ Automatic client-side rendering
13
+ * 🌐 Optional CDN-based runtime
14
+ * 🔌 Works with remark and the unified ecosystem
15
+ * 🧩 Built on top of [ZikoJS](https://github.com/zikojs)
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install remark-mind-elixir
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```js
26
+ import { remark } from 'remark'
27
+ import remarkMindElixir from 'remark-mind-elixir'
28
+
29
+ const markdown = `
30
+ # My Mind Map
31
+
32
+ \`\`\`elixir-mind
33
+ root:
34
+ topic: JavaScript
35
+ children:
36
+ - topic: Browser
37
+ - topic: Node.js
38
+ \`\`\`
39
+ `
40
+
41
+ const file = await remark()
42
+ .use(remarkMindElixir)
43
+ .process(markdown)
44
+
45
+ console.log(String(file))
46
+ ```
47
+
48
+ ## Markdown Syntax
49
+
50
+ Use an `elixir-mind` fenced code block:
51
+
52
+ ````markdown
53
+ ```elixir-mind
54
+ root:
55
+ topic: JavaScript
56
+ children:
57
+ - topic: Browser
58
+ - topic: Node.js
59
+ - topic: Deno
60
+ ```
61
+ ````
62
+
63
+ The YAML is converted into the data structure expected by Mind Elixir.
64
+
65
+ ## Configuration
66
+
67
+ A configuration document can optionally be placed before the mind-map data.
68
+
69
+ Separate the configuration and data using `---`:
70
+
71
+ ````markdown
72
+ ```elixir-mind
73
+ ---
74
+ direction: right
75
+ ---
76
+ root:
77
+ topic: JavaScript
78
+ children:
79
+ - topic: Browser
80
+ - topic: Node.js
81
+ ```
82
+ ````
83
+
84
+ The first YAML document is interpreted as plugin configuration, while the second document contains the mind-map data.
85
+
86
+ ## Multiple Mind Maps
87
+
88
+ A Markdown document can contain multiple `elixir-mind` blocks:
89
+
90
+ ````markdown
91
+ # Frontend
92
+
93
+ ```elixir-mind
94
+ root:
95
+ topic: Frontend
96
+ children:
97
+ - topic: HTML
98
+ - topic: CSS
99
+ - topic: JavaScript
100
+ ```
101
+
102
+ # Backend
103
+
104
+ ```elixir-mind
105
+ root:
106
+ topic: Backend
107
+ children:
108
+ - topic: Node.js
109
+ - topic: Python
110
+ - topic: Rust
111
+ ```
112
+ ````
113
+
114
+ The client runtime is injected once when at least one mind map is present.
115
+
116
+ ## Options
117
+
118
+ ```js
119
+ remarkMindElixir({
120
+ useCdn: true,
121
+ })
122
+ ```
123
+
124
+ ### `useCdn`
125
+
126
+ Controls whether the plugin injects the Mind Elixir browser runtime from a CDN.
127
+
128
+ **Type:** `boolean`
129
+
130
+ **Default:** `true`
131
+
132
+ ```js
133
+ remarkMindElixir({
134
+ useCdn: false,
135
+ })
136
+ ```
137
+
138
+ When disabled, the plugin does not inject the CDN runtime. Your application must provide the client-side Mind Elixir runtime.
139
+
140
+ ## Client Runtime
141
+
142
+ By default, the plugin injects the Mind Elixir runtime using `esm.sh`.
143
+
144
+ The generated Markdown contains a container similar to:
145
+
146
+ ```html
147
+ <div
148
+ data-elixir-mind
149
+ data-xmind-body="..."
150
+ data-xmind-config="..."
151
+ ></div>
152
+ ```
153
+
154
+ The client runtime finds these containers and mounts a Mind Elixir map into each one.
155
+
156
+ ## How It Works
157
+
158
+ ```text
159
+ Markdown
160
+ │
161
+ ▼
162
+ remark
163
+ │
164
+ ▼
165
+ remark-mind-elixir
166
+ │
167
+ ├── Find `elixir-mind` blocks
168
+ │
169
+ ├── Parse YAML
170
+ │
171
+ ├── Convert YAML to Mind Elixir data
172
+ │
173
+ └── Generate HTML container
174
+ │
175
+ ▼
176
+ Client runtime
177
+ │
178
+ ▼
179
+ Mind Elixir map
180
+ ```
181
+
182
+ ## Ecosystem
183
+
184
+ `remark-mind-elixir` is designed to work with remark-compatible Markdown pipelines, including:
185
+
186
+ * [Remark](https://github.com/remarkjs/remark)
187
+ * [Unified](https://unifiedjs.com/)
188
+ * [MDX](https://mdxjs.com/)
189
+ * [Astro](https://astro.build/)
190
+ * [Vite](https://vite.dev/)
191
+
192
+ It is built on top of ZikoJS utilities while remaining a remark plugin rather than a ZikoJS-specific Markdown processor.
193
+
194
+ ## Related Projects
195
+
196
+ * [ZikoJS](https://github.com/zikojs)
197
+ * [Mind Elixir](https://github.com/SSShooter/mind-elixir-core)
198
+ * [Remark](https://github.com/remarkjs/remark)
199
+ * [Unified](https://unifiedjs.com/)
200
+
201
+ <!-- ## Documentation -->
202
+
203
+ <!-- See the [ZikoJS Remark Plugins documentation](https://remark.zikojs.org/) for guides, syntax references, and examples. -->
204
+
205
+ ## License
206
+
207
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remark-mind-elixir",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "remark",
package/src/client.js CHANGED
@@ -1,7 +1,5 @@
1
1
  import { MindMap } from '@zikojs/mind-elixir/no-css'
2
2
 
3
- console.log('.... CLIENT ....')
4
-
5
3
  document.addEventListener('DOMContentLoaded', () => {
6
4
  document.querySelectorAll('[data-elixir-mind]').forEach((element) => {
7
5
  const raw = element.dataset.xmindBody
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { visit } from 'unist-util-visit'
2
- import { parse } from 'yaml'
2
+ import { parse, parseAllDocuments } from "yaml";
3
3
 
4
4
  import { yaml2MindElixirData } from '@zikojs/mind-elixir/utils'
5
5
 
@@ -12,25 +12,35 @@ const remarkElixirMind = ({
12
12
  visit(tree, 'code', (node, index, parent) => {
13
13
  if (node.lang !== 'elixir-mind') return
14
14
 
15
- hasElixirMind = true
15
+ hasElixirMind = true;
16
+ let config = {}, body = null;
16
17
 
17
- const body = yaml2MindElixirData(node.value.trim())
18
+ const documents = splitDocuments(node.value.trim());
19
+ if(documents.length === 1) body = yaml2MindElixirData(documents[0])
20
+ else {
21
+ config = parse(documents[0])
22
+ body = yaml2MindElixirData(documents[1])
23
+ }
18
24
 
19
25
  // parent creates circular references, so serialize a clean copy
20
- const serialized = JSON.stringify(body, (key, value) => {
26
+ const serialized_body = JSON.stringify(body, (key, value) => {
21
27
  if (key === 'parent') return undefined
22
28
  return value
23
29
  })
24
30
 
31
+ const serialized_config = JSON.stringify(config)
32
+
25
33
  // Escape the JSON for use inside an HTML attribute
26
- const encoded = escapeHtmlAttribute(serialized)
34
+ const encoded_body = escapeHtmlAttribute(serialized_body)
35
+ const encoded_config = escapeHtmlAttribute(serialized_config)
27
36
 
28
37
  parent.children[index] = {
29
38
  type: 'html',
30
39
  value: `
31
40
  <div
32
41
  data-elixir-mind
33
- data-xmind-body="${encoded}"
42
+ data-xmind-body="${encoded_body}"
43
+ data-xmind-config="${encoded_config}"
34
44
  ></div>
35
45
  `
36
46
  }
@@ -45,24 +55,20 @@ const remarkElixirMind = ({
45
55
  @import url('https://esm.sh/mind-elixir/style')
46
56
  </style>
47
57
 
48
- <script type="module">
49
- import 'https://esm.sh/remark-mind-elixir/client'
58
+ <script type="module" data-engine="zikojs, remark, mind-elixir">
50
59
  import { MindMap } from 'https://esm.sh/@zikojs/mind-elixir@latest/src/mind/main.js'
51
-
52
- document.querySelectorAll('[data-elixir-mind]').forEach((element) => {
53
- const raw = element.dataset.xmindBody
54
-
55
- if (!raw) return
56
-
57
- const nodeData = JSON.parse(raw)
58
-
59
- const map = MindMap({
60
- height: '400px',
61
- direction: 2
62
- }, nodeData)
63
-
64
- map.mount(element)
60
+ document.addEventListener('DOMContentLoaded', () => {
61
+ document.querySelectorAll('[data-elixir-mind]').forEach((element) => {
62
+ const raw = element.dataset.xmindBody
63
+ // const config = element.dataset?.xmindConfig
64
+ if (!raw) return
65
+ const nodeData = JSON.parse(raw)
66
+ // const nodeConfig = JSON.parse(config)
67
+ const map = MindMap({}, nodeData)
68
+ map.mount(element)
69
+ })
65
70
  })
71
+
66
72
  </script>
67
73
  `
68
74
  })
@@ -77,4 +83,61 @@ function escapeHtmlAttribute(value) {
77
83
  .replace(/>/g, '&gt;')
78
84
  }
79
85
 
80
- export default remarkElixirMind
86
+ export default remarkElixirMind
87
+
88
+ const splitDocuments = (text) => {
89
+ const documents = []
90
+ let current = ''
91
+
92
+ let quote = null
93
+ let escaped = false
94
+
95
+ const lines = text.trim().split('\n')
96
+
97
+ for (const line of lines) {
98
+ const isSeparator = line.match(/^---[ \t]*$/)
99
+
100
+ if (isSeparator && !quote) {
101
+ if (current.trim()) {
102
+ documents.push(current.trim())
103
+ }
104
+ current = ''
105
+ continue
106
+ }
107
+
108
+ current += (current ? '\n' : '') + line
109
+
110
+ // Track JS string state
111
+ for (let i = 0; i < line.length; i++) {
112
+ const char = line[i]
113
+
114
+ if (escaped) {
115
+ escaped = false
116
+ continue
117
+ }
118
+
119
+ if (char === '\\') {
120
+ escaped = true
121
+ continue
122
+ }
123
+
124
+ if (quote) {
125
+ if (char === quote) {
126
+ quote = null
127
+ }
128
+ } else if (
129
+ char === "'" ||
130
+ char === '"' ||
131
+ char === '`'
132
+ ) {
133
+ quote = char
134
+ }
135
+ }
136
+ }
137
+
138
+ if (current.trim()) {
139
+ documents.push(current.trim())
140
+ }
141
+
142
+ return documents
143
+ }