Skip to content

Commit b3ef700

Browse files
committed
mermaid node with class and class wrapper implementation
1 parent 0fc76bf commit b3ef700

File tree

2 files changed

+95
-65
lines changed

2 files changed

+95
-65
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import {
2+
createJSXElement,
3+
IComputeResult,
4+
} from '@devhelpr/visual-programming-system';
5+
import mermaid from 'mermaid';
6+
7+
export class MermaidNode {
8+
nodeRenderElement: HTMLElement | undefined = undefined;
9+
constructor() {
10+
mermaid.initialize({
11+
startOnLoad: true,
12+
});
13+
}
14+
compute = (
15+
input: string,
16+
_loopIndex?: number,
17+
_payload?: any
18+
): Promise<IComputeResult> => {
19+
return new Promise<IComputeResult>((resolve) => {
20+
if (this.nodeRenderElement && input) {
21+
const mermaidDefintion = input
22+
.replaceAll('```mermaid', '')
23+
.replaceAll('```', '')
24+
.trim();
25+
mermaid
26+
.render('dynamic', mermaidDefintion)
27+
.then((renderResult) => {
28+
if (this.nodeRenderElement) {
29+
this.nodeRenderElement.innerHTML = renderResult.svg;
30+
}
31+
// if (rect && rect.resize) {
32+
// rect.resize(undefined, true, '.mermaid');
33+
// }
34+
resolve({
35+
result: input,
36+
output: input,
37+
followPath: undefined,
38+
});
39+
})
40+
.catch((error) => {
41+
console.error('Error rendering mermaid diagram', error);
42+
resolve({
43+
result: input,
44+
output: input,
45+
followPath: undefined,
46+
});
47+
});
48+
}
49+
});
50+
};
51+
52+
render = () => {
53+
return (
54+
<div class="mermaid w-min h-min p-4 border-4 border-slate-400 border-solid rounded"></div>
55+
);
56+
};
57+
}

apps/vps-web/src/app/custom-nodes/mermaid.tsx

Lines changed: 38 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,16 @@ import {
33
FormField,
44
IComputeResult,
55
InitialValues,
6+
IRectNodeComponent,
67
NodeTask,
78
Rect,
9+
renderElement,
810
ThumbConnectionType,
911
ThumbType,
1012
visualNodeFactory,
1113
} from '@devhelpr/visual-programming-system';
1214
import { NodeInfo } from '@devhelpr/web-flow-executor';
13-
import mermaid from 'mermaid';
14-
15-
const MermaidImage = ({
16-
render,
17-
}: {
18-
render: (element: HTMLElement) => void;
19-
}) => {
20-
mermaid.initialize({
21-
startOnLoad: true,
22-
});
23-
24-
return (
25-
<div
26-
class="mermaid w-min h-min p-4 border-4 border-slate-400 border-solid rounded"
27-
getElement={(element: HTMLElement) => {
28-
render(element);
29-
}}
30-
></div>
31-
);
32-
};
15+
import { MermaidNode } from './classes/mermaid-node-class';
3316

3417
const fieldName = 'mermaid-input';
3518
const nodeTitle = 'Mermaid diagram';
@@ -60,10 +43,10 @@ export const getMermaidNode =
6043
() =>
6144
// (): NodeTaskFactory<NodeInfo> =>
6245
(_updated: () => void): NodeTask<NodeInfo> => {
63-
//let node: IRectNodeComponent<NodeInfo>;
46+
let node: IRectNodeComponent<NodeInfo>;
6447
let rect: Rect<NodeInfo> | undefined;
65-
66-
let nodeRenderElement: HTMLElement | undefined = undefined;
48+
let mermaidNode: MermaidNode;
49+
let nodeRenderElement: HTMLElement | null = null;
6750
const initializeCompute = () => {
6851
return;
6952
};
@@ -72,47 +55,9 @@ export const getMermaidNode =
7255
_loopIndex?: number,
7356
_payload?: any
7457
) => {
75-
return new Promise<IComputeResult>((resolve) => {
76-
if (nodeRenderElement && input) {
77-
const mermaidDefintion = input
78-
.replaceAll('```mermaid', '')
79-
.replaceAll('```', '')
80-
.trim();
81-
mermaid
82-
.render('dynamic', mermaidDefintion)
83-
.then((renderResult) => {
84-
if (nodeRenderElement) {
85-
nodeRenderElement.innerHTML = renderResult.svg;
86-
}
87-
if (rect && rect.resize) {
88-
rect.resize(undefined, true, '.mermaid');
89-
}
90-
resolve({
91-
result: input,
92-
output: input,
93-
followPath: undefined,
94-
});
95-
})
96-
.catch((error) => {
97-
console.error('Error rendering mermaid diagram', error);
98-
resolve({
99-
result: input,
100-
output: input,
101-
followPath: undefined,
102-
});
103-
});
104-
}
105-
});
106-
};
107-
const onRender = (element: HTMLElement) => {
108-
nodeRenderElement = element;
109-
const resizeObserver = new ResizeObserver(() => {
110-
if (rect && rect.resize) {
111-
rect.resize(undefined, true, '.mermaid');
112-
}
113-
});
114-
resizeObserver.observe(element);
58+
return mermaidNode.compute(input);
11559
};
60+
11661
return visualNodeFactory(
11762
mermaidNodeName,
11863
nodeTitle,
@@ -129,7 +74,34 @@ export const getMermaidNode =
12974
},
13075
(nodeInstance) => {
13176
rect = nodeInstance.rect;
132-
//node = nodeInstance.node as IRectNodeComponent<NodeInfo>;
77+
node = nodeInstance.node as IRectNodeComponent<NodeInfo>;
78+
mermaidNode = new MermaidNode();
79+
80+
const childNodeWrapper = (nodeRenderElement = (
81+
rect?.nodeComponent?.domElement as HTMLElement
82+
).querySelector('.child-node-wrapper'));
83+
const childNodeInstance =
84+
childNodeWrapper?.querySelector('.child-instance');
85+
if (childNodeInstance) {
86+
childNodeInstance.remove();
87+
}
88+
renderElement(mermaidNode.render(), childNodeWrapper);
89+
nodeRenderElement = (
90+
rect?.nodeComponent?.domElement as HTMLElement
91+
).querySelector('.child-node-wrapper > *:first-child');
92+
if (nodeRenderElement) {
93+
mermaidNode.nodeRenderElement = nodeRenderElement;
94+
const resizeObserver = new ResizeObserver(() => {
95+
if (rect && rect.resize) {
96+
rect.resize(
97+
undefined,
98+
true,
99+
'.child-node-wrapper > *:first-child'
100+
);
101+
}
102+
});
103+
resizeObserver.observe(nodeRenderElement);
104+
}
133105
if (rect && rect.resize) {
134106
rect.resize();
135107
}
@@ -139,8 +111,9 @@ export const getMermaidNode =
139111
hasStaticWidthHeight: true,
140112
hasCustomStyling: true,
141113
customClassName: 'mermaid-node',
114+
childNodeWrapperClass: 'child-node-wrapper',
142115
},
143-
<MermaidImage render={onRender} />,
116+
<div class="child-instance"></div>,
144117
true
145118
);
146119
};

0 commit comments

Comments
 (0)