@tldraw/mermaid 4.6.0-internal.c7df3c92455a
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-cjs/blueprint.js +17 -0
- package/dist-cjs/blueprint.js.map +7 -0
- package/dist-cjs/colors.js +173 -0
- package/dist-cjs/colors.js.map +7 -0
- package/dist-cjs/createMermaidDiagram.js +144 -0
- package/dist-cjs/createMermaidDiagram.js.map +7 -0
- package/dist-cjs/flowchartDiagram.js +202 -0
- package/dist-cjs/flowchartDiagram.js.map +7 -0
- package/dist-cjs/index.d.ts +114 -0
- package/dist-cjs/index.js +34 -0
- package/dist-cjs/index.js.map +7 -0
- package/dist-cjs/renderBlueprint.js +314 -0
- package/dist-cjs/renderBlueprint.js.map +7 -0
- package/dist-cjs/sequenceDiagram.js +686 -0
- package/dist-cjs/sequenceDiagram.js.map +7 -0
- package/dist-cjs/stateDiagram.js +373 -0
- package/dist-cjs/stateDiagram.js.map +7 -0
- package/dist-cjs/svgParsing.js +187 -0
- package/dist-cjs/svgParsing.js.map +7 -0
- package/dist-cjs/utils.js +75 -0
- package/dist-cjs/utils.js.map +7 -0
- package/dist-esm/blueprint.mjs +1 -0
- package/dist-esm/blueprint.mjs.map +7 -0
- package/dist-esm/colors.mjs +153 -0
- package/dist-esm/colors.mjs.map +7 -0
- package/dist-esm/createMermaidDiagram.mjs +114 -0
- package/dist-esm/createMermaidDiagram.mjs.map +7 -0
- package/dist-esm/flowchartDiagram.mjs +188 -0
- package/dist-esm/flowchartDiagram.mjs.map +7 -0
- package/dist-esm/index.d.mts +114 -0
- package/dist-esm/index.mjs +14 -0
- package/dist-esm/index.mjs.map +7 -0
- package/dist-esm/renderBlueprint.mjs +298 -0
- package/dist-esm/renderBlueprint.mjs.map +7 -0
- package/dist-esm/sequenceDiagram.mjs +666 -0
- package/dist-esm/sequenceDiagram.mjs.map +7 -0
- package/dist-esm/stateDiagram.mjs +359 -0
- package/dist-esm/stateDiagram.mjs.map +7 -0
- package/dist-esm/svgParsing.mjs +167 -0
- package/dist-esm/svgParsing.mjs.map +7 -0
- package/dist-esm/utils.mjs +55 -0
- package/dist-esm/utils.mjs.map +7 -0
- package/package.json +62 -0
- package/src/blueprint.ts +75 -0
- package/src/colors.ts +215 -0
- package/src/createMermaidDiagram.test.ts +31 -0
- package/src/createMermaidDiagram.ts +155 -0
- package/src/flowchartDiagram.ts +232 -0
- package/src/index.ts +18 -0
- package/src/mermaidDiagrams.test.ts +880 -0
- package/src/renderBlueprint.ts +373 -0
- package/src/sequenceDiagram.ts +851 -0
- package/src/stateDiagram.ts +477 -0
- package/src/svgParsing.ts +240 -0
- package/src/utils.ts +73 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
let nextMermaidId = 0
|
|
2
|
+
|
|
3
|
+
import mermaid from 'mermaid'
|
|
4
|
+
import type { FlowDB } from 'mermaid/dist/diagrams/flowchart/flowDb.d.ts'
|
|
5
|
+
import type { FlowEdge, FlowSubGraph, FlowVertex } from 'mermaid/dist/diagrams/flowchart/types.js'
|
|
6
|
+
import type { SequenceDB } from 'mermaid/dist/diagrams/sequence/sequenceDb.d.ts'
|
|
7
|
+
import type { StateDB } from 'mermaid/dist/diagrams/state/stateDb.d.ts'
|
|
8
|
+
import { Editor } from 'tldraw'
|
|
9
|
+
import { flowchartToBlueprint, parseFlowchartLayout } from './flowchartDiagram'
|
|
10
|
+
import { BlueprintRenderingOptions, renderBlueprint } from './renderBlueprint'
|
|
11
|
+
import { countSequenceEvents, parseSequenceLayout, sequenceToBlueprint } from './sequenceDiagram'
|
|
12
|
+
import { parseStateDiagramLayout, stateToBlueprint } from './stateDiagram'
|
|
13
|
+
|
|
14
|
+
/** @public */
|
|
15
|
+
export class MermaidDiagramError extends Error {
|
|
16
|
+
constructor(
|
|
17
|
+
public diagramType: string,
|
|
18
|
+
public type: 'parse' | 'unsupported'
|
|
19
|
+
) {
|
|
20
|
+
super(`mermaid diagram error: ${diagramType}`)
|
|
21
|
+
this.name = 'MermaidDiagramError'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Inflate the font size so Mermaid's layout engine allocates larger nodes,
|
|
26
|
+
// compensating for tldraw's hand-drawn font being wider than Mermaid's default.
|
|
27
|
+
const FONT_INFLATE = 1.4
|
|
28
|
+
|
|
29
|
+
const MERMAID_CONFIG = {
|
|
30
|
+
startOnLoad: false,
|
|
31
|
+
flowchart: { nodeSpacing: 80, rankSpacing: 80, padding: 20 },
|
|
32
|
+
state: { nodeSpacing: 80, rankSpacing: 80, padding: 20 },
|
|
33
|
+
sequence: { actorMargin: 50, noteMargin: 20 },
|
|
34
|
+
themeVariables: { fontSize: `${18 * FONT_INFLATE}px` },
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @public */
|
|
38
|
+
export interface MermaidDiagramOptions {
|
|
39
|
+
mermaidConfig?: Record<string, any>
|
|
40
|
+
blueprintRender?: BlueprintRenderingOptions
|
|
41
|
+
onUnsupportedDiagram?(svg: string): Promise<void>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Parse mermaid text and create tldraw shapes for supported diagram types.
|
|
46
|
+
* Returns the SVG string for supported diagrams, or `null` when the diagram type
|
|
47
|
+
* is unsupported (after calling `onUnsupportedDiagram` if provided).
|
|
48
|
+
* Throws {@link MermaidDiagramError} if parsing fails.
|
|
49
|
+
* @public
|
|
50
|
+
*/
|
|
51
|
+
export async function createMermaidDiagram(
|
|
52
|
+
editor: Editor,
|
|
53
|
+
text: string,
|
|
54
|
+
options: MermaidDiagramOptions = {}
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
mermaid.initialize({
|
|
57
|
+
...MERMAID_CONFIG,
|
|
58
|
+
...(options.mermaidConfig ?? {}),
|
|
59
|
+
flowchart: { ...MERMAID_CONFIG.flowchart, ...options.mermaidConfig?.flowchart },
|
|
60
|
+
state: { ...MERMAID_CONFIG.state, ...options.mermaidConfig?.state },
|
|
61
|
+
sequence: { ...MERMAID_CONFIG.sequence, ...options.mermaidConfig?.sequence },
|
|
62
|
+
themeVariables: { ...MERMAID_CONFIG.themeVariables, ...options.mermaidConfig?.themeVariables },
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const parsedResult = await mermaid.parse(text, { suppressErrors: true })
|
|
66
|
+
|
|
67
|
+
if (!parsedResult) {
|
|
68
|
+
throw new MermaidDiagramError('not a mermaid diagram', 'parse')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const offscreen = document.createElement('div')
|
|
72
|
+
offscreen.style.position = 'absolute'
|
|
73
|
+
offscreen.style.left = '-9999px'
|
|
74
|
+
offscreen.style.top = '-9999px'
|
|
75
|
+
offscreen.style.overflow = 'hidden'
|
|
76
|
+
document.body.appendChild(offscreen)
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const parsedSvg = (await mermaid.render(`mermaid-${nextMermaidId++}`, text, offscreen)).svg
|
|
80
|
+
|
|
81
|
+
// Reuse the live SVG that mermaid.render() already mounted into the
|
|
82
|
+
// offscreen container. This avoids a second DOM mount and ensures
|
|
83
|
+
// getBBox() works for every diagram type (state diagrams in particular
|
|
84
|
+
// lack explicit dimension attributes and rely on live layout).
|
|
85
|
+
let liveSvg = offscreen.querySelector('svg')
|
|
86
|
+
|
|
87
|
+
if (!liveSvg) {
|
|
88
|
+
offscreen.innerHTML = parsedSvg
|
|
89
|
+
liveSvg = offscreen.querySelector('svg')
|
|
90
|
+
if (!liveSvg) {
|
|
91
|
+
throw new MermaidDiagramError(parsedResult.diagramType, 'parse')
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
96
|
+
const diagramResult = await mermaid.mermaidAPI.getDiagramFromText(text)
|
|
97
|
+
|
|
98
|
+
let blueprint
|
|
99
|
+
switch (parsedResult.diagramType) {
|
|
100
|
+
case 'flowchart-v2': {
|
|
101
|
+
const db = diagramResult.db as FlowDB
|
|
102
|
+
const vertices = db.getVertices() as Map<string, FlowVertex>
|
|
103
|
+
const edges = db.getEdges() as FlowEdge[]
|
|
104
|
+
const subGraphs = db.getSubGraphs() as FlowSubGraph[]
|
|
105
|
+
const classes = db.getClasses()
|
|
106
|
+
const layout = parseFlowchartLayout(liveSvg)
|
|
107
|
+
blueprint = flowchartToBlueprint(layout, vertices, edges, subGraphs, classes)
|
|
108
|
+
break
|
|
109
|
+
}
|
|
110
|
+
case 'sequence': {
|
|
111
|
+
const db = diagramResult.db as SequenceDB
|
|
112
|
+
const actors = db.getActors()
|
|
113
|
+
const actorKeys = db.getActorKeys()
|
|
114
|
+
const messages = db.getMessages()
|
|
115
|
+
const layout = parseSequenceLayout(liveSvg, actorKeys.length, countSequenceEvents(messages))
|
|
116
|
+
blueprint = sequenceToBlueprint(
|
|
117
|
+
layout,
|
|
118
|
+
actors,
|
|
119
|
+
actorKeys,
|
|
120
|
+
messages,
|
|
121
|
+
db.getCreatedActors(),
|
|
122
|
+
db.getDestroyedActors()
|
|
123
|
+
)
|
|
124
|
+
break
|
|
125
|
+
}
|
|
126
|
+
case 'state':
|
|
127
|
+
case 'stateDiagram': {
|
|
128
|
+
const db = diagramResult.db as StateDB
|
|
129
|
+
const states = db.getStates()
|
|
130
|
+
const relations = db.getRelations()
|
|
131
|
+
const classes = db.getClasses()
|
|
132
|
+
const layout = parseStateDiagramLayout(liveSvg)
|
|
133
|
+
blueprint = stateToBlueprint(layout, states, relations, classes)
|
|
134
|
+
break
|
|
135
|
+
}
|
|
136
|
+
default:
|
|
137
|
+
if (options.onUnsupportedDiagram) {
|
|
138
|
+
await options.onUnsupportedDiagram(parsedSvg)
|
|
139
|
+
} else {
|
|
140
|
+
throw new MermaidDiagramError(parsedResult.diagramType, 'unsupported')
|
|
141
|
+
}
|
|
142
|
+
break
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (blueprint) {
|
|
146
|
+
renderBlueprint(editor, blueprint, options.blueprintRender)
|
|
147
|
+
}
|
|
148
|
+
} catch (e) {
|
|
149
|
+
if (e instanceof MermaidDiagramError) throw e
|
|
150
|
+
console.error(e)
|
|
151
|
+
throw new MermaidDiagramError(parsedResult.diagramType, 'parse')
|
|
152
|
+
} finally {
|
|
153
|
+
offscreen.remove()
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FlowClass,
|
|
3
|
+
FlowEdge,
|
|
4
|
+
FlowSubGraph,
|
|
5
|
+
FlowVertex,
|
|
6
|
+
} from 'mermaid/dist/diagrams/flowchart/types.js'
|
|
7
|
+
import { TLArrowShapeArrowheadStyle, TLDefaultDashStyle, TLGeoShape } from 'tldraw'
|
|
8
|
+
import type {
|
|
9
|
+
DiagramMermaidBlueprint,
|
|
10
|
+
MermaidBlueprintEdge,
|
|
11
|
+
MermaidBlueprintGeoNode,
|
|
12
|
+
} from './blueprint'
|
|
13
|
+
import { buildClassDefColorMap, parseCssStyles, parseNodeInlineColor } from './colors'
|
|
14
|
+
import {
|
|
15
|
+
buildNodeCentersFromSvg,
|
|
16
|
+
parseAllEdgePointsFromSvg,
|
|
17
|
+
parseClustersFromSvg,
|
|
18
|
+
type ParsedDiagramLayout,
|
|
19
|
+
parseNodesFromSvg,
|
|
20
|
+
scaleLayout,
|
|
21
|
+
} from './svgParsing'
|
|
22
|
+
import { getArrowBend, LAYOUT_SCALE, orderTopDown } from './utils'
|
|
23
|
+
|
|
24
|
+
function mapEdgeTypeToArrowhead(type: string | undefined): TLArrowShapeArrowheadStyle {
|
|
25
|
+
if (!type) return 'arrow'
|
|
26
|
+
|
|
27
|
+
if (type.includes('point')) return 'arrow'
|
|
28
|
+
if (type.includes('circle')) return 'dot'
|
|
29
|
+
if (type.includes('cross')) return 'bar'
|
|
30
|
+
if (type.includes('open')) return 'none'
|
|
31
|
+
|
|
32
|
+
return 'arrow'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mapFlowShapeTypeToGeo(type: string | undefined): TLGeoShape['props']['geo'] {
|
|
36
|
+
switch (type) {
|
|
37
|
+
case 'diamond':
|
|
38
|
+
return 'diamond'
|
|
39
|
+
case 'ellipse':
|
|
40
|
+
case 'circle':
|
|
41
|
+
case 'doublecircle':
|
|
42
|
+
case 'stadium':
|
|
43
|
+
case 'cylinder':
|
|
44
|
+
return 'ellipse'
|
|
45
|
+
case 'hexagon':
|
|
46
|
+
return 'hexagon'
|
|
47
|
+
case 'trapezoid':
|
|
48
|
+
// TODO: implement inv_trapezoid in SDK
|
|
49
|
+
case 'inv_trapezoid':
|
|
50
|
+
return 'trapezoid'
|
|
51
|
+
case 'lean_right':
|
|
52
|
+
return 'rhombus'
|
|
53
|
+
case 'lean_left':
|
|
54
|
+
return 'rhombus-2'
|
|
55
|
+
case 'square':
|
|
56
|
+
case 'rect':
|
|
57
|
+
case 'round':
|
|
58
|
+
case 'subroutine':
|
|
59
|
+
default:
|
|
60
|
+
return 'rectangle'
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function mapEdgeStrokeToDash(stroke: string | undefined): TLDefaultDashStyle {
|
|
65
|
+
if (!stroke) return 'solid'
|
|
66
|
+
if (stroke === 'dotted') return 'dotted'
|
|
67
|
+
return 'solid'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const FRAME_TOP_PAD = 14
|
|
71
|
+
|
|
72
|
+
function buildHierarchy(subGraphs: FlowSubGraph[]) {
|
|
73
|
+
const subGraphIds = new Set(subGraphs.map((subGraph) => subGraph.id))
|
|
74
|
+
const nodeToSubGraph = new Map<string, string>()
|
|
75
|
+
const subGraphParent = new Map<string, string>()
|
|
76
|
+
for (const subGraph of subGraphs) {
|
|
77
|
+
for (const nodeId of subGraph.nodes) {
|
|
78
|
+
if (subGraphIds.has(nodeId)) {
|
|
79
|
+
subGraphParent.set(nodeId, subGraph.id)
|
|
80
|
+
} else if (!nodeToSubGraph.has(nodeId)) {
|
|
81
|
+
nodeToSubGraph.set(nodeId, subGraph.id)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { nodeToSubGraph, subGraphParent }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Parse flowchart-specific SVG layout data for use by {@link flowchartToBlueprint}. */
|
|
89
|
+
export function parseFlowchartLayout(root: Element): ParsedDiagramLayout {
|
|
90
|
+
const nodes = parseNodesFromSvg(root, '.node', (domId) => {
|
|
91
|
+
const match = domId.match(/^flowchart-(.+)-\d+$/)
|
|
92
|
+
return match ? match[1] : domId
|
|
93
|
+
})
|
|
94
|
+
const clusters = parseClustersFromSvg(root, '.cluster')
|
|
95
|
+
const edges = parseAllEdgePointsFromSvg(root, (dataId) => {
|
|
96
|
+
const match = dataId.match(/^L_(.+)_([^_]+)_\d+$/)
|
|
97
|
+
return match ? { start: match[1], end: match[2] } : null
|
|
98
|
+
})
|
|
99
|
+
scaleLayout(nodes, clusters, edges, LAYOUT_SCALE)
|
|
100
|
+
return { nodes, clusters, edges }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Convert a parsed Mermaid flowchart into a tldraw blueprint of nodes and edges. */
|
|
104
|
+
export function flowchartToBlueprint(
|
|
105
|
+
layout: ParsedDiagramLayout,
|
|
106
|
+
vertices: Map<string, FlowVertex>,
|
|
107
|
+
edges: FlowEdge[],
|
|
108
|
+
subGraphs?: FlowSubGraph[],
|
|
109
|
+
classDefs?: Map<string, FlowClass>
|
|
110
|
+
): DiagramMermaidBlueprint {
|
|
111
|
+
const nodeColorMap = classDefs ? buildClassDefColorMap(classDefs, vertices) : new Map()
|
|
112
|
+
const { nodes: svgNodes, clusters: svgClusters, edges: svgEdges } = layout
|
|
113
|
+
const nodeCenters = buildNodeCentersFromSvg(svgNodes, svgClusters)
|
|
114
|
+
|
|
115
|
+
const allSubGraphs = subGraphs || []
|
|
116
|
+
const { nodeToSubGraph, subGraphParent } = buildHierarchy(allSubGraphs)
|
|
117
|
+
|
|
118
|
+
const nodes: MermaidBlueprintGeoNode[] = []
|
|
119
|
+
const blueprintEdges: MermaidBlueprintEdge[] = []
|
|
120
|
+
|
|
121
|
+
// Frames for subgraphs
|
|
122
|
+
for (const subGraph of orderTopDown(
|
|
123
|
+
allSubGraphs,
|
|
124
|
+
(subGraph) => subGraph.id,
|
|
125
|
+
(subGraph) => subGraphParent.get(subGraph.id)
|
|
126
|
+
)) {
|
|
127
|
+
const cluster = svgClusters.get(subGraph.id)
|
|
128
|
+
if (!cluster) continue
|
|
129
|
+
|
|
130
|
+
nodes.push({
|
|
131
|
+
id: subGraph.id,
|
|
132
|
+
x: cluster.topLeft.x,
|
|
133
|
+
y: cluster.topLeft.y - FRAME_TOP_PAD,
|
|
134
|
+
w: cluster.width,
|
|
135
|
+
h: cluster.height + FRAME_TOP_PAD,
|
|
136
|
+
geo: 'rectangle',
|
|
137
|
+
parentId: subGraphParent.get(subGraph.id),
|
|
138
|
+
label: subGraph.title || subGraph.id,
|
|
139
|
+
fill: 'semi',
|
|
140
|
+
color: 'black',
|
|
141
|
+
dash: 'draw',
|
|
142
|
+
size: 's',
|
|
143
|
+
align: 'middle',
|
|
144
|
+
verticalAlign: 'start',
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Node shapes
|
|
149
|
+
for (const [id, vertex] of vertices) {
|
|
150
|
+
const svgNode = svgNodes.get(id)
|
|
151
|
+
if (!svgNode) continue
|
|
152
|
+
|
|
153
|
+
const geo = mapFlowShapeTypeToGeo(vertex.type)
|
|
154
|
+
const colors = nodeColorMap.get(id) ?? parseNodeInlineColor(vertex.styles)
|
|
155
|
+
|
|
156
|
+
let { width: w, height: h } = svgNode
|
|
157
|
+
if (vertex.type === 'circle' || vertex.type === 'doublecircle') {
|
|
158
|
+
w = h = Math.max(w, h)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
nodes.push({
|
|
162
|
+
id,
|
|
163
|
+
x: svgNode.center.x - w / 2,
|
|
164
|
+
y: svgNode.center.y - h / 2,
|
|
165
|
+
w,
|
|
166
|
+
h,
|
|
167
|
+
geo,
|
|
168
|
+
parentId: nodeToSubGraph.get(id),
|
|
169
|
+
label: vertex.text || undefined,
|
|
170
|
+
...(colors?.fillColor && { fill: 'solid' as const }),
|
|
171
|
+
...(colors && { color: colors.strokeColor ?? colors.fillColor }),
|
|
172
|
+
align: 'middle',
|
|
173
|
+
verticalAlign: 'middle',
|
|
174
|
+
size: 'm',
|
|
175
|
+
} satisfies MermaidBlueprintGeoNode)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Edges: match DB edges to SVG edges by proximity, compute bends
|
|
179
|
+
const claimed = new Set<number>()
|
|
180
|
+
for (const edge of edges) {
|
|
181
|
+
const startCenter = nodeCenters.get(edge.start)
|
|
182
|
+
const endCenter = nodeCenters.get(edge.end)
|
|
183
|
+
|
|
184
|
+
let bend = 0
|
|
185
|
+
if (startCenter && endCenter) {
|
|
186
|
+
let bestIndex = -1
|
|
187
|
+
let bestDist = Infinity
|
|
188
|
+
for (let i = 0; i < svgEdges.length; i++) {
|
|
189
|
+
if (claimed.has(i) || svgEdges[i].points.length < 2) continue
|
|
190
|
+
|
|
191
|
+
const points = svgEdges[i].points
|
|
192
|
+
const distance =
|
|
193
|
+
Math.hypot(points[0].x - startCenter.x, points[0].y - startCenter.y) +
|
|
194
|
+
Math.hypot(
|
|
195
|
+
points[points.length - 1].x - endCenter.x,
|
|
196
|
+
points[points.length - 1].y - endCenter.y
|
|
197
|
+
)
|
|
198
|
+
if (distance < bestDist) {
|
|
199
|
+
bestDist = distance
|
|
200
|
+
bestIndex = i
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (bestIndex >= 0) {
|
|
204
|
+
claimed.add(bestIndex)
|
|
205
|
+
bend = getArrowBend(svgEdges[bestIndex])
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const cssOverrides = edge.style ? parseCssStyles(edge.style) : undefined
|
|
210
|
+
const arrowheadEnd = mapEdgeTypeToArrowhead(edge.type)
|
|
211
|
+
const dash = cssOverrides?.dashOverride ?? mapEdgeStrokeToDash(edge.stroke)
|
|
212
|
+
const size = cssOverrides?.sizeOverride ?? (edge.stroke === 'thick' ? 'l' : 's')
|
|
213
|
+
|
|
214
|
+
blueprintEdges.push({
|
|
215
|
+
startNodeId: edge.start,
|
|
216
|
+
endNodeId: edge.end,
|
|
217
|
+
label: edge.text,
|
|
218
|
+
bend,
|
|
219
|
+
arrowheadEnd,
|
|
220
|
+
arrowheadStart: edge.type?.includes('double_arrow') ? arrowheadEnd : undefined,
|
|
221
|
+
dash,
|
|
222
|
+
size,
|
|
223
|
+
color: cssOverrides?.color,
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const nodeIds = new Set(nodes.map((n) => n.id))
|
|
228
|
+
const validEdges = blueprintEdges.filter(
|
|
229
|
+
(e) => nodeIds.has(e.startNodeId) && nodeIds.has(e.endNodeId)
|
|
230
|
+
)
|
|
231
|
+
return { nodes, edges: validEdges }
|
|
232
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerTldrawLibraryVersion } from '@tldraw/utils'
|
|
2
|
+
|
|
3
|
+
export type {
|
|
4
|
+
DiagramMermaidBlueprint,
|
|
5
|
+
MermaidBlueprintEdge,
|
|
6
|
+
MermaidBlueprintGeoNode,
|
|
7
|
+
MermaidBlueprintLineNode,
|
|
8
|
+
} from './blueprint'
|
|
9
|
+
export { createMermaidDiagram, MermaidDiagramError } from './createMermaidDiagram'
|
|
10
|
+
export type { MermaidDiagramOptions } from './createMermaidDiagram'
|
|
11
|
+
export { renderBlueprint } from './renderBlueprint'
|
|
12
|
+
export type { BlueprintRenderingOptions } from './renderBlueprint'
|
|
13
|
+
|
|
14
|
+
registerTldrawLibraryVersion(
|
|
15
|
+
(globalThis as any).TLDRAW_LIBRARY_NAME,
|
|
16
|
+
(globalThis as any).TLDRAW_LIBRARY_VERSION,
|
|
17
|
+
(globalThis as any).TLDRAW_LIBRARY_MODULES
|
|
18
|
+
)
|