@zombie-mermaid/svg-renderer 3.1.0 → 4.0.0

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 (50) hide show
  1. package/dist/index.cjs +49 -39
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +54 -4
  4. package/dist/index.d.ts +54 -4
  5. package/dist/index.js +2779 -1097
  6. package/dist/index.js.map +1 -1
  7. package/package.json +3 -3
  8. package/src/__tests__/c4-label-clearance-1290.test.ts +112 -0
  9. package/src/__tests__/c4-line-ends-1208.test.ts +52 -0
  10. package/src/__tests__/c4-mermaid-reference.test.ts +124 -0
  11. package/src/__tests__/c4-svg.test.ts +337 -0
  12. package/src/__tests__/c4-text-width-1210.test.ts +43 -0
  13. package/src/__tests__/class-component-order-1249.test.ts +40 -0
  14. package/src/__tests__/class-diamond-markers-1232.test.ts +59 -0
  15. package/src/__tests__/class-member-right-padding-1238.test.ts +43 -0
  16. package/src/__tests__/class-namespace-1196.test.ts +165 -0
  17. package/src/__tests__/class-namespace-sparse-elk-1196.test.ts +96 -0
  18. package/src/__tests__/class-visibility-markers-1237.test.ts +27 -0
  19. package/src/__tests__/er-attribute-right-padding-1262.test.ts +47 -0
  20. package/src/__tests__/er-cardinality-markers-1233.test.ts +35 -0
  21. package/src/__tests__/er-default-direction-1250.test.ts +69 -0
  22. package/src/__tests__/er-edge-label-contrast-1244.test.ts +58 -0
  23. package/src/__tests__/fixtures/c4-mermaid-reference.json +626 -0
  24. package/src/__tests__/sequence-label-clearance-1242.test.ts +162 -0
  25. package/src/__tests__/sequence-nested-activation-1241.test.ts +37 -0
  26. package/src/__tests__/xychart-smooth-curve.test.ts +42 -0
  27. package/src/__tests__/xychart-x-label-overlap-1243.test.ts +62 -0
  28. package/src/c4/arial-widths.ts +59 -0
  29. package/src/c4/layout.ts +680 -0
  30. package/src/c4/metrics.ts +261 -0
  31. package/src/c4/renderer.ts +366 -0
  32. package/src/class/layout.ts +178 -13
  33. package/src/class/renderer.ts +38 -8
  34. package/src/er/layout.ts +20 -4
  35. package/src/er/renderer.ts +24 -2
  36. package/src/layout-engine/back-edges.ts +73 -0
  37. package/src/layout-engine/compound-flat.ts +916 -0
  38. package/src/layout-engine/elk-graph-builder.ts +9 -4
  39. package/src/layout-engine/from-elk.ts +7 -2
  40. package/src/layout-engine/inner-edges.ts +329 -0
  41. package/src/layout-engine/layout-hints.ts +27 -0
  42. package/src/layout-engine/to-elk.ts +170 -20
  43. package/src/layout-engine.ts +38 -1
  44. package/src/registry.ts +62 -2
  45. package/src/renderer.ts +26 -2
  46. package/src/sequence/layout.ts +72 -4
  47. package/src/sequence/renderer.ts +155 -15
  48. package/src/title-gaps.ts +146 -0
  49. package/src/xychart/layout.ts +58 -13
  50. package/src/xychart/renderer.ts +34 -42
package/dist/index.d.cts CHANGED
@@ -26,6 +26,13 @@ import { SvgEmitOptions } from '@zombie-mermaid/core';
26
26
  import { XYChart } from '@zombie-mermaid/mermaid-parser';
27
27
  import { XyChartRenderOptions } from '@zombie-mermaid/core';
28
28
 
29
+ /**
30
+ * Distance from the bottom of a stick-figure (`actor`) icon to the vertical
31
+ * centre of its label. Shared with the renderer so the label lands where the
32
+ * layout reserved room for it.
33
+ */
34
+ export declare const ACTOR_LABEL_OFFSET = 14;
35
+
29
36
  /** Arrow head dimensions — matches spec: 8px wide × ~5px tall */
