compasso 0.4.0 → 0.5.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 (100) hide show
  1. package/README.md +115 -5
  2. package/dist/{chunk-ZBDABVIO.js → chunk-2NDET6O5.js} +3 -3
  3. package/dist/{chunk-ZBDABVIO.js.map → chunk-2NDET6O5.js.map} +1 -1
  4. package/dist/{chunk-Q6DVTCXD.js → chunk-3RGYLVTN.js} +18 -6
  5. package/dist/chunk-3RGYLVTN.js.map +1 -0
  6. package/dist/chunk-BM7UJBK5.js +680 -0
  7. package/dist/chunk-BM7UJBK5.js.map +1 -0
  8. package/dist/chunk-DVLWT565.js +372 -0
  9. package/dist/chunk-DVLWT565.js.map +1 -0
  10. package/dist/{chunk-F47C6ZEB.js → chunk-JBDA7E2O.js} +3 -3
  11. package/dist/{chunk-F47C6ZEB.js.map → chunk-JBDA7E2O.js.map} +1 -1
  12. package/dist/chunk-MIJTBYX2.js +982 -0
  13. package/dist/chunk-MIJTBYX2.js.map +1 -0
  14. package/dist/{chunk-JP4N42AY.js → chunk-PJHLWSGD.js} +3 -3
  15. package/dist/{chunk-JP4N42AY.js.map → chunk-PJHLWSGD.js.map} +1 -1
  16. package/dist/{chunk-LRHHUJFZ.js → chunk-RDH4XHA2.js} +3 -3
  17. package/dist/{chunk-LRHHUJFZ.js.map → chunk-RDH4XHA2.js.map} +1 -1
  18. package/dist/{chunk-UJVU7B44.js → chunk-WEHUSHVI.js} +31 -51
  19. package/dist/chunk-WEHUSHVI.js.map +1 -0
  20. package/dist/{chunk-RWPGGWO5.js → chunk-Z66YUOUM.js} +34 -10
  21. package/dist/chunk-Z66YUOUM.js.map +1 -0
  22. package/dist/core/index.cjs +247 -0
  23. package/dist/core/index.cjs.map +1 -1
  24. package/dist/core/index.d.cts +94 -2
  25. package/dist/core/index.d.ts +94 -2
  26. package/dist/core/index.js +1 -1
  27. package/dist/ecomap/index.cjs +34 -11
  28. package/dist/ecomap/index.cjs.map +1 -1
  29. package/dist/ecomap/index.d.cts +12 -0
  30. package/dist/ecomap/index.d.ts +12 -0
  31. package/dist/ecomap/index.js +2 -2
  32. package/dist/fault-tree/index.d.cts +2 -2
  33. package/dist/fault-tree/index.d.ts +2 -2
  34. package/dist/fault-tree/index.js +2 -2
  35. package/dist/fishbone/index.js +2 -2
  36. package/dist/genogram/index.cjs +57 -7
  37. package/dist/genogram/index.cjs.map +1 -1
  38. package/dist/genogram/index.d.cts +22 -6
  39. package/dist/genogram/index.d.ts +22 -6
  40. package/dist/genogram/index.js +2 -2
  41. package/dist/geometry-P-XGqGe7.d.cts +8 -0
  42. package/dist/geometry-P-XGqGe7.d.ts +8 -0
  43. package/dist/grid-BMgUSly1.d.cts +79 -0
  44. package/dist/grid-BMgUSly1.d.ts +79 -0
  45. package/dist/index.cjs +2360 -395
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.cts +14 -7
  48. package/dist/index.d.ts +14 -7
  49. package/dist/index.js +10 -8
  50. package/dist/{kinship-DqEklrDN.d.ts → kinship-BF90HyyS.d.ts} +1 -1
  51. package/dist/{kinship-Dy_ijjJV.d.cts → kinship-BOUss5cT.d.cts} +1 -1
  52. package/dist/{labels-RtFw9tX1.d.cts → labels-B0aOMbHy.d.cts} +12 -0
  53. package/dist/{labels-RtFw9tX1.d.ts → labels-B0aOMbHy.d.ts} +12 -0
  54. package/dist/labels-Br8yjc3C.d.cts +29 -0
  55. package/dist/labels-Br8yjc3C.d.ts +29 -0
  56. package/dist/{labels-DNqRkWuI.d.ts → labels-CuLbFyrz.d.ts} +1 -1
  57. package/dist/labels-D1v1RWZd.d.cts +97 -0
  58. package/dist/labels-D1v1RWZd.d.ts +97 -0
  59. package/dist/{labels-CBQ_3Ec9.d.cts → labels-DhQe7I8m.d.cts} +1 -1
  60. package/dist/layered-DmZluAqe.d.cts +72 -0
  61. package/dist/layered-DmZluAqe.d.ts +72 -0
  62. package/dist/locales/pt-br.cjs +53 -0
  63. package/dist/locales/pt-br.cjs.map +1 -1
  64. package/dist/locales/pt-br.d.cts +11 -5
  65. package/dist/locales/pt-br.d.ts +11 -5
  66. package/dist/locales/pt-br.js +50 -1
  67. package/dist/locales/pt-br.js.map +1 -1
  68. package/dist/org-chart/index.cjs +138 -94
  69. package/dist/org-chart/index.cjs.map +1 -1
  70. package/dist/org-chart/index.d.cts +24 -33
  71. package/dist/org-chart/index.d.ts +24 -33
  72. package/dist/org-chart/index.js +2 -2
  73. package/dist/pedigree/index.d.cts +6 -6
  74. package/dist/pedigree/index.d.ts +6 -6
  75. package/dist/pedigree/index.js +2 -2
  76. package/dist/phylo/index.d.cts +2 -2
  77. package/dist/phylo/index.d.ts +2 -2
  78. package/dist/phylo/index.js +2 -2
  79. package/dist/prisma/index.cjs +882 -0
  80. package/dist/prisma/index.cjs.map +1 -0
  81. package/dist/prisma/index.d.cts +174 -0
  82. package/dist/prisma/index.d.ts +174 -0
  83. package/dist/prisma/index.js +4 -0
  84. package/dist/prisma/index.js.map +1 -0
  85. package/dist/{text-DuO_PwYw.d.cts → text-DDVzpwPZ.d.cts} +1 -8
  86. package/dist/{text-DuO_PwYw.d.ts → text-DDVzpwPZ.d.ts} +1 -8
  87. package/dist/{types-BnMG7TCd.d.cts → types-jE2fdM1t.d.cts} +8 -0
  88. package/dist/{types-BnMG7TCd.d.ts → types-jE2fdM1t.d.ts} +8 -0
  89. package/dist/uml/index.cjs +1214 -0
  90. package/dist/uml/index.cjs.map +1 -0
  91. package/dist/uml/index.d.cts +189 -0
  92. package/dist/uml/index.d.ts +189 -0
  93. package/dist/uml/index.js +4 -0
  94. package/dist/uml/index.js.map +1 -0
  95. package/package.json +28 -2
  96. package/dist/chunk-O3BT2O42.js +0 -145
  97. package/dist/chunk-O3BT2O42.js.map +0 -1
  98. package/dist/chunk-Q6DVTCXD.js.map +0 -1
  99. package/dist/chunk-RWPGGWO5.js.map +0 -1
  100. package/dist/chunk-UJVU7B44.js.map +0 -1
@@ -1,6 +1,10 @@
1
1
  export { x as xmlEscape } from '../xml-DDae1eUr.js';
2
- export { C as CHAR_W, F as FONT_FAMILY, P as Point, c as clampLabel, e as estimateTextWidth, p as pathData, w as wrapLabel, a as wrapLabelBalanced } from '../text-DuO_PwYw.js';
2
+ import { P as Point } from '../geometry-P-XGqGe7.js';
3
+ export { p as pathData } from '../geometry-P-XGqGe7.js';
4
+ export { C as CHAR_W, F as FONT_FAMILY, c as clampLabel, e as estimateTextWidth, w as wrapLabel, a as wrapLabelBalanced } from '../text-DDVzpwPZ.js';
3
5
  export { E as EDGE_STROKE, a as EdgeLineStyle, b as EdgeStroke, Q as QUALITY_LEXICON_EN, c as QualityLexicon, n as normalizeText, q as qualityLineStyle } from '../stroke-MQ427drt.js';
6
+ export { B as BandRow, a as BandStackOpts, b as BandStackResult, P as PackGaps, c as PackNode, d as PackResult, e as allocateLanes, f as bandStack, p as packSubtree } from '../layered-DmZluAqe.js';
7
+ export { C as CompartmentMetrics, G as GridCell, a as GridResult, m as measureCompartmentBox, p as packGrid } from '../grid-BMgUSly1.js';
4
8
 
5
9
  /** Uppercase Roman numeral for an integer in 1..3999 (1→"I", 4→"IV", 1990→"MCMXC").
6
10
  * Out of range or non-integer → the Arabic number as a string (graceful fallback). */
