@tldraw/mermaid 5.5.0-next.b6a9f7cd7be2 → 5.5.0-next.c91b2de0a423

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.
Files changed (46) hide show
  1. package/dist-cjs/colors.js +2 -2
  2. package/dist-cjs/colors.js.map +2 -2
  3. package/dist-cjs/createMermaidDiagram.js +3 -1
  4. package/dist-cjs/createMermaidDiagram.js.map +2 -2
  5. package/dist-cjs/flowchartDiagram.js +35 -11
  6. package/dist-cjs/flowchartDiagram.js.map +3 -3
  7. package/dist-cjs/index.js +1 -1
  8. package/dist-cjs/mermaidNodeCreateShape.js +23 -0
  9. package/dist-cjs/mermaidNodeCreateShape.js.map +2 -2
  10. package/dist-cjs/renderBlueprint.js +3 -1
  11. package/dist-cjs/renderBlueprint.js.map +2 -2
  12. package/dist-cjs/sequenceDiagram.js +33 -16
  13. package/dist-cjs/sequenceDiagram.js.map +2 -2
  14. package/dist-cjs/stateDiagram.js +6 -6
  15. package/dist-cjs/stateDiagram.js.map +2 -2
  16. package/dist-cjs/svgParsing.js +16 -5
  17. package/dist-cjs/svgParsing.js.map +2 -2
  18. package/dist-esm/colors.mjs +2 -2
  19. package/dist-esm/colors.mjs.map +2 -2
  20. package/dist-esm/createMermaidDiagram.mjs +3 -1
  21. package/dist-esm/createMermaidDiagram.mjs.map +2 -2
  22. package/dist-esm/flowchartDiagram.mjs +36 -12
  23. package/dist-esm/flowchartDiagram.mjs.map +3 -3
  24. package/dist-esm/index.mjs +1 -1
  25. package/dist-esm/mermaidNodeCreateShape.mjs +28 -1
  26. package/dist-esm/mermaidNodeCreateShape.mjs.map +2 -2
  27. package/dist-esm/renderBlueprint.mjs +3 -1
  28. package/dist-esm/renderBlueprint.mjs.map +2 -2
  29. package/dist-esm/sequenceDiagram.mjs +33 -16
  30. package/dist-esm/sequenceDiagram.mjs.map +2 -2
  31. package/dist-esm/stateDiagram.mjs +7 -7
  32. package/dist-esm/stateDiagram.mjs.map +2 -2
  33. package/dist-esm/svgParsing.mjs +16 -5
  34. package/dist-esm/svgParsing.mjs.map +2 -2
  35. package/package.json +5 -4
  36. package/src/colors.ts +4 -2
  37. package/src/createMermaidDiagram.ts +3 -1
  38. package/src/flowchartDiagram.ts +54 -13
  39. package/src/mermaidDiagrams.test.ts +142 -11
  40. package/src/mermaidNodeCreateShape.ts +38 -2
  41. package/src/renderBlueprint.test.ts +24 -0
  42. package/src/renderBlueprint.ts +3 -1
  43. package/src/sequenceDiagram.ts +49 -24
  44. package/src/stateDiagram.ts +7 -7
  45. package/src/svgParsing.test.ts +107 -0
  46. package/src/svgParsing.ts +30 -10