30
37
  export declare const ARROW_HEAD: {
31
38
  readonly width: 8;
@@ -122,6 +129,11 @@ export declare const CLS: {
122
129
  /** Horizontal / vertical padding inside a note box, around its text */
123
130
  readonly notePadX: 10;
124
131
  readonly notePadY: 6;
132
+ /** Space reserved above a namespace's classes for its title */
133
+ readonly namespaceTitleHeight: 28;
134
+ /** Padding between a namespace frame and its classes (other three sides) */
135
+ readonly namespacePad: 16;
136
+ readonly namespaceTitleFontSize: 12;
125
137
  };
126
138
 
127
139
  /**
@@ -168,10 +180,14 @@ export declare function directionToElk(dir: Direction | undefined, fallback: Elk
168
180
  * single fixed orientation, matching Mermaid's own TB class rendering —
169
181
  * which `../class/layout.ts` relies on to put a `note for X` above its
170
182
  * class.
171
- * - **ER** — `RIGHT`. An ER diagram's `direction` is optional
183
+ * - **C4** — `DOWN`. `C4Diagram.direction` is never set by the parser (C4
184
+ * sources have no direction statement), only by `RenderOptions.direction`,
185
+ * so an unset one is the top-down layout every C4 diagram is drawn in.
186
+ * - **ER** — `DOWN`. An ER diagram's `direction` is optional
172
187
  * (`ErDiagram.direction?`), left `undefined` when the source has no
173
- * `direction` statement, and this renderer has always laid those out
174
- * left-to-right. `direction TB`/`LR`/`BT`/`RL` in the source (or
188
+ * `direction` statement, and official Mermaid lays those out top-to-bottom
189
+ * (#1250; this renderer used to lay them out left-to-right).
190
+ * `direction TB`/`LR`/`BT`/`RL` in the source (or
175
191
  * `RenderOptions.direction`, applied via `withDirectionOverride`) still
176
192
  * wins over it.
177
193
  *
@@ -185,7 +201,8 @@ export declare const ELK_DIRECTION_FALLBACK: {
185
201
  readonly flowchart: "DOWN";
186
202
  readonly state: "DOWN";
187
203
  readonly class: "DOWN";
188
- readonly er: "RIGHT";
204
+ readonly er: "DOWN";
205
+ readonly c4: "DOWN";
189
206
  };
190
207
 
191
208
  /** The four values ELK's `elk.direction` option accepts in this codebase. */
@@ -304,6 +321,14 @@ export declare type FontSizes = {
304
321
  [K in keyof typeof FONT_SIZES]: number;
305
322
  };
306
323
 
324
+ /**
325
+ * Format a set of evenly-spaced tick values with enough decimal places to
326
+ * keep every label distinct. Precision comes from the tick step, not the
327
+ * magnitude of the value: a 0.5 step around 100 needs one decimal, or
328
+ * 99.5 and 100.5 both collapse into neighbouring whole numbers.
329
+ */
330
+ export declare function formatTickLabels(ticks: number[]): string[];
331
+
307
332
  /** Vertical gap between a subgraph header band and the content area below it (px).
308
333
  * Without this, nested subgraph headers sit flush against their parent's header band.
309
334
  * Increased from 8 to 12 to provide more clearance for edges routing near headers. */
@@ -328,6 +353,15 @@ export declare function layoutClassDiagramSync(diagram: ClassDiagram, options?:
328
353
  */
329
354
  export declare function layoutErDiagramSync(diagram: ErDiagram, options?: ErRenderOptions): PositionedErDiagram;
330
355
 
356
+ /**
357
+ * Lay out a flowchart, with its subgraphs arranged the way mermaid.js arranges
358
+ * them (see `layout-engine/compound-flat.ts`). Anything that layout doesn't
359
+ * handle, or can't make fit, is laid out by `layoutGraphSync`, so this is a
360
+ * drop-in for it wherever the graph is a flowchart. Other diagram types that
361
+ * share the engine (state, architecture) keep using `layoutGraphSync`.
362
+ */
363
+ export declare function layoutFlowchartSync(graph: MermaidGraph, options?: FlowchartRenderOptions): PositionedGraph;
364
+
331
365
  /**
332
366
  * Lay out a parsed MermaidGraph using ELK.js (synchronous).
333
367
  * Returns a fully positioned graph ready for rendering.
@@ -351,6 +385,9 @@ export declare const MONO_FONT: "'JetBrains Mono'";
351
385
  /** Full CSS fallback chain for monospace text */
352
386
  export declare const MONO_FONT_STACK: "'JetBrains Mono', 'SF Mono', 'Fira Code', ui-monospace, monospace";
353
387
 
388
+ /** Generate "nice" tick values for a numeric range */
389
+ export declare function niceTickValues(min: number, max: number): number[];
390
+
354
391
  /** Padding inside node shapes */
355
392
  export declare const NODE_PADDING: {
356
393
  /** Horizontal padding inside rectangles/rounded/stadium (increased from 16 for better label fit) */
@@ -552,6 +589,11 @@ export declare function resolveCssColors(svg: string, colors: DiagramColors): st
552
589
  */
553
590
  export declare function resolveFontSizes(overrides?: FontSizeOptions): FontSizes;
554
591
 
592
+ export declare function smoothCurvePath(points: Array<{
593
+ x: number;
594
+ y: number;
595
+ }>): string;
596
+
555
597
  /** Stroke widths per element type (in px) */
556
598
  export declare const STROKE_WIDTHS: {
557
599
  readonly outerBox: 1;
@@ -610,4 +652,12 @@ export declare function themeCssVariables(options?: RenderOptions): string;
610
652
  */
611
653
  export declare function withDataSrc(svgTag: string, source: string | undefined): string;
612
654
 
655
+ /**
656
+ * Step between shown x-axis labels: 1 when every pair of neighbouring labels
657
+ * keeps `X_LABEL_MIN_GAP` of clear space, otherwise the smallest n for which
658
+ * every pair of shown (every n-th) labels does. Checked pairwise on the real
659
+ * widths so one long label doesn't thin out an otherwise roomy axis.
660
+ */
661
+ export declare function xLabelStep(labels: string[], bandWidth: number): number;
662
+
613
663
  export { }
package/dist/index.d.ts CHANGED
@@ -26,6 +26,13 @@ import { SvgEmitOptions } from '@zombie-mermaid/core';
26
26
  import { XYChart } from '@zombie-mermaid/mermaid-parser';
27
27
  import { XyChartRenderOptions } from '@zombie-mermaid/core';
28
28
 
29
+ /**
30
+ * Distance from the bottom of a stick-figure (`actor`) icon to the vertical
31
+ * centre of its label. Shared with the renderer so the label lands where the
32
+ * layout reserved room for it.
33
+ */
34
+ export declare const ACTOR_LABEL_OFFSET = 14;
35
+
29
36
  /** Arrow head dimensions — matches spec: 8px wide × ~5px tall */
30
37
  export declare const ARROW_HEAD: {
31
38
  readonly width: 8;
@@ -122,6 +129,11 @@ export declare const CLS: {
122
129
  /** Horizontal / vertical padding inside a note box, around its text */
123
130
  readonly notePadX: 10;
124
131
  readonly notePadY: 6;
132
+ /** Space reserved above a namespace's classes for its title */
133
+ readonly namespaceTitleHeight: 28;
134
+ /** Padding between a namespace frame and its classes (other three sides) */
135
+ readonly namespacePad: 16;
136
+ readonly namespaceTitleFontSize: 12;
125
137
  };
126
138
 
127
139
  /**
@@ -168,10 +180,14 @@ export declare function directionToElk(dir: Direction | undefined, fallback: Elk
168
180
  * single fixed orientation, matching Mermaid's own TB class rendering —
169
181
  * which `../class/layout.ts` relies on to put a `note for X` above its
170
182
  * class.
171
- * - **ER** — `RIGHT`. An ER diagram's `direction` is optional
183
+ * - **C4** — `DOWN`. `C4Diagram.direction` is never set by the parser (C4
184
+ * sources have no direction statement), only by `RenderOptions.direction`,
185
+ * so an unset one is the top-down layout every C4 diagram is drawn in.
186
+ * - **ER** — `DOWN`. An ER diagram's `direction` is optional
172
187
  * (`ErDiagram.direction?`), left `undefined` when the source has no
173
- * `direction` statement, and this renderer has always laid those out
174
- * left-to-right. `direction TB`/`LR`/`BT`/`RL` in the source (or
188
+ * `direction` statement, and official Mermaid lays those out top-to-bottom
189
+ * (#1250; this renderer used to lay them out left-to-right).
190
+ * `direction TB`/`LR`/`BT`/`RL` in the source (or
175
191
  * `RenderOptions.direction`, applied via `withDirectionOverride`) still
176
192
  * wins over it.
177
193
  *
@@ -185,7 +201,8 @@ export declare const ELK_DIRECTION_FALLBACK: {
185
201
  readonly flowchart: "DOWN";
186
202
  readonly state: "DOWN";
187
203
  readonly class: "DOWN";
188
- readonly er: "RIGHT";
204
+ readonly er: "DOWN";
205
+ readonly c4: "DOWN";
189
206
  };
190
207
 
191
208
  /** The four values ELK's `elk.direction` option accepts in this codebase. */
@@ -304,6 +321,14 @@ export declare type FontSizes = {
304
321
  [K in keyof typeof FONT_SIZES]: number;
305
322
  };
306
323
 
324
+ /**
325
+ * Format a set of evenly-spaced tick values with enough decimal places to
326
+ * keep every label distinct. Precision comes from the tick step, not the
327
+ * magnitude of the value: a 0.5 step around 100 needs one decimal, or
328
+ * 99.5 and 100.5 both collapse into neighbouring whole numbers.
329
+ */
330
+ export declare function formatTickLabels(ticks: number[]): string[];
331
+
307
332
  /** Vertical gap between a subgraph header band and the content area below it (px).
308
333
  * Without this, nested subgraph headers sit flush against their parent's header band.
309
334
  * Increased from 8 to 12 to provide more clearance for edges routing near headers. */
@@ -328,6 +353,15 @@ export declare function layoutClassDiagramSync(diagram: ClassDiagram, options?:
328
353
  */
329
354
  export declare function layoutErDiagramSync(diagram: ErDiagram, options?: ErRenderOptions): PositionedErDiagram;
330
355
 
356
+ /**
357
+ * Lay out a flowchart, with its subgraphs arranged the way mermaid.js arranges
358
+ * them (see `layout-engine/compound-flat.ts`). Anything that layout doesn't
359
+ * handle, or can't make fit, is laid out by `layoutGraphSync`, so this is a
360
+ * drop-in for it wherever the graph is a flowchart. Other diagram types that
361
+ * share the engine (state, architecture) keep using `layoutGraphSync`.
362
+ */
363
+ export declare function layoutFlowchartSync(graph: MermaidGraph, options?: FlowchartRenderOptions): PositionedGraph;
364
+
331
365
  /**
332
366
  * Lay out a parsed MermaidGraph using ELK.js (synchronous).
333
367
  * Returns a fully positioned graph ready for rendering.
@@ -351,6 +385,9 @@ export declare const MONO_FONT: "'JetBrains Mono'";
351
385
  /** Full CSS fallback chain for monospace text */
352
386
  export declare const MONO_FONT_STACK: "'JetBrains Mono', 'SF Mono', 'Fira Code', ui-monospace, monospace";
353
387
 
388
+ /** Generate "nice" tick values for a numeric range */
389
+ export declare function niceTickValues(min: number, max: number): number[];
390
+
354
391
  /** Padding inside node shapes */
355
392
  export declare const NODE_PADDING: {
356
393
  /** Horizontal padding inside rectangles/rounded/stadium (increased from 16 for better label fit) */
@@ -552,6 +589,11 @@ export declare function resolveCssColors(svg: string, colors: DiagramColors): st
552
589
  */
553
590
  export declare function resolveFontSizes(overrides?: FontSizeOptions): FontSizes;
554
591
 
592
+ export declare function smoothCurvePath(points: Array<{
593
+ x: number;
594
+ y: number;
595
+ }>): string;
596
+
555
597
  /** Stroke widths per element type (in px) */
556
598
  export declare const STROKE_WIDTHS: {
557
599
  readonly outerBox: 1;
@@ -610,4 +652,12 @@ export declare function themeCssVariables(options?: RenderOptions): string;
610
652
  */
611
653
  export declare function withDataSrc(svgTag: string, source: string | undefined): string;
612
654
 
655
+ /**
656
+ * Step between shown x-axis labels: 1 when every pair of neighbouring labels
657
+ * keeps `X_LABEL_MIN_GAP` of clear space, otherwise the smallest n for which
658
+ * every pair of shown (every n-th) labels does. Checked pairwise on the real
659
+ * widths so one long label doesn't thin out an otherwise roomy axis.
660
+ */
661
+ export declare function xLabelStep(labels: string[], bandWidth: number): number;
662
+
613
663
  export { }