@@ -37,4 +41,92 @@ interface LegendBlock {
37
41
  */
38
42
  declare function legendBlock(entries: readonly LegendEntry[], startY: number): LegendBlock;
39
43
 
40
- export { LEGEND_FONT, LEGEND_GAP, LEGEND_PAD, LEGEND_ROW_H, LEGEND_SWATCH_W, type LegendBlock, type LegendEntry, legendBlock, romanNumeral };
44
+ declare const ANNOTATION_INK = "#52525b";
45
+ /**
46
+ * A small filled dot marking an annotated NODE. Pass the point where it should sit — callers
47
+ * place it at the node's upper-right (inset), the conventional "has a note" corner.
48
+ */
49
+ declare function annotationDot(cx: number, cy: number): string;
50
+ /**
51
+ * A short tick perpendicular to an annotated EDGE at the midpoint of its middle segment.
52
+ * Org-chart / genogram polylines are axis-aligned, so the perpendicular is trivial; a tick on
53
+ * a near-diagonal falls back to a vertical mark. Returns "" for a degenerate (<2-point) path.
54
+ */
55
+ declare function annotationTick(points: readonly Point[]): string;
56
+ /** Legend swatch for the annotation row: the same dot, centred in the swatch column. */
57
+ declare function annotationSwatch(x: number, yCenter: number): string;
58
+
59
+ /** Cardinal direction; tip of the glyph points in this direction. */
60
+ type Dir = "up" | "down" | "left" | "right";
61
+ /** Open/filled arrowhead length (from tip to base). */
62
+ declare const GLYPH_ARROW_LEN = 10;
63
+ /** Open/filled arrowhead half-width at the base. */
64
+ declare const GLYPH_ARROW_HALF = 5;
65
+ /** Generalization/realization triangle length (from tip to base). */
66
+ declare const GLYPH_TRI_LEN = 14;
67
+ /** Generalization/realization triangle half-width at the base. */
68
+ declare const GLYPH_TRI_HALF = 8;
69
+ /** Aggregation/composition diamond length (tip to base, full axis). */
70
+ declare const GLYPH_DIAMOND_LEN = 16;
71
+ /** Aggregation/composition diamond half-width at mid-point. */
72
+ declare const GLYPH_DIAMOND_HALF = 6;
73
+ /**
74
+ * Three-point open arrowhead ("<" shape, 2-stroke polyline).
75
+ * Caller should set fill="none".
76
+ *
77
+ * @param tip - apex of the arrowhead (where the line ends)
78
+ * @param dir - direction the tip points
79
+ * @param len - depth of the arrowhead (default GLYPH_ARROW_LEN)
80
+ * @param half - half-width at the base (default GLYPH_ARROW_HALF)
81
+ */
82
+ declare function arrowOpenPoints(tip: Point, dir: Dir, len?: number, half?: number): string;
83
+ /**
84
+ * Three-point solid (filled) arrowhead.
85
+ * Caller should set fill to the desired ink color.
86
+ *
87
+ * @param tip - apex of the arrowhead (where the line ends)
88
+ * @param dir - direction the tip points
89
+ * @param len - depth of the arrowhead (default GLYPH_ARROW_LEN)
90
+ * @param half - half-width at the base (default GLYPH_ARROW_HALF)
91
+ */
92
+ declare function arrowFilledPoints(tip: Point, dir: Dir, len?: number, half?: number): string;
93
+ /**
94
+ * Three-point isoceles triangle (generalization/realization head).
95
+ * Same geometry as the arrowhead; caller fills white (open triangle) or ink (realization).
96
+ *
97
+ * @param tip - apex of the triangle (where the line ends)
98
+ * @param dir - direction the tip points
99
+ * @param len - depth tip→base (default GLYPH_TRI_LEN)
100
+ * @param half - half-width at the base (default GLYPH_TRI_HALF)
101
+ */
102
+ declare function trianglePoints(tip: Point, dir: Dir, len?: number, half?: number): string;
103
+ /**
104
+ * Four-point rhombus (aggregation / composition diamond).
105
+ * Points in order: tip → left-side → base → right-side.
106
+ *
107
+ * The `tip` is the outer apex (the one on the LINE, away from the source box).
108
+ * The diamond extends `len` in the `dir` direction (toward the source box).
109
+ * Left/right side-points are `half` perpendicular units off the mid-axis.
110
+ *
111
+ * @param tip - outer apex (where the line ends, nearest the target)
112
+ * @param dir - direction from tip toward the source box
113
+ * @param len - length of the full diamond axis (default GLYPH_DIAMOND_LEN)
114
+ * @param half - half-width at the widest point (default GLYPH_DIAMOND_HALF)
115
+ */
116
+ declare function diamondPoints(tip: Point, dir: Dir, len?: number, half?: number): string;
117
+ /**
118
+ * How far the LINE must stop short of the box edge so it meets the glyph BASE
119
+ * (not the box face). Layout reserves this space; svg draws the line to this
120
+ * point and the polygon from it.
121
+ *
122
+ * For arrows and triangles: the line ends at the glyph base, which is `len`
123
+ * from the tip (the tip sits at the box edge). Inset = len.
124
+ *
125
+ * For diamonds: the diamond BASE is at the box edge; the tip is `len` outward.
126
+ * The line ends at the diamond tip = `len` from the box edge. Inset = len.
127
+ *
128
+ * Direction does not affect the scalar inset value (rotation is sign-flip only).
129
+ */
130
+ declare function glyphInset(_dir: Dir, kind: "arrow" | "triangle" | "diamond"): number;
131
+
132
+ export { ANNOTATION_INK, type Dir, GLYPH_ARROW_HALF, GLYPH_ARROW_LEN, GLYPH_DIAMOND_HALF, GLYPH_DIAMOND_LEN, GLYPH_TRI_HALF, GLYPH_TRI_LEN, LEGEND_FONT, LEGEND_GAP, LEGEND_PAD, LEGEND_ROW_H, LEGEND_SWATCH_W, type LegendBlock, type LegendEntry, Point, annotationDot, annotationSwatch, annotationTick, arrowFilledPoints, arrowOpenPoints, diamondPoints, glyphInset, legendBlock, romanNumeral, trianglePoints };
@@ -1,3 +1,3 @@
1
- export { CHAR_W, EDGE_STROKE, FONT_FAMILY, LEGEND_FONT, LEGEND_GAP, LEGEND_PAD, LEGEND_ROW_H, LEGEND_SWATCH_W, QUALITY_LEXICON_EN, clampLabel, estimateTextWidth, legendBlock, normalizeText, pathData, qualityLineStyle, romanNumeral, wrapLabel, wrapLabelBalanced, xmlEscape } from '../chunk-O3BT2O42.js';
1
+ export { ANNOTATION_INK, CHAR_W, EDGE_STROKE, FONT_FAMILY, GLYPH_ARROW_HALF, GLYPH_ARROW_LEN, GLYPH_DIAMOND_HALF, GLYPH_DIAMOND_LEN, GLYPH_TRI_HALF, GLYPH_TRI_LEN, LEGEND_FONT, LEGEND_GAP, LEGEND_PAD, LEGEND_ROW_H, LEGEND_SWATCH_W, QUALITY_LEXICON_EN, allocateLanes, annotationDot, annotationSwatch, annotationTick, arrowFilledPoints, arrowOpenPoints, bandStack, clampLabel, diamondPoints, estimateTextWidth, glyphInset, legendBlock, measureCompartmentBox, normalizeText, packGrid, packSubtree, pathData, qualityLineStyle, romanNumeral, trianglePoints, wrapLabel, wrapLabelBalanced, xmlEscape } from '../chunk-DVLWT565.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -108,6 +108,17 @@ function qualityLineStyle(quality, lexicon = QUALITY_LEXICON_EN) {
108
108
  return matched.length === 1 ? matched[0] : "plain";
109
109
  }
110
110
 
111
+ // src/core/annotation.ts
112
+ var round = (n) => Math.round(n * 100) / 100;
113
+ var ANNOTATION_INK = "#52525b";
114
+ var DOT_R = 3;
115
+ function annotationDot(cx, cy) {
116
+ return `<circle cx="${round(cx)}" cy="${round(cy)}" r="${DOT_R}" fill="${ANNOTATION_INK}" fill-opacity="0.6"/>`;
117
+ }
118
+ function annotationSwatch(x, yCenter) {
119
+ return annotationDot(x + LEGEND_SWATCH_W / 2, yCenter);
120
+ }
121
+
111
122
  // src/ecomap/render.ts