@@ -81,8 +81,8 @@ function parseCssStyles(styles) {
81
81
  if (strokeWidth) {
82
82
  const pixels = parseFloat(strokeWidth);
83
83
  if (Number.isFinite(pixels)) {
84
- if (pixels <= 1) result.sizeOverride = "s";
85
- else if (pixels <= 2) result.sizeOverride = "m";
84
+ if (pixels < 1) result.sizeOverride = "s";
85
+ else if (pixels < 2) result.sizeOverride = "m";
86
86
  else result.sizeOverride = "l";
87
87
  }
88
88
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/colors.ts"],
4
- "sourcesContent": ["import { hasOwnProperty } from '@tldraw/utils'\nimport { DEFAULT_THEME, TLDefaultColorStyle, TLDefaultDashStyle, TLDefaultSizeStyle } from 'tldraw'\nimport type { MermaidBlueprintNode } from './blueprint'\n\ntype Color = [number, number, number, number]\n\nexport interface ParsedNodeColors {\n\tfillColor?: TLDefaultColorStyle\n\tstrokeColor?: TLDefaultColorStyle\n}\n\n/**\n * Build a map of node id \u2192 parsed fill/stroke colors from Mermaid's classDef definitions.\n *\n * Uses the structured data from `db.getClasses()` and each node's `classes`\n * array. For each node, looks up its applied classDef styles and maps fill and\n * stroke independently to the nearest tldraw palette color.\n */\nexport function buildClassDefColorMap(\n\tclassDefs: Map<string, { styles: string[] }>,\n\titems: Iterable<[string, { classes?: string[] }]>\n): Map<string, ParsedNodeColors> {\n\tconst result = new Map<string, ParsedNodeColors>()\n\tif (classDefs.size === 0) return result\n\n\tfor (const [nodeId, item] of items) {\n\t\tfor (const className of item.classes ?? []) {\n\t\t\tconst colors = parseNodeInlineColor(classDefs.get(className)?.styles)\n\t\t\tif (colors) {\n\t\t\t\tresult.set(nodeId, colors)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n/** Blueprint node style props for parsed fill/stroke colors: solid fill when a fill was set, stroke color preferred. */\nexport function toNodeColorProps(\n\tcolors: ParsedNodeColors | undefined\n): Pick<MermaidBlueprintNode, 'fill' | 'color'> {\n\tif (!colors) return {}\n\treturn {\n\t\t...(colors.fillColor && { fill: 'solid' as const }),\n\t\tcolor: colors.strokeColor ?? colors.fillColor,\n\t}\n}\n\nexport function parseRgbToTldrawColor(\n\ttext: string\n): { color: TLDefaultColorStyle; hasAlpha: boolean } | null {\n\tconst color = toColor(text)\n\tif (!color) return null\n\treturn { color: nearestTldrawColor(color), hasAlpha: color[3] < 255 }\n}\n\ninterface ParsedCssOverrides {\n\tcolor?: TLDefaultColorStyle\n\tdashOverride?: TLDefaultDashStyle\n\tsizeOverride?: TLDefaultSizeStyle\n}\n\nfunction parseCssProps(styles: string[]): Map<string, string> {\n\tconst props = new Map<string, string>()\n\tfor (const entry of styles) {\n\t\tfor (const part of entry.split(';')) {\n\t\t\tconst colon = part.indexOf(':')\n\t\t\tif (colon < 0) continue\n\t\t\tconst key = part.slice(0, colon).trim().toLowerCase()\n\t\t\tconst value = part.slice(colon + 1).trim()\n\t\t\tif (key && value) props.set(key, value)\n\t\t}\n\t}\n\treturn props\n}\n\n/**\n * Parse a Mermaid CSS style array from an edge (FlowEdge.style / linkStyle)\n * and return tldraw-compatible overrides.\n */\nexport function parseCssStyles(styles: string[] | undefined): ParsedCssOverrides {\n\tif (!styles || styles.length === 0) return {}\n\n\tconst props = parseCssProps(styles)\n\tconst result: ParsedCssOverrides = {}\n\n\tconst stroke = toColor(props.get('stroke'))\n\tif (stroke) {\n\t\tresult.color = nearestTldrawColor(stroke)\n\t}\n\n\tif (props.has('stroke-dasharray')) {\n\t\tresult.dashOverride = 'dashed'\n\t}\n\n\tconst strokeWidth = props.get('stroke-width')\n\tif (strokeWidth) {\n\t\tconst pixels = parseFloat(strokeWidth)\n\t\tif (Number.isFinite(pixels)) {\n\t\t\tif (pixels <= 1) result.sizeOverride = 's'\n\t\t\telse if (pixels <= 2) result.sizeOverride = 'm'\n\t\t\telse result.sizeOverride = 'l'\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * Parse inline `style nodeId fill:\u2026,stroke:\u2026` directives from a FlowVertex.styles\n * array and return fill and stroke as independent tldraw colors.\n */\nexport function parseNodeInlineColor(styles: string[] | undefined): ParsedNodeColors | undefined {\n\tif (!styles || styles.length === 0) return undefined\n\n\tconst props = parseCssProps(styles)\n\tconst fill = toColor(props.get('fill'))\n\tconst stroke = toColor(props.get('stroke'))\n\n\tif (!fill && !stroke) return undefined\n\n\tconst colors: ParsedNodeColors = {}\n\tif (fill) colors.fillColor = nearestTldrawColor(fill)\n\tif (stroke) colors.strokeColor = nearestTldrawColor(stroke)\n\treturn colors\n}\n\nfunction parseHexToRgb(hex: string): [number, number, number] | null {\n\tconst stripped = hex.replace(/^#/, '')\n\tif (stripped.length === 3 || stripped.length === 4) {\n\t\treturn [\n\t\t\tparseInt(stripped[0] + stripped[0], 16),\n\t\t\tparseInt(stripped[1] + stripped[1], 16),\n\t\t\tparseInt(stripped[2] + stripped[2], 16),\n\t\t]\n\t}\n\tif (stripped.length === 6 || stripped.length === 8) {\n\t\treturn [\n\t\t\tparseInt(stripped.slice(0, 2), 16),\n\t\t\tparseInt(stripped.slice(2, 4), 16),\n\t\t\tparseInt(stripped.slice(4, 6), 16),\n\t\t]\n\t}\n\treturn null\n}\n\nconst defaultColorNames: TLDefaultColorStyle[] = [\n\t'black',\n\t'grey',\n\t'light-violet',\n\t'violet',\n\t'blue',\n\t'light-blue',\n\t'yellow',\n\t'orange',\n\t'green',\n\t'light-green',\n\t'light-red',\n\t'red',\n\t'white',\n]\n\nconst TLDRAW_PALETTE: [TLDefaultColorStyle, number, number, number][] = defaultColorNames.map(\n\t(name) => {\n\t\tconst { solid } = DEFAULT_THEME.colors.light[name]!\n\t\tconst rgb = parseHexToRgb(solid)!\n\t\treturn [name, rgb[0], rgb[1], rgb[2]]\n\t}\n)\n\n/** Map an arbitrary Color tuple to the nearest tldraw named color (best-effort). */\nfunction nearestTldrawColor(rgb: Color): TLDefaultColorStyle {\n\tlet [r, g, b] = rgb\n\n\tconst max = Math.max(r, g, b)\n\tconst min = Math.min(r, g, b)\n\tconst lightness = (max + min) / 2 / 255\n\tconst chroma = max - min\n\n\t// For very light pastels, strip the white base and amplify the\n\t// chromatic signal so the distance metric can see the hue.\n\tif (lightness > 0.75 && chroma > 5) {\n\t\tconst target = 200\n\t\tr = Math.round(((r - min) / chroma) * target)\n\t\tg = Math.round(((g - min) / chroma) * target)\n\t\tb = Math.round(((b - min) / chroma) * target)\n\t}\n\n\tlet best: TLDefaultColorStyle = 'black'\n\tlet bestDistance = Infinity\n\tfor (const [name, red, green, blue] of TLDRAW_PALETTE) {\n\t\t// \"Redmean\" weighted Euclidean distance (Compuphase approximation).\n\t\t// Weights RGB channels by the average red value of the two colors to\n\t\t// approximate human perception, which is more sensitive to green and\n\t\t// varies in red/blue sensitivity depending on the color's warmth.\n\t\tconst rMean = (r + red) / 2\n\t\tconst dR = r - red\n\t\tconst dG = g - green\n\t\tconst dB = b - blue\n\t\tconst distance = (2 + rMean / 256) * dR * dR + 4 * dG * dG + (2 + (255 - rMean) / 256) * dB * dB\n\t\tif (distance < bestDistance) {\n\t\t\tbestDistance = distance\n\t\t\tbest = name\n\t\t}\n\t}\n\treturn best\n}\n\nfunction toColor(value: string | undefined): Color | undefined {\n\tif (!value) return undefined\n\n\tconst trimmed = value.trim()\n\tif (!trimmed || trimmed === 'none' || trimmed === 'transparent') return undefined\n\n\tif (trimmed.startsWith('rgb')) {\n\t\tconst match = trimmed.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([\\d.]+)\\s*)?\\)/)\n\t\tif (!match) return undefined\n\t\treturn [\n\t\t\tparseInt(match[1], 10),\n\t\t\tparseInt(match[2], 10),\n\t\t\tparseInt(match[3], 10),\n\t\t\tmatch[4] !== undefined ? Math.round(parseFloat(match[4]) * 255) : 255,\n\t\t]\n\t}\n\tif (trimmed.startsWith('#')) {\n\t\tconst rgb = parseHexToRgb(trimmed)\n\t\tif (!rgb) return undefined\n\t\treturn [rgb[0], rgb[1], rgb[2], 255]\n\t}\n\tconst keyword = trimmed.toLowerCase()\n\tif (hasOwnProperty(CSS_NAMED_COLORS, keyword)) {\n\t\tconst rgb = parseHexToRgb(CSS_NAMED_COLORS[keyword])!\n\t\treturn [rgb[0], rgb[1], rgb[2], 255]\n\t}\n\treturn undefined\n}\n\n// Mermaid accepts CSS color keywords wherever it takes a color, and sequence `box` statements\n// can't take a hex color at all, so without these a box's color is usually lost.\nconst CSS_NAMED_COLORS: Record<string, string> = {\n\taliceblue: 'f0f8ff',\n\tantiquewhite: 'faebd7',\n\taqua: '00ffff',\n\taquamarine: '7fffd4',\n\tazure: 'f0ffff',\n\tbeige: 'f5f5dc',\n\tbisque: 'ffe4c4',\n\tblack: '000000',\n\tblanchedalmond: 'ffebcd',\n\tblue: '0000ff',\n\tblueviolet: '8a2be2',\n\tbrown: 'a52a2a',\n\tburlywood: 'deb887',\n\tcadetblue: '5f9ea0',\n\tchartreuse: '7fff00',\n\tchocolate: 'd2691e',\n\tcoral: 'ff7f50',\n\tcornflowerblue: '6495ed',\n\tcornsilk: 'fff8dc',\n\tcrimson: 'dc143c',\n\tcyan: '00ffff',\n\tdarkblue: '00008b',\n\tdarkcyan: '008b8b',\n\tdarkgoldenrod: 'b8860b',\n\tdarkgray: 'a9a9a9',\n\tdarkgreen: '006400',\n\tdarkgrey: 'a9a9a9',\n\tdarkkhaki: 'bdb76b',\n\tdarkmagenta: '8b008b',\n\tdarkolivegreen: '556b2f',\n\tdarkorange: 'ff8c00',\n\tdarkorchid: '9932cc',\n\tdarkred: '8b0000',\n\tdarksalmon: 'e9967a',\n\tdarkseagreen: '8fbc8f',\n\tdarkslateblue: '483d8b',\n\tdarkslategray: '2f4f4f',\n\tdarkslategrey: '2f4f4f',\n\tdarkturquoise: '00ced1',\n\tdarkviolet: '9400d3',\n\tdeeppink: 'ff1493',\n\tdeepskyblue: '00bfff',\n\tdimgray: '696969',\n\tdimgrey: '696969',\n\tdodgerblue: '1e90ff',\n\tfirebrick: 'b22222',\n\tfloralwhite: 'fffaf0',\n\tforestgreen: '228b22',\n\tfuchsia: 'ff00ff',\n\tgainsboro: 'dcdcdc',\n\tghostwhite: 'f8f8ff',\n\tgold: 'ffd700',\n\tgoldenrod: 'daa520',\n\tgray: '808080',\n\tgreen: '008000',\n\tgreenyellow: 'adff2f',\n\tgrey: '808080',\n\thoneydew: 'f0fff0',\n\thotpink: 'ff69b4',\n\tindianred: 'cd5c5c',\n\tindigo: '4b0082',\n\tivory: 'fffff0',\n\tkhaki: 'f0e68c',\n\tlavender: 'e6e6fa',\n\tlavenderblush: 'fff0f5',\n\tlawngreen: '7cfc00',\n\tlemonchiffon: 'fffacd',\n\tlightblue: 'add8e6',\n\tlightcoral: 'f08080',\n\tlightcyan: 'e0ffff',\n\tlightgoldenrodyellow: 'fafad2',\n\tlightgray: 'd3d3d3',\n\tlightgreen: '90ee90',\n\tlightgrey: 'd3d3d3',\n\tlightpink: 'ffb6c1',\n\tlightsalmon: 'ffa07a',\n\tlightseagreen: '20b2aa',\n\tlightskyblue: '87cefa',\n\tlightslategray: '778899',\n\tlightslategrey: '778899',\n\tlightsteelblue: 'b0c4de',\n\tlightyellow: 'ffffe0',\n\tlime: '00ff00',\n\tlimegreen: '32cd32',\n\tlinen: 'faf0e6',\n\tmagenta: 'ff00ff',\n\tmaroon: '800000',\n\tmediumaquamarine: '66cdaa',\n\tmediumblue: '0000cd',\n\tmediumorchid: 'ba55d3',\n\tmediumpurple: '9370db',\n\tmediumseagreen: '3cb371',\n\tmediumslateblue: '7b68ee',\n\tmediumspringgreen: '00fa9a',\n\tmediumturquoise: '48d1cc',\n\tmediumvioletred: 'c71585',\n\tmidnightblue: '191970',\n\tmintcream: 'f5fffa',\n\tmistyrose: 'ffe4e1',\n\tmoccasin: 'ffe4b5',\n\tnavajowhite: 'ffdead',\n\tnavy: '000080',\n\toldlace: 'fdf5e6',\n\tolive: '808000',\n\tolivedrab: '6b8e23',\n\torange: 'ffa500',\n\torangered: 'ff4500',\n\torchid: 'da70d6',\n\tpalegoldenrod: 'eee8aa',\n\tpalegreen: '98fb98',\n\tpaleturquoise: 'afeeee',\n\tpalevioletred: 'db7093',\n\tpapayawhip: 'ffefd5',\n\tpeachpuff: 'ffdab9',\n\tperu: 'cd853f',\n\tpink: 'ffc0cb',\n\tplum: 'dda0dd',\n\tpowderblue: 'b0e0e6',\n\tpurple: '800080',\n\trebeccapurple: '663399',\n\tred: 'ff0000',\n\trosybrown: 'bc8f8f',\n\troyalblue: '4169e1',\n\tsaddlebrown: '8b4513',\n\tsalmon: 'fa8072',\n\tsandybrown: 'f4a460',\n\tseagreen: '2e8b57',\n\tseashell: 'fff5ee',\n\tsienna: 'a0522d',\n\tsilver: 'c0c0c0',\n\tskyblue: '87ceeb',\n\tslateblue: '6a5acd',\n\tslategray: '708090',\n\tslategrey: '708090',\n\tsnow: 'fffafa',\n\tspringgreen: '00ff7f',\n\tsteelblue: '4682b4',\n\ttan: 'd2b48c',\n\tteal: '008080',\n\tthistle: 'd8bfd8',\n\ttomato: 'ff6347',\n\tturquoise: '40e0d0',\n\tviolet: 'ee82ee',\n\twheat: 'f5deb3',\n\twhite: 'ffffff',\n\twhitesmoke: 'f5f5f5',\n\tyellow: 'ffff00',\n\tyellowgreen: '9acd32',\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { hasOwnProperty } from '@tldraw/utils'\nimport { DEFAULT_THEME, TLDefaultColorStyle, TLDefaultDashStyle, TLDefaultSizeStyle } from 'tldraw'\nimport type { MermaidBlueprintNode } from './blueprint'\n\ntype Color = [number, number, number, number]\n\nexport interface ParsedNodeColors {\n\tfillColor?: TLDefaultColorStyle\n\tstrokeColor?: TLDefaultColorStyle\n}\n\n/**\n * Build a map of node id \u2192 parsed fill/stroke colors from Mermaid's classDef definitions.\n *\n * Uses the structured data from `db.getClasses()` and each node's `classes`\n * array. For each node, looks up its applied classDef styles and maps fill and\n * stroke independently to the nearest tldraw palette color.\n */\nexport function buildClassDefColorMap(\n\tclassDefs: Map<string, { styles: string[] }>,\n\titems: Iterable<[string, { classes?: string[] }]>\n): Map<string, ParsedNodeColors> {\n\tconst result = new Map<string, ParsedNodeColors>()\n\tif (classDefs.size === 0) return result\n\n\tfor (const [nodeId, item] of items) {\n\t\tfor (const className of item.classes ?? []) {\n\t\t\tconst colors = parseNodeInlineColor(classDefs.get(className)?.styles)\n\t\t\tif (colors) {\n\t\t\t\tresult.set(nodeId, colors)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n/** Blueprint node style props for parsed fill/stroke colors: solid fill when a fill was set, stroke color preferred. */\nexport function toNodeColorProps(\n\tcolors: ParsedNodeColors | undefined\n): Pick<MermaidBlueprintNode, 'fill' | 'color'> {\n\tif (!colors) return {}\n\treturn {\n\t\t...(colors.fillColor && { fill: 'solid' as const }),\n\t\tcolor: colors.strokeColor ?? colors.fillColor,\n\t}\n}\n\nexport function parseRgbToTldrawColor(\n\ttext: string\n): { color: TLDefaultColorStyle; hasAlpha: boolean } | null {\n\tconst color = toColor(text)\n\tif (!color) return null\n\treturn { color: nearestTldrawColor(color), hasAlpha: color[3] < 255 }\n}\n\ninterface ParsedCssOverrides {\n\tcolor?: TLDefaultColorStyle\n\tdashOverride?: TLDefaultDashStyle\n\tsizeOverride?: TLDefaultSizeStyle\n}\n\nfunction parseCssProps(styles: string[]): Map<string, string> {\n\tconst props = new Map<string, string>()\n\tfor (const entry of styles) {\n\t\tfor (const part of entry.split(';')) {\n\t\t\tconst colon = part.indexOf(':')\n\t\t\tif (colon < 0) continue\n\t\t\tconst key = part.slice(0, colon).trim().toLowerCase()\n\t\t\tconst value = part.slice(colon + 1).trim()\n\t\t\tif (key && value) props.set(key, value)\n\t\t}\n\t}\n\treturn props\n}\n\n/**\n * Parse a Mermaid CSS style array from an edge (FlowEdge.style / linkStyle)\n * and return tldraw-compatible overrides.\n */\nexport function parseCssStyles(styles: string[] | undefined): ParsedCssOverrides {\n\tif (!styles || styles.length === 0) return {}\n\n\tconst props = parseCssProps(styles)\n\tconst result: ParsedCssOverrides = {}\n\n\tconst stroke = toColor(props.get('stroke'))\n\tif (stroke) {\n\t\tresult.color = nearestTldrawColor(stroke)\n\t}\n\n\tif (props.has('stroke-dasharray')) {\n\t\tresult.dashOverride = 'dashed'\n\t}\n\n\tconst strokeWidth = props.get('stroke-width')\n\tif (strokeWidth) {\n\t\tconst pixels = parseFloat(strokeWidth)\n\t\tif (Number.isFinite(pixels)) {\n\t\t\t// Mermaid's unstyled edge is 1px, drawn at 'm'. A lower cut-off would draw\n\t\t\t// `stroke-width:1px` thinner than no style at all.\n\t\t\tif (pixels < 1) result.sizeOverride = 's'\n\t\t\telse if (pixels < 2) result.sizeOverride = 'm'\n\t\t\telse result.sizeOverride = 'l'\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * Parse inline `style nodeId fill:\u2026,stroke:\u2026` directives from a FlowVertex.styles\n * array and return fill and stroke as independent tldraw colors.\n */\nexport function parseNodeInlineColor(styles: string[] | undefined): ParsedNodeColors | undefined {\n\tif (!styles || styles.length === 0) return undefined\n\n\tconst props = parseCssProps(styles)\n\tconst fill = toColor(props.get('fill'))\n\tconst stroke = toColor(props.get('stroke'))\n\n\tif (!fill && !stroke) return undefined\n\n\tconst colors: ParsedNodeColors = {}\n\tif (fill) colors.fillColor = nearestTldrawColor(fill)\n\tif (stroke) colors.strokeColor = nearestTldrawColor(stroke)\n\treturn colors\n}\n\nfunction parseHexToRgb(hex: string): [number, number, number] | null {\n\tconst stripped = hex.replace(/^#/, '')\n\tif (stripped.length === 3 || stripped.length === 4) {\n\t\treturn [\n\t\t\tparseInt(stripped[0] + stripped[0], 16),\n\t\t\tparseInt(stripped[1] + stripped[1], 16),\n\t\t\tparseInt(stripped[2] + stripped[2], 16),\n\t\t]\n\t}\n\tif (stripped.length === 6 || stripped.length === 8) {\n\t\treturn [\n\t\t\tparseInt(stripped.slice(0, 2), 16),\n\t\t\tparseInt(stripped.slice(2, 4), 16),\n\t\t\tparseInt(stripped.slice(4, 6), 16),\n\t\t]\n\t}\n\treturn null\n}\n\nconst defaultColorNames: TLDefaultColorStyle[] = [\n\t'black',\n\t'grey',\n\t'light-violet',\n\t'violet',\n\t'blue',\n\t'light-blue',\n\t'yellow',\n\t'orange',\n\t'green',\n\t'light-green',\n\t'light-red',\n\t'red',\n\t'white',\n]\n\nconst TLDRAW_PALETTE: [TLDefaultColorStyle, number, number, number][] = defaultColorNames.map(\n\t(name) => {\n\t\tconst { solid } = DEFAULT_THEME.colors.light[name]!\n\t\tconst rgb = parseHexToRgb(solid)!\n\t\treturn [name, rgb[0], rgb[1], rgb[2]]\n\t}\n)\n\n/** Map an arbitrary Color tuple to the nearest tldraw named color (best-effort). */\nfunction nearestTldrawColor(rgb: Color): TLDefaultColorStyle {\n\tlet [r, g, b] = rgb\n\n\tconst max = Math.max(r, g, b)\n\tconst min = Math.min(r, g, b)\n\tconst lightness = (max + min) / 2 / 255\n\tconst chroma = max - min\n\n\t// For very light pastels, strip the white base and amplify the\n\t// chromatic signal so the distance metric can see the hue.\n\tif (lightness > 0.75 && chroma > 5) {\n\t\tconst target = 200\n\t\tr = Math.round(((r - min) / chroma) * target)\n\t\tg = Math.round(((g - min) / chroma) * target)\n\t\tb = Math.round(((b - min) / chroma) * target)\n\t}\n\n\tlet best: TLDefaultColorStyle = 'black'\n\tlet bestDistance = Infinity\n\tfor (const [name, red, green, blue] of TLDRAW_PALETTE) {\n\t\t// \"Redmean\" weighted Euclidean distance (Compuphase approximation).\n\t\t// Weights RGB channels by the average red value of the two colors to\n\t\t// approximate human perception, which is more sensitive to green and\n\t\t// varies in red/blue sensitivity depending on the color's warmth.\n\t\tconst rMean = (r + red) / 2\n\t\tconst dR = r - red\n\t\tconst dG = g - green\n\t\tconst dB = b - blue\n\t\tconst distance = (2 + rMean / 256) * dR * dR + 4 * dG * dG + (2 + (255 - rMean) / 256) * dB * dB\n\t\tif (distance < bestDistance) {\n\t\t\tbestDistance = distance\n\t\t\tbest = name\n\t\t}\n\t}\n\treturn best\n}\n\nfunction toColor(value: string | undefined): Color | undefined {\n\tif (!value) return undefined\n\n\tconst trimmed = value.trim()\n\tif (!trimmed || trimmed === 'none' || trimmed === 'transparent') return undefined\n\n\tif (trimmed.startsWith('rgb')) {\n\t\tconst match = trimmed.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([\\d.]+)\\s*)?\\)/)\n\t\tif (!match) return undefined\n\t\treturn [\n\t\t\tparseInt(match[1], 10),\n\t\t\tparseInt(match[2], 10),\n\t\t\tparseInt(match[3], 10),\n\t\t\tmatch[4] !== undefined ? Math.round(parseFloat(match[4]) * 255) : 255,\n\t\t]\n\t}\n\tif (trimmed.startsWith('#')) {\n\t\tconst rgb = parseHexToRgb(trimmed)\n\t\tif (!rgb) return undefined\n\t\treturn [rgb[0], rgb[1], rgb[2], 255]\n\t}\n\tconst keyword = trimmed.toLowerCase()\n\tif (hasOwnProperty(CSS_NAMED_COLORS, keyword)) {\n\t\tconst rgb = parseHexToRgb(CSS_NAMED_COLORS[keyword])!\n\t\treturn [rgb[0], rgb[1], rgb[2], 255]\n\t}\n\treturn undefined\n}\n\n// Mermaid accepts CSS color keywords wherever it takes a color, and sequence `box` statements\n// can't take a hex color at all, so without these a box's color is usually lost.\nconst CSS_NAMED_COLORS: Record<string, string> = {\n\taliceblue: 'f0f8ff',\n\tantiquewhite: 'faebd7',\n\taqua: '00ffff',\n\taquamarine: '7fffd4',\n\tazure: 'f0ffff',\n\tbeige: 'f5f5dc',\n\tbisque: 'ffe4c4',\n\tblack: '000000',\n\tblanchedalmond: 'ffebcd',\n\tblue: '0000ff',\n\tblueviolet: '8a2be2',\n\tbrown: 'a52a2a',\n\tburlywood: 'deb887',\n\tcadetblue: '5f9ea0',\n\tchartreuse: '7fff00',\n\tchocolate: 'd2691e',\n\tcoral: 'ff7f50',\n\tcornflowerblue: '6495ed',\n\tcornsilk: 'fff8dc',\n\tcrimson: 'dc143c',\n\tcyan: '00ffff',\n\tdarkblue: '00008b',\n\tdarkcyan: '008b8b',\n\tdarkgoldenrod: 'b8860b',\n\tdarkgray: 'a9a9a9',\n\tdarkgreen: '006400',\n\tdarkgrey: 'a9a9a9',\n\tdarkkhaki: 'bdb76b',\n\tdarkmagenta: '8b008b',\n\tdarkolivegreen: '556b2f',\n\tdarkorange: 'ff8c00',\n\tdarkorchid: '9932cc',\n\tdarkred: '8b0000',\n\tdarksalmon: 'e9967a',\n\tdarkseagreen: '8fbc8f',\n\tdarkslateblue: '483d8b',\n\tdarkslategray: '2f4f4f',\n\tdarkslategrey: '2f4f4f',\n\tdarkturquoise: '00ced1',\n\tdarkviolet: '9400d3',\n\tdeeppink: 'ff1493',\n\tdeepskyblue: '00bfff',\n\tdimgray: '696969',\n\tdimgrey: '696969',\n\tdodgerblue: '1e90ff',\n\tfirebrick: 'b22222',\n\tfloralwhite: 'fffaf0',\n\tforestgreen: '228b22',\n\tfuchsia: 'ff00ff',\n\tgainsboro: 'dcdcdc',\n\tghostwhite: 'f8f8ff',\n\tgold: 'ffd700',\n\tgoldenrod: 'daa520',\n\tgray: '808080',\n\tgreen: '008000',\n\tgreenyellow: 'adff2f',\n\tgrey: '808080',\n\thoneydew: 'f0fff0',\n\thotpink: 'ff69b4',\n\tindianred: 'cd5c5c',\n\tindigo: '4b0082',\n\tivory: 'fffff0',\n\tkhaki: 'f0e68c',\n\tlavender: 'e6e6fa',\n\tlavenderblush: 'fff0f5',\n\tlawngreen: '7cfc00',\n\tlemonchiffon: 'fffacd',\n\tlightblue: 'add8e6',\n\tlightcoral: 'f08080',\n\tlightcyan: 'e0ffff',\n\tlightgoldenrodyellow: 'fafad2',\n\tlightgray: 'd3d3d3',\n\tlightgreen: '90ee90',\n\tlightgrey: 'd3d3d3',\n\tlightpink: 'ffb6c1',\n\tlightsalmon: 'ffa07a',\n\tlightseagreen: '20b2aa',\n\tlightskyblue: '87cefa',\n\tlightslategray: '778899',\n\tlightslategrey: '778899',\n\tlightsteelblue: 'b0c4de',\n\tlightyellow: 'ffffe0',\n\tlime: '00ff00',\n\tlimegreen: '32cd32',\n\tlinen: 'faf0e6',\n\tmagenta: 'ff00ff',\n\tmaroon: '800000',\n\tmediumaquamarine: '66cdaa',\n\tmediumblue: '0000cd',\n\tmediumorchid: 'ba55d3',\n\tmediumpurple: '9370db',\n\tmediumseagreen: '3cb371',\n\tmediumslateblue: '7b68ee',\n\tmediumspringgreen: '00fa9a',\n\tmediumturquoise: '48d1cc',\n\tmediumvioletred: 'c71585',\n\tmidnightblue: '191970',\n\tmintcream: 'f5fffa',\n\tmistyrose: 'ffe4e1',\n\tmoccasin: 'ffe4b5',\n\tnavajowhite: 'ffdead',\n\tnavy: '000080',\n\toldlace: 'fdf5e6',\n\tolive: '808000',\n\tolivedrab: '6b8e23',\n\torange: 'ffa500',\n\torangered: 'ff4500',\n\torchid: 'da70d6',\n\tpalegoldenrod: 'eee8aa',\n\tpalegreen: '98fb98',\n\tpaleturquoise: 'afeeee',\n\tpalevioletred: 'db7093',\n\tpapayawhip: 'ffefd5',\n\tpeachpuff: 'ffdab9',\n\tperu: 'cd853f',\n\tpink: 'ffc0cb',\n\tplum: 'dda0dd',\n\tpowderblue: 'b0e0e6',\n\tpurple: '800080',\n\trebeccapurple: '663399',\n\tred: 'ff0000',\n\trosybrown: 'bc8f8f',\n\troyalblue: '4169e1',\n\tsaddlebrown: '8b4513',\n\tsalmon: 'fa8072',\n\tsandybrown: 'f4a460',\n\tseagreen: '2e8b57',\n\tseashell: 'fff5ee',\n\tsienna: 'a0522d',\n\tsilver: 'c0c0c0',\n\tskyblue: '87ceeb',\n\tslateblue: '6a5acd',\n\tslategray: '708090',\n\tslategrey: '708090',\n\tsnow: 'fffafa',\n\tspringgreen: '00ff7f',\n\tsteelblue: '4682b4',\n\ttan: 'd2b48c',\n\tteal: '008080',\n\tthistle: 'd8bfd8',\n\ttomato: 'ff6347',\n\tturquoise: '40e0d0',\n\tviolet: 'ee82ee',\n\twheat: 'f5deb3',\n\twhite: 'ffffff',\n\twhitesmoke: 'f5f5f5',\n\tyellow: 'ffff00',\n\tyellowgreen: '9acd32',\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -33,6 +33,7 @@ __export(createMermaidDiagram_exports, {
33
33
  });
34
34
  module.exports = __toCommonJS(createMermaidDiagram_exports);
35
35
  var import_flowchartDiagram = require("./flowchartDiagram");
36
+ var import_mermaidNodeCreateShape = require("./mermaidNodeCreateShape");
36
37
  var import_mindmapDiagram = require("./mindmapDiagram");
37
38
  var import_renderBlueprint = require("./renderBlueprint");
38
39
  var import_sequenceDiagram = require("./sequenceDiagram");
@@ -120,7 +121,8 @@ async function createMermaidDiagram(editor, text, options = {}) {
120
121
  actorKeys,
121
122
  messages,
122
123
  db.getCreatedActors(),
123
- db.getDestroyedActors()
124
+ db.getDestroyedActors(),
125
+ (0, import_mermaidNodeCreateShape.createLabelWidthMeasurer)(editor)
124
126
  );
125
127
  break;
126
128
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/createMermaidDiagram.ts"],
4
- "sourcesContent": ["import type { FlowDB } from 'mermaid/dist/diagrams/flowchart/flowDb.d.ts'\nimport type { FlowEdge, FlowSubGraph, FlowVertex } from 'mermaid/dist/diagrams/flowchart/types.js'\nimport type { MindmapDB } from 'mermaid/dist/diagrams/mindmap/mindmapDb.d.ts'\nimport type { SequenceDB } from 'mermaid/dist/diagrams/sequence/sequenceDb.d.ts'\nimport type { StateDB } from 'mermaid/dist/diagrams/state/stateDb.d.ts'\nimport { Editor } from 'tldraw'\nimport { flowchartToBlueprint, parseFlowchartLayout } from './flowchartDiagram'\nimport { mindmapToBlueprint, parseMindmapLayout } from './mindmapDiagram'\nimport { BlueprintRenderingOptions, renderBlueprint } from './renderBlueprint'\nimport { countSequenceEvents, parseSequenceLayout, sequenceToBlueprint } from './sequenceDiagram'\nimport { parseStateDiagramLayout, stateToBlueprint } from './stateDiagram'\n\nlet nextMermaidId = 0\n\n/** @public */\nexport class MermaidDiagramError extends Error {\n\tconstructor(\n\t\tpublic diagramType: string,\n\t\tpublic type: 'parse' | 'unsupported'\n\t) {\n\t\tsuper(`mermaid diagram error: ${diagramType}`)\n\t\tthis.name = 'MermaidDiagramError'\n\t}\n}\n\n// Inflate the font size so Mermaid's layout engine allocates larger nodes,\n// compensating for tldraw's hand-drawn font being wider than Mermaid's default.\nconst FONT_INFLATE = 1.4\n\nconst MERMAID_CONFIG = {\n\tstartOnLoad: false,\n\tflowchart: { nodeSpacing: 80, rankSpacing: 80, padding: 20 },\n\tstate: { nodeSpacing: 80, rankSpacing: 80, padding: 20 },\n\tmindmap: { padding: 20 },\n\tsequence: { actorMargin: 50, noteMargin: 20 },\n\tthemeVariables: { fontSize: `${18 * FONT_INFLATE}px` },\n}\n\n/** @public */\nexport interface MermaidDiagramOptions {\n\tmermaidConfig?: Record<string, any>\n\tblueprintRender?: BlueprintRenderingOptions\n\tonUnsupportedDiagram?(svg: string): Promise<void>\n}\n\n/**\n * Parse mermaid text and create tldraw shapes for supported diagram types.\n * Returns the SVG string for supported diagrams, or `null` when the diagram type\n * is unsupported (after calling `onUnsupportedDiagram` if provided).\n * Throws {@link MermaidDiagramError} if parsing fails.\n * @public\n */\nexport async function createMermaidDiagram(\n\teditor: Editor,\n\ttext: string,\n\toptions: MermaidDiagramOptions = {}\n): Promise<void> {\n\t// load mermaid lazily: it's a large, ESM-only dependency only needed when a\n\t// diagram is actually created. a dynamic import() works from CommonJS (unlike\n\t// a static import, which compiles to require(<esm>) and throws\n\t// ERR_REQUIRE_ESM on Node <20.19, Jest, and ts-node) and avoids pulling\n\t// mermaid in when @tldraw/mermaid is merely imported.\n\tconst mermaid = (await import('mermaid')).default\n\n\tmermaid.initialize({\n\t\t...MERMAID_CONFIG,\n\t\t...(options.mermaidConfig ?? {}),\n\t\tflowchart: { ...MERMAID_CONFIG.flowchart, ...options.mermaidConfig?.flowchart },\n\t\tstate: { ...MERMAID_CONFIG.state, ...options.mermaidConfig?.state },\n\t\tmindmap: { ...MERMAID_CONFIG.mindmap, ...options.mermaidConfig?.mindmap },\n\t\tsequence: { ...MERMAID_CONFIG.sequence, ...options.mermaidConfig?.sequence },\n\t\tthemeVariables: { ...MERMAID_CONFIG.themeVariables, ...options.mermaidConfig?.themeVariables },\n\t\t// A diagram's own `%%{init}%%` or frontmatter config outranks `initialize`, so one that sets\n\t\t// `fontSize` undoes FONT_INFLATE: every box is measured small while tldraw still draws its\n\t\t// wider face, and labels break mid-word. Mermaid strips `secure` keys from in-diagram config\n\t\t// at any depth, and keeps its own defaults alongside the ones listed here.\n\t\tsecure: [...(options.mermaidConfig?.secure ?? []), 'fontSize'],\n\t})\n\n\tconst parsedResult = await mermaid.parse(text, { suppressErrors: true })\n\n\tif (!parsedResult) {\n\t\tthrow new MermaidDiagramError('not a mermaid diagram', 'parse')\n\t}\n\n\tconst offscreen = document.createElement('div')\n\tObject.assign(offscreen.style, {\n\t\tposition: 'absolute',\n\t\tleft: '-9999px',\n\t\ttop: '-9999px',\n\t\toverflow: 'hidden',\n\t})\n\tdocument.body.appendChild(offscreen)\n\n\ttry {\n\t\tconst parsedSvg = (await mermaid.render(`mermaid-${nextMermaidId++}`, text, offscreen)).svg\n\n\t\t// Reuse the live SVG that mermaid.render() already mounted into the\n\t\t// offscreen container. This avoids a second DOM mount and ensures\n\t\t// getBBox() works for every diagram type (state diagrams in particular\n\t\t// lack explicit dimension attributes and rely on live layout).\n\t\tlet liveSvg = offscreen.querySelector('svg')\n\n\t\tif (!liveSvg) {\n\t\t\toffscreen.innerHTML = parsedSvg\n\t\t\tliveSvg = offscreen.querySelector('svg')\n\t\t\tif (!liveSvg) {\n\t\t\t\tthrow new MermaidDiagramError(parsedResult.diagramType, 'parse')\n\t\t\t}\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tconst diagramResult = await mermaid.mermaidAPI.getDiagramFromText(text)\n\n\t\tlet blueprint\n\t\tswitch (parsedResult.diagramType) {\n\t\t\tcase 'flowchart-v2': {\n\t\t\t\tconst db = diagramResult.db as FlowDB\n\t\t\t\tconst vertices = db.getVertices() as Map<string, FlowVertex>\n\t\t\t\tconst edges = db.getEdges() as FlowEdge[]\n\t\t\t\tconst subGraphs = db.getSubGraphs() as FlowSubGraph[]\n\t\t\t\tconst classes = db.getClasses()\n\t\t\t\tconst layout = parseFlowchartLayout(liveSvg)\n\t\t\t\tblueprint = flowchartToBlueprint(layout, vertices, edges, subGraphs, classes)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'sequence': {\n\t\t\t\tconst db = diagramResult.db as SequenceDB\n\t\t\t\tconst actors = db.getActors()\n\t\t\t\tconst actorKeys = db.getActorKeys()\n\t\t\t\tconst messages = db.getMessages()\n\t\t\t\tconst layout = parseSequenceLayout(liveSvg, actorKeys.length, countSequenceEvents(messages))\n\t\t\t\tblueprint = sequenceToBlueprint(\n\t\t\t\t\tlayout,\n\t\t\t\t\tactors,\n\t\t\t\t\tactorKeys,\n\t\t\t\t\tmessages,\n\t\t\t\t\tdb.getCreatedActors(),\n\t\t\t\t\tdb.getDestroyedActors()\n\t\t\t\t)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'state':\n\t\t\tcase 'stateDiagram': {\n\t\t\t\tconst db = diagramResult.db as StateDB\n\t\t\t\tconst states = db.getStates()\n\t\t\t\tconst relations = db.getRelations()\n\t\t\t\tconst classes = db.getClasses()\n\t\t\t\tconst layout = parseStateDiagramLayout(liveSvg)\n\t\t\t\tblueprint = stateToBlueprint(layout, states, relations, classes)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'mindmap': {\n\t\t\t\tconst db = diagramResult.db as MindmapDB\n\t\t\t\tconst tree = db.getMindmap()\n\t\t\t\tif (tree) {\n\t\t\t\t\tdb.assignSections(tree)\n\t\t\t\t\tconst layout = parseMindmapLayout(liveSvg)\n\t\t\t\t\tblueprint = mindmapToBlueprint(layout, tree, liveSvg)\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif (options.onUnsupportedDiagram) {\n\t\t\t\t\tawait options.onUnsupportedDiagram(parsedSvg)\n\t\t\t\t} else {\n\t\t\t\t\tthrow new MermaidDiagramError(parsedResult.diagramType, 'unsupported')\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t}\n\n\t\tif (blueprint) {\n\t\t\trenderBlueprint(editor, blueprint, options.blueprintRender)\n\t\t}\n\t} catch (e) {\n\t\tif (e instanceof MermaidDiagramError) throw e\n\t\tconsole.error(e)\n\t\tthrow new MermaidDiagramError(parsedResult.diagramType, 'parse')\n\t} finally {\n\t\toffscreen.remove()\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { FlowDB } from 'mermaid/dist/diagrams/flowchart/flowDb.d.ts'\nimport type { FlowEdge, FlowSubGraph, FlowVertex } from 'mermaid/dist/diagrams/flowchart/types.js'\nimport type { MindmapDB } from 'mermaid/dist/diagrams/mindmap/mindmapDb.d.ts'\nimport type { SequenceDB } from 'mermaid/dist/diagrams/sequence/sequenceDb.d.ts'\nimport type { StateDB } from 'mermaid/dist/diagrams/state/stateDb.d.ts'\nimport { Editor } from 'tldraw'\nimport { flowchartToBlueprint, parseFlowchartLayout } from './flowchartDiagram'\nimport { createLabelWidthMeasurer } from './mermaidNodeCreateShape'\nimport { mindmapToBlueprint, parseMindmapLayout } from './mindmapDiagram'\nimport { BlueprintRenderingOptions, renderBlueprint } from './renderBlueprint'\nimport { countSequenceEvents, parseSequenceLayout, sequenceToBlueprint } from './sequenceDiagram'\nimport { parseStateDiagramLayout, stateToBlueprint } from './stateDiagram'\n\nlet nextMermaidId = 0\n\n/** @public */\nexport class MermaidDiagramError extends Error {\n\tconstructor(\n\t\tpublic diagramType: string,\n\t\tpublic type: 'parse' | 'unsupported'\n\t) {\n\t\tsuper(`mermaid diagram error: ${diagramType}`)\n\t\tthis.name = 'MermaidDiagramError'\n\t}\n}\n\n// Inflate the font size so Mermaid's layout engine allocates larger nodes,\n// compensating for tldraw's hand-drawn font being wider than Mermaid's default.\nconst FONT_INFLATE = 1.4\n\nconst MERMAID_CONFIG = {\n\tstartOnLoad: false,\n\tflowchart: { nodeSpacing: 80, rankSpacing: 80, padding: 20 },\n\tstate: { nodeSpacing: 80, rankSpacing: 80, padding: 20 },\n\tmindmap: { padding: 20 },\n\tsequence: { actorMargin: 50, noteMargin: 20 },\n\tthemeVariables: { fontSize: `${18 * FONT_INFLATE}px` },\n}\n\n/** @public */\nexport interface MermaidDiagramOptions {\n\tmermaidConfig?: Record<string, any>\n\tblueprintRender?: BlueprintRenderingOptions\n\tonUnsupportedDiagram?(svg: string): Promise<void>\n}\n\n/**\n * Parse mermaid text and create tldraw shapes for supported diagram types.\n * Returns the SVG string for supported diagrams, or `null` when the diagram type\n * is unsupported (after calling `onUnsupportedDiagram` if provided).\n * Throws {@link MermaidDiagramError} if parsing fails.\n * @public\n */\nexport async function createMermaidDiagram(\n\teditor: Editor,\n\ttext: string,\n\toptions: MermaidDiagramOptions = {}\n): Promise<void> {\n\t// load mermaid lazily: it's a large, ESM-only dependency only needed when a\n\t// diagram is actually created. a dynamic import() works from CommonJS (unlike\n\t// a static import, which compiles to require(<esm>) and throws\n\t// ERR_REQUIRE_ESM on Node <20.19, Jest, and ts-node) and avoids pulling\n\t// mermaid in when @tldraw/mermaid is merely imported.\n\tconst mermaid = (await import('mermaid')).default\n\n\tmermaid.initialize({\n\t\t...MERMAID_CONFIG,\n\t\t...(options.mermaidConfig ?? {}),\n\t\tflowchart: { ...MERMAID_CONFIG.flowchart, ...options.mermaidConfig?.flowchart },\n\t\tstate: { ...MERMAID_CONFIG.state, ...options.mermaidConfig?.state },\n\t\tmindmap: { ...MERMAID_CONFIG.mindmap, ...options.mermaidConfig?.mindmap },\n\t\tsequence: { ...MERMAID_CONFIG.sequence, ...options.mermaidConfig?.sequence },\n\t\tthemeVariables: { ...MERMAID_CONFIG.themeVariables, ...options.mermaidConfig?.themeVariables },\n\t\t// A diagram's own `%%{init}%%` or frontmatter config outranks `initialize`, so one that sets\n\t\t// `fontSize` undoes FONT_INFLATE: every box is measured small while tldraw still draws its\n\t\t// wider face, and labels break mid-word. Mermaid strips `secure` keys from in-diagram config\n\t\t// at any depth, and keeps its own defaults alongside the ones listed here.\n\t\tsecure: [...(options.mermaidConfig?.secure ?? []), 'fontSize'],\n\t})\n\n\tconst parsedResult = await mermaid.parse(text, { suppressErrors: true })\n\n\tif (!parsedResult) {\n\t\tthrow new MermaidDiagramError('not a mermaid diagram', 'parse')\n\t}\n\n\tconst offscreen = document.createElement('div')\n\tObject.assign(offscreen.style, {\n\t\tposition: 'absolute',\n\t\tleft: '-9999px',\n\t\ttop: '-9999px',\n\t\toverflow: 'hidden',\n\t})\n\tdocument.body.appendChild(offscreen)\n\n\ttry {\n\t\tconst parsedSvg = (await mermaid.render(`mermaid-${nextMermaidId++}`, text, offscreen)).svg\n\n\t\t// Reuse the live SVG that mermaid.render() already mounted into the\n\t\t// offscreen container. This avoids a second DOM mount and ensures\n\t\t// getBBox() works for every diagram type (state diagrams in particular\n\t\t// lack explicit dimension attributes and rely on live layout).\n\t\tlet liveSvg = offscreen.querySelector('svg')\n\n\t\tif (!liveSvg) {\n\t\t\toffscreen.innerHTML = parsedSvg\n\t\t\tliveSvg = offscreen.querySelector('svg')\n\t\t\tif (!liveSvg) {\n\t\t\t\tthrow new MermaidDiagramError(parsedResult.diagramType, 'parse')\n\t\t\t}\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tconst diagramResult = await mermaid.mermaidAPI.getDiagramFromText(text)\n\n\t\tlet blueprint\n\t\tswitch (parsedResult.diagramType) {\n\t\t\tcase 'flowchart-v2': {\n\t\t\t\tconst db = diagramResult.db as FlowDB\n\t\t\t\tconst vertices = db.getVertices() as Map<string, FlowVertex>\n\t\t\t\tconst edges = db.getEdges() as FlowEdge[]\n\t\t\t\tconst subGraphs = db.getSubGraphs() as FlowSubGraph[]\n\t\t\t\tconst classes = db.getClasses()\n\t\t\t\tconst layout = parseFlowchartLayout(liveSvg)\n\t\t\t\tblueprint = flowchartToBlueprint(layout, vertices, edges, subGraphs, classes)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'sequence': {\n\t\t\t\tconst db = diagramResult.db as SequenceDB\n\t\t\t\tconst actors = db.getActors()\n\t\t\t\tconst actorKeys = db.getActorKeys()\n\t\t\t\tconst messages = db.getMessages()\n\t\t\t\tconst layout = parseSequenceLayout(liveSvg, actorKeys.length, countSequenceEvents(messages))\n\t\t\t\tblueprint = sequenceToBlueprint(\n\t\t\t\t\tlayout,\n\t\t\t\t\tactors,\n\t\t\t\t\tactorKeys,\n\t\t\t\t\tmessages,\n\t\t\t\t\tdb.getCreatedActors(),\n\t\t\t\t\tdb.getDestroyedActors(),\n\t\t\t\t\tcreateLabelWidthMeasurer(editor)\n\t\t\t\t)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'state':\n\t\t\tcase 'stateDiagram': {\n\t\t\t\tconst db = diagramResult.db as StateDB\n\t\t\t\tconst states = db.getStates()\n\t\t\t\tconst relations = db.getRelations()\n\t\t\t\tconst classes = db.getClasses()\n\t\t\t\tconst layout = parseStateDiagramLayout(liveSvg)\n\t\t\t\tblueprint = stateToBlueprint(layout, states, relations, classes)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'mindmap': {\n\t\t\t\tconst db = diagramResult.db as MindmapDB\n\t\t\t\tconst tree = db.getMindmap()\n\t\t\t\tif (tree) {\n\t\t\t\t\tdb.assignSections(tree)\n\t\t\t\t\tconst layout = parseMindmapLayout(liveSvg)\n\t\t\t\t\tblueprint = mindmapToBlueprint(layout, tree, liveSvg)\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif (options.onUnsupportedDiagram) {\n\t\t\t\t\tawait options.onUnsupportedDiagram(parsedSvg)\n\t\t\t\t} else {\n\t\t\t\t\tthrow new MermaidDiagramError(parsedResult.diagramType, 'unsupported')\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t}\n\n\t\tif (blueprint) {\n\t\t\trenderBlueprint(editor, blueprint, options.blueprintRender)\n\t\t}\n\t} catch (e) {\n\t\tif (e instanceof MermaidDiagramError) throw e\n\t\tconsole.error(e)\n\t\tthrow new MermaidDiagramError(parsedResult.diagramType, 'parse')\n\t} finally {\n\t\toffscreen.remove()\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -48,13 +48,37 @@ function buildHierarchy(subGraphs) {
48
48
  }
49
49
  return { nodeToSubGraph, subGraphParent };
50
50
  }
