Skip to content

Commit

Permalink
feat: add diagram plugin scaffold
Browse files Browse the repository at this point in the history
  • Loading branch information
Saul-Mirone committed Sep 14, 2021
1 parent dc40459 commit 16b9838
Show file tree
Hide file tree
Showing 10 changed files with 513 additions and 3 deletions.
10 changes: 10 additions & 0 deletions gh-pages/component/Demo/content/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ You can also type `:emoji:` to toggle the emoji picker.

---

Diagrams

```mermaid
sequenceDiagram
Alice->John: Hello John, how are you?
Note over Alice,John: A typical interaction
```

---

Have fun!

[repo]: https://github.com/Saul-Mirone/milkdown
Expand Down
2 changes: 2 additions & 0 deletions gh-pages/component/MilkdownEditor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Complete, defaultValueCtx, Editor, editorViewOptionsCtx, MilkdownPlugin, rootCtx } from '@milkdown/core';
import { clipboard } from '@milkdown/plugin-clipboard';
import { cursor } from '@milkdown/plugin-cursor';
import { diagrams } from '@milkdown/plugin-diagrams';
import { emoji } from '@milkdown/plugin-emoji';
import { history } from '@milkdown/plugin-history';
import { listener, listenerCtx } from '@milkdown/plugin-listener';
Expand Down Expand Up @@ -46,6 +47,7 @@ export const createEditor = (
.use(history)
.use(cursor)
.use(prism)
.use(diagrams)
.use(tooltip)
.use(math)
.use(emoji)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@milkdown/plugin-slash": "workspace:*",
"@milkdown/plugin-table": "workspace:*",
"@milkdown/plugin-tooltip": "workspace:*",
"@milkdown/plugin-diagrams": "workspace:*",
"@milkdown/preset-commonmark": "workspace:*",
"@milkdown/preset-gfm": "workspace:*",
"@milkdown/react": "workspace:*",
Expand Down
35 changes: 35 additions & 0 deletions packages/plugin-diagrams/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@milkdown/plugin-diagrams",
"version": "4.11.1",
"main": "lib/index.js",
"module": "lib/index.js",
"types": "lib/index.d.ts",
"sideEffects": false,
"license": "MIT",
"scripts": {
"start": "vite",
"watch": "tsc -w",
"test": "jest",
"tsc": "tsc --noEmit",
"build": "tsc"
},
"files": [
"lib"
],
"keywords": [
"milkdown",
"milkdown plugin",
"diagrams"
],
"peerDependencies": {
"@milkdown/core": "*"
},
"dependencies": {
"@emotion/css": "^11.1.3",
"@milkdown/utils": "workspace:*",
"@types/mermaid": "^8.2.7",
"mermaid": "^8.12.1",
"tslib": "^2.2.0",
"unist-util-visit": "^4.0.0"
}
}
10 changes: 10 additions & 0 deletions packages/plugin-diagrams/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* Copyright 2021, Milkdown by Mirone. */

import { AtomList } from '@milkdown/utils';

import { diagramNode } from './node';
import { remarkPlugin } from './remark-mermaid';

export * from './remark-mermaid';

export const diagrams = AtomList.create([remarkPlugin, diagramNode()]);
110 changes: 110 additions & 0 deletions packages/plugin-diagrams/src/node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* Copyright 2021, Milkdown by Mirone. */
import { createNode } from '@milkdown/utils';
import mermaid from 'mermaid';

let i = 0;

export const diagramNode = createNode((options, utils) => {
const id = 'diagram';
return {
id,
schema: {
content: 'text*',
group: 'block',
marks: '',
defining: true,
code: true,
attrs: {
value: {
default: '',
},
identity: {
default: id + i++,
},
},
parseDOM: [
{
tag: 'div[data-type="diagram"]',
preserveWhitespace: 'full',
getAttrs: (dom) => {
if (!(dom instanceof HTMLElement)) {
throw new Error();
}
return {
value: dom.innerHTML,
};
},
},
],
toDOM: (node) => {
return [
'div',
{
id: node.attrs.identity,
class: utils.getClassName(node.attrs, 'mermaid'),
'data-type': id,
'data-value': node.attrs.value,
},
0,
];
},
},
parser: {
match: ({ type }) => type === id,
runner: (state, node, type) => {
const value = node.value as string;
state.openNode(type, { value });
state.addText(value);
state.closeNode();
},
},
serializer: {
match: (node) => node.type.name === id,
runner: (state, node) => {
state.addNode('code', undefined, node.content.firstChild?.text || '', { lang: 'mermaid' });
},
},
view: (editor, nodeType, node, view, getPos, decorations) => {
if (options?.view) {
return options.view(editor, nodeType, node, view, getPos, decorations);
}
const dom = document.createElement('div');
const code = document.createElement('div');
code.dataset.type = id;
code.dataset.value = node.attrs.value;
code.contentEditable = 'true';
code.innerText = node.attrs.value;

const rendered = document.createElement('div');
rendered.id = node.attrs.identity;

dom.append(code);
dom.append(rendered);

mermaid.mermaidAPI.render(node.attrs.identity, node.attrs.value, (svg) => {
rendered.innerHTML = svg;
});

return {
dom: dom,
update: (updatedNode) => {
if (updatedNode.type.name !== 'code' || updatedNode.attrs.lang !== 'mermaid') return false;

// console.log(updatedNode);

return true;
},
selectNode() {
if (!view.editable) return;

dom.classList.add('selected');
code.classList.add('ProseMirror-selectednode');
},
deselectNode() {
dom.classList.remove('selected');
code.classList.remove('ProseMirror-selectednode');
},
};
},
};
});
38 changes: 38 additions & 0 deletions packages/plugin-diagrams/src/remark-mermaid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* Copyright 2021, Milkdown by Mirone. */

import { remarkPluginFactory } from '@milkdown/core';
import { Node } from 'unist';
import { visit } from 'unist-util-visit';

const createMermaidDiv = (contents: string) => ({
type: 'diagram',
value: contents,
});

const visitCodeBlock = (ast: Node) =>
visit(ast, 'code', (node, index, parent) => {
const { lang, value } = node;

// If this codeblock is not mermaid, bail.
if (lang !== 'mermaid') {
return node;
}

const newNode = createMermaidDiv(value);

if (parent && index) {
parent.children.splice(index, 1, newNode);
}

return node;
});

const mermaidPlugin = () => {
function transformer(tree: Node) {
visitCodeBlock(tree);
}

return transformer;
};

export const remarkPlugin = remarkPluginFactory(mermaidPlugin);
9 changes: 9 additions & 0 deletions packages/plugin-diagrams/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib"
},
"include": ["src"],
"references": [{ "path": "../core" }, { "path": "../utils" }]
}

0 comments on commit 16b9838

Please sign in to comment.