112
123
  var ECOMAP_LABELS_EN = {
113
124
  bondStyles: {
@@ -133,7 +144,7 @@ var SINGLE_RING_MAX = 8;
133
144
  var NODE_STROKE = "#52525b";
134
145
  var LABEL_FILL = "#3f3f46";
135
146
  var EDGE_INK = "#71717a";
136
- var round = (n) => Math.round(n * 100) / 100;
147
+ var round2 = (n) => Math.round(n * 100) / 100;
137
148
  function arrowHead(tipX, tipY, ux, uy, opacity) {
138
149
  const LEN = 9;
139
150
  const HALF_W = 4.5;
@@ -142,9 +153,9 @@ function arrowHead(tipX, tipY, ux, uy, opacity) {
142
153
  const px = -uy;
143
154
  const py = ux;
144
155
  const points = [
145
- `${round(tipX)},${round(tipY)}`,
146
- `${round(bx + px * HALF_W)},${round(by + py * HALF_W)}`,
147
- `${round(bx - px * HALF_W)},${round(by - py * HALF_W)}`
156
+ `${round2(tipX)},${round2(tipY)}`,
157
+ `${round2(bx + px * HALF_W)},${round2(by + py * HALF_W)}`,
158
+ `${round2(bx - px * HALF_W)},${round2(by - py * HALF_W)}`
148
159
  ].join(" ");
149
160
  return `<polygon points="${points}" fill="${EDGE_INK}" fill-opacity="${opacity}"/>`;
150
161
  }
@@ -234,7 +245,7 @@ function ecomapSvg(input, opts = {}) {
234
245
  const dashAttr = ink.dash === null ? "" : ` stroke-dasharray="${ink.dash[0]} ${ink.dash[1]}"`;
235
246
  const title = s.tie.title ?? (s.tie.quality !== null ? `${s.tie.label} \xB7 ${s.tie.quality}` : s.tie.label);
236
247
  const body = [
237
- `<line x1="${round(x1)}" y1="${round(y1)}" x2="${round(x2)}" y2="${round(y2)}" stroke="${EDGE_INK}" stroke-width="${ink.width}" stroke-opacity="${ink.opacity}"${dashAttr}/>`
248
+ `<line x1="${round2(x1)}" y1="${round2(y1)}" x2="${round2(x2)}" y2="${round2(y2)}" stroke="${EDGE_INK}" stroke-width="${ink.width}" stroke-opacity="${ink.opacity}"${dashAttr}/>`
238
249
  ];
239
250
  if (s.tie.direction === "in" || s.tie.direction === "both") {
240
251
  body.push(arrowHead(x2, y2, ux, uy, ink.opacity));
@@ -246,19 +257,25 @@ function ecomapSvg(input, opts = {}) {
246
257
  }
247
258
  {
248
259
  const tspans = centerLines.map(
249
- (line, i) => `<tspan x="${round(cx)}" y="${round(cy - (centerLines.length - 1) * LINE_H / 2 + i * LINE_H + fontSize * 0.32)}">${xmlEscape(line)}</tspan>`
260
+ (line, i) => `<tspan x="${round2(cx)}" y="${round2(cy - (centerLines.length - 1) * LINE_H / 2 + i * LINE_H + fontSize * 0.32)}">${xmlEscape(line)}</tspan>`
250
261
  ).join("");
251
262
  parts.push(
252
- `<g data-individual-id="center"><title>${xmlEscape(input.centerLabel)}</title><circle cx="${round(cx)}" cy="${round(cy)}" r="${round(centerR)}" fill="transparent" stroke="${NODE_STROKE}" stroke-width="2"/><text text-anchor="middle" font-family="${FONT_FAMILY}" font-size="${fontSize}" fill="${LABEL_FILL}">${tspans}</text></g>`
263
+ `<g data-individual-id="center"><title>${xmlEscape(input.centerLabel)}</title><circle cx="${round2(cx)}" cy="${round2(cy)}" r="${round2(centerR)}" fill="transparent" stroke="${NODE_STROKE}" stroke-width="2"/><text text-anchor="middle" font-family="${FONT_FAMILY}" font-size="${fontSize}" fill="${LABEL_FILL}">${tspans}</text></g>`
253
264
  );
254
265
  }
255
266
  for (const s of sats) {
256
267
  const tspans = s.lines.map(
257
- (line, i) => `<tspan x="${round(s.x)}" y="${round(s.y - (s.lines.length - 1) * LINE_H / 2 + i * LINE_H + fontSize * 0.32)}">${xmlEscape(line)}</tspan>`
268
+ (line, i) => `<tspan x="${round2(s.x)}" y="${round2(s.y - (s.lines.length - 1) * LINE_H / 2 + i * LINE_H + fontSize * 0.32)}">${xmlEscape(line)}</tspan>`
258
269
  ).join("");
259
- parts.push(
260
- `<g data-individual-id="e${s.tie.id}"><title>${xmlEscape(s.tie.label)}</title><ellipse cx="${round(s.x)}" cy="${round(s.y)}" rx="${round(s.rx)}" ry="${round(s.ry)}" fill="transparent" stroke="${NODE_STROKE}" stroke-width="1.5"/><text text-anchor="middle" font-family="${FONT_FAMILY}" font-size="${fontSize}" fill="${LABEL_FILL}">${tspans}</text></g>`
261
- );
270
+ const pieces = [
271
+ `<title>${xmlEscape(s.tie.label)}</title>`,
272
+ `<ellipse cx="${round2(s.x)}" cy="${round2(s.y)}" rx="${round2(s.rx)}" ry="${round2(s.ry)}" fill="transparent" stroke="${NODE_STROKE}" stroke-width="1.5"/>`,
273
+ `<text text-anchor="middle" font-family="${FONT_FAMILY}" font-size="${fontSize}" fill="${LABEL_FILL}">${tspans}</text>`
274
+ ];
275
+ if (s.tie.annotated) {
276
+ pieces.push(annotationDot(s.x + 0.7 * s.rx, s.y - 0.7 * s.ry));
277
+ }
278
+ parts.push(`<g data-individual-id="e${s.tie.id}">${pieces.join("")}</g>`);
262
279
  }
263
280
  if (opts.legend !== false && sats.length > 0) {
264
281
  const entries = [];
@@ -284,6 +301,12 @@ function ecomapSvg(input, opts = {}) {
284
301
  label: labels.direction
285
302
  });
286
303
  }
304
+ if (opts.annotationLabel !== void 0 && sats.some((s) => s.tie.annotated)) {
305
+ entries.push({
306
+ swatch: (x, y) => annotationSwatch(x, y),
307
+ label: opts.annotationLabel
308
+ });
309
+ }
287
310
  if (entries.length > 0) {
288
311
  const block = legendBlock(entries, height);
289
312
  parts.push(block.svg);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/xml.ts","../../src/core/text.ts","../../src/core/legend.ts","../../src/core/stroke.ts","../../src/ecomap/render.ts"],"names":["w","h"],"mappings":"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","file":"index.cjs","sourcesContent":["// XML/SVG escaping — every interpolated text in an emitted SVG MUST pass through\n// this. Diagram labels are typically user/author-controlled, and the SVG string may\n// be injected via innerHTML in a browser or embedded as vectors in a PDF — an\n// unescaped label is an XSS / `</svg>`-breakout vector on every surface at once.\n\n/** Escapes a string for use in SVG/XML text content AND attribute values. */\nexport function xmlEscape(text: string): string {\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n","// Pure, deterministic text metrics — no DOM, no canvas, no font files. Every layout\n// in this library reserves space from these estimates and every emitter draws with\n// the same constants, so what is proven collision-free is what is drawn.\n\n/**\n * Conservative per-character advance, as a fraction of the font size. The pure module\n * can't measure real glyphs (no DOM/canvas), so it estimates width = chars * font *\n * CHAR_W. It is deliberately a touch WIDER than Helvetica's ~0.5 average advance: a\n * layout reserves slightly more room than the text needs, so the real render always\n * fits inside its reserved box.\n */\nexport const CHAR_W = 0.6;\n\n/** Pure, deterministic width estimate for a single line of text at `fontPx`. */\nexport function estimateTextWidth(text: string, fontPx: number): number {\n return text.length * fontPx * CHAR_W;\n}\n\n/**\n * Wraps a label onto up to `maxLines` lines (default 2) so long labels don't sprawl.\n * Greedy word fill; each line capped at `perLine` chars (…-truncated only if a line\n * still overflows). The LAST allowed line absorbs every remaining word before the cap\n * applies — words are never dropped mid-label, only visibly elided. Pure + shared so\n * every renderer wraps identically. The full text is always kept elsewhere (the\n * node's `label`, an SVG <title>, or a side list), so nothing is silently lost.\n *\n * INVARIANT: with the default `maxLines` the output is byte-identical to the\n * historical two-line implementation (pinned by test/core/text.test.ts) — both\n * shipped renderers wrap through here.\n */\nexport function wrapLabel(label: string, perLine: number, maxLines = 2): string[] {\n if (label.length <= perLine) return [label];\n const cap = (s: string): string =>\n s.length > perLine ? s.slice(0, Math.max(1, perLine - 1)) + \"…\" : s;\n const lines: string[] = [\"\"];\n for (const word of label.split(/\\s+/)) {\n const last = lines.length - 1;\n const current = lines[last]!;\n if (current === \"\" || (current + \" \" + word).length <= perLine) {\n lines[last] = current === \"\" ? word : `${current} ${word}`;\n } else if (lines.length < maxLines) {\n lines.push(word);\n } else {\n lines[last] = `${current} ${word}`;\n }\n }\n // A trailing-whitespace \"word\" (\"a b \".split(/\\s+/) → [\"a\",\"b\",\"\"]) may open a line\n // it never fills; the historical code dropped that empty line, so this does too.\n if (lines.length > 1 && lines[lines.length - 1] === \"\") lines.pop();\n return lines.map(cap);\n}\n\n/**\n * House \"balanced\" wrap policy (extracted verbatim from the ecomap's tie-label wrap,\n * itself mirroring the genogram's): per-line budget `min(26, max(14, ceil(len/2)+2))`\n * splits a medium label into two roughly even lines instead of one long + one short,\n * then the greedy `wrapLabel` fill (and its `maxLines` semantics) applies. The shipped\n * renderers keep their local copies for now — new modules consume this one; migrating\n * them is a separate provably-zero-change refactor.\n */\nexport function wrapLabelBalanced(label: string, maxLines?: number): string[] {\n const perLine = Math.min(26, Math.max(14, Math.ceil(label.length / 2) + 2));\n return wrapLabel(label, perLine, maxLines);\n}\n\n/** Caps a verbatim label for a COMPACT render (preview); full text kept by the caller. */\nexport function clampLabel(label: string, maxChars: number | undefined): string {\n if (maxChars === undefined || label.length <= maxChars) return label;\n return label.slice(0, Math.max(1, maxChars - 1)) + \"…\";\n}\n\n/** Font stack shared by every emitter; PDF embedders typically map it onto Helvetica. */\nexport const FONT_FAMILY = \"Helvetica, Arial, sans-serif\";\n","// Shared legend machinery — the exact row format the genogram and ecomap emitters\n// currently duplicate character-for-character (`<g data-compasso-legend=\"true\">` with\n// swatch-closure rows). Extracted so new diagram modules don't add a third copy;\n// the two shipped emitters keep their local blocks for now (migrating them is a\n// separate, provably-zero-change refactor — pinned byte-for-byte against the ecomap's\n// emitted legend in test/core/legend.test.ts).\n//\n// The caller stays in charge of the HONESTY RULE half: it decides WHICH entries exist\n// (used-keys-only) and what each swatch draws; this module only owns the row geometry,\n// the text emission (xmlEscape — labels may come from caller-supplied packs), and the\n// width/height bookkeeping both renderers compute identically.\n\nimport { FONT_FAMILY, estimateTextWidth } from \"./text\";\nimport { xmlEscape } from \"./xml\";\n\n// Row metrics shared by every legend in the library. Exported because swatch builders\n// need them (a line swatch spans LEGEND_SWATCH_W; a glyph swatch centers on it).\nexport const LEGEND_ROW_H = 18;\nexport const LEGEND_PAD = 16;\nexport const LEGEND_SWATCH_W = 22;\nexport const LEGEND_GAP = 14;\nexport const LEGEND_FONT = 11;\n\n// Legend text ink — the zinc glyph stroke both shipped emitters use for legend labels.\nconst LEGEND_TEXT_FILL = \"#52525b\";\n\nexport interface LegendEntry {\n /**\n * Swatch markup builder, called with the swatch's left x and the row's center y.\n * The builder owns its own escaping/rounding (it typically reuses the module's\n * glyph/line emitters); it should draw within LEGEND_SWATCH_W of x.\n */\n swatch: (x: number, yCenter: number) => string;\n /** Display label (escaped here; verbatim pack text in, escaped SVG out). */\n label: string;\n}\n\nexport interface LegendBlock {\n /** `<g data-compasso-legend=\"true\">…</g>` — empty string when there are no entries. */\n svg: string;\n /** Minimum canvas width the legend needs; callers take `max(width, block.width)`. */\n width: number;\n /** New total canvas height including the legend; callers assign it directly. */\n height: number;\n}\n\n/**\n * Emits the legend group for the given entries below `startY` (the diagram's current\n * height). Pure + deterministic; coordinates are interpolated exactly as the shipped\n * emitters do. Zero entries (used-keys-only found nothing) → no markup, zero width\n * contribution, height unchanged — safe to call unconditionally.\n */\nexport function legendBlock(entries: readonly LegendEntry[], startY: number): LegendBlock {\n if (entries.length === 0) return { svg: \"\", width: 0, height: startY };\n const rows = entries.map((entry, i) => {\n const rowCenterY = startY + i * LEGEND_ROW_H + LEGEND_ROW_H / 2;\n const textX = LEGEND_PAD + LEGEND_SWATCH_W + LEGEND_GAP;\n return (\n entry.swatch(LEGEND_PAD, rowCenterY) +\n `<text x=\"${textX}\" y=\"${rowCenterY + LEGEND_FONT * 0.32}\" font-family=\"${FONT_FAMILY}\" font-size=\"${LEGEND_FONT}\" fill=\"${LEGEND_TEXT_FILL}\">${xmlEscape(entry.label)}</text>`\n );\n });\n const widestLabel = entries.reduce((m, e) => Math.max(m, estimateTextWidth(e.label, LEGEND_FONT)), 0);\n return {\n svg: `<g data-compasso-legend=\"true\">${rows.join(\"\")}</g>`,\n width: LEGEND_PAD + LEGEND_SWATCH_W + LEGEND_GAP + widestLabel + LEGEND_PAD,\n height: startY + entries.length * LEGEND_ROW_H + LEGEND_PAD / 2,\n };\n}\n","// Edge line styles — a neutral, presentation-only style for a relationship line.\n// NOT a judgment: a deterministic, lexical hint derived from the author's own quality\n// word. The literal word always rides the element's <title>, so a style never replaces\n// what was said. Unknown/ambiguous quality → \"plain\".\n\nexport type EdgeLineStyle = \"plain\" | \"close\" | \"distant\" | \"conflict\" | \"cutoff\";\n\n/** Stroke attributes per style — shared by every renderer so SVG and PDF match. */\nexport interface EdgeStroke {\n width: number;\n /** SVG dash array / PDF dash pattern as [dash, gap]; null = solid. */\n dash: [number, number] | null;\n opacity: number;\n}\n\nexport const EDGE_STROKE: Record<EdgeLineStyle, EdgeStroke> = {\n plain: { width: 1.5, dash: null, opacity: 0.6 },\n close: { width: 3, dash: null, opacity: 0.85 },\n distant: { width: 1.5, dash: [4, 4], opacity: 0.55 },\n conflict: { width: 2, dash: [2, 2], opacity: 0.75 },\n cutoff: { width: 1.5, dash: [6, 5], opacity: 0.4 },\n};\n\n/**\n * A pluggable lexicon mapping free-text quality words onto line styles. Needles are\n * diacritic-free, lowercase substrings of the author's own words; `negations` are\n * whole words that flip the meaning of the very word a needle would match (\"not\n * close\"), so their presence makes the matcher abstain to \"plain\" rather than risk\n * an inverted visual. Locale packs (e.g. `compasso/locales/pt-br`) ship alternates.\n */\nexport interface QualityLexicon {\n buckets: readonly { style: Exclude<EdgeLineStyle, \"plain\">; needles: readonly string[] }[];\n negations: readonly string[];\n}\n\n// English default. Conservative stems: each needle is a substring match on the\n// normalized text, and the SINGLE-BUCKET rule below keeps competing signals honest.\n// \"no\" alone is deliberately NOT a negation: \"no contact\" is a genuine cutoff signal.\nexport const QUALITY_LEXICON_EN: QualityLexicon = {\n buckets: [\n {\n style: \"close\",\n needles: [\"close\", \"warm\", \"support\", \"lov\", \"affection\", \"caring\", \"tight\", \"harmon\", \"healthy\"],\n },\n {\n style: \"distant\",\n needles: [\"distant\", \"detach\", \"absent\", \"cold\", \"drift\"],\n },\n {\n style: \"conflict\",\n needles: [\"conflict\", \"fight\", \"tens\", \"difficult\", \"hostil\", \"violen\", \"abus\", \"aggress\", \"complicat\", \"toxic\", \"argu\"],\n },\n {\n style: \"cutoff\",\n needles: [\"estrang\", \"cut off\", \"cutoff\", \"no contact\", \"broken off\", \"sever\"],\n },\n ],\n negations: [\"not\", \"never\", \"no longer\", \"hardly\"],\n};\n\n/** Lowercase + strip diacritics so matching ignores accents. */\nexport function normalizeText(text: string): string {\n return text.normalize(\"NFD\").replace(/[̀-ͯ]/g, \"\").toLowerCase();\n}\n\nconst escapeRegExp = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n/**\n * Maps a free-text relationship quality to a neutral line style. Deterministic and\n * conservative: returns a specific style ONLY when exactly one lexical bucket matches;\n * null/empty/ambiguous/negated/unknown all fall back to \"plain\". The caller still\n * keeps the verbatim quality word, so nothing the author said is ever lost.\n */\nexport function qualityLineStyle(\n quality: string | null,\n lexicon: QualityLexicon = QUALITY_LEXICON_EN,\n): EdgeLineStyle {\n if (quality === null) return \"plain\";\n const haystack = normalizeText(quality);\n if (haystack.trim() === \"\") return \"plain\";\n\n if (lexicon.negations.length > 0) {\n const negation = new RegExp(`\\\\b(${lexicon.negations.map(escapeRegExp).join(\"|\")})\\\\b`);\n if (negation.test(haystack)) return \"plain\";\n }\n\n const matched: EdgeLineStyle[] = [];\n for (const { style, needles } of lexicon.buckets) {\n if (needles.some((n) => haystack.includes(n))) matched.push(style);\n }\n return matched.length === 1 ? matched[0]! : \"plain\";\n}\n","// Radial ecomap renderer — center node + declared external ties on 1–2 concentric\n// rings, as a SELF-CONTAINED SVG string. Pure (data in, string out), deterministic\n// (same input → same SVG), no DOM, no dependencies.\n//\n// HONESTY RULE: the diagram presents ONLY what the caller declared. A tie's line style\n// is a conservative lexical hint from the author's own quality word (ambiguous/null →\n// neutral solid line, never a synthesized value); an arrowhead appears ONLY when a\n// direction was declared (null = no arrow, never a default). The verbatim text always\n// rides the element's <title>, so a style never replaces what was said.\n//\n// Ring assignment is a deterministic PRESENTATION rule — by input order (sorted by id),\n// alternating rings when the set is large — never by any reading of the tie's content.\n//\n// Every interpolated text passes xmlEscape (labels are author-controlled; the SVG may\n// be inlined via innerHTML or embedded in a PDF). All presentation attributes are\n// literal: a standalone SVG has no stylesheet. Arrowheads are explicit polygons, NOT\n// <marker> defs — marker support is unreliable in SVG-to-PDF embedders, and inline\n// polygons also avoid def-id collisions when several SVGs share one document.\n\nimport {\n EDGE_STROKE,\n FONT_FAMILY,\n LEGEND_SWATCH_W,\n clampLabel,\n estimateTextWidth,\n legendBlock,\n qualityLineStyle,\n wrapLabelBalanced,\n xmlEscape,\n type EdgeLineStyle,\n type LegendEntry,\n type QualityLexicon,\n} from \"../core\";\n\n// ── Input model ───────────────────────────────────────────────────────────────\n\n/** Declared flow of the tie, relative to the CENTER: \"in\" = toward the center. */\nexport type EcomapDirection = \"in\" | \"out\" | \"both\";\n\n/**\n * One declared tie between the center (person/household) and an external system\n * (work, faith, friends, healthcare…). `label` is the author's own naming, kept\n * verbatim. `quality` is the author's verbatim wording about the tie (null = not\n * declared = neutral line). `direction` follows the same doctrine: null = no arrow.\n */\nexport interface EcomapTie {\n id: number;\n label: string;\n quality: string | null;\n direction: EcomapDirection | null;\n /** Optional verbatim <title> override (defaults to \"label · quality\"). */\n title?: string;\n}\n\nexport interface EcomapInput {\n /** Center node label (e.g. the person or household the map is about). */\n centerLabel: string;\n ties: EcomapTie[];\n}\n\n// ── Display vocabulary ────────────────────────────────────────────────────────\n\nexport interface EcomapLabels {\n bondStyles: Record<Exclude<EdgeLineStyle, \"plain\">, string>;\n /** Legend label for the neutral solid line (a declared tie with no styled quality). */\n neutralTie: string;\n /** Legend label for the arrowhead (declared direction of the tie). */\n direction: string;\n ariaLabel: string;\n}\n\nexport const ECOMAP_LABELS_EN: EcomapLabels = {\n bondStyles: {\n close: \"Close\",\n distant: \"Distant\",\n conflict: \"Conflictual\",\n cutoff: \"Cut off (no contact)\",\n },\n neutralTie: \"Declared tie\",\n direction: \"Declared direction of the tie\",\n ariaLabel: \"Ecomap\",\n};\n\nexport interface EcomapSvgOptions {\n /** Display clamp per tie label (verbatim text stays in the <title>). */\n maxLabelChars?: number;\n /** Node label font size (px); default 12. */\n fontSize?: number;\n /** Set false to suppress the legend (compact preview); default true. */\n legend?: boolean;\n /** Quality-word lexicon — English default; see `compasso/locales/pt-br`. */\n qualityLexicon?: QualityLexicon;\n /** Display vocabulary — English default; see locale packs. */\n labels?: EcomapLabels;\n}\n\n// ── Geometry constants ────────────────────────────────────────────────────────\n\nconst PADDING = 32;\nconst LINE_H = 14;\nconst NODE_PAD_X = 14;\nconst NODE_PAD_Y = 9;\nconst CENTER_MIN_R = 36;\nconst RING_MIN_R = 150;\n/** Min gap between two adjacent node boxes on the same ring. */\nconst NODE_GAP = 24;\n/** Radial gap between the center circle and the inner ring's nearest box edge. */\nconst RADIAL_GAP = 40;\n/** Radial gap between the two rings when the set is large enough to split. */\nconst RING_GAP = 26;\n/** Above this many ties the layout alternates between two rings. */\nconst SINGLE_RING_MAX = 8;\n\n// Ink (zinc ramp on white — matches the genogram emitter).\nconst NODE_STROKE = \"#52525b\";\nconst LABEL_FILL = \"#3f3f46\";\nconst EDGE_INK = \"#71717a\";\n// Legend row geometry + the swatch span both live in ../core (LEGEND_SWATCH_W imported\n// above for the swatch closures); the row/text/width/height bookkeeping is legendBlock.\n\nconst round = (n: number): number => Math.round(n * 100) / 100;\n\n// ── Internal shapes ───────────────────────────────────────────────────────────\n\ninterface SatNode {\n tie: EcomapTie;\n lines: string[];\n rx: number;\n ry: number;\n /** Filled once ring radii are known. */\n x: number;\n y: number;\n angle: number;\n style: EdgeLineStyle;\n}\n\n/** Arrowhead polygon: tip at (tipX,tipY), pointing along the unit vector (ux,uy). */\nfunction arrowHead(tipX: number, tipY: number, ux: number, uy: number, opacity: number): string {\n const LEN = 9;\n const HALF_W = 4.5;\n const bx = tipX - ux * LEN;\n const by = tipY - uy * LEN;\n const px = -uy;\n const py = ux;\n const points = [\n `${round(tipX)},${round(tipY)}`,\n `${round(bx + px * HALF_W)},${round(by + py * HALF_W)}`,\n `${round(bx - px * HALF_W)},${round(by - py * HALF_W)}`,\n ].join(\" \");\n return `<polygon points=\"${points}\" fill=\"${EDGE_INK}\" fill-opacity=\"${opacity}\"/>`;\n}\n\n/**\n * Renders a declared ecomap to a self-contained SVG string. Deterministic: same data →\n * same SVG. Zero ties yield a valid center-only SVG; callers decide their own empty\n * state before calling. The root keeps numeric width/height attributes plus a matching\n * viewBox (PDF-embedder contract).\n */\nexport function ecomapSvg(input: EcomapInput, opts: EcomapSvgOptions = {}): string {\n const fontSize = opts.fontSize ?? 12;\n const labels = opts.labels ?? ECOMAP_LABELS_EN;\n\n // ── Measure every satellite box (deterministic order: by tie id). ───────────\n const sats: SatNode[] = [...input.ties]\n .sort((a, b) => a.id - b.id)\n .map((tie) => {\n const lines = wrapLabelBalanced(clampLabel(tie.label, opts.maxLabelChars));\n const w = Math.max(...lines.map((l) => estimateTextWidth(l, fontSize))) + NODE_PAD_X * 2;\n const h = lines.length * LINE_H + NODE_PAD_Y * 2;\n return {\n tie,\n lines,\n rx: Math.max(40, w / 2),\n ry: Math.max(20, h / 2),\n x: 0,\n y: 0,\n angle: 0,\n style: qualityLineStyle(tie.quality, opts.qualityLexicon),\n };\n });\n\n const centerLines = wrapLabelBalanced(input.centerLabel);\n const centerR = Math.max(\n CENTER_MIN_R,\n Math.max(...centerLines.map((l) => estimateTextWidth(l, fontSize))) / 2 + 12,\n (centerLines.length * LINE_H) / 2 + 12,\n );\n\n // ── Ring radii: wide enough that NO two node boxes can ever touch. The safe\n // center-to-center distance is the diagonal of the worst-case box pair: if the\n // euclidean distance is ≥ hypot(width-sum, height-sum), the axis-aligned boxes\n // cannot overlap in both axes at once. Overlap-proof by construction, not by luck.\n const n = sats.length;\n const maxRx = n > 0 ? Math.max(...sats.map((s) => s.rx)) : 0;\n const maxRy = n > 0 ? Math.max(...sats.map((s) => s.ry)) : 0;\n const twoRings = n > SINGLE_RING_MAX;\n const stepAngle = n > 0 ? (Math.PI * 2) / n : Math.PI;\n const safeDist = Math.hypot(2 * maxRx + NODE_GAP, 2 * maxRy + NODE_GAP);\n /** Min radius so two nodes `steps` angular steps apart on the SAME ring clear safeDist. */\n const sameRingRadius = (steps: number): number => {\n const theta = steps * stepAngle;\n if (n <= 1 || theta >= Math.PI) return 0; // ≤2 nodes on the ring: no chord constraint\n return safeDist / (2 * Math.sin(theta / 2));\n };\n const ringStep = maxRy * 2 + RING_GAP;\n let innerR = Math.max(\n RING_MIN_R,\n centerR + RADIAL_GAP + maxRy,\n sameRingRadius(twoRings ? 2 : 1),\n );\n if (twoRings) {\n // Cross-ring neighbors sit 1 step apart at radii r and r+ringStep. Their distance\n // sqrt(r² + (r+s)² − 2r(r+s)cosΔ) grows monotonically with r — widen the inner ring\n // in fixed increments until it clears safeDist (deterministic, always terminates).\n const crossDist = (r: number): number =>\n Math.sqrt(r * r + (r + ringStep) ** 2 - 2 * r * (r + ringStep) * Math.cos(stepAngle));\n while (crossDist(innerR) < safeDist) innerR += 8;\n }\n const outerR = innerR + ringStep;\n\n for (let i = 0; i < n; i++) {\n const s = sats[i]!;\n s.angle = -Math.PI / 2 + (i * Math.PI * 2) / n;\n const r = twoRings && i % 2 === 1 ? outerR : innerR;\n s.x = r * Math.cos(s.angle);\n s.y = r * Math.sin(s.angle);\n }\n\n // ── Canvas bounds (center at origin until here), then shift positive. ───────\n let minX = -centerR;\n let minY = -centerR;\n let maxX = centerR;\n let maxY = centerR;\n for (const s of sats) {\n minX = Math.min(minX, s.x - s.rx);\n minY = Math.min(minY, s.y - s.ry);\n maxX = Math.max(maxX, s.x + s.rx);\n maxY = Math.max(maxY, s.y + s.ry);\n }\n const dx = PADDING - minX;\n const dy = PADDING - minY;\n const cx = dx;\n const cy = dy;\n for (const s of sats) {\n s.x += dx;\n s.y += dy;\n }\n let width = maxX - minX + PADDING * 2;\n let height = maxY - minY + PADDING * 2;\n\n const parts: string[] = [];\n\n // ── Tie lines first (nodes sit on top), one group per declared tie. ─────────\n for (const s of sats) {\n const ux = (cx - s.x) / Math.hypot(cx - s.x, cy - s.y);\n const uy = (cy - s.y) / Math.hypot(cx - s.x, cy - s.y);\n // Node-edge endpoint: ellipse boundary along the unit vector toward the center.\n const scale = 1 / Math.hypot(ux / s.rx, uy / s.ry);\n const x1 = s.x + ux * scale;\n const y1 = s.y + uy * scale;\n // Center-edge endpoint: circle boundary along the same direction.\n const x2 = cx - ux * centerR;\n const y2 = cy - uy * centerR;\n\n const ink = EDGE_STROKE[s.style];\n const dashAttr = ink.dash === null ? \"\" : ` stroke-dasharray=\"${ink.dash[0]} ${ink.dash[1]}\"`;\n const title = s.tie.title ?? (s.tie.quality !== null ? `${s.tie.label} · ${s.tie.quality}` : s.tie.label);\n const body: string[] = [\n `<line x1=\"${round(x1)}\" y1=\"${round(y1)}\" x2=\"${round(x2)}\" y2=\"${round(y2)}\" stroke=\"${EDGE_INK}\" stroke-width=\"${ink.width}\" stroke-opacity=\"${ink.opacity}\"${dashAttr}/>`,\n ];\n // Arrowheads ONLY for a declared direction. \"in\" points at the center, \"out\" at\n // the external system, \"both\" draws both. Tips back off the boundary so the\n // triangle never pokes into the shape.\n if (s.tie.direction === \"in\" || s.tie.direction === \"both\") {\n body.push(arrowHead(x2, y2, ux, uy, ink.opacity)); // tip at the center edge\n }\n if (s.tie.direction === \"out\" || s.tie.direction === \"both\") {\n body.push(arrowHead(x1, y1, -ux, -uy, ink.opacity)); // tip at the system edge\n }\n parts.push(`<g data-edge-id=\"${s.tie.id}\"><title>${xmlEscape(title)}</title>${body.join(\"\")}</g>`);\n }\n\n // ── Center node. ─────────────────────────────────────────────────────────────\n {\n const tspans = centerLines\n .map(\n (line, i) =>\n `<tspan x=\"${round(cx)}\" y=\"${round(cy - ((centerLines.length - 1) * LINE_H) / 2 + i * LINE_H + fontSize * 0.32)}\">${xmlEscape(line)}</tspan>`,\n )\n .join(\"\");\n parts.push(\n `<g data-individual-id=\"center\"><title>${xmlEscape(input.centerLabel)}</title>` +\n `<circle cx=\"${round(cx)}\" cy=\"${round(cy)}\" r=\"${round(centerR)}\" fill=\"transparent\" stroke=\"${NODE_STROKE}\" stroke-width=\"2\"/>` +\n `<text text-anchor=\"middle\" font-family=\"${FONT_FAMILY}\" font-size=\"${fontSize}\" fill=\"${LABEL_FILL}\">${tspans}</text></g>`,\n );\n }\n\n // ── Satellite nodes. ─────────────────────────────────────────────────────────\n for (const s of sats) {\n const tspans = s.lines\n .map(\n (line, i) =>\n `<tspan x=\"${round(s.x)}\" y=\"${round(s.y - ((s.lines.length - 1) * LINE_H) / 2 + i * LINE_H + fontSize * 0.32)}\">${xmlEscape(line)}</tspan>`,\n )\n .join(\"\");\n parts.push(\n `<g data-individual-id=\"e${s.tie.id}\"><title>${xmlEscape(s.tie.label)}</title>` +\n `<ellipse cx=\"${round(s.x)}\" cy=\"${round(s.y)}\" rx=\"${round(s.rx)}\" ry=\"${round(s.ry)}\" fill=\"transparent\" stroke=\"${NODE_STROKE}\" stroke-width=\"1.5\"/>` +\n `<text text-anchor=\"middle\" font-family=\"${FONT_FAMILY}\" font-size=\"${fontSize}\" fill=\"${LABEL_FILL}\">${tspans}</text></g>`,\n );\n }\n\n // ── Minimal legend: only entries actually used. ──────────────────────────────\n if (opts.legend !== false && sats.length > 0) {\n const entries: LegendEntry[] = [];\n\n if (sats.some((s) => s.style === \"plain\")) {\n entries.push({\n swatch: (x, y) =>\n `<line x1=\"${x}\" y1=\"${y}\" x2=\"${x + LEGEND_SWATCH_W}\" y2=\"${y}\" stroke=\"${EDGE_INK}\" stroke-width=\"${EDGE_STROKE.plain.width}\" stroke-opacity=\"${EDGE_STROKE.plain.opacity}\"/>`,\n label: labels.neutralTie,\n });\n }\n const stylesUsed = new Set(sats.map((s) => s.style));\n for (const style of [\"close\", \"distant\", \"conflict\", \"cutoff\"] as const) {\n if (!stylesUsed.has(style)) continue;\n const ink = EDGE_STROKE[style];\n const dashAttr = ink.dash === null ? \"\" : ` stroke-dasharray=\"${ink.dash[0]} ${ink.dash[1]}\"`;\n entries.push({\n swatch: (x, y) =>\n `<line x1=\"${x}\" y1=\"${y}\" x2=\"${x + LEGEND_SWATCH_W}\" y2=\"${y}\" stroke=\"${EDGE_INK}\" stroke-width=\"${ink.width}\" stroke-opacity=\"${ink.opacity}\"${dashAttr}/>`,\n label: labels.bondStyles[style],\n });\n }\n if (sats.some((s) => s.tie.direction !== null)) {\n entries.push({\n swatch: (x, y) =>\n `<line x1=\"${x}\" y1=\"${y}\" x2=\"${x + LEGEND_SWATCH_W - 8}\" y2=\"${y}\" stroke=\"${EDGE_INK}\" stroke-width=\"1.5\" stroke-opacity=\"0.75\"/>` +\n arrowHead(x + LEGEND_SWATCH_W, y, 1, 0, 0.75),\n label: labels.direction,\n });\n }\n\n if (entries.length > 0) {\n const block = legendBlock(entries, height);\n parts.push(block.svg);\n width = Math.max(width, block.width);\n height = block.height;\n }\n }\n\n const w = Math.ceil(width);\n const h = Math.ceil(height);\n return (\n `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${w} ${h}\" width=\"${w}\" height=\"${h}\" role=\"img\" aria-label=\"${xmlEscape(labels.ariaLabel)}\">` +\n parts.join(\"\") +\n `</svg>`\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/core/xml.ts","../../src/core/text.ts","../../src/core/legend.ts","../../src/core/stroke.ts","../../src/core/annotation.ts","../../src/ecomap/render.ts"],"names":["round","w","h"],"mappings":"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","file":"index.cjs","sourcesContent":["// XML/SVG escaping — every interpolated text in an emitted SVG MUST pass through\n// this. Diagram labels are typically user/author-controlled, and the SVG string may\n// be injected via innerHTML in a browser or embedded as vectors in a PDF — an\n// unescaped label is an XSS / `</svg>`-breakout vector on every surface at once.\n\n/** Escapes a string for use in SVG/XML text content AND attribute values. */\nexport function xmlEscape(text: string): string {\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n","// Pure, deterministic text metrics — no DOM, no canvas, no font files. Every layout\n// in this library reserves space from these estimates and every emitter draws with\n// the same constants, so what is proven collision-free is what is drawn.\n\n/**\n * Conservative per-character advance, as a fraction of the font size. The pure module\n * can't measure real glyphs (no DOM/canvas), so it estimates width = chars * font *\n * CHAR_W. It is deliberately a touch WIDER than Helvetica's ~0.5 average advance: a\n * layout reserves slightly more room than the text needs, so the real render always\n * fits inside its reserved box.\n */\nexport const CHAR_W = 0.6;\n\n/** Pure, deterministic width estimate for a single line of text at `fontPx`. */\nexport function estimateTextWidth(text: string, fontPx: number): number {\n return text.length * fontPx * CHAR_W;\n}\n\n/**\n * Wraps a label onto up to `maxLines` lines (default 2) so long labels don't sprawl.\n * Greedy word fill; each line capped at `perLine` chars (…-truncated only if a line\n * still overflows). The LAST allowed line absorbs every remaining word before the cap\n * applies — words are never dropped mid-label, only visibly elided. Pure + shared so\n * every renderer wraps identically. The full text is always kept elsewhere (the\n * node's `label`, an SVG <title>, or a side list), so nothing is silently lost.\n *\n * INVARIANT: with the default `maxLines` the output is byte-identical to the\n * historical two-line implementation (pinned by test/core/text.test.ts) — both\n * shipped renderers wrap through here.\n */\nexport function wrapLabel(label: string, perLine: number, maxLines = 2): string[] {\n if (label.length <= perLine) return [label];\n const cap = (s: string): string =>\n s.length > perLine ? s.slice(0, Math.max(1, perLine - 1)) + \"…\" : s;\n const lines: string[] = [\"\"];\n for (const word of label.split(/\\s+/)) {\n const last = lines.length - 1;\n const current = lines[last]!;\n if (current === \"\" || (current + \" \" + word).length <= perLine) {\n lines[last] = current === \"\" ? word : `${current} ${word}`;\n } else if (lines.length < maxLines) {\n lines.push(word);\n } else {\n lines[last] = `${current} ${word}`;\n }\n }\n // A trailing-whitespace \"word\" (\"a b \".split(/\\s+/) → [\"a\",\"b\",\"\"]) may open a line\n // it never fills; the historical code dropped that empty line, so this does too.\n if (lines.length > 1 && lines[lines.length - 1] === \"\") lines.pop();\n return lines.map(cap);\n}\n\n/**\n * House \"balanced\" wrap policy (extracted verbatim from the ecomap's tie-label wrap,\n * itself mirroring the genogram's): per-line budget `min(26, max(14, ceil(len/2)+2))`\n * splits a medium label into two roughly even lines instead of one long + one short,\n * then the greedy `wrapLabel` fill (and its `maxLines` semantics) applies. The shipped\n * renderers keep their local copies for now — new modules consume this one; migrating\n * them is a separate provably-zero-change refactor.\n */\nexport function wrapLabelBalanced(label: string, maxLines?: number): string[] {\n const perLine = Math.min(26, Math.max(14, Math.ceil(label.length / 2) + 2));\n return wrapLabel(label, perLine, maxLines);\n}\n\n/** Caps a verbatim label for a COMPACT render (preview); full text kept by the caller. */\nexport function clampLabel(label: string, maxChars: number | undefined): string {\n if (maxChars === undefined || label.length <= maxChars) return label;\n return label.slice(0, Math.max(1, maxChars - 1)) + \"…\";\n}\n\n/** Font stack shared by every emitter; PDF embedders typically map it onto Helvetica. */\nexport const FONT_FAMILY = \"Helvetica, Arial, sans-serif\";\n","// Shared legend machinery — the exact row format the genogram and ecomap emitters\n// currently duplicate character-for-character (`<g data-compasso-legend=\"true\">` with\n// swatch-closure rows). Extracted so new diagram modules don't add a third copy;\n// the two shipped emitters keep their local blocks for now (migrating them is a\n// separate, provably-zero-change refactor — pinned byte-for-byte against the ecomap's\n// emitted legend in test/core/legend.test.ts).\n//\n// The caller stays in charge of the HONESTY RULE half: it decides WHICH entries exist\n// (used-keys-only) and what each swatch draws; this module only owns the row geometry,\n// the text emission (xmlEscape — labels may come from caller-supplied packs), and the\n// width/height bookkeeping both renderers compute identically.\n\nimport { FONT_FAMILY, estimateTextWidth } from \"./text\";\nimport { xmlEscape } from \"./xml\";\n\n// Row metrics shared by every legend in the library. Exported because swatch builders\n// need them (a line swatch spans LEGEND_SWATCH_W; a glyph swatch centers on it).\nexport const LEGEND_ROW_H = 18;\nexport const LEGEND_PAD = 16;\nexport const LEGEND_SWATCH_W = 22;\nexport const LEGEND_GAP = 14;\nexport const LEGEND_FONT = 11;\n\n// Legend text ink — the zinc glyph stroke both shipped emitters use for legend labels.\nconst LEGEND_TEXT_FILL = \"#52525b\";\n\nexport interface LegendEntry {\n /**\n * Swatch markup builder, called with the swatch's left x and the row's center y.\n * The builder owns its own escaping/rounding (it typically reuses the module's\n * glyph/line emitters); it should draw within LEGEND_SWATCH_W of x.\n */\n swatch: (x: number, yCenter: number) => string;\n /** Display label (escaped here; verbatim pack text in, escaped SVG out). */\n label: string;\n}\n\nexport interface LegendBlock {\n /** `<g data-compasso-legend=\"true\">…</g>` — empty string when there are no entries. */\n svg: string;\n /** Minimum canvas width the legend needs; callers take `max(width, block.width)`. */\n width: number;\n /** New total canvas height including the legend; callers assign it directly. */\n height: number;\n}\n\n/**\n * Emits the legend group for the given entries below `startY` (the diagram's current\n * height). Pure + deterministic; coordinates are interpolated exactly as the shipped\n * emitters do. Zero entries (used-keys-only found nothing) → no markup, zero width\n * contribution, height unchanged — safe to call unconditionally.\n */\nexport function legendBlock(entries: readonly LegendEntry[], startY: number): LegendBlock {\n if (entries.length === 0) return { svg: \"\", width: 0, height: startY };\n const rows = entries.map((entry, i) => {\n const rowCenterY = startY + i * LEGEND_ROW_H + LEGEND_ROW_H / 2;\n const textX = LEGEND_PAD + LEGEND_SWATCH_W + LEGEND_GAP;\n return (\n entry.swatch(LEGEND_PAD, rowCenterY) +\n `<text x=\"${textX}\" y=\"${rowCenterY + LEGEND_FONT * 0.32}\" font-family=\"${FONT_FAMILY}\" font-size=\"${LEGEND_FONT}\" fill=\"${LEGEND_TEXT_FILL}\">${xmlEscape(entry.label)}</text>`\n );\n });\n const widestLabel = entries.reduce((m, e) => Math.max(m, estimateTextWidth(e.label, LEGEND_FONT)), 0);\n return {\n svg: `<g data-compasso-legend=\"true\">${rows.join(\"\")}</g>`,\n width: LEGEND_PAD + LEGEND_SWATCH_W + LEGEND_GAP + widestLabel + LEGEND_PAD,\n height: startY + entries.length * LEGEND_ROW_H + LEGEND_PAD / 2,\n };\n}\n","// Edge line styles — a neutral, presentation-only style for a relationship line.\n// NOT a judgment: a deterministic, lexical hint derived from the author's own quality\n// word. The literal word always rides the element's <title>, so a style never replaces\n// what was said. Unknown/ambiguous quality → \"plain\".\n\nexport type EdgeLineStyle = \"plain\" | \"close\" | \"distant\" | \"conflict\" | \"cutoff\";\n\n/** Stroke attributes per style — shared by every renderer so SVG and PDF match. */\nexport interface EdgeStroke {\n width: number;\n /** SVG dash array / PDF dash pattern as [dash, gap]; null = solid. */\n dash: [number, number] | null;\n opacity: number;\n}\n\nexport const EDGE_STROKE: Record<EdgeLineStyle, EdgeStroke> = {\n plain: { width: 1.5, dash: null, opacity: 0.6 },\n close: { width: 3, dash: null, opacity: 0.85 },\n distant: { width: 1.5, dash: [4, 4], opacity: 0.55 },\n conflict: { width: 2, dash: [2, 2], opacity: 0.75 },\n cutoff: { width: 1.5, dash: [6, 5], opacity: 0.4 },\n};\n\n/**\n * A pluggable lexicon mapping free-text quality words onto line styles. Needles are\n * diacritic-free, lowercase substrings of the author's own words; `negations` are\n * whole words that flip the meaning of the very word a needle would match (\"not\n * close\"), so their presence makes the matcher abstain to \"plain\" rather than risk\n * an inverted visual. Locale packs (e.g. `compasso/locales/pt-br`) ship alternates.\n */\nexport interface QualityLexicon {\n buckets: readonly { style: Exclude<EdgeLineStyle, \"plain\">; needles: readonly string[] }[];\n negations: readonly string[];\n}\n\n// English default. Conservative stems: each needle is a substring match on the\n// normalized text, and the SINGLE-BUCKET rule below keeps competing signals honest.\n// \"no\" alone is deliberately NOT a negation: \"no contact\" is a genuine cutoff signal.\nexport const QUALITY_LEXICON_EN: QualityLexicon = {\n buckets: [\n {\n style: \"close\",\n needles: [\"close\", \"warm\", \"support\", \"lov\", \"affection\", \"caring\", \"tight\", \"harmon\", \"healthy\"],\n },\n {\n style: \"distant\",\n needles: [\"distant\", \"detach\", \"absent\", \"cold\", \"drift\"],\n },\n {\n style: \"conflict\",\n needles: [\"conflict\", \"fight\", \"tens\", \"difficult\", \"hostil\", \"violen\", \"abus\", \"aggress\", \"complicat\", \"toxic\", \"argu\"],\n },\n {\n style: \"cutoff\",\n needles: [\"estrang\", \"cut off\", \"cutoff\", \"no contact\", \"broken off\", \"sever\"],\n },\n ],\n negations: [\"not\", \"never\", \"no longer\", \"hardly\"],\n};\n\n/** Lowercase + strip diacritics so matching ignores accents. */\nexport function normalizeText(text: string): string {\n return text.normalize(\"NFD\").replace(/[̀-ͯ]/g, \"\").toLowerCase();\n}\n\nconst escapeRegExp = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n/**\n * Maps a free-text relationship quality to a neutral line style. Deterministic and\n * conservative: returns a specific style ONLY when exactly one lexical bucket matches;\n * null/empty/ambiguous/negated/unknown all fall back to \"plain\". The caller still\n * keeps the verbatim quality word, so nothing the author said is ever lost.\n */\nexport function qualityLineStyle(\n quality: string | null,\n lexicon: QualityLexicon = QUALITY_LEXICON_EN,\n): EdgeLineStyle {\n if (quality === null) return \"plain\";\n const haystack = normalizeText(quality);\n if (haystack.trim() === \"\") return \"plain\";\n\n if (lexicon.negations.length > 0) {\n const negation = new RegExp(`\\\\b(${lexicon.negations.map(escapeRegExp).join(\"|\")})\\\\b`);\n if (negation.test(haystack)) return \"plain\";\n }\n\n const matched: EdgeLineStyle[] = [];\n for (const { style, needles } of lexicon.buckets) {\n if (needles.some((n) => haystack.includes(n))) matched.push(style);\n }\n return matched.length === 1 ? matched[0]! : \"plain\";\n}\n","// A discreet, NEUTRAL \"this element was annotated by the caller\" marker, shared by every\n// diagram family. compasso never decides what an annotation MEANS — the caller asserts the\n// `annotated` flag from its own domain knowledge and supplies the legend label; the library\n// only draws a standardised mark. Pure presentation: literal SVG primitives, no <defs>, no\n// <marker>, no CSS. The mark is a DECORATION drawn inside an element's existing <g> (like a\n// genogram deceased slash) — never a layout box or routed segment, so it cannot create or\n// hide an overlap. Ink is the shared zinc-600 glyph stroke (#52525b) for cross-family unity.\nimport { LEGEND_SWATCH_W } from \"./legend\";\nimport type { Point } from \"./geometry\";\n\nconst round = (n: number): number => Math.round(n * 100) / 100;\n\nexport const ANNOTATION_INK = \"#52525b\";\nconst DOT_R = 3;\nconst TICK_HALF = 3;\n\n/**\n * A small filled dot marking an annotated NODE. Pass the point where it should sit — callers\n * place it at the node's upper-right (inset), the conventional \"has a note\" corner.\n */\nexport function annotationDot(cx: number, cy: number): string {\n return `<circle cx=\"${round(cx)}\" cy=\"${round(cy)}\" r=\"${DOT_R}\" fill=\"${ANNOTATION_INK}\" fill-opacity=\"0.6\"/>`;\n}\n\n/**\n * A short tick perpendicular to an annotated EDGE at the midpoint of its middle segment.\n * Org-chart / genogram polylines are axis-aligned, so the perpendicular is trivial; a tick on\n * a near-diagonal falls back to a vertical mark. Returns \"\" for a degenerate (<2-point) path.\n */\nexport function annotationTick(points: readonly Point[]): string {\n if (points.length < 2) return \"\";\n const i = Math.floor((points.length - 1) / 2);\n const a = points[i]!;\n const b = points[i + 1] ?? points[i]!;\n const mx = (a.x + b.x) / 2;\n const my = (a.y + b.y) / 2;\n const horizontal = Math.abs(a.y - b.y) <= Math.abs(a.x - b.x);\n const x1 = horizontal ? mx : mx - TICK_HALF;\n const x2 = horizontal ? mx : mx + TICK_HALF;\n const y1 = horizontal ? my - TICK_HALF : my;\n const y2 = horizontal ? my + TICK_HALF : my;\n return `<line x1=\"${round(x1)}\" y1=\"${round(y1)}\" x2=\"${round(x2)}\" y2=\"${round(y2)}\" stroke=\"${ANNOTATION_INK}\" stroke-width=\"1.5\"/>`;\n}\n\n/** Legend swatch for the annotation row: the same dot, centred in the swatch column. */\nexport function annotationSwatch(x: number, yCenter: number): string {\n return annotationDot(x + LEGEND_SWATCH_W / 2, yCenter);\n}\n","// Radial ecomap renderer — center node + declared external ties on 1–2 concentric\n// rings, as a SELF-CONTAINED SVG string. Pure (data in, string out), deterministic\n// (same input → same SVG), no DOM, no dependencies.\n//\n// HONESTY RULE: the diagram presents ONLY what the caller declared. A tie's line style\n// is a conservative lexical hint from the author's own quality word (ambiguous/null →\n// neutral solid line, never a synthesized value); an arrowhead appears ONLY when a\n// direction was declared (null = no arrow, never a default). The verbatim text always\n// rides the element's <title>, so a style never replaces what was said.\n//\n// Ring assignment is a deterministic PRESENTATION rule — by input order (sorted by id),\n// alternating rings when the set is large — never by any reading of the tie's content.\n//\n// Every interpolated text passes xmlEscape (labels are author-controlled; the SVG may\n// be inlined via innerHTML or embedded in a PDF). All presentation attributes are\n// literal: a standalone SVG has no stylesheet. Arrowheads are explicit polygons, NOT\n// <marker> defs — marker support is unreliable in SVG-to-PDF embedders, and inline\n// polygons also avoid def-id collisions when several SVGs share one document.\n\nimport {\n EDGE_STROKE,\n FONT_FAMILY,\n LEGEND_SWATCH_W,\n annotationDot,\n annotationSwatch,\n clampLabel,\n estimateTextWidth,\n legendBlock,\n qualityLineStyle,\n wrapLabelBalanced,\n xmlEscape,\n type EdgeLineStyle,\n type LegendEntry,\n type QualityLexicon,\n} from \"../core\";\n\n// ── Input model ───────────────────────────────────────────────────────────────\n\n/** Declared flow of the tie, relative to the CENTER: \"in\" = toward the center. */\nexport type EcomapDirection = \"in\" | \"out\" | \"both\";\n\n/**\n * One declared tie between the center (person/household) and an external system\n * (work, faith, friends, healthcare…). `label` is the author's own naming, kept\n * verbatim. `quality` is the author's verbatim wording about the tie (null = not\n * declared = neutral line). `direction` follows the same doctrine: null = no arrow.\n */\nexport interface EcomapTie {\n id: number;\n label: string;\n quality: string | null;\n direction: EcomapDirection | null;\n /** Optional verbatim <title> override (defaults to \"label · quality\"). */\n title?: string;\n /**\n * Caller-asserted flag: this tie was annotated (e.g. edited by a professional).\n * compasso never interprets this — it only draws a neutral marker and, when\n * `annotationLabel` is supplied, adds a legend row. Default undefined = not annotated.\n */\n annotated?: boolean;\n}\n\nexport interface EcomapInput {\n /** Center node label (e.g. the person or household the map is about). */\n centerLabel: string;\n ties: EcomapTie[];\n}\n\n// ── Display vocabulary ────────────────────────────────────────────────────────\n\nexport interface EcomapLabels {\n bondStyles: Record<Exclude<EdgeLineStyle, \"plain\">, string>;\n /** Legend label for the neutral solid line (a declared tie with no styled quality). */\n neutralTie: string;\n /** Legend label for the arrowhead (declared direction of the tie). */\n direction: string;\n ariaLabel: string;\n}\n\nexport const ECOMAP_LABELS_EN: EcomapLabels = {\n bondStyles: {\n close: \"Close\",\n distant: \"Distant\",\n conflict: \"Conflictual\",\n cutoff: \"Cut off (no contact)\",\n },\n neutralTie: \"Declared tie\",\n direction: \"Declared direction of the tie\",\n ariaLabel: \"Ecomap\",\n};\n\nexport interface EcomapSvgOptions {\n /** Display clamp per tie label (verbatim text stays in the <title>). */\n maxLabelChars?: number;\n /** Node label font size (px); default 12. */\n fontSize?: number;\n /** Set false to suppress the legend (compact preview); default true. */\n legend?: boolean;\n /** Quality-word lexicon — English default; see `compasso/locales/pt-br`. */\n qualityLexicon?: QualityLexicon;\n /** Display vocabulary — English default; see locale packs. */\n labels?: EcomapLabels;\n /**\n * When provided AND at least one tie has `annotated: true`, a legend row is added\n * with this label (used-keys-only pattern). compasso supplies no default — the caller\n * owns the wording (domain-agnostic).\n */\n annotationLabel?: string;\n}\n\n// ── Geometry constants ────────────────────────────────────────────────────────\n\nconst PADDING = 32;\nconst LINE_H = 14;\nconst NODE_PAD_X = 14;\nconst NODE_PAD_Y = 9;\nconst CENTER_MIN_R = 36;\nconst RING_MIN_R = 150;\n/** Min gap between two adjacent node boxes on the same ring. */\nconst NODE_GAP = 24;\n/** Radial gap between the center circle and the inner ring's nearest box edge. */\nconst RADIAL_GAP = 40;\n/** Radial gap between the two rings when the set is large enough to split. */\nconst RING_GAP = 26;\n/** Above this many ties the layout alternates between two rings. */\nconst SINGLE_RING_MAX = 8;\n\n// Ink (zinc ramp on white — matches the genogram emitter).\nconst NODE_STROKE = \"#52525b\";\nconst LABEL_FILL = \"#3f3f46\";\nconst EDGE_INK = \"#71717a\";\n// Legend row geometry + the swatch span both live in ../core (LEGEND_SWATCH_W imported\n// above for the swatch closures); the row/text/width/height bookkeeping is legendBlock.\n\nconst round = (n: number): number => Math.round(n * 100) / 100;\n\n// ── Internal shapes ───────────────────────────────────────────────────────────\n\ninterface SatNode {\n tie: EcomapTie;\n lines: string[];\n rx: number;\n ry: number;\n /** Filled once ring radii are known. */\n x: number;\n y: number;\n angle: number;\n style: EdgeLineStyle;\n}\n\n/** Arrowhead polygon: tip at (tipX,tipY), pointing along the unit vector (ux,uy). */\nfunction arrowHead(tipX: number, tipY: number, ux: number, uy: number, opacity: number): string {\n const LEN = 9;\n const HALF_W = 4.5;\n const bx = tipX - ux * LEN;\n const by = tipY - uy * LEN;\n const px = -uy;\n const py = ux;\n const points = [\n `${round(tipX)},${round(tipY)}`,\n `${round(bx + px * HALF_W)},${round(by + py * HALF_W)}`,\n `${round(bx - px * HALF_W)},${round(by - py * HALF_W)}`,\n ].join(\" \");\n return `<polygon points=\"${points}\" fill=\"${EDGE_INK}\" fill-opacity=\"${opacity}\"/>`;\n}\n\n/**\n * Renders a declared ecomap to a self-contained SVG string. Deterministic: same data →\n * same SVG. Zero ties yield a valid center-only SVG; callers decide their own empty\n * state before calling. The root keeps numeric width/height attributes plus a matching\n * viewBox (PDF-embedder contract).\n */\nexport function ecomapSvg(input: EcomapInput, opts: EcomapSvgOptions = {}): string {\n const fontSize = opts.fontSize ?? 12;\n const labels = opts.labels ?? ECOMAP_LABELS_EN;\n\n // ── Measure every satellite box (deterministic order: by tie id). ───────────\n const sats: SatNode[] = [...input.ties]\n .sort((a, b) => a.id - b.id)\n .map((tie) => {\n const lines = wrapLabelBalanced(clampLabel(tie.label, opts.maxLabelChars));\n const w = Math.max(...lines.map((l) => estimateTextWidth(l, fontSize))) + NODE_PAD_X * 2;\n const h = lines.length * LINE_H + NODE_PAD_Y * 2;\n return {\n tie,\n lines,\n rx: Math.max(40, w / 2),\n ry: Math.max(20, h / 2),\n x: 0,\n y: 0,\n angle: 0,\n style: qualityLineStyle(tie.quality, opts.qualityLexicon),\n };\n });\n\n const centerLines = wrapLabelBalanced(input.centerLabel);\n const centerR = Math.max(\n CENTER_MIN_R,\n Math.max(...centerLines.map((l) => estimateTextWidth(l, fontSize))) / 2 + 12,\n (centerLines.length * LINE_H) / 2 + 12,\n );\n\n // ── Ring radii: wide enough that NO two node boxes can ever touch. The safe\n // center-to-center distance is the diagonal of the worst-case box pair: if the\n // euclidean distance is ≥ hypot(width-sum, height-sum), the axis-aligned boxes\n // cannot overlap in both axes at once. Overlap-proof by construction, not by luck.\n const n = sats.length;\n const maxRx = n > 0 ? Math.max(...sats.map((s) => s.rx)) : 0;\n const maxRy = n > 0 ? Math.max(...sats.map((s) => s.ry)) : 0;\n const twoRings = n > SINGLE_RING_MAX;\n const stepAngle = n > 0 ? (Math.PI * 2) / n : Math.PI;\n const safeDist = Math.hypot(2 * maxRx + NODE_GAP, 2 * maxRy + NODE_GAP);\n /** Min radius so two nodes `steps` angular steps apart on the SAME ring clear safeDist. */\n const sameRingRadius = (steps: number): number => {\n const theta = steps * stepAngle;\n if (n <= 1 || theta >= Math.PI) return 0; // ≤2 nodes on the ring: no chord constraint\n return safeDist / (2 * Math.sin(theta / 2));\n };\n const ringStep = maxRy * 2 + RING_GAP;\n let innerR = Math.max(\n RING_MIN_R,\n centerR + RADIAL_GAP + maxRy,\n sameRingRadius(twoRings ? 2 : 1),\n );\n if (twoRings) {\n // Cross-ring neighbors sit 1 step apart at radii r and r+ringStep. Their distance\n // sqrt(r² + (r+s)² − 2r(r+s)cosΔ) grows monotonically with r — widen the inner ring\n // in fixed increments until it clears safeDist (deterministic, always terminates).\n const crossDist = (r: number): number =>\n Math.sqrt(r * r + (r + ringStep) ** 2 - 2 * r * (r + ringStep) * Math.cos(stepAngle));\n while (crossDist(innerR) < safeDist) innerR += 8;\n }\n const outerR = innerR + ringStep;\n\n for (let i = 0; i < n; i++) {\n const s = sats[i]!;\n s.angle = -Math.PI / 2 + (i * Math.PI * 2) / n;\n const r = twoRings && i % 2 === 1 ? outerR : innerR;\n s.x = r * Math.cos(s.angle);\n s.y = r * Math.sin(s.angle);\n }\n\n // ── Canvas bounds (center at origin until here), then shift positive. ───────\n let minX = -centerR;\n let minY = -centerR;\n let maxX = centerR;\n let maxY = centerR;\n for (const s of sats) {\n minX = Math.min(minX, s.x - s.rx);\n minY = Math.min(minY, s.y - s.ry);\n maxX = Math.max(maxX, s.x + s.rx);\n maxY = Math.max(maxY, s.y + s.ry);\n }\n const dx = PADDING - minX;\n const dy = PADDING - minY;\n const cx = dx;\n const cy = dy;\n for (const s of sats) {\n s.x += dx;\n s.y += dy;\n }\n let width = maxX - minX + PADDING * 2;\n let height = maxY - minY + PADDING * 2;\n\n const parts: string[] = [];\n\n // ── Tie lines first (nodes sit on top), one group per declared tie. ─────────\n for (const s of sats) {\n const ux = (cx - s.x) / Math.hypot(cx - s.x, cy - s.y);\n const uy = (cy - s.y) / Math.hypot(cx - s.x, cy - s.y);\n // Node-edge endpoint: ellipse boundary along the unit vector toward the center.\n const scale = 1 / Math.hypot(ux / s.rx, uy / s.ry);\n const x1 = s.x + ux * scale;\n const y1 = s.y + uy * scale;\n // Center-edge endpoint: circle boundary along the same direction.\n const x2 = cx - ux * centerR;\n const y2 = cy - uy * centerR;\n\n const ink = EDGE_STROKE[s.style];\n const dashAttr = ink.dash === null ? \"\" : ` stroke-dasharray=\"${ink.dash[0]} ${ink.dash[1]}\"`;\n const title = s.tie.title ?? (s.tie.quality !== null ? `${s.tie.label} · ${s.tie.quality}` : s.tie.label);\n const body: string[] = [\n `<line x1=\"${round(x1)}\" y1=\"${round(y1)}\" x2=\"${round(x2)}\" y2=\"${round(y2)}\" stroke=\"${EDGE_INK}\" stroke-width=\"${ink.width}\" stroke-opacity=\"${ink.opacity}\"${dashAttr}/>`,\n ];\n // Arrowheads ONLY for a declared direction. \"in\" points at the center, \"out\" at\n // the external system, \"both\" draws both. Tips back off the boundary so the\n // triangle never pokes into the shape.\n if (s.tie.direction === \"in\" || s.tie.direction === \"both\") {\n body.push(arrowHead(x2, y2, ux, uy, ink.opacity)); // tip at the center edge\n }\n if (s.tie.direction === \"out\" || s.tie.direction === \"both\") {\n body.push(arrowHead(x1, y1, -ux, -uy, ink.opacity)); // tip at the system edge\n }\n parts.push(`<g data-edge-id=\"${s.tie.id}\"><title>${xmlEscape(title)}</title>${body.join(\"\")}</g>`);\n }\n\n // ── Center node. ─────────────────────────────────────────────────────────────\n {\n const tspans = centerLines\n .map(\n (line, i) =>\n `<tspan x=\"${round(cx)}\" y=\"${round(cy - ((centerLines.length - 1) * LINE_H) / 2 + i * LINE_H + fontSize * 0.32)}\">${xmlEscape(line)}</tspan>`,\n )\n .join(\"\");\n parts.push(\n `<g data-individual-id=\"center\"><title>${xmlEscape(input.centerLabel)}</title>` +\n `<circle cx=\"${round(cx)}\" cy=\"${round(cy)}\" r=\"${round(centerR)}\" fill=\"transparent\" stroke=\"${NODE_STROKE}\" stroke-width=\"2\"/>` +\n `<text text-anchor=\"middle\" font-family=\"${FONT_FAMILY}\" font-size=\"${fontSize}\" fill=\"${LABEL_FILL}\">${tspans}</text></g>`,\n );\n }\n\n // ── Satellite nodes. ─────────────────────────────────────────────────────────\n for (const s of sats) {\n const tspans = s.lines\n .map(\n (line, i) =>\n `<tspan x=\"${round(s.x)}\" y=\"${round(s.y - ((s.lines.length - 1) * LINE_H) / 2 + i * LINE_H + fontSize * 0.32)}\">${xmlEscape(line)}</tspan>`,\n )\n .join(\"\");\n const pieces: string[] = [\n `<title>${xmlEscape(s.tie.label)}</title>`,\n `<ellipse cx=\"${round(s.x)}\" cy=\"${round(s.y)}\" rx=\"${round(s.rx)}\" ry=\"${round(s.ry)}\" fill=\"transparent\" stroke=\"${NODE_STROKE}\" stroke-width=\"1.5\"/>`,\n `<text text-anchor=\"middle\" font-family=\"${FONT_FAMILY}\" font-size=\"${fontSize}\" fill=\"${LABEL_FILL}\">${tspans}</text>`,\n ];\n if (s.tie.annotated) {\n pieces.push(annotationDot(s.x + 0.7 * s.rx, s.y - 0.7 * s.ry));\n }\n parts.push(`<g data-individual-id=\"e${s.tie.id}\">${pieces.join(\"\")}</g>`);\n }\n\n // ── Minimal legend: only entries actually used. ──────────────────────────────\n if (opts.legend !== false && sats.length > 0) {\n const entries: LegendEntry[] = [];\n\n if (sats.some((s) => s.style === \"plain\")) {\n entries.push({\n swatch: (x, y) =>\n `<line x1=\"${x}\" y1=\"${y}\" x2=\"${x + LEGEND_SWATCH_W}\" y2=\"${y}\" stroke=\"${EDGE_INK}\" stroke-width=\"${EDGE_STROKE.plain.width}\" stroke-opacity=\"${EDGE_STROKE.plain.opacity}\"/>`,\n label: labels.neutralTie,\n });\n }\n const stylesUsed = new Set(sats.map((s) => s.style));\n for (const style of [\"close\", \"distant\", \"conflict\", \"cutoff\"] as const) {\n if (!stylesUsed.has(style)) continue;\n const ink = EDGE_STROKE[style];\n const dashAttr = ink.dash === null ? \"\" : ` stroke-dasharray=\"${ink.dash[0]} ${ink.dash[1]}\"`;\n entries.push({\n swatch: (x, y) =>\n `<line x1=\"${x}\" y1=\"${y}\" x2=\"${x + LEGEND_SWATCH_W}\" y2=\"${y}\" stroke=\"${EDGE_INK}\" stroke-width=\"${ink.width}\" stroke-opacity=\"${ink.opacity}\"${dashAttr}/>`,\n label: labels.bondStyles[style],\n });\n }\n if (sats.some((s) => s.tie.direction !== null)) {\n entries.push({\n swatch: (x, y) =>\n `<line x1=\"${x}\" y1=\"${y}\" x2=\"${x + LEGEND_SWATCH_W - 8}\" y2=\"${y}\" stroke=\"${EDGE_INK}\" stroke-width=\"1.5\" stroke-opacity=\"0.75\"/>` +\n arrowHead(x + LEGEND_SWATCH_W, y, 1, 0, 0.75),\n label: labels.direction,\n });\n }\n if (opts.annotationLabel !== undefined && sats.some((s) => s.tie.annotated)) {\n entries.push({\n swatch: (x, y) => annotationSwatch(x, y),\n label: opts.annotationLabel,\n });\n }\n\n if (entries.length > 0) {\n const block = legendBlock(entries, height);\n parts.push(block.svg);\n width = Math.max(width, block.width);\n height = block.height;\n }\n }\n\n const w = Math.ceil(width);\n const h = Math.ceil(height);\n return (\n `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${w} ${h}\" width=\"${w}\" height=\"${h}\" role=\"img\" aria-label=\"${xmlEscape(labels.ariaLabel)}\">` +\n parts.join(\"\") +\n `</svg>`\n );\n}\n"]}
@@ -15,6 +15,12 @@ interface EcomapTie {
15
15
  direction: EcomapDirection | null;
16
16
  /** Optional verbatim <title> override (defaults to "label · quality"). */
17
17
  title?: string;
18
+ /**
19
+ * Caller-asserted flag: this tie was annotated (e.g. edited by a professional).
20
+ * compasso never interprets this — it only draws a neutral marker and, when
21
+ * `annotationLabel` is supplied, adds a legend row. Default undefined = not annotated.
22
+ */
23
+ annotated?: boolean;
18
24
  }
19
25
  interface EcomapInput {
20
26
  /** Center node label (e.g. the person or household the map is about). */
@@ -41,6 +47,12 @@ interface EcomapSvgOptions {
41
47
  qualityLexicon?: QualityLexicon;
42
48
  /** Display vocabulary — English default; see locale packs. */
43
49
  labels?: EcomapLabels;
50
+ /**
51
+ * When provided AND at least one tie has `annotated: true`, a legend row is added
52
+ * with this label (used-keys-only pattern). compasso supplies no default — the caller
53
+ * owns the wording (domain-agnostic).
54
+ */
55
+ annotationLabel?: string;
44
56
  }
45
57
  /**
46
58
  * Renders a declared ecomap to a self-contained SVG string. Deterministic: same data →
@@ -15,6 +15,12 @@ interface EcomapTie {
15
15
  direction: EcomapDirection | null;
16
16
  /** Optional verbatim <title> override (defaults to "label · quality"). */
17
17
  title?: string;
18
+ /**
19
+ * Caller-asserted flag: this tie was annotated (e.g. edited by a professional).
20
+ * compasso never interprets this — it only draws a neutral marker and, when
21
+ * `annotationLabel` is supplied, adds a legend row. Default undefined = not annotated.
22
+ */
23
+ annotated?: boolean;
18
24
  }
19
25
  interface EcomapInput {
20
26
  /** Center node label (e.g. the person or household the map is about). */
@@ -41,6 +47,12 @@ interface EcomapSvgOptions {
41
47
  qualityLexicon?: QualityLexicon;
42
48
  /** Display vocabulary — English default; see locale packs. */
43
49
  labels?: EcomapLabels;
50
+ /**
51
+ * When provided AND at least one tie has `annotated: true`, a legend row is added
52
+ * with this label (used-keys-only pattern). compasso supplies no default — the caller
53
+ * owns the wording (domain-agnostic).
54
+ */
55
+ annotationLabel?: string;
44
56
  }
45
57
  /**
46
58
  * Renders a declared ecomap to a self-contained SVG string. Deterministic: same data →
@@ -1,4 +1,4 @@
1
- export { ECOMAP_LABELS_EN, ecomapSvg } from '../chunk-Q6DVTCXD.js';
2
- import '../chunk-O3BT2O42.js';
1
+ export { ECOMAP_LABELS_EN, ecomapSvg } from '../chunk-3RGYLVTN.js';
2
+ import '../chunk-DVLWT565.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  import { f as FaultTreeInput, i as GateType, d as FaultTreeEventKind, h as FaultTreeTitleLabels, g as FaultTreeSvgLabels } from '../labels-CYbM5XV7.cjs';
2
2
  export { A as AndGate, F as FAULT_TREE_EVENT_KINDS, a as FAULT_TREE_SVG_LABELS_EN, b as FAULT_TREE_TITLE_LABELS_EN, c as FaultTreeEvent, e as FaultTreeGate, G as GATE_TYPES, I as InhibitGate, O as OrGate, V as VoteGate, X as XorGate } from '../labels-CYbM5XV7.cjs';
3
- import { P as Point } from '../text-DuO_PwYw.cjs';
4
- export { e as estimateTextWidth } from '../text-DuO_PwYw.cjs';
3
+ import { P as Point } from '../geometry-P-XGqGe7.cjs';
4
+ export { e as estimateTextWidth } from '../text-DDVzpwPZ.cjs';
5
5
 
6
6
  /** Stable machine-readable issue codes (kebab-case; part of the public contract). */
7
7
  type FaultTreeIssueCode = "duplicate-id" | "top-not-intermediate" | "top-as-input" | "gate-on-non-intermediate" | "transfer-with-gate" | "event-with-two-gates" | "event-without-gate" | "intermediate-reused" | "unknown-input" | "conditioning-as-input" | "inhibit-condition" | "gate-arity" | "vote-threshold" | "unreachable-event" | "cycle";
@@ -1,7 +1,7 @@
1
1
  import { f as FaultTreeInput, i as GateType, d as FaultTreeEventKind, h as FaultTreeTitleLabels, g as FaultTreeSvgLabels } from '../labels-CYbM5XV7.js';
2
2
  export { A as AndGate, F as FAULT_TREE_EVENT_KINDS, a as FAULT_TREE_SVG_LABELS_EN, b as FAULT_TREE_TITLE_LABELS_EN, c as FaultTreeEvent, e as FaultTreeGate, G as GATE_TYPES, I as InhibitGate, O as OrGate, V as VoteGate, X as XorGate } from '../labels-CYbM5XV7.js';
3
- import { P as Point } from '../text-DuO_PwYw.js';
4
- export { e as estimateTextWidth } from '../text-DuO_PwYw.js';
3
+ import { P as Point } from '../geometry-P-XGqGe7.js';
4
+ export { e as estimateTextWidth } from '../text-DDVzpwPZ.js';
5
5
 
6
6
  /** Stable machine-readable issue codes (kebab-case; part of the public contract). */
7
7
  type FaultTreeIssueCode = "duplicate-id" | "top-not-intermediate" | "top-as-input" | "gate-on-non-intermediate" | "transfer-with-gate" | "event-with-two-gates" | "event-without-gate" | "intermediate-reused" | "unknown-input" | "conditioning-as-input" | "inhibit-condition" | "gate-arity" | "vote-threshold" | "unreachable-event" | "cycle";
@@ -1,4 +1,4 @@
1
- export { CODE_FONT, FAULT_TREE_EVENT_KINDS, FAULT_TREE_SVG_LABELS_EN, FAULT_TREE_TITLE_LABELS_EN, FT_BUS_ID_BASE, FT_CONDITION_ID_BASE, FT_DROP_ID_BASE, FT_LABEL_FONT, FT_LABEL_LINE_H, FT_RISER_ID_BASE, FT_STEM_ID_BASE, FaultTreeValidationError, GATE_TYPES, LABEL_GAP, computeFaultTreeLayout, faultTreeIssues, faultTreeLayoutSvg, faultTreeSvg, validateFaultTree } from '../chunk-LRHHUJFZ.js';
2
- export { estimateTextWidth } from '../chunk-O3BT2O42.js';
1
+ export { CODE_FONT, FAULT_TREE_EVENT_KINDS, FAULT_TREE_SVG_LABELS_EN, FAULT_TREE_TITLE_LABELS_EN, FT_BUS_ID_BASE, FT_CONDITION_ID_BASE, FT_DROP_ID_BASE, FT_LABEL_FONT, FT_LABEL_LINE_H, FT_RISER_ID_BASE, FT_STEM_ID_BASE, FaultTreeValidationError, GATE_TYPES, LABEL_GAP, computeFaultTreeLayout, faultTreeIssues, faultTreeLayoutSvg, faultTreeSvg, validateFaultTree } from '../chunk-RDH4XHA2.js';
2
+ export { estimateTextWidth } from '../chunk-DVLWT565.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- export { FISHBONE_LABELS_EN, FishboneValidationError, fishboneSvg } from '../chunk-ZBDABVIO.js';
2
- import '../chunk-O3BT2O42.js';
1
+ export { FISHBONE_LABELS_EN, FishboneValidationError, fishboneSvg } from '../chunk-2NDET6O5.js';
2
+ import '../chunk-DVLWT565.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map