51
+ function parseEdgeId(dataId, points, centers) {
52
+ const match = dataId.match(/(?:^|-)L_(.+)_\d+$/);
53
+ if (!match) return null;
54
+ const joined = match[1];
55
+ const last = points[points.length - 1];
56
+ let best;
57
+ let bestDistance = Infinity;
58
+ for (let at2 = joined.indexOf("_"); at2 > 0; at2 = joined.indexOf("_", at2 + 1)) {
59
+ const start = joined.slice(0, at2);
60
+ const end = joined.slice(at2 + 1);
61
+ const startCenter = centers.get(start);
62
+ const endCenter = centers.get(end);
63
+ if (!startCenter || !endCenter) continue;
64
+ const distance = last ? Math.hypot(points[0].x - startCenter.x, points[0].y - startCenter.y) + Math.hypot(last.x - endCenter.x, last.y - endCenter.y) : 0;
65
+ if (distance < bestDistance) {
66
+ bestDistance = distance;
67
+ best = { start, end };
68
+ }
69
+ }
70
+ if (best) return best;
71
+ const at = joined.lastIndexOf("_");
72
+ return at > 0 ? { start: joined.slice(0, at), end: joined.slice(at + 1) } : null;
73
+ }
51
74
  function parseFlowchartLayout(root) {
52
75
  const nodes = (0, import_svgParsing.parseNodesFromSvg)(root, ".node", (domId) => (0, import_svgParsing.parseDomId)(domId, NODE_ID));
53
76
  const clusters = (0, import_svgParsing.parseClustersFromSvg)(root, ".cluster", import_svgParsing.stripDiagramIdPrefix);
54
- const edges = (0, import_svgParsing.parseAllEdgePointsFromSvg)(root, (dataId) => {
55
- const match = dataId.match(/(?:^|-)L_(.+)_([^_]+)_\d+$/);
56
- return match ? { start: match[1], end: match[2] } : null;
57
- });
77
+ const centers = (0, import_svgParsing.buildNodeCentersFromSvg)(nodes, clusters);
78
+ const edges = (0, import_svgParsing.parseAllEdgePointsFromSvg)(
79
+ root,
80
+ (dataId, points) => parseEdgeId(dataId, points, centers)
81
+ );
58
82
  const layout = { nodes, clusters, edges, edgeLabels: (0, import_svgParsing.parseEdgeLabelsFromSvg)(root) };
59
83
  (0, import_svgParsing.scaleLayout)(layout, import_utils.LAYOUT_SCALE);
60
84
  return layout;
@@ -115,12 +139,12 @@ function flowchartToBlueprint(layout, vertices, edges, subGraphs, classDefs) {
115
139
  }
116
140
  const claimed = /* @__PURE__ */ new Set();
117
141
  for (const edge of edges) {
118
- const svgEdge = (0, import_svgParsing.claimNearestEdge)(
119
- svgEdges,
120
- claimed,
121
- nodeCenters.get(edge.start),
122
- nodeCenters.get(edge.end)
123
- );
142
+ const svgEdge = (0, import_svgParsing.claimEdge)(svgEdges, claimed, {
143
+ startId: edge.start,
144
+ endId: edge.end,
145
+ startCenter: nodeCenters.get(edge.start),
146
+ endCenter: nodeCenters.get(edge.end)
147
+ });
124
148
  const svgNode = svgNodes.get(edge.start);
125
149
  const selfLoop = edge.start === edge.end && svgEdge && svgNode ? (0, import_svgParsing.getSelfLoopEdgeLayout)(svgEdge, svgNode, layout.edgeLabels) : void 0;
126
150
  const cssOverrides = (0, import_colors.parseCssStyles)(edge.style);
@@ -134,7 +158,7 @@ function flowchartToBlueprint(layout, vertices, edges, subGraphs, classDefs) {
134
158
  arrowheadEnd,
135
159
  arrowheadStart: edge.type?.includes("double_arrow") ? arrowheadEnd : void 0,
136
160
  dash: cssOverrides.dashOverride ?? (edge.stroke === "dotted" ? "dotted" : "solid"),
137
- size: cssOverrides.sizeOverride ?? (edge.stroke === "thick" ? "l" : "s"),
161
+ size: cssOverrides.sizeOverride ?? (edge.stroke === "thick" ? "l" : "m"),
138
162
  color: cssOverrides.color
139
163
  });
140
164
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/flowchartDiagram.ts"],
4
- "sourcesContent": ["import type {\n\tFlowClass,\n\tFlowEdge,\n\tFlowSubGraph,\n\tFlowVertex,\n} from 'mermaid/dist/diagrams/flowchart/types.js'\nimport { TLArrowShapeArrowheadStyle } from 'tldraw'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintNode,\n} from './blueprint'\nimport {\n\tbuildClassDefColorMap,\n\tparseCssStyles,\n\tparseNodeInlineColor,\n\ttoNodeColorProps,\n} from './colors'\nimport {\n\tbuildNodeCentersFromSvg,\n\tclaimNearestEdge,\n\tgetSelfLoopEdgeLayout,\n\tparseAllEdgePointsFromSvg,\n\tparseClustersFromSvg,\n\tparseDomId,\n\tparseEdgeLabelsFromSvg,\n\ttype ParsedDiagramLayout,\n\tparseNodesFromSvg,\n\tscaleLayout,\n\tstripDiagramIdPrefix,\n} from './svgParsing'\nimport { dropDanglingEdges, getArrowBend, LAYOUT_SCALE, orderTopDown } from './utils'\n\nfunction mapEdgeTypeToArrowhead(type: string | undefined): TLArrowShapeArrowheadStyle {\n\tif (type?.includes('circle')) return 'dot'\n\tif (type?.includes('cross')) return 'bar'\n\tif (type?.includes('open')) return 'none'\n\treturn 'arrow'\n}\n\nconst FRAME_TOP_PAD = 14\nconst NODE_ID = /^flowchart-(.+)-\\d+$/\n\nfunction buildHierarchy(subGraphs: FlowSubGraph[]) {\n\tconst subGraphIds = new Set(subGraphs.map((subGraph) => subGraph.id))\n\tconst nodeToSubGraph = new Map<string, string>()\n\tconst subGraphParent = new Map<string, string>()\n\tfor (const subGraph of subGraphs) {\n\t\tfor (const nodeId of subGraph.nodes) {\n\t\t\tif (subGraphIds.has(nodeId)) {\n\t\t\t\tsubGraphParent.set(nodeId, subGraph.id)\n\t\t\t} else if (!nodeToSubGraph.has(nodeId)) {\n\t\t\t\tnodeToSubGraph.set(nodeId, subGraph.id)\n\t\t\t}\n\t\t}\n\t}\n\treturn { nodeToSubGraph, subGraphParent }\n}\n\n/** Parse flowchart-specific SVG layout data for use by {@link flowchartToBlueprint}. */\nexport function parseFlowchartLayout(root: Element): ParsedDiagramLayout {\n\tconst nodes = parseNodesFromSvg(root, '.node', (domId) => parseDomId(domId, NODE_ID))\n\tconst clusters = parseClustersFromSvg(root, '.cluster', stripDiagramIdPrefix)\n\tconst edges = parseAllEdgePointsFromSvg(root, (dataId) => {\n\t\tconst match = dataId.match(/(?:^|-)L_(.+)_([^_]+)_\\d+$/)\n\t\treturn match ? { start: match[1], end: match[2] } : null\n\t})\n\tconst layout = { nodes, clusters, edges, edgeLabels: parseEdgeLabelsFromSvg(root) }\n\tscaleLayout(layout, LAYOUT_SCALE)\n\treturn layout\n}\n\n/** Convert a parsed Mermaid flowchart into a tldraw blueprint of nodes and edges. */\nexport function flowchartToBlueprint(\n\tlayout: ParsedDiagramLayout,\n\tvertices: Map<string, FlowVertex>,\n\tedges: FlowEdge[],\n\tsubGraphs?: FlowSubGraph[],\n\tclassDefs?: Map<string, FlowClass>\n): DiagramMermaidBlueprint {\n\tconst nodeColorMap = buildClassDefColorMap(classDefs ?? new Map(), vertices)\n\tconst { nodes: svgNodes, clusters: svgClusters, edges: svgEdges } = layout\n\tconst nodeCenters = buildNodeCentersFromSvg(svgNodes, svgClusters)\n\n\tconst allSubGraphs = subGraphs || []\n\tconst { nodeToSubGraph, subGraphParent } = buildHierarchy(allSubGraphs)\n\n\tconst nodes: MermaidBlueprintNode[] = []\n\tconst blueprintEdges: MermaidBlueprintEdge[] = []\n\n\t// Frames for subgraphs\n\tfor (const subGraph of orderTopDown(\n\t\tallSubGraphs,\n\t\t(subGraph) => subGraph.id,\n\t\t(subGraph) => subGraphParent.get(subGraph.id)\n\t)) {\n\t\tconst cluster = svgClusters.get(subGraph.id)\n\t\tif (!cluster) continue\n\n\t\tnodes.push({\n\t\t\tid: subGraph.id,\n\t\t\tkind: 'subgraph',\n\t\t\tx: cluster.topLeft.x,\n\t\t\ty: cluster.topLeft.y - FRAME_TOP_PAD,\n\t\t\tw: cluster.width,\n\t\t\th: cluster.height + FRAME_TOP_PAD,\n\t\t\tparentId: subGraphParent.get(subGraph.id),\n\t\t\tlabel: subGraph.title || subGraph.id,\n\t\t\tfill: 'semi',\n\t\t\tcolor: 'black',\n\t\t\tdash: 'draw',\n\t\t\tsize: 's',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'start',\n\t\t})\n\t}\n\n\t// Node shapes\n\tfor (const [id, vertex] of vertices) {\n\t\tconst svgNode = svgNodes.get(id)\n\t\tif (!svgNode) continue\n\n\t\tlet { width: w, height: h } = svgNode\n\t\tif (vertex.type === 'circle' || vertex.type === 'doublecircle') {\n\t\t\tw = h = Math.max(w, h)\n\t\t}\n\n\t\tnodes.push({\n\t\t\tid,\n\t\t\tkind: vertex.type ?? 'rect',\n\t\t\tx: svgNode.center.x - w / 2,\n\t\t\ty: svgNode.center.y - h / 2,\n\t\t\tw,\n\t\t\th,\n\t\t\tparentId: nodeToSubGraph.get(id),\n\t\t\tlabel: vertex.text || undefined,\n\t\t\t...toNodeColorProps(nodeColorMap.get(id) ?? parseNodeInlineColor(vertex.styles)),\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'middle',\n\t\t\tsize: 'm',\n\t\t})\n\t}\n\n\t// Edges: match DB edges to SVG edges by proximity, compute bends\n\tconst claimed = new Set<number>()\n\tfor (const edge of edges) {\n\t\tconst svgEdge = claimNearestEdge(\n\t\t\tsvgEdges,\n\t\t\tclaimed,\n\t\t\tnodeCenters.get(edge.start),\n\t\t\tnodeCenters.get(edge.end)\n\t\t)\n\t\tconst svgNode = svgNodes.get(edge.start)\n\t\tconst selfLoop =\n\t\t\tedge.start === edge.end && svgEdge && svgNode\n\t\t\t\t? getSelfLoopEdgeLayout(svgEdge, svgNode, layout.edgeLabels)\n\t\t\t\t: undefined\n\t\tconst cssOverrides = parseCssStyles(edge.style)\n\t\tconst arrowheadEnd = mapEdgeTypeToArrowhead(edge.type)\n\n\t\tblueprintEdges.push({\n\t\t\tstartNodeId: edge.start,\n\t\t\tendNodeId: edge.end,\n\t\t\tlabel: edge.text,\n\t\t\tbend: svgEdge ? getArrowBend(svgEdge) : 0,\n\t\t\t...selfLoop,\n\t\t\tarrowheadEnd,\n\t\t\tarrowheadStart: edge.type?.includes('double_arrow') ? arrowheadEnd : undefined,\n\t\t\tdash: cssOverrides.dashOverride ?? (edge.stroke === 'dotted' ? 'dotted' : 'solid'),\n\t\t\tsize: cssOverrides.sizeOverride ?? (edge.stroke === 'thick' ? 'l' : 's'),\n\t\t\tcolor: cssOverrides.color,\n\t\t})\n\t}\n\n\treturn { diagramKind: 'flowchart', nodes, edges: dropDanglingEdges(nodes, blueprintEdges) }\n}\n"],
5
- "mappings": "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",
6
- "names": ["subGraph"]
4
+ "sourcesContent": ["import type {\n\tFlowClass,\n\tFlowEdge,\n\tFlowSubGraph,\n\tFlowVertex,\n} from 'mermaid/dist/diagrams/flowchart/types.js'\nimport { TLArrowShapeArrowheadStyle } from 'tldraw'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintNode,\n} from './blueprint'\nimport {\n\tbuildClassDefColorMap,\n\tparseCssStyles,\n\tparseNodeInlineColor,\n\ttoNodeColorProps,\n} from './colors'\nimport {\n\tbuildNodeCentersFromSvg,\n\tclaimEdge,\n\tgetSelfLoopEdgeLayout,\n\tparseAllEdgePointsFromSvg,\n\tparseClustersFromSvg,\n\tparseDomId,\n\tparseEdgeLabelsFromSvg,\n\ttype ParsedDiagramLayout,\n\tparseNodesFromSvg,\n\tscaleLayout,\n\tstripDiagramIdPrefix,\n\ttype Vec2,\n} from './svgParsing'\nimport { dropDanglingEdges, getArrowBend, LAYOUT_SCALE, orderTopDown } from './utils'\n\nfunction mapEdgeTypeToArrowhead(type: string | undefined): TLArrowShapeArrowheadStyle {\n\tif (type?.includes('circle')) return 'dot'\n\tif (type?.includes('cross')) return 'bar'\n\tif (type?.includes('open')) return 'none'\n\treturn 'arrow'\n}\n\nconst FRAME_TOP_PAD = 14\nconst NODE_ID = /^flowchart-(.+)-\\d+$/\n\nfunction buildHierarchy(subGraphs: FlowSubGraph[]) {\n\tconst subGraphIds = new Set(subGraphs.map((subGraph) => subGraph.id))\n\tconst nodeToSubGraph = new Map<string, string>()\n\tconst subGraphParent = new Map<string, string>()\n\tfor (const subGraph of subGraphs) {\n\t\tfor (const nodeId of subGraph.nodes) {\n\t\t\tif (subGraphIds.has(nodeId)) {\n\t\t\t\tsubGraphParent.set(nodeId, subGraph.id)\n\t\t\t} else if (!nodeToSubGraph.has(nodeId)) {\n\t\t\t\tnodeToSubGraph.set(nodeId, subGraph.id)\n\t\t\t}\n\t\t}\n\t}\n\treturn { nodeToSubGraph, subGraphParent }\n}\n\n/**\n * Split mermaid's edge id, `L_<start>_<end>_<n>`, back into the two ids it joins. Node ids can\n * contain underscores themselves, so the split is ambiguous: `L_a_b_c_0` joins `a` to `b_c` in a\n * diagram with those, and `a_b` to `c` in one with those. A diagram with all four settles it the\n * only way left, by which pair the path was actually drawn between. `centers` holds everything an\n * edge can end on, subgraphs as well as nodes, since mermaid links those too.\n */\nfunction parseEdgeId(dataId: string, points: Vec2[], centers: Map<string, Vec2>) {\n\tconst match = dataId.match(/(?:^|-)L_(.+)_\\d+$/)\n\tif (!match) return null\n\n\tconst joined = match[1]\n\tconst last = points[points.length - 1]\n\tlet best: { start: string; end: string } | undefined\n\tlet bestDistance = Infinity\n\tfor (let at = joined.indexOf('_'); at > 0; at = joined.indexOf('_', at + 1)) {\n\t\tconst start = joined.slice(0, at)\n\t\tconst end = joined.slice(at + 1)\n\t\tconst startCenter = centers.get(start)\n\t\tconst endCenter = centers.get(end)\n\t\tif (!startCenter || !endCenter) continue\n\n\t\tconst distance = last\n\t\t\t? Math.hypot(points[0].x - startCenter.x, points[0].y - startCenter.y) +\n\t\t\t\tMath.hypot(last.x - endCenter.x, last.y - endCenter.y)\n\t\t\t: 0\n\t\tif (distance < bestDistance) {\n\t\t\tbestDistance = distance\n\t\t\tbest = { start, end }\n\t\t}\n\t}\n\tif (best) return best\n\n\t// An id naming no pair the diagram drew, such as an edge to a node mermaid left out. Splitting at\n\t// the last underscore is right whenever the end id has none, and leaves the edge to be matched by\n\t// proximity when it isn't.\n\tconst at = joined.lastIndexOf('_')\n\treturn at > 0 ? { start: joined.slice(0, at), end: joined.slice(at + 1) } : null\n}\n\n/** Parse flowchart-specific SVG layout data for use by {@link flowchartToBlueprint}. */\nexport function parseFlowchartLayout(root: Element): ParsedDiagramLayout {\n\tconst nodes = parseNodesFromSvg(root, '.node', (domId) => parseDomId(domId, NODE_ID))\n\tconst clusters = parseClustersFromSvg(root, '.cluster', stripDiagramIdPrefix)\n\tconst centers = buildNodeCentersFromSvg(nodes, clusters)\n\tconst edges = parseAllEdgePointsFromSvg(root, (dataId, points) =>\n\t\tparseEdgeId(dataId, points, centers)\n\t)\n\tconst layout = { nodes, clusters, edges, edgeLabels: parseEdgeLabelsFromSvg(root) }\n\tscaleLayout(layout, LAYOUT_SCALE)\n\treturn layout\n}\n\n/** Convert a parsed Mermaid flowchart into a tldraw blueprint of nodes and edges. */\nexport function flowchartToBlueprint(\n\tlayout: ParsedDiagramLayout,\n\tvertices: Map<string, FlowVertex>,\n\tedges: FlowEdge[],\n\tsubGraphs?: FlowSubGraph[],\n\tclassDefs?: Map<string, FlowClass>\n): DiagramMermaidBlueprint {\n\tconst nodeColorMap = buildClassDefColorMap(classDefs ?? new Map(), vertices)\n\tconst { nodes: svgNodes, clusters: svgClusters, edges: svgEdges } = layout\n\tconst nodeCenters = buildNodeCentersFromSvg(svgNodes, svgClusters)\n\n\tconst allSubGraphs = subGraphs || []\n\tconst { nodeToSubGraph, subGraphParent } = buildHierarchy(allSubGraphs)\n\n\tconst nodes: MermaidBlueprintNode[] = []\n\tconst blueprintEdges: MermaidBlueprintEdge[] = []\n\n\t// Frames for subgraphs\n\tfor (const subGraph of orderTopDown(\n\t\tallSubGraphs,\n\t\t(subGraph) => subGraph.id,\n\t\t(subGraph) => subGraphParent.get(subGraph.id)\n\t)) {\n\t\tconst cluster = svgClusters.get(subGraph.id)\n\t\tif (!cluster) continue\n\n\t\tnodes.push({\n\t\t\tid: subGraph.id,\n\t\t\tkind: 'subgraph',\n\t\t\tx: cluster.topLeft.x,\n\t\t\ty: cluster.topLeft.y - FRAME_TOP_PAD,\n\t\t\tw: cluster.width,\n\t\t\th: cluster.height + FRAME_TOP_PAD,\n\t\t\tparentId: subGraphParent.get(subGraph.id),\n\t\t\tlabel: subGraph.title || subGraph.id,\n\t\t\tfill: 'semi',\n\t\t\tcolor: 'black',\n\t\t\tdash: 'draw',\n\t\t\tsize: 's',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'start',\n\t\t})\n\t}\n\n\t// Node shapes\n\tfor (const [id, vertex] of vertices) {\n\t\tconst svgNode = svgNodes.get(id)\n\t\tif (!svgNode) continue\n\n\t\tlet { width: w, height: h } = svgNode\n\t\tif (vertex.type === 'circle' || vertex.type === 'doublecircle') {\n\t\t\tw = h = Math.max(w, h)\n\t\t}\n\n\t\tnodes.push({\n\t\t\tid,\n\t\t\tkind: vertex.type ?? 'rect',\n\t\t\tx: svgNode.center.x - w / 2,\n\t\t\ty: svgNode.center.y - h / 2,\n\t\t\tw,\n\t\t\th,\n\t\t\tparentId: nodeToSubGraph.get(id),\n\t\t\tlabel: vertex.text || undefined,\n\t\t\t...toNodeColorProps(nodeColorMap.get(id) ?? parseNodeInlineColor(vertex.styles)),\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'middle',\n\t\t\tsize: 'm',\n\t\t})\n\t}\n\n\t// Edges: match DB edges to the paths mermaid drew for them, and take each one's bend\n\tconst claimed = new Set<number>()\n\tfor (const edge of edges) {\n\t\tconst svgEdge = claimEdge(svgEdges, claimed, {\n\t\t\tstartId: edge.start,\n\t\t\tendId: edge.end,\n\t\t\tstartCenter: nodeCenters.get(edge.start),\n\t\t\tendCenter: nodeCenters.get(edge.end),\n\t\t})\n\t\tconst svgNode = svgNodes.get(edge.start)\n\t\tconst selfLoop =\n\t\t\tedge.start === edge.end && svgEdge && svgNode\n\t\t\t\t? getSelfLoopEdgeLayout(svgEdge, svgNode, layout.edgeLabels)\n\t\t\t\t: undefined\n\t\tconst cssOverrides = parseCssStyles(edge.style)\n\t\tconst arrowheadEnd = mapEdgeTypeToArrowhead(edge.type)\n\n\t\tblueprintEdges.push({\n\t\t\tstartNodeId: edge.start,\n\t\t\tendNodeId: edge.end,\n\t\t\tlabel: edge.text,\n\t\t\tbend: svgEdge ? getArrowBend(svgEdge) : 0,\n\t\t\t...selfLoop,\n\t\t\tarrowheadEnd,\n\t\t\tarrowheadStart: edge.type?.includes('double_arrow') ? arrowheadEnd : undefined,\n\t\t\tdash: cssOverrides.dashOverride ?? (edge.stroke === 'dotted' ? 'dotted' : 'solid'),\n\t\t\tsize: cssOverrides.sizeOverride ?? (edge.stroke === 'thick' ? 'l' : 'm'),\n\t\t\tcolor: cssOverrides.color,\n\t\t})\n\t}\n\n\treturn { diagramKind: 'flowchart', nodes, edges: dropDanglingEdges(nodes, blueprintEdges) }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["at", "subGraph"]
7
7
  }
package/dist-cjs/index.js CHANGED
@@ -35,7 +35,7 @@ var import_mermaidNodeCreateShape = require("./mermaidNodeCreateShape");
35
35
  var import_renderBlueprint = require("./renderBlueprint");
36
36
  (0, import_utils.registerTldrawLibraryVersion)(
37
37
  "@tldraw/mermaid",
38
- "5.5.0-next.b6a9f7cd7be2",
38
+ "5.5.0-next.c91b2de0a423",
39
39
  "cjs"
40
40
  );
41
41
  //# sourceMappingURL=index.js.map
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var mermaidNodeCreateShape_exports = {};
20
20
  __export(mermaidNodeCreateShape_exports, {
21
+ createLabelWidthMeasurer: () => createLabelWidthMeasurer,
21
22
  defaultCreateMermaidNodeFromBlueprint: () => defaultCreateMermaidNodeFromBlueprint
22
23
  });
23
24
  module.exports = __toCommonJS(mermaidNodeCreateShape_exports);
@@ -47,4 +48,26 @@ function defaultCreateMermaidNodeFromBlueprint(args) {
47
48
  });
