@dxos/plugin-mermaid 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5
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/dist/lib/browser/index.mjs +133 -74
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/MermaidPlugin.d.ts +2 -1
- package/dist/types/src/MermaidPlugin.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +1 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/mermaid-extension.d.ts +7 -0
- package/dist/types/src/extensions/mermaid-extension.d.ts.map +1 -0
- package/dist/types/src/extensions/mermaid.stories.d.ts +11 -11
- package/dist/types/src/extensions/mermaid.stories.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -3
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +35 -25
- package/src/MermaidPlugin.tsx +13 -10
- package/src/extensions/index.ts +1 -1
- package/src/extensions/mermaid-extension.ts +215 -0
- package/src/extensions/mermaid.stories.tsx +20 -21
- package/src/meta.ts +8 -6
- package/dist/lib/node-esm/index.mjs +0 -134
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/types/src/extensions/mermaid.d.ts +0 -4
- package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
- package/src/extensions/mermaid.ts +0 -155
package/package.json
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-mermaid",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.fcfe5033a5",
|
|
4
4
|
"description": "Mermaid markdown plugin",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
13
|
"sideEffects": true,
|
|
10
14
|
"type": "module",
|
|
15
|
+
"imports": {
|
|
16
|
+
"#meta": "./src/meta.ts"
|
|
17
|
+
},
|
|
11
18
|
"exports": {
|
|
12
19
|
".": {
|
|
20
|
+
"source": "./src/index.ts",
|
|
13
21
|
"types": "./dist/types/src/index.d.ts",
|
|
14
22
|
"browser": "./dist/lib/browser/index.mjs"
|
|
15
23
|
}
|
|
@@ -23,34 +31,36 @@
|
|
|
23
31
|
"src"
|
|
24
32
|
],
|
|
25
33
|
"dependencies": {
|
|
26
|
-
"@codemirror/language": "^6.
|
|
27
|
-
"@codemirror/state": "^6.
|
|
28
|
-
"@codemirror/view": "^6.
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"@dxos/
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
34
|
+
"@codemirror/language": "^6.11.3",
|
|
35
|
+
"@codemirror/state": "^6.5.2",
|
|
36
|
+
"@codemirror/view": "^6.38.4",
|
|
37
|
+
"mermaid": "^10.9.4",
|
|
38
|
+
"@dxos/operation": "0.8.4-main.fcfe5033a5",
|
|
39
|
+
"@dxos/app-framework": "0.8.4-main.fcfe5033a5",
|
|
40
|
+
"@dxos/plugin-markdown": "0.8.4-main.fcfe5033a5",
|
|
41
|
+
"@dxos/react-ui-editor": "0.8.4-main.fcfe5033a5",
|
|
42
|
+
"@dxos/ui-editor": "0.8.4-main.fcfe5033a5",
|
|
43
|
+
"@dxos/util": "0.8.4-main.fcfe5033a5",
|
|
44
|
+
"@dxos/plugin-space": "0.8.4-main.fcfe5033a5"
|
|
36
45
|
},
|
|
37
46
|
"devDependencies": {
|
|
38
|
-
"@types/react": "~
|
|
39
|
-
"@types/react-dom": "~
|
|
40
|
-
"
|
|
41
|
-
"react
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
+
"@types/react": "~19.2.7",
|
|
48
|
+
"@types/react-dom": "~19.2.3",
|
|
49
|
+
"effect": "3.20.0",
|
|
50
|
+
"react": "~19.2.3",
|
|
51
|
+
"react-dom": "~19.2.3",
|
|
52
|
+
"vite": "^7.1.11",
|
|
53
|
+
"@dxos/storybook-utils": "0.8.4-main.fcfe5033a5",
|
|
54
|
+
"@dxos/echo": "0.8.4-main.fcfe5033a5",
|
|
55
|
+
"@dxos/ui-theme": "0.8.4-main.fcfe5033a5",
|
|
56
|
+
"@dxos/react-ui": "0.8.4-main.fcfe5033a5"
|
|
47
57
|
},
|
|
48
58
|
"peerDependencies": {
|
|
49
|
-
"effect": "
|
|
50
|
-
"react": "~
|
|
51
|
-
"react-dom": "~
|
|
52
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
53
|
-
"@dxos/
|
|
59
|
+
"effect": "3.20.0",
|
|
60
|
+
"react": "~19.2.3",
|
|
61
|
+
"react-dom": "~19.2.3",
|
|
62
|
+
"@dxos/react-ui": "0.8.4-main.fcfe5033a5",
|
|
63
|
+
"@dxos/ui-theme": "0.8.4-main.fcfe5033a5"
|
|
54
64
|
},
|
|
55
65
|
"publishConfig": {
|
|
56
66
|
"access": "public"
|
package/src/MermaidPlugin.tsx
CHANGED
|
@@ -2,17 +2,20 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { Capability, Plugin } from '@dxos/app-framework';
|
|
6
8
|
import { MarkdownCapabilities, MarkdownEvents } from '@dxos/plugin-markdown';
|
|
7
9
|
|
|
10
|
+
import { meta } from '#meta';
|
|
11
|
+
|
|
8
12
|
import { mermaid } from './extensions';
|
|
9
|
-
import { meta } from './meta';
|
|
10
13
|
|
|
11
|
-
export const MermaidPlugin = ()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
export const MermaidPlugin = Plugin.define(meta).pipe(
|
|
15
|
+
Plugin.addModule({
|
|
16
|
+
id: 'markdown',
|
|
17
|
+
activatesOn: MarkdownEvents.SetupExtensions,
|
|
18
|
+
activate: () => Effect.succeed(Capability.contributes(MarkdownCapabilities.Extensions, [mermaid])),
|
|
19
|
+
}),
|
|
20
|
+
Plugin.make,
|
|
21
|
+
);
|
package/src/extensions/index.ts
CHANGED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { syntaxTree } from '@codemirror/language';
|
|
6
|
+
import { type Extension } from '@codemirror/state';
|
|
7
|
+
import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';
|
|
8
|
+
import _mermaid from 'mermaid';
|
|
9
|
+
|
|
10
|
+
export type MermaidOptions = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Extension to create mermaid diagrams.
|
|
14
|
+
*/
|
|
15
|
+
export const mermaid = (_options: MermaidOptions = {}): Extension => {
|
|
16
|
+
return [
|
|
17
|
+
ViewPlugin.fromClass(
|
|
18
|
+
class {
|
|
19
|
+
decorations: DecorationSet;
|
|
20
|
+
|
|
21
|
+
constructor(view: EditorView) {
|
|
22
|
+
this.decorations = this.buildDecorations(view);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
update(update: ViewUpdate) {
|
|
26
|
+
// Always rebuild decorations when selection changes to handle arrow key navigation.
|
|
27
|
+
if (update.docChanged || update.viewportChanged || update.selectionSet || update.focusChanged) {
|
|
28
|
+
this.decorations = this.buildDecorations(update.view);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
buildDecorations(view: EditorView): DecorationSet {
|
|
33
|
+
const decorations: Array<{ from: number; to: number; decoration: Decoration }> = [];
|
|
34
|
+
|
|
35
|
+
syntaxTree(view.state).iterate({
|
|
36
|
+
enter: (node) => {
|
|
37
|
+
if (node.name === 'FencedCode') {
|
|
38
|
+
const cursor = view.state.selection.main.head;
|
|
39
|
+
// Show widget when cursor is outside the code block.
|
|
40
|
+
// Add a buffer of 1 position before and after to handle edge cases.
|
|
41
|
+
const showWidget = view.state.readOnly || cursor < node.from - 1 || cursor > node.to + 1;
|
|
42
|
+
if (showWidget) {
|
|
43
|
+
const info = node.node.getChild('CodeInfo');
|
|
44
|
+
if (info) {
|
|
45
|
+
const type = view.state.sliceDoc(info.from, info.to);
|
|
46
|
+
const text = node.node.getChild('CodeText');
|
|
47
|
+
if (type === 'mermaid' && text) {
|
|
48
|
+
const content = view.state.sliceDoc(text.from, text.to).trim();
|
|
49
|
+
const label = content.split(' ')[0];
|
|
50
|
+
|
|
51
|
+
// Create widget.
|
|
52
|
+
const widget = new MermaidWidget(`mermaid-${node.from}`, content, label);
|
|
53
|
+
|
|
54
|
+
// Find the line after the code block to place the widget.
|
|
55
|
+
const endLine = view.state.doc.lineAt(node.to);
|
|
56
|
+
const nextLinePos = endLine.to + 1;
|
|
57
|
+
|
|
58
|
+
// Add widget after the code block.
|
|
59
|
+
if (nextLinePos <= view.state.doc.length) {
|
|
60
|
+
decorations.push({
|
|
61
|
+
from: nextLinePos,
|
|
62
|
+
to: nextLinePos,
|
|
63
|
+
decoration: Decoration.widget({
|
|
64
|
+
widget,
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
// Check if at the end of the document.
|
|
69
|
+
decorations.push({
|
|
70
|
+
from: endLine.to,
|
|
71
|
+
to: endLine.to,
|
|
72
|
+
decoration: Decoration.widget({
|
|
73
|
+
widget,
|
|
74
|
+
side: 1,
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Hide each line of the code block.
|
|
80
|
+
const startLine = view.state.doc.lineAt(node.from);
|
|
81
|
+
for (let lineNum = startLine.number; lineNum <= endLine.number; lineNum++) {
|
|
82
|
+
const line = view.state.doc.line(lineNum);
|
|
83
|
+
decorations.push({
|
|
84
|
+
from: line.from,
|
|
85
|
+
to: line.from,
|
|
86
|
+
decoration: Decoration.line({
|
|
87
|
+
class: 'cm-mermaid-hidden',
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return Decoration.set(
|
|
99
|
+
decorations.sort((a, b) => a.from - b.from || a.to - b.to).map((d) => d.decoration.range(d.from, d.to)),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
decorations: (v) => v.decorations,
|
|
105
|
+
},
|
|
106
|
+
),
|
|
107
|
+
EditorView.theme({
|
|
108
|
+
'& .cm-mermaid': {
|
|
109
|
+
position: 'relative',
|
|
110
|
+
display: 'inline-flex',
|
|
111
|
+
width: '100%',
|
|
112
|
+
maring: '4px 0',
|
|
113
|
+
padding: '16px',
|
|
114
|
+
justifyContent: 'center',
|
|
115
|
+
backgroundColor: 'var(--color-group-surface)',
|
|
116
|
+
borderRadius: '8px',
|
|
117
|
+
},
|
|
118
|
+
'& .cm-mermaid-label': {
|
|
119
|
+
position: 'absolute',
|
|
120
|
+
right: '16px',
|
|
121
|
+
fontFamily: 'unset',
|
|
122
|
+
color: 'var(--color-subdued)',
|
|
123
|
+
},
|
|
124
|
+
'& .cm-mermaid-error': {
|
|
125
|
+
display: 'inline-block',
|
|
126
|
+
color: 'var(--color-error)',
|
|
127
|
+
},
|
|
128
|
+
'& .cm-mermaid-hidden': {
|
|
129
|
+
display: 'none !important',
|
|
130
|
+
},
|
|
131
|
+
}),
|
|
132
|
+
];
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
class MermaidWidget extends WidgetType {
|
|
136
|
+
_svg: string | undefined;
|
|
137
|
+
_error: string | undefined;
|
|
138
|
+
|
|
139
|
+
// TODO(burdon): Mermaid API requires unique id.
|
|
140
|
+
constructor(
|
|
141
|
+
private readonly _id: string,
|
|
142
|
+
private readonly _source: string,
|
|
143
|
+
private readonly _label?: string,
|
|
144
|
+
) {
|
|
145
|
+
super();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
override eq(other: this) {
|
|
149
|
+
return this._source === other._source;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
override ignoreEvent(ev: Event) {
|
|
153
|
+
return !/^mouse/.test(ev.type);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
override toDOM(view: EditorView) {
|
|
157
|
+
const div = document.createElement('div');
|
|
158
|
+
div.className = 'cm-mermaid';
|
|
159
|
+
|
|
160
|
+
setTimeout(async () => {
|
|
161
|
+
// https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts
|
|
162
|
+
_mermaid.initialize({
|
|
163
|
+
darkMode: view.state.facet(EditorView.darkTheme),
|
|
164
|
+
theme: 'neutral',
|
|
165
|
+
// TODO(burdon): Styles.
|
|
166
|
+
// NOTE: Must specify 'base' in order to override.
|
|
167
|
+
// theme: 'base',
|
|
168
|
+
// themeVariables: {
|
|
169
|
+
// primaryColor: getToken('extend.colors.red.100'),
|
|
170
|
+
// primaryBorderColor: getToken('extend.colors.neutral.200'),
|
|
171
|
+
// },
|
|
172
|
+
// https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagrams/flowchart/styles.ts
|
|
173
|
+
// https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagrams/sequence/styles.js
|
|
174
|
+
// https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagrams/state/styles.js
|
|
175
|
+
// themeCSS: '.node rect { fill: red; }',
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// TODO(burdon): Cache?
|
|
179
|
+
const svg = await this.render(div);
|
|
180
|
+
if (this._error) {
|
|
181
|
+
div.className = 'cm-mermaid-error';
|
|
182
|
+
div.innerText = this._error;
|
|
183
|
+
} else {
|
|
184
|
+
div.className = 'cm-mermaid';
|
|
185
|
+
div.innerHTML = svg!;
|
|
186
|
+
|
|
187
|
+
if (this._label) {
|
|
188
|
+
const label = document.createElement('span');
|
|
189
|
+
label.innerText = this._label;
|
|
190
|
+
label.className = 'cm-mermaid-label';
|
|
191
|
+
div.appendChild(label);
|
|
192
|
+
view.requestMeasure();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return div;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async render(_container: Element): Promise<string | undefined> {
|
|
201
|
+
try {
|
|
202
|
+
// https://github.com/mermaid-js/mermaid
|
|
203
|
+
const valid = await _mermaid.parse(this._source);
|
|
204
|
+
if (valid) {
|
|
205
|
+
const result = await _mermaid.render(this._id, this._source);
|
|
206
|
+
this._error = undefined;
|
|
207
|
+
this._svg = result.svg;
|
|
208
|
+
return result.svg;
|
|
209
|
+
}
|
|
210
|
+
} catch (err: any) {
|
|
211
|
+
this._error = String(err);
|
|
212
|
+
this._svg = undefined;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -2,39 +2,36 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
6
|
-
|
|
7
|
-
import { type Meta } from '@storybook/react-vite';
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React from 'react';
|
|
9
7
|
|
|
10
8
|
import { useThemeContext } from '@dxos/react-ui';
|
|
9
|
+
import { useTextEditor } from '@dxos/react-ui-editor';
|
|
10
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
11
|
import {
|
|
12
12
|
createBasicExtensions,
|
|
13
13
|
createMarkdownExtensions,
|
|
14
14
|
createThemeExtensions,
|
|
15
15
|
decorateMarkdown,
|
|
16
|
-
|
|
17
|
-
} from '@dxos/react-ui-editor';
|
|
18
|
-
import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
16
|
+
} from '@dxos/ui-editor';
|
|
19
17
|
|
|
20
|
-
import { mermaid } from './mermaid';
|
|
18
|
+
import { mermaid } from './mermaid-extension';
|
|
21
19
|
|
|
22
20
|
const str = (...lines: string[]) => lines.join('\n');
|
|
23
21
|
|
|
24
|
-
type
|
|
22
|
+
type DefaultStoryProps = {
|
|
25
23
|
text?: string;
|
|
26
24
|
};
|
|
27
25
|
|
|
28
|
-
const DefaultStory = ({ text }:
|
|
26
|
+
const DefaultStory = ({ text }: DefaultStoryProps) => {
|
|
29
27
|
const { themeMode } = useThemeContext();
|
|
30
28
|
const { parentRef, focusAttributes } = useTextEditor(
|
|
31
29
|
() => ({
|
|
32
30
|
initialValue: text,
|
|
33
31
|
extensions: [
|
|
34
32
|
createBasicExtensions(),
|
|
35
|
-
createMarkdownExtensions(
|
|
33
|
+
createMarkdownExtensions(),
|
|
36
34
|
createThemeExtensions({ themeMode, syntaxHighlighting: true }),
|
|
37
|
-
// TODO(burdon): Bug if mermaid extension is provided after decorateMarkdown.
|
|
38
35
|
mermaid(),
|
|
39
36
|
decorateMarkdown(),
|
|
40
37
|
],
|
|
@@ -45,7 +42,17 @@ const DefaultStory = ({ text }: StoryProps) => {
|
|
|
45
42
|
return <div className='w-[50rem]' ref={parentRef} {...focusAttributes} />;
|
|
46
43
|
};
|
|
47
44
|
|
|
48
|
-
|
|
45
|
+
const meta = {
|
|
46
|
+
title: 'plugins/plugin-mermaid/extensions/mermaid',
|
|
47
|
+
render: DefaultStory,
|
|
48
|
+
decorators: [withTheme(), withLayout({ layout: 'column' })],
|
|
49
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
50
|
+
|
|
51
|
+
export default meta;
|
|
52
|
+
|
|
53
|
+
type Story = StoryObj<typeof meta>;
|
|
54
|
+
|
|
55
|
+
export const Default: Story = {
|
|
49
56
|
args: {
|
|
50
57
|
text: str(
|
|
51
58
|
'# Mermaid',
|
|
@@ -68,7 +75,7 @@ export const Default = {
|
|
|
68
75
|
},
|
|
69
76
|
};
|
|
70
77
|
|
|
71
|
-
export const Error = {
|
|
78
|
+
export const Error: Story = {
|
|
72
79
|
args: {
|
|
73
80
|
text: str(
|
|
74
81
|
'# Mermaid',
|
|
@@ -85,11 +92,3 @@ export const Error = {
|
|
|
85
92
|
),
|
|
86
93
|
},
|
|
87
94
|
};
|
|
88
|
-
|
|
89
|
-
const meta: Meta = {
|
|
90
|
-
title: 'plugins/plugin-mermaid/extensions',
|
|
91
|
-
render: DefaultStory,
|
|
92
|
-
decorators: [withTheme, withLayout({ fullscreen: true, classNames: 'justify-center' })],
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export default meta;
|
package/src/meta.ts
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type Plugin } from '@dxos/app-framework';
|
|
6
|
+
import { trim } from '@dxos/util';
|
|
6
7
|
|
|
7
|
-
export const
|
|
8
|
-
|
|
9
|
-
export const meta: PluginMeta = {
|
|
10
|
-
id: MERMAID_PLUGIN,
|
|
8
|
+
export const meta: Plugin.Meta = {
|
|
9
|
+
id: 'org.dxos.plugin.mermaid',
|
|
11
10
|
name: 'Mermaid',
|
|
12
|
-
description:
|
|
11
|
+
description: trim`
|
|
12
|
+
Generate diagrams from simple text-based definitions using Mermaid syntax.
|
|
13
|
+
Create flowcharts, sequence diagrams, and other visualizations that stay in sync with your documentation.
|
|
14
|
+
`,
|
|
13
15
|
icon: 'ph--anchor-simple--regular',
|
|
14
16
|
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-mermaid',
|
|
15
17
|
};
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
|
-
|
|
3
|
-
// src/MermaidPlugin.tsx
|
|
4
|
-
import { contributes, defineModule, definePlugin } from "@dxos/app-framework";
|
|
5
|
-
import { MarkdownCapabilities, MarkdownEvents } from "@dxos/plugin-markdown";
|
|
6
|
-
|
|
7
|
-
// src/extensions/mermaid.ts
|
|
8
|
-
import { syntaxTree } from "@codemirror/language";
|
|
9
|
-
import { RangeSetBuilder, StateField } from "@codemirror/state";
|
|
10
|
-
import { Decoration, EditorView, WidgetType } from "@codemirror/view";
|
|
11
|
-
import _mermaid from "mermaid";
|
|
12
|
-
var mermaid = (options = {}) => {
|
|
13
|
-
return [
|
|
14
|
-
StateField.define({
|
|
15
|
-
create: (state) => update(state, options),
|
|
16
|
-
update: (_, tr) => update(tr.state, options),
|
|
17
|
-
provide: (field) => EditorView.decorations.from(field)
|
|
18
|
-
}),
|
|
19
|
-
styles
|
|
20
|
-
];
|
|
21
|
-
};
|
|
22
|
-
var update = (state, options) => {
|
|
23
|
-
const builder = new RangeSetBuilder();
|
|
24
|
-
syntaxTree(state).iterate({
|
|
25
|
-
enter: (node) => {
|
|
26
|
-
if (node.name === "FencedCode") {
|
|
27
|
-
const cursor = state.selection.main.head;
|
|
28
|
-
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
29
|
-
const info = node.node.getChild("CodeInfo");
|
|
30
|
-
if (info) {
|
|
31
|
-
const type = state.sliceDoc(info.from, info.to);
|
|
32
|
-
const text = node.node.getChild("CodeText");
|
|
33
|
-
if (type === "mermaid" && text) {
|
|
34
|
-
const content = state.sliceDoc(text.from, text.to);
|
|
35
|
-
builder.add(node.from, node.to, Decoration.replace({
|
|
36
|
-
widget: new MermaidWidget(`mermaid-${node.from}`, content)
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
return builder.finish();
|
|
45
|
-
};
|
|
46
|
-
var MermaidWidget = class extends WidgetType {
|
|
47
|
-
// TODO(burdon): Mermaid API requires unique id.
|
|
48
|
-
constructor(_id, _source) {
|
|
49
|
-
super(), this._id = _id, this._source = _source;
|
|
50
|
-
}
|
|
51
|
-
eq(other) {
|
|
52
|
-
return this._source === other._source;
|
|
53
|
-
}
|
|
54
|
-
toDOM(view) {
|
|
55
|
-
const div = document.createElement("div");
|
|
56
|
-
setTimeout(async () => {
|
|
57
|
-
_mermaid.initialize({
|
|
58
|
-
darkMode: view.state.facet(EditorView.darkTheme),
|
|
59
|
-
theme: "neutral"
|
|
60
|
-
});
|
|
61
|
-
const svg = await this.render(div);
|
|
62
|
-
if (this._error) {
|
|
63
|
-
div.className = "cm-mermaid-error";
|
|
64
|
-
div.innerText = this._error;
|
|
65
|
-
} else {
|
|
66
|
-
div.className = "cm-mermaid";
|
|
67
|
-
div.innerHTML = svg;
|
|
68
|
-
view.requestMeasure();
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
return div;
|
|
72
|
-
}
|
|
73
|
-
async render(container) {
|
|
74
|
-
try {
|
|
75
|
-
const valid = await _mermaid.parse(this._source);
|
|
76
|
-
if (valid) {
|
|
77
|
-
const result = await _mermaid.render(this._id, this._source);
|
|
78
|
-
this._error = void 0;
|
|
79
|
-
this._svg = result.svg;
|
|
80
|
-
return result.svg;
|
|
81
|
-
}
|
|
82
|
-
} catch (err) {
|
|
83
|
-
this._error = String(err);
|
|
84
|
-
this._svg = void 0;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
ignoreEvent(e) {
|
|
88
|
-
return !/^mouse/.test(e.type);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
var styles = EditorView.theme({
|
|
92
|
-
"& .cm-mermaid": {
|
|
93
|
-
position: "relative",
|
|
94
|
-
display: "inline-flex",
|
|
95
|
-
width: "100%",
|
|
96
|
-
justifyContent: "center"
|
|
97
|
-
},
|
|
98
|
-
// '& .cm-mermaid-label': {
|
|
99
|
-
// position: 'absolute',
|
|
100
|
-
// right: 0,
|
|
101
|
-
// textSize: 10,
|
|
102
|
-
// },
|
|
103
|
-
"& .cm-mermaid-error": {
|
|
104
|
-
display: "inline-block",
|
|
105
|
-
color: "var(--dx-errorText)"
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// src/meta.ts
|
|
110
|
-
var MERMAID_PLUGIN = "dxos.org/plugin/mermaid";
|
|
111
|
-
var meta = {
|
|
112
|
-
id: MERMAID_PLUGIN,
|
|
113
|
-
name: "Mermaid",
|
|
114
|
-
description: "Tool that renders text definitions to create diagrams.",
|
|
115
|
-
icon: "ph--anchor-simple--regular",
|
|
116
|
-
source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-mermaid"
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// src/MermaidPlugin.tsx
|
|
120
|
-
var MermaidPlugin = () => definePlugin(meta, [
|
|
121
|
-
defineModule({
|
|
122
|
-
id: `${meta.id}/module/markdown`,
|
|
123
|
-
activatesOn: MarkdownEvents.SetupExtensions,
|
|
124
|
-
activate: () => contributes(MarkdownCapabilities.Extensions, [
|
|
125
|
-
mermaid
|
|
126
|
-
])
|
|
127
|
-
})
|
|
128
|
-
]);
|
|
129
|
-
export {
|
|
130
|
-
MERMAID_PLUGIN,
|
|
131
|
-
MermaidPlugin,
|
|
132
|
-
meta
|
|
133
|
-
};
|
|
134
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/MermaidPlugin.tsx", "../../../src/extensions/mermaid.ts", "../../../src/meta.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { contributes, defineModule, definePlugin } from '@dxos/app-framework';\nimport { MarkdownCapabilities, MarkdownEvents } from '@dxos/plugin-markdown';\n\nimport { mermaid } from './extensions';\nimport { meta } from './meta';\n\nexport const MermaidPlugin = () =>\n definePlugin(meta, [\n defineModule({\n id: `${meta.id}/module/markdown`,\n activatesOn: MarkdownEvents.SetupExtensions,\n activate: () => contributes(MarkdownCapabilities.Extensions, [mermaid]),\n }),\n ]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport {\n type EditorState,\n type Extension,\n type RangeSet,\n RangeSetBuilder,\n StateField,\n type Transaction,\n} from '@codemirror/state';\nimport { Decoration, EditorView, WidgetType } from '@codemirror/view';\nimport _mermaid from 'mermaid';\n\nexport type MermaidOptions = {};\n\nexport const mermaid = (options: MermaidOptions = {}): Extension => {\n return [\n StateField.define<RangeSet<Decoration>>({\n create: (state) => update(state, options),\n update: (_: RangeSet<Decoration>, tr: Transaction) => update(tr.state, options),\n provide: (field) => EditorView.decorations.from(field),\n }),\n styles,\n ];\n};\n\nconst update = (state: EditorState, options: MermaidOptions) => {\n const builder = new RangeSetBuilder<Decoration>();\n syntaxTree(state).iterate({\n enter: (node) => {\n if (node.name === 'FencedCode') {\n const cursor = state.selection.main.head;\n if (state.readOnly || cursor < node.from || cursor > node.to) {\n const info = node.node.getChild('CodeInfo');\n if (info) {\n const type = state.sliceDoc(info.from, info.to);\n const text = node.node.getChild('CodeText');\n if (type === 'mermaid' && text) {\n const content = state.sliceDoc(text.from, text.to);\n // TODO(burdon): Error if extension defined AFTER decorateMarkdown.\n // Decorations that replace line breaks may not be specified via plugins\n builder.add(\n node.from,\n node.to,\n Decoration.replace({\n widget: new MermaidWidget(`mermaid-${node.from}`, content),\n }),\n );\n }\n }\n }\n }\n },\n });\n\n return builder.finish();\n};\n\nclass MermaidWidget extends WidgetType {\n _svg: string | undefined;\n _error: string | undefined;\n\n // TODO(burdon): Mermaid API requires unique id.\n constructor(\n private readonly _id: string,\n private readonly _source: string,\n ) {\n super();\n }\n\n override eq(other: this): boolean {\n return this._source === other._source;\n }\n\n override toDOM(view: EditorView): HTMLDivElement {\n const div = document.createElement('div');\n setTimeout(async () => {\n // https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts\n _mermaid.initialize({\n darkMode: view.state.facet(EditorView.darkTheme),\n theme: 'neutral',\n // TODO(burdon): Styles.\n // NOTE: Must specify 'base' in order to override.\n // theme: 'base',\n // themeVariables: {\n // primaryColor: getToken('extend.colors.red.100'),\n // primaryBorderColor: getToken('extend.colors.neutral.200'),\n // },\n // https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagrams/flowchart/styles.ts\n // https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagrams/sequence/styles.js\n // https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagrams/state/styles.js\n // themeCSS: '.node rect { fill: red; }',\n });\n\n // TODO(burdon): Cache?\n const svg = await this.render(div);\n if (this._error) {\n div.className = 'cm-mermaid-error';\n div.innerText = this._error;\n } else {\n div.className = 'cm-mermaid';\n div.innerHTML = svg!;\n\n // const label = document.createElement('span');\n // label.innerText = 'Mermaid';\n // label.className = 'cm-mermaid-label';\n // wrapper.appendChild(label);\n view.requestMeasure();\n }\n });\n\n return div;\n }\n\n async render(container: Element): Promise<string | undefined> {\n try {\n // https://github.com/mermaid-js/mermaid\n const valid = await _mermaid.parse(this._source);\n if (valid) {\n const result = await _mermaid.render(this._id, this._source);\n this._error = undefined;\n this._svg = result.svg;\n return result.svg;\n }\n } catch (err: any) {\n this._error = String(err);\n this._svg = undefined;\n }\n }\n\n override ignoreEvent(e: Event): boolean {\n return !/^mouse/.test(e.type);\n }\n}\n\nconst styles = EditorView.theme({\n '& .cm-mermaid': {\n position: 'relative',\n display: 'inline-flex',\n width: '100%',\n justifyContent: 'center',\n },\n // '& .cm-mermaid-label': {\n // position: 'absolute',\n // right: 0,\n // textSize: 10,\n // },\n '& .cm-mermaid-error': {\n display: 'inline-block',\n color: 'var(--dx-errorText)',\n },\n});\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type PluginMeta } from '@dxos/app-framework';\n\nexport const MERMAID_PLUGIN = 'dxos.org/plugin/mermaid';\n\nexport const meta: PluginMeta = {\n id: MERMAID_PLUGIN,\n name: 'Mermaid',\n description: 'Tool that renders text definitions to create diagrams.',\n icon: 'ph--anchor-simple--regular',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-mermaid',\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["contributes", "defineModule", "definePlugin", "MarkdownCapabilities", "MarkdownEvents", "syntaxTree", "RangeSetBuilder", "StateField", "Decoration", "EditorView", "WidgetType", "_mermaid", "mermaid", "options", "StateField", "define", "create", "state", "update", "_", "tr", "provide", "field", "EditorView", "decorations", "from", "styles", "builder", "RangeSetBuilder", "syntaxTree", "iterate", "enter", "node", "name", "cursor", "selection", "main", "head", "readOnly", "to", "info", "getChild", "type", "sliceDoc", "text", "content", "add", "Decoration", "replace", "widget", "MermaidWidget", "finish", "WidgetType", "_id", "_source", "eq", "other", "toDOM", "view", "div", "document", "createElement", "setTimeout", "_mermaid", "initialize", "darkMode", "facet", "darkTheme", "theme", "svg", "render", "_error", "className", "innerText", "innerHTML", "requestMeasure", "container", "valid", "parse", "result", "undefined", "_svg", "err", "String", "ignoreEvent", "e", "test", "position", "display", "width", "justifyContent", "color", "MERMAID_PLUGIN", "meta", "id", "name", "description", "icon", "source", "MermaidPlugin", "definePlugin", "meta", "defineModule", "id", "activatesOn", "MarkdownEvents", "SetupExtensions", "activate", "contributes", "MarkdownCapabilities", "Extensions", "mermaid"]
|
|
7
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"inputs":{"src/extensions/mermaid.ts":{"bytes":15195,"imports":[{"path":"@codemirror/language","kind":"import-statement","external":true},{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"@codemirror/view","kind":"import-statement","external":true},{"path":"mermaid","kind":"import-statement","external":true}],"format":"esm"},"src/extensions/index.ts":{"bytes":468,"imports":[{"path":"src/extensions/mermaid.ts","kind":"import-statement","original":"./mermaid"}],"format":"esm"},"src/meta.ts":{"bytes":1476,"imports":[],"format":"esm"},"src/MermaidPlugin.tsx":{"bytes":2302,"imports":[{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/plugin-markdown","kind":"import-statement","external":true},{"path":"src/extensions/index.ts","kind":"import-statement","original":"./extensions"},{"path":"src/meta.ts","kind":"import-statement","original":"./meta"}],"format":"esm"},"src/index.ts":{"bytes":551,"imports":[{"path":"src/MermaidPlugin.tsx","kind":"import-statement","original":"./MermaidPlugin"},{"path":"src/meta.ts","kind":"import-statement","original":"./meta"}],"format":"esm"}},"outputs":{"dist/lib/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":9647},"dist/lib/node-esm/index.mjs":{"imports":[{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/plugin-markdown","kind":"import-statement","external":true},{"path":"@codemirror/language","kind":"import-statement","external":true},{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"@codemirror/view","kind":"import-statement","external":true},{"path":"mermaid","kind":"import-statement","external":true}],"exports":["MERMAID_PLUGIN","MermaidPlugin","meta"],"entryPoint":"src/index.ts","inputs":{"src/MermaidPlugin.tsx":{"bytesInOutput":405},"src/extensions/mermaid.ts":{"bytesInOutput":2870},"src/extensions/index.ts":{"bytesInOutput":0},"src/meta.ts":{"bytesInOutput":299},"src/index.ts":{"bytesInOutput":0}},"bytes":3853}}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../../../src/extensions/mermaid.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,SAAS,EAKf,MAAM,mBAAmB,CAAC;AAI3B,MAAM,MAAM,cAAc,GAAG,EAAE,CAAC;AAEhC,eAAO,MAAM,OAAO,GAAI,UAAS,cAAmB,KAAG,SAStD,CAAC"}
|