48
49
  return editor.getShape(shapeId);
49
50
  }
51
+ function createLabelWidthMeasurer(editor) {
52
+ const util = editor.getShapeUtil("geo");
53
+ const defaultProps = util.getDefaultProps();
54
+ return (label, size) => {
55
+ const shape = { type: "geo", props: { ...defaultProps, size } };
56
+ const dv = (0, import_tldraw.getDisplayValues)(util, shape);
57
+ const richText = (0, import_tldraw.toRichText)((0, import_utils.sanitizeDiagramText)(label));
58
+ const { w } = editor.textMeasure.measureHtml(
59
+ (0, import_tldraw.renderHtmlFromRichTextForMeasurement)(editor, richText),
60
+ {
61
+ fontStyle: "normal",
62
+ fontWeight: "normal",
63
+ padding: "0px",
64
+ fontFamily: dv.labelFontFamily,
65
+ fontSize: dv.labelFontSize,
66
+ lineHeight: dv.labelLineHeight,
67
+ maxWidth: null
68
+ }
69
+ );
70
+ return Math.ceil(w + dv.labelPadding * 2);
71
+ };
72
+ }
50
73
  //# sourceMappingURL=mermaidNodeCreateShape.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/mermaidNodeCreateShape.ts"],
4
- "sourcesContent": ["import type { Editor, TLShape, TLShapeId } from 'tldraw'\nimport { toRichText } from 'tldraw'\nimport type {\n\tMermaidBlueprintNode,\n\tMermaidBlueprintNodeRenderSpec,\n\tMermaidDiagramKind,\n} from './blueprint'\nimport { sanitizeDiagramText } from './utils'\n\n/**\n * Arguments for {@link defaultCreateMermaidNodeFromBlueprint}. `x` / `y` are in shape space (parent-relative when\n * `parentShapeId` is set), matching {@link renderBlueprint}.\n * @public\n */\nexport interface MermaidNodeCreateFunctionArgs {\n\teditor: Editor\n\tnode: MermaidBlueprintNode\n\tshapeId: TLShapeId\n\tx: number\n\ty: number\n\tparentShapeId?: TLShapeId\n\tdiagramKind: MermaidDiagramKind\n\t/** Materialization spec (from {@link resolveMermaidNodeRender} or your mapper). */\n\trender: MermaidBlueprintNodeRenderSpec\n}\n\n/**\n * Creates the tldraw shape for one Mermaid blueprint node using `render` and layout-derived props.\n * @public\n */\nexport function defaultCreateMermaidNodeFromBlueprint(\n\targs: MermaidNodeCreateFunctionArgs\n): TLShape {\n\tconst { editor, node, shapeId, x, y, parentShapeId, render } = args\n\tconst baseProps = {\n\t\tw: node.w,\n\t\th: node.h,\n\t\tfill: node.fill ?? 'none',\n\t\tcolor: node.color ?? 'black',\n\t\tdash: node.dash ?? 'draw',\n\t\tsize: node.size ?? 'm',\n\t\t...(node.label && { richText: toRichText(sanitizeDiagramText(node.label)) }),\n\t\t...(node.align && { align: node.align }),\n\t\t...(node.verticalAlign && { verticalAlign: node.verticalAlign }),\n\t}\n\n\tconst { type, props } =\n\t\trender.variant === 'geo'\n\t\t\t? { type: 'geo', props: { geo: render.geo } }\n\t\t\t: { type: render.type, props: render.props }\n\teditor.createShape({\n\t\tid: shapeId,\n\t\ttype: type as any,\n\t\tx,\n\t\ty,\n\t\tparentId: parentShapeId,\n\t\tprops: { ...baseProps, ...props },\n\t})\n\treturn editor.getShape(shapeId)!\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAA2B;AAM3B,mBAAoC;AAuB7B,SAAS,sCACf,MACU;AACV,QAAM,EAAE,QAAQ,MAAM,SAAS,GAAG,GAAG,eAAe,OAAO,IAAI;AAC/D,QAAM,YAAY;AAAA,IACjB,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,MAAM,KAAK,QAAQ;AAAA,IACnB,OAAO,KAAK,SAAS;AAAA,IACrB,MAAM,KAAK,QAAQ;AAAA,IACnB,MAAM,KAAK,QAAQ;AAAA,IACnB,GAAI,KAAK,SAAS,EAAE,cAAU,8BAAW,kCAAoB,KAAK,KAAK,CAAC,EAAE;AAAA,IAC1E,GAAI,KAAK,SAAS,EAAE,OAAO,KAAK,MAAM;AAAA,IACtC,GAAI,KAAK,iBAAiB,EAAE,eAAe,KAAK,cAAc;AAAA,EAC/D;AAEA,QAAM,EAAE,MAAM,MAAM,IACnB,OAAO,YAAY,QAChB,EAAE,MAAM,OAAO,OAAO,EAAE,KAAK,OAAO,IAAI,EAAE,IAC1C,EAAE,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM;AAC7C,SAAO,YAAY;AAAA,IAClB,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,OAAO,EAAE,GAAG,WAAW,GAAG,MAAM;AAAA,EACjC,CAAC;AACD,SAAO,OAAO,SAAS,OAAO;AAC/B;",
4
+ "sourcesContent": ["import type { Editor, TLDefaultSizeStyle, TLGeoShape, TLShape, TLShapeId } from 'tldraw'\nimport {\n\tGeoShapeUtil,\n\tgetDisplayValues,\n\trenderHtmlFromRichTextForMeasurement,\n\ttoRichText,\n} from 'tldraw'\nimport type {\n\tMermaidBlueprintNode,\n\tMermaidBlueprintNodeRenderSpec,\n\tMermaidDiagramKind,\n} from './blueprint'\nimport { sanitizeDiagramText } from './utils'\n\n/**\n * Arguments for {@link defaultCreateMermaidNodeFromBlueprint}. `x` / `y` are in shape space (parent-relative when\n * `parentShapeId` is set), matching {@link renderBlueprint}.\n * @public\n */\nexport interface MermaidNodeCreateFunctionArgs {\n\teditor: Editor\n\tnode: MermaidBlueprintNode\n\tshapeId: TLShapeId\n\tx: number\n\ty: number\n\tparentShapeId?: TLShapeId\n\tdiagramKind: MermaidDiagramKind\n\t/** Materialization spec (from {@link resolveMermaidNodeRender} or your mapper). */\n\trender: MermaidBlueprintNodeRenderSpec\n}\n\n/**\n * Creates the tldraw shape for one Mermaid blueprint node using `render` and layout-derived props.\n * @public\n */\nexport function defaultCreateMermaidNodeFromBlueprint(\n\targs: MermaidNodeCreateFunctionArgs\n): TLShape {\n\tconst { editor, node, shapeId, x, y, parentShapeId, render } = args\n\tconst baseProps = {\n\t\tw: node.w,\n\t\th: node.h,\n\t\tfill: node.fill ?? 'none',\n\t\tcolor: node.color ?? 'black',\n\t\tdash: node.dash ?? 'draw',\n\t\tsize: node.size ?? 'm',\n\t\t...(node.label && { richText: toRichText(sanitizeDiagramText(node.label)) }),\n\t\t...(node.align && { align: node.align }),\n\t\t...(node.verticalAlign && { verticalAlign: node.verticalAlign }),\n\t}\n\n\tconst { type, props } =\n\t\trender.variant === 'geo'\n\t\t\t? { type: 'geo', props: { geo: render.geo } }\n\t\t\t: { type: render.type, props: render.props }\n\teditor.createShape({\n\t\tid: shapeId,\n\t\ttype: type as any,\n\t\tx,\n\t\ty,\n\t\tparentId: parentShapeId,\n\t\tprops: { ...baseProps, ...props },\n\t})\n\treturn editor.getShape(shapeId)!\n}\n\n/** The width a geo shape needs to hold a label without wrapping any of its lines. */\nexport type MeasureLabelWidth = (label: string, size: TLDefaultSizeStyle) => number\n\n/**\n * Measures labels the way {@link defaultCreateMermaidNodeFromBlueprint} draws them: in a geo shape,\n * in tldraw's font. Mermaid measures its own font, so a box sized from mermaid's layout alone can be\n * too narrow for the same text.\n */\nexport function createLabelWidthMeasurer(editor: Editor): MeasureLabelWidth {\n\tconst util = editor.getShapeUtil<GeoShapeUtil>('geo')\n\tconst defaultProps = util.getDefaultProps()\n\treturn (label, size) => {\n\t\tconst shape = { type: 'geo', props: { ...defaultProps, size } } as TLGeoShape\n\t\tconst dv = getDisplayValues(util, shape)\n\t\tconst richText = toRichText(sanitizeDiagramText(label))\n\t\tconst { w } = editor.textMeasure.measureHtml(\n\t\t\trenderHtmlFromRichTextForMeasurement(editor, richText),\n\t\t\t{\n\t\t\t\tfontStyle: 'normal',\n\t\t\t\tfontWeight: 'normal',\n\t\t\t\tpadding: '0px',\n\t\t\t\tfontFamily: dv.labelFontFamily,\n\t\t\t\tfontSize: dv.labelFontSize,\n\t\t\t\tlineHeight: dv.labelLineHeight,\n\t\t\t\tmaxWidth: null,\n\t\t\t}\n\t\t)\n\t\treturn Math.ceil(w + dv.labelPadding * 2)\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAKO;AAMP,mBAAoC;AAuB7B,SAAS,sCACf,MACU;AACV,QAAM,EAAE,QAAQ,MAAM,SAAS,GAAG,GAAG,eAAe,OAAO,IAAI;AAC/D,QAAM,YAAY;AAAA,IACjB,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,MAAM,KAAK,QAAQ;AAAA,IACnB,OAAO,KAAK,SAAS;AAAA,IACrB,MAAM,KAAK,QAAQ;AAAA,IACnB,MAAM,KAAK,QAAQ;AAAA,IACnB,GAAI,KAAK,SAAS,EAAE,cAAU,8BAAW,kCAAoB,KAAK,KAAK,CAAC,EAAE;AAAA,IAC1E,GAAI,KAAK,SAAS,EAAE,OAAO,KAAK,MAAM;AAAA,IACtC,GAAI,KAAK,iBAAiB,EAAE,eAAe,KAAK,cAAc;AAAA,EAC/D;AAEA,QAAM,EAAE,MAAM,MAAM,IACnB,OAAO,YAAY,QAChB,EAAE,MAAM,OAAO,OAAO,EAAE,KAAK,OAAO,IAAI,EAAE,IAC1C,EAAE,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM;AAC7C,SAAO,YAAY;AAAA,IAClB,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,OAAO,EAAE,GAAG,WAAW,GAAG,MAAM;AAAA,EACjC,CAAC;AACD,SAAO,OAAO,SAAS,OAAO;AAC/B;AAUO,SAAS,yBAAyB,QAAmC;AAC3E,QAAM,OAAO,OAAO,aAA2B,KAAK;AACpD,QAAM,eAAe,KAAK,gBAAgB;AAC1C,SAAO,CAAC,OAAO,SAAS;AACvB,UAAM,QAAQ,EAAE,MAAM,OAAO,OAAO,EAAE,GAAG,cAAc,KAAK,EAAE;AAC9D,UAAM,SAAK,gCAAiB,MAAM,KAAK;AACvC,UAAM,eAAW,8BAAW,kCAAoB,KAAK,CAAC;AACtD,UAAM,EAAE,EAAE,IAAI,OAAO,YAAY;AAAA,UAChC,oDAAqC,QAAQ,QAAQ;AAAA,MACrD;AAAA,QACC,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,YAAY,GAAG;AAAA,QACf,UAAU,GAAG;AAAA,QACb,YAAY,GAAG;AAAA,QACf,UAAU;AAAA,MACX;AAAA,IACD;AACA,WAAO,KAAK,KAAK,IAAI,GAAG,eAAe,CAAC;AAAA,EACzC;AACD;",
6
6
  "names": []
7
7
  }
@@ -146,7 +146,9 @@ function createArrowFromEdge(editor, edge, shapeIds) {
146
146
  }
147
147
  const baseProps = {
148
148
  dash: edge.dash ?? "solid",
149
- size: edge.size ?? "s",
149
+ // Match the node default: an arrow's size also sets its label font, so a smaller edge labels
150
+ // itself in smaller text than the boxes it joins.
151
+ size: edge.size ?? "m",
150
152
  arrowheadEnd: edge.arrowheadEnd ?? "arrow",
151
153
  ...edge.arrowheadStart && { arrowheadStart: edge.arrowheadStart },
152
154
  color: edge.color ?? "black",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/renderBlueprint.ts"],
4
- "sourcesContent": ["import { createShapeId, Editor, IndexKey, TLLineShape, TLShapeId, toRichText, Vec } from 'tldraw'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintLineNode,\n\tMermaidBlueprintNode,\n\tMermaidNodeRenderMapper,\n} from './blueprint'\nimport { resolveMermaidNodeRender } from './defaultMermaidNodeRenderSpec'\nimport { defaultCreateMermaidNodeFromBlueprint } from './mermaidNodeCreateShape'\nimport { orderTopDown, sanitizeDiagramText } from './utils'\n\n/** @public */\nexport interface BlueprintRenderingOptions {\n\tcenterOnPosition?: boolean\n\tposition?: { x: number; y: number }\n\t/**\n\t * Return a custom {@link MermaidBlueprintNodeRenderSpec} per node, or `undefined` for package defaults.\n\t * Called from {@link renderBlueprint} for each node (after layout offsets are known).\n\t */\n\tmapNodeToRenderSpec?: MermaidNodeRenderMapper\n}\n\nconst defaultBlueprintRenderingOptions = {\n\tcenterOnPosition: true,\n}\n\n/** @public */\nexport function renderBlueprint(\n\teditor: Editor,\n\tblueprint: DiagramMermaidBlueprint,\n\topts?: BlueprintRenderingOptions\n) {\n\tconst options = { ...defaultBlueprintRenderingOptions, ...opts }\n\tconst { nodes, edges, lines, diagramKind } = blueprint\n\tconst mapper = options.mapNodeToRenderSpec\n\n\tconst bounds = computeBlueprintBounds(nodes, lines)\n\tconst center =\n\t\toptions.position ??\n\t\t(editor.user.getIsPasteAtCursorMode()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\tconst offsetX = options.centerOnPosition\n\t\t? center.x - (bounds.maxX + bounds.minX) / 2\n\t\t: center.x - bounds.minX\n\tconst offsetY = options.centerOnPosition\n\t\t? center.y - (bounds.maxY + bounds.minY) / 2\n\t\t: center.y - bounds.minY\n\n\tconst ordered = orderTopDown(\n\t\tnodes,\n\t\t(n) => n.id,\n\t\t(n) => n.parentId\n\t)\n\tconst nodeById = new Map(nodes.map((node) => [node.id, node]))\n\n\tconst shapeIds = new Map<string, TLShapeId>()\n\n\t// Lines first so nodes render on top (z-order = creation order in tldraw)\n\tfor (const line of lines ?? []) {\n\t\tconst lineId = createShapeId()\n\t\tshapeIds.set(line.id, lineId)\n\t\teditor.createShape<TLLineShape>({\n\t\t\tid: lineId,\n\t\t\ttype: 'line',\n\t\t\tx: offsetX + line.x,\n\t\t\ty: offsetY + line.y,\n\t\t\tprops: {\n\t\t\t\tdash: line.dash ?? 'solid',\n\t\t\t\tsize: line.size ?? 's',\n\t\t\t\tcolor: line.color ?? 'black',\n\t\t\t\tspline: 'line',\n\t\t\t\tpoints: {\n\t\t\t\t\ta1: { id: 'a1', index: 'a1' as IndexKey, x: 0, y: 0 },\n\t\t\t\t\ta2: { id: 'a2', index: 'a2' as IndexKey, x: line.endX ?? 0, y: line.endY },\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\tconst backgroundIds: TLShapeId[] = []\n\tfor (const node of ordered) {\n\t\tconst shapeId = createShapeId()\n\t\tshapeIds.set(node.id, shapeId)\n\t\tif (node.background) backgroundIds.push(shapeId)\n\n\t\tconst parent = node.parentId ? nodeById.get(node.parentId) : undefined\n\t\tconst parentShapeId = node.parentId ? shapeIds.get(node.parentId) : undefined\n\n\t\tdefaultCreateMermaidNodeFromBlueprint({\n\t\t\teditor,\n\t\t\tnode,\n\t\t\tshapeId,\n\t\t\tx: parent ? node.x - parent.x : offsetX + node.x,\n\t\t\ty: parent ? node.y - parent.y : offsetY + node.y,\n\t\t\tparentShapeId,\n\t\t\tdiagramKind,\n\t\t\trender: resolveMermaidNodeRender(diagramKind, node, mapper),\n\t\t})\n\t}\n\n\t// One call, so the background nodes keep the blueprint's order among themselves.\n\tif (backgroundIds.length > 0) editor.sendToBack(backgroundIds)\n\n\tconst arrowIds: TLShapeId[] = []\n\tfor (const edge of edges) {\n\t\tconst arrowId = createArrowFromEdge(editor, edge, shapeIds)\n\t\tif (arrowId) arrowIds.push(arrowId)\n\t}\n\n\t// Create sub-groups and track which shape IDs are consumed by a group\n\tconst groupedIds = new Set<TLShapeId>()\n\tconst topLevelIds: TLShapeId[] = []\n\tfor (const group of blueprint.groups ?? []) {\n\t\tconst members: TLShapeId[] = []\n\t\tfor (const blueprintId of group) {\n\t\t\tconst memberShapeId = shapeIds.get(blueprintId)\n\t\t\tif (memberShapeId) {\n\t\t\t\tmembers.push(memberShapeId)\n\t\t\t\tgroupedIds.add(memberShapeId)\n\t\t\t}\n\t\t}\n\t\tif (members.length > 0) topLevelIds.push(groupShapes(editor, members) ?? members[0])\n\t}\n\n\t// Collect ungrouped top-level IDs\n\tfor (const item of [...nodes.filter((node) => !node.parentId), ...(lines ?? [])]) {\n\t\tconst itemShapeId = shapeIds.get(item.id)\n\t\tif (itemShapeId && !groupedIds.has(itemShapeId)) topLevelIds.push(itemShapeId)\n\t}\n\ttopLevelIds.push(...arrowIds)\n\n\tconst rootShapeId = groupShapes(editor, topLevelIds)\n\tif (rootShapeId) {\n\t\tconst actualBounds = editor.getShapePageBounds(rootShapeId)\n\t\tif (actualBounds) {\n\t\t\tconst desiredX = options.centerOnPosition ? center.x - actualBounds.w / 2 : center.x\n\t\t\tconst desiredY = options.centerOnPosition ? center.y - actualBounds.h / 2 : center.y\n\t\t\tconst dx = desiredX - actualBounds.x\n\t\t\tconst dy = desiredY - actualBounds.y\n\t\t\tif (Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5) {\n\t\t\t\tconst shape = editor.getShape(rootShapeId)!\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: rootShapeId,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: shape.x + dx,\n\t\t\t\t\ty: shape.y + dy,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Group `ids` and return the group id (or the single id when there is only one).\n * Returns undefined when nothing was grouped, e.g. no ids or grouping failed.\n */\nfunction groupShapes(editor: Editor, ids: TLShapeId[]): TLShapeId | undefined {\n\tif (ids.length === 0) return undefined\n\tif (ids.length === 1) return ids[0]\n\tconst groupId = createShapeId()\n\teditor.groupShapes(ids, { groupId })\n\treturn editor.getShape(groupId) ? groupId : undefined\n}\n\ninterface ArrowTerminal {\n\tpoint: { x: number; y: number }\n\tanchor: { x: number; y: number }\n\tisExact: boolean\n\tisPrecise: boolean\n}\n\nfunction createArrowFromEdge(\n\teditor: Editor,\n\tedge: MermaidBlueprintEdge,\n\tshapeIds: Map<string, TLShapeId>\n): TLShapeId | undefined {\n\tconst startShapeId = shapeIds.get(edge.startNodeId)\n\tconst endShapeId = shapeIds.get(edge.endNodeId)\n\tif (!startShapeId || !endShapeId) return undefined\n\n\tconst startBounds = editor.getShapePageBounds(startShapeId)\n\tconst endBounds = editor.getShapePageBounds(endShapeId)\n\tif (!startBounds || !endBounds) return undefined\n\n\tlet labelText = edge.label\n\tif (edge.decoration?.type === 'autonumber') {\n\t\tconst num = edge.decoration.value\n\t\tlabelText = labelText ? `${num} ${labelText}` : num\n\t}\n\n\tconst baseProps = {\n\t\tdash: edge.dash ?? ('solid' as const),\n\t\tsize: edge.size ?? ('s' as const),\n\t\tarrowheadEnd: edge.arrowheadEnd ?? ('arrow' as const),\n\t\t...(edge.arrowheadStart && { arrowheadStart: edge.arrowheadStart }),\n\t\tcolor: edge.color ?? ('black' as const),\n\t\t...(labelText && { richText: toRichText(sanitizeDiagramText(labelText)) }),\n\t}\n\n\tlet origin: { x: number; y: number }\n\tlet start: ArrowTerminal\n\tlet end: ArrowTerminal\n\tlet bend = edge.bend\n\n\tif (\n\t\tedge.anchorStartX !== undefined ||\n\t\tedge.anchorStartY !== undefined ||\n\t\tedge.anchorEndX !== undefined ||\n\t\tedge.anchorEndY !== undefined\n\t) {\n\t\tconst startAnchor = { x: edge.anchorStartX ?? 0.5, y: edge.anchorStartY ?? 0.5 }\n\t\tconst endAnchor = { x: edge.anchorEndX ?? 0.5, y: edge.anchorEndY ?? 0.5 }\n\t\tconst isExact = edge.isExact ?? true\n\t\tconst isPrecise = edge.isPrecise ?? true\n\t\tstart = {\n\t\t\tpoint: {\n\t\t\t\tx: startBounds.x + startBounds.w * startAnchor.x,\n\t\t\t\ty: startBounds.y + startBounds.h * startAnchor.y,\n\t\t\t},\n\t\t\tanchor: startAnchor,\n\t\t\tisExact,\n\t\t\tisPrecise,\n\t\t}\n\t\tend = {\n\t\t\tpoint: {\n\t\t\t\tx: endBounds.x + endBounds.w * endAnchor.x,\n\t\t\t\ty: endBounds.y + endBounds.h * endAnchor.y,\n\t\t\t},\n\t\t\tanchor: endAnchor,\n\t\t\tisExact: edge.isExactEnd ?? isExact,\n\t\t\tisPrecise: edge.isPreciseEnd ?? isPrecise,\n\t\t}\n\t\torigin = Vec.Min(start.point, end.point)\n\t} else if (startShapeId === endShapeId) {\n\t\torigin = { x: startBounds.x, y: startBounds.y }\n\t\tstart = {\n\t\t\tpoint: { x: startBounds.midX, y: startBounds.y },\n\t\t\tanchor: { x: 0.9, y: 0.5 },\n\t\t\tisExact: false,\n\t\t\tisPrecise: false,\n\t\t}\n\t\tend = {\n\t\t\tpoint: { x: startBounds.maxX, y: startBounds.midY },\n\t\t\tanchor: { x: 0.85, y: 0.8 },\n\t\t\tisExact: false,\n\t\t\tisPrecise: false,\n\t\t}\n\t\tbend = -80\n\t} else {\n\t\tstart = {\n\t\t\tpoint: startBounds.center,\n\t\t\tanchor: { x: 0.5, y: 0.5 },\n\t\t\tisExact: false,\n\t\t\tisPrecise: false,\n\t\t}\n\t\tend = { point: endBounds.center, anchor: { x: 0.5, y: 0.5 }, isExact: false, isPrecise: false }\n\t\torigin = Vec.Min(start.point, end.point)\n\t}\n\n\tconst arrowId = createShapeId()\n\teditor.run(() => {\n\t\teditor.createShape({\n\t\t\tid: arrowId,\n\t\t\ttype: 'arrow',\n\t\t\tx: origin.x,\n\t\t\ty: origin.y,\n\t\t\tprops: {\n\t\t\t\t...baseProps,\n\t\t\t\tstart: { x: start.point.x - origin.x, y: start.point.y - origin.y },\n\t\t\t\tend: { x: end.point.x - origin.x, y: end.point.y - origin.y },\n\t\t\t\tbend,\n\t\t\t},\n\t\t})\n\t\teditor.createBindings([\n\t\t\tmakeArrowBinding(arrowId, startShapeId, 'start', start),\n\t\t\tmakeArrowBinding(arrowId, endShapeId, 'end', end),\n\t\t])\n\t})\n\treturn arrowId\n}\n\nfunction makeArrowBinding(\n\tarrowId: TLShapeId,\n\ttargetId: TLShapeId,\n\tterminal: 'start' | 'end',\n\t{ anchor, isExact, isPrecise }: ArrowTerminal\n) {\n\treturn {\n\t\tfromId: arrowId,\n\t\ttoId: targetId,\n\t\ttype: 'arrow' as const,\n\t\tprops: { terminal, normalizedAnchor: anchor, isExact, isPrecise },\n\t}\n}\n\nfunction computeBlueprintBounds(\n\tnodes: MermaidBlueprintNode[],\n\tlines?: MermaidBlueprintLineNode[]\n): { minX: number; minY: number; maxX: number; maxY: number } {\n\tlet minX = Infinity\n\tlet minY = Infinity\n\tlet maxX = -Infinity\n\tlet maxY = -Infinity\n\tfor (const node of nodes) {\n\t\tif (node.parentId) continue\n\t\tminX = Math.min(minX, node.x)\n\t\tminY = Math.min(minY, node.y)\n\t\tmaxX = Math.max(maxX, node.x + node.w)\n\t\tmaxY = Math.max(maxY, node.y + node.h)\n\t}\n\tfor (const line of lines ?? []) {\n\t\tminX = Math.min(minX, line.x)\n\t\tminY = Math.min(minY, line.y)\n\t\tmaxX = Math.max(maxX, line.x)\n\t\tmaxY = Math.max(maxY, line.y + line.endY)\n\t}\n\treturn { minX, minY, maxX, maxY }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createShapeId, Editor, IndexKey, TLLineShape, TLShapeId, toRichText, Vec } from 'tldraw'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintLineNode,\n\tMermaidBlueprintNode,\n\tMermaidNodeRenderMapper,\n} from './blueprint'\nimport { resolveMermaidNodeRender } from './defaultMermaidNodeRenderSpec'\nimport { defaultCreateMermaidNodeFromBlueprint } from './mermaidNodeCreateShape'\nimport { orderTopDown, sanitizeDiagramText } from './utils'\n\n/** @public */\nexport interface BlueprintRenderingOptions {\n\tcenterOnPosition?: boolean\n\tposition?: { x: number; y: number }\n\t/**\n\t * Return a custom {@link MermaidBlueprintNodeRenderSpec} per node, or `undefined` for package defaults.\n\t * Called from {@link renderBlueprint} for each node (after layout offsets are known).\n\t */\n\tmapNodeToRenderSpec?: MermaidNodeRenderMapper\n}\n\nconst defaultBlueprintRenderingOptions = {\n\tcenterOnPosition: true,\n}\n\n/** @public */\nexport function renderBlueprint(\n\teditor: Editor,\n\tblueprint: DiagramMermaidBlueprint,\n\topts?: BlueprintRenderingOptions\n) {\n\tconst options = { ...defaultBlueprintRenderingOptions, ...opts }\n\tconst { nodes, edges, lines, diagramKind } = blueprint\n\tconst mapper = options.mapNodeToRenderSpec\n\n\tconst bounds = computeBlueprintBounds(nodes, lines)\n\tconst center =\n\t\toptions.position ??\n\t\t(editor.user.getIsPasteAtCursorMode()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\tconst offsetX = options.centerOnPosition\n\t\t? center.x - (bounds.maxX + bounds.minX) / 2\n\t\t: center.x - bounds.minX\n\tconst offsetY = options.centerOnPosition\n\t\t? center.y - (bounds.maxY + bounds.minY) / 2\n\t\t: center.y - bounds.minY\n\n\tconst ordered = orderTopDown(\n\t\tnodes,\n\t\t(n) => n.id,\n\t\t(n) => n.parentId\n\t)\n\tconst nodeById = new Map(nodes.map((node) => [node.id, node]))\n\n\tconst shapeIds = new Map<string, TLShapeId>()\n\n\t// Lines first so nodes render on top (z-order = creation order in tldraw)\n\tfor (const line of lines ?? []) {\n\t\tconst lineId = createShapeId()\n\t\tshapeIds.set(line.id, lineId)\n\t\teditor.createShape<TLLineShape>({\n\t\t\tid: lineId,\n\t\t\ttype: 'line',\n\t\t\tx: offsetX + line.x,\n\t\t\ty: offsetY + line.y,\n\t\t\tprops: {\n\t\t\t\tdash: line.dash ?? 'solid',\n\t\t\t\tsize: line.size ?? 's',\n\t\t\t\tcolor: line.color ?? 'black',\n\t\t\t\tspline: 'line',\n\t\t\t\tpoints: {\n\t\t\t\t\ta1: { id: 'a1', index: 'a1' as IndexKey, x: 0, y: 0 },\n\t\t\t\t\ta2: { id: 'a2', index: 'a2' as IndexKey, x: line.endX ?? 0, y: line.endY },\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\tconst backgroundIds: TLShapeId[] = []\n\tfor (const node of ordered) {\n\t\tconst shapeId = createShapeId()\n\t\tshapeIds.set(node.id, shapeId)\n\t\tif (node.background) backgroundIds.push(shapeId)\n\n\t\tconst parent = node.parentId ? nodeById.get(node.parentId) : undefined\n\t\tconst parentShapeId = node.parentId ? shapeIds.get(node.parentId) : undefined\n\n\t\tdefaultCreateMermaidNodeFromBlueprint({\n\t\t\teditor,\n\t\t\tnode,\n\t\t\tshapeId,\n\t\t\tx: parent ? node.x - parent.x : offsetX + node.x,\n\t\t\ty: parent ? node.y - parent.y : offsetY + node.y,\n\t\t\tparentShapeId,\n\t\t\tdiagramKind,\n\t\t\trender: resolveMermaidNodeRender(diagramKind, node, mapper),\n\t\t})\n\t}\n\n\t// One call, so the background nodes keep the blueprint's order among themselves.\n\tif (backgroundIds.length > 0) editor.sendToBack(backgroundIds)\n\n\tconst arrowIds: TLShapeId[] = []\n\tfor (const edge of edges) {\n\t\tconst arrowId = createArrowFromEdge(editor, edge, shapeIds)\n\t\tif (arrowId) arrowIds.push(arrowId)\n\t}\n\n\t// Create sub-groups and track which shape IDs are consumed by a group\n\tconst groupedIds = new Set<TLShapeId>()\n\tconst topLevelIds: TLShapeId[] = []\n\tfor (const group of blueprint.groups ?? []) {\n\t\tconst members: TLShapeId[] = []\n\t\tfor (const blueprintId of group) {\n\t\t\tconst memberShapeId = shapeIds.get(blueprintId)\n\t\t\tif (memberShapeId) {\n\t\t\t\tmembers.push(memberShapeId)\n\t\t\t\tgroupedIds.add(memberShapeId)\n\t\t\t}\n\t\t}\n\t\tif (members.length > 0) topLevelIds.push(groupShapes(editor, members) ?? members[0])\n\t}\n\n\t// Collect ungrouped top-level IDs\n\tfor (const item of [...nodes.filter((node) => !node.parentId), ...(lines ?? [])]) {\n\t\tconst itemShapeId = shapeIds.get(item.id)\n\t\tif (itemShapeId && !groupedIds.has(itemShapeId)) topLevelIds.push(itemShapeId)\n\t}\n\ttopLevelIds.push(...arrowIds)\n\n\tconst rootShapeId = groupShapes(editor, topLevelIds)\n\tif (rootShapeId) {\n\t\tconst actualBounds = editor.getShapePageBounds(rootShapeId)\n\t\tif (actualBounds) {\n\t\t\tconst desiredX = options.centerOnPosition ? center.x - actualBounds.w / 2 : center.x\n\t\t\tconst desiredY = options.centerOnPosition ? center.y - actualBounds.h / 2 : center.y\n\t\t\tconst dx = desiredX - actualBounds.x\n\t\t\tconst dy = desiredY - actualBounds.y\n\t\t\tif (Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5) {\n\t\t\t\tconst shape = editor.getShape(rootShapeId)!\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: rootShapeId,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: shape.x + dx,\n\t\t\t\t\ty: shape.y + dy,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Group `ids` and return the group id (or the single id when there is only one).\n * Returns undefined when nothing was grouped, e.g. no ids or grouping failed.\n */\nfunction groupShapes(editor: Editor, ids: TLShapeId[]): TLShapeId | undefined {\n\tif (ids.length === 0) return undefined\n\tif (ids.length === 1) return ids[0]\n\tconst groupId = createShapeId()\n\teditor.groupShapes(ids, { groupId })\n\treturn editor.getShape(groupId) ? groupId : undefined\n}\n\ninterface ArrowTerminal {\n\tpoint: { x: number; y: number }\n\tanchor: { x: number; y: number }\n\tisExact: boolean\n\tisPrecise: boolean\n}\n\nfunction createArrowFromEdge(\n\teditor: Editor,\n\tedge: MermaidBlueprintEdge,\n\tshapeIds: Map<string, TLShapeId>\n): TLShapeId | undefined {\n\tconst startShapeId = shapeIds.get(edge.startNodeId)\n\tconst endShapeId = shapeIds.get(edge.endNodeId)\n\tif (!startShapeId || !endShapeId) return undefined\n\n\tconst startBounds = editor.getShapePageBounds(startShapeId)\n\tconst endBounds = editor.getShapePageBounds(endShapeId)\n\tif (!startBounds || !endBounds) return undefined\n\n\tlet labelText = edge.label\n\tif (edge.decoration?.type === 'autonumber') {\n\t\tconst num = edge.decoration.value\n\t\tlabelText = labelText ? `${num} ${labelText}` : num\n\t}\n\n\tconst baseProps = {\n\t\tdash: edge.dash ?? ('solid' as const),\n\t\t// Match the node default: an arrow's size also sets its label font, so a smaller edge labels\n\t\t// itself in smaller text than the boxes it joins.\n\t\tsize: edge.size ?? ('m' as const),\n\t\tarrowheadEnd: edge.arrowheadEnd ?? ('arrow' as const),\n\t\t...(edge.arrowheadStart && { arrowheadStart: edge.arrowheadStart }),\n\t\tcolor: edge.color ?? ('black' as const),\n\t\t...(labelText && { richText: toRichText(sanitizeDiagramText(labelText)) }),\n\t}\n\n\tlet origin: { x: number; y: number }\n\tlet start: ArrowTerminal\n\tlet end: ArrowTerminal\n\tlet bend = edge.bend\n\n\tif (\n\t\tedge.anchorStartX !== undefined ||\n\t\tedge.anchorStartY !== undefined ||\n\t\tedge.anchorEndX !== undefined ||\n\t\tedge.anchorEndY !== undefined\n\t) {\n\t\tconst startAnchor = { x: edge.anchorStartX ?? 0.5, y: edge.anchorStartY ?? 0.5 }\n\t\tconst endAnchor = { x: edge.anchorEndX ?? 0.5, y: edge.anchorEndY ?? 0.5 }\n\t\tconst isExact = edge.isExact ?? true\n\t\tconst isPrecise = edge.isPrecise ?? true\n\t\tstart = {\n\t\t\tpoint: {\n\t\t\t\tx: startBounds.x + startBounds.w * startAnchor.x,\n\t\t\t\ty: startBounds.y + startBounds.h * startAnchor.y,\n\t\t\t},\n\t\t\tanchor: startAnchor,\n\t\t\tisExact,\n\t\t\tisPrecise,\n\t\t}\n\t\tend = {\n\t\t\tpoint: {\n\t\t\t\tx: endBounds.x + endBounds.w * endAnchor.x,\n\t\t\t\ty: endBounds.y + endBounds.h * endAnchor.y,\n\t\t\t},\n\t\t\tanchor: endAnchor,\n\t\t\tisExact: edge.isExactEnd ?? isExact,\n\t\t\tisPrecise: edge.isPreciseEnd ?? isPrecise,\n\t\t}\n\t\torigin = Vec.Min(start.point, end.point)\n\t} else if (startShapeId === endShapeId) {\n\t\torigin = { x: startBounds.x, y: startBounds.y }\n\t\tstart = {\n\t\t\tpoint: { x: startBounds.midX, y: startBounds.y },\n\t\t\tanchor: { x: 0.9, y: 0.5 },\n\t\t\tisExact: false,\n\t\t\tisPrecise: false,\n\t\t}\n\t\tend = {\n\t\t\tpoint: { x: startBounds.maxX, y: startBounds.midY },\n\t\t\tanchor: { x: 0.85, y: 0.8 },\n\t\t\tisExact: false,\n\t\t\tisPrecise: false,\n\t\t}\n\t\tbend = -80\n\t} else {\n\t\tstart = {\n\t\t\tpoint: startBounds.center,\n\t\t\tanchor: { x: 0.5, y: 0.5 },\n\t\t\tisExact: false,\n\t\t\tisPrecise: false,\n\t\t}\n\t\tend = { point: endBounds.center, anchor: { x: 0.5, y: 0.5 }, isExact: false, isPrecise: false }\n\t\torigin = Vec.Min(start.point, end.point)\n\t}\n\n\tconst arrowId = createShapeId()\n\teditor.run(() => {\n\t\teditor.createShape({\n\t\t\tid: arrowId,\n\t\t\ttype: 'arrow',\n\t\t\tx: origin.x,\n\t\t\ty: origin.y,\n\t\t\tprops: {\n\t\t\t\t...baseProps,\n\t\t\t\tstart: { x: start.point.x - origin.x, y: start.point.y - origin.y },\n\t\t\t\tend: { x: end.point.x - origin.x, y: end.point.y - origin.y },\n\t\t\t\tbend,\n\t\t\t},\n\t\t})\n\t\teditor.createBindings([\n\t\t\tmakeArrowBinding(arrowId, startShapeId, 'start', start),\n\t\t\tmakeArrowBinding(arrowId, endShapeId, 'end', end),\n\t\t])\n\t})\n\treturn arrowId\n}\n\nfunction makeArrowBinding(\n\tarrowId: TLShapeId,\n\ttargetId: TLShapeId,\n\tterminal: 'start' | 'end',\n\t{ anchor, isExact, isPrecise }: ArrowTerminal\n) {\n\treturn {\n\t\tfromId: arrowId,\n\t\ttoId: targetId,\n\t\ttype: 'arrow' as const,\n\t\tprops: { terminal, normalizedAnchor: anchor, isExact, isPrecise },\n\t}\n}\n\nfunction computeBlueprintBounds(\n\tnodes: MermaidBlueprintNode[],\n\tlines?: MermaidBlueprintLineNode[]\n): { minX: number; minY: number; maxX: number; maxY: number } {\n\tlet minX = Infinity\n\tlet minY = Infinity\n\tlet maxX = -Infinity\n\tlet maxY = -Infinity\n\tfor (const node of nodes) {\n\t\tif (node.parentId) continue\n\t\tminX = Math.min(minX, node.x)\n\t\tminY = Math.min(minY, node.y)\n\t\tmaxX = Math.max(maxX, node.x + node.w)\n\t\tmaxY = Math.max(maxY, node.y + node.h)\n\t}\n\tfor (const line of lines ?? []) {\n\t\tminX = Math.min(minX, line.x)\n\t\tminY = Math.min(minY, line.y)\n\t\tmaxX = Math.max(maxX, line.x)\n\t\tmaxY = Math.max(maxY, line.y + line.endY)\n\t}\n\treturn { minX, minY, maxX, maxY }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -162,9 +162,6 @@ const FALLBACK_EVENT_SPACING = 80;
162
162
  const FALLBACK_NOTE_WIDTH = 120;
163
163
  const FALLBACK_NOTE_HEIGHT = 50;
164
164
  const NOTE_PADDING = 5;
165
- const NOTE_CHAR_WIDTH = 11;
166
- const NOTE_TEXT_PADDING = 40;
167
- const NOTE_LINE_BREAK = /<br\s*\/?>|\n/i;
168
165
  const FRAGMENT_PADDING_X = 30;
169
166
  const FRAGMENT_PADDING_TOP = 50;
170
167
  const FRAGMENT_PADDING_BOTTOM = 25;
@@ -299,24 +296,24 @@ function computeActorLayouts(root, actorCount, eventCount) {
299
296
  const scale = Math.max(1, TARGET_ACTOR_SPACING / minSpacing);
300
297
  const xCenters = svgCenters.map((c) => (c - svgCenters[0]) * scale);
301
298
  const totalSpan = xCenters.length > 1 ? xCenters[xCenters.length - 1] : 0;
302
- const topRowBottom = Math.max(...top.map((r) => r.y + r.h));
303
- const bottomRowTop = Math.min(...bottom.map((r) => r.y));
304
- const yStretch = Math.max(0, MIN_VERTICAL_GAP - (bottomRowTop - topRowBottom));
299
+ const headerBottom = Math.min(...top.map((r) => r.y + r.h));
300
+ const footerTop = Math.max(...bottom.map((r) => r.y));
301
+ const yStretch = Math.max(0, MIN_VERTICAL_GAP - (footerTop - headerBottom));
305
302
  const topMinY = Math.min(...top.map((r) => r.y));
306
303
  const bottomMaxY = Math.max(...bottom.map((r) => r.y + r.h));
307
304
  const originY = -(bottomMaxY + yStretch + topMinY) / 2;
308
- const headerBottom = Math.min(...top.map((r) => r.y + r.h));
309
- const footerTop = Math.max(...bottom.map((r) => r.y));
310
305
  const toLayoutY = (svgY) => originY + svgY + (footerTop > headerBottom ? yStretch * (0, import_tldraw.clamp)((0, import_utils.invLerp)(headerBottom, footerTop, svgY), 0, 1) : 0);
311
306
  const actorLayouts = top.map((topRect, i) => {
312
307
  const w = topRect.w + ACTOR_PADDING_WIDTH;
313
308
  const h = topRect.h + ACTOR_PADDING_HEIGHT;
314
309
  return {
315
310
  x: xCenters[i] - totalSpan / 2 - w / 2,
316
- y: originY + topRect.y,
311
+ // Through `toLayoutY` so a created or destroyed participant's mid-diagram box takes
312
+ // the same share of the stretch as the row it sits on, rather than all of it or none.
313
+ y: toLayoutY(topRect.y),
317
314
  w,
318
315
  h,
319
- bottomY: originY + bottom[i].y + yStretch
316
+ bottomY: toLayoutY(bottom[i].y)
320
317
  };
321
318
  });
322
319
  return { actorLayouts, toLayoutY };
@@ -393,6 +390,21 @@ function parseFragmentFrames(root, toLayoutY) {
393
390
  }
394
391
  return frames;
395
392
  }
393
+ function getActorLabel(actors, key) {
394
+ const actor = actors.get(key);
395
+ return actor?.description || actor?.name || key;
396
+ }
397
+ function fitActorsToLabels(layouts, labels, measureLabelWidth) {
398
+ let shift = 0;
399
+ let previousGrowth = 0;
400
+ return layouts.map((layout, i) => {
401
+ const w = Math.max(layout.w, measureLabelWidth(labels[i], "s"));
402
+ const growth = w - layout.w;
403
+ shift += (previousGrowth + growth) / 2;
404
+ previousGrowth = growth;
405
+ return { ...layout, x: layout.x + shift - growth / 2, w };
406
+ });
407
+ }
396
408
  function getMessageLabel(msg) {
397
409
  return typeof msg.message === "string" ? msg.message : void 0;
398
410
  }
@@ -408,7 +420,7 @@ function parseSequenceLayout(root, actorCount, eventCount) {
408
420
  fragmentFrames: toLayoutY ? parseFragmentFrames(root, toLayoutY) : /* @__PURE__ */ new Map()
409
421
  };
410
422
  }
411
- function sequenceToBlueprint(layout, actors, actorKeys, messages, createdActors = /* @__PURE__ */ new Map(), destroyedActors = /* @__PURE__ */ new Map()) {
423
+ function sequenceToBlueprint(layout, actors, actorKeys, messages, createdActors = /* @__PURE__ */ new Map(), destroyedActors = /* @__PURE__ */ new Map(), measureLabelWidth = () => 0) {
412
424
  const actorCount = actorKeys.length;
413
425
  if (actorCount === 0)
414
426
  return { diagramKind: "sequence", nodes: [], edges: [], lines: [], groups: [] };
@@ -510,7 +522,11 @@ function sequenceToBlueprint(layout, actors, actorKeys, messages, createdActors
510
522
  eventAutonumbers.push(isSignal && autonumberVisible ? String(autonumber) : void 0);
511
523
  if (isSignal) autonumber = Math.round((autonumber + autonumberStep) * 100) / 100;
512
524
  }
513
- const layouts = layout.actorLayouts;
525
+ const layouts = fitActorsToLabels(
526
+ layout.actorLayouts,
527
+ actorKeys.map((key) => getActorLabel(actors, key)),
528
+ measureLabelWidth
529
+ );
514
530
  const svgNoteRects = layout.noteRects;
515
531
  let svgNoteIndex = 0;
516
532
  const nodes = [];
@@ -672,7 +688,7 @@ function sequenceToBlueprint(layout, actors, actorKeys, messages, createdActors
672
688
  const { topBoxY, bottomBoxY } = lifecycles[i];
673
689
  const shared = {
674
690
  kind: actor.type,
675
- label: actor.description || actor.name || key,
691
+ label: getActorLabel(actors, key),
676
692
  x,
677
693
  w,
678
694
  h,
@@ -741,9 +757,10 @@ function sequenceToBlueprint(layout, actors, actorKeys, messages, createdActors
741
757
  const isSpanning = msgPlacement === PLACEMENT.OVER && msg.from !== msg.to && toIdx !== void 0;
742
758
  const svgNote = svgNoteRects[svgNoteIndex++];
743
759
  const noteHeight = svgNote?.h ?? FALLBACK_NOTE_HEIGHT;
744
- const longestLine = label ? Math.max(...label.split(NOTE_LINE_BREAK).map((line) => line.trim().length)) : 0;
745
- const textWidth = longestLine ? longestLine * NOTE_CHAR_WIDTH + NOTE_TEXT_PADDING : 0;
746
- const baseWidth = Math.max(svgNote?.w ?? FALLBACK_NOTE_WIDTH, textWidth);
760
+ const baseWidth = Math.max(
761
+ svgNote?.w ?? FALLBACK_NOTE_WIDTH,
762
+ label ? measureLabelWidth(label, "s") : 0
763
+ );
747
764
  const noteWidth = isSpanning ? Math.max(baseWidth, Math.abs(toCenterX - fromCenterX) + NOTE_PADDING) : baseWidth;
748
765
  let noteX;
749
766
  if (msgPlacement === PLACEMENT.LEFTOF) {