@diagrammo/dgmo 0.87.0 → 0.89.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 (149) hide show
  1. package/README.md +4 -2
  2. package/dist/advanced.d.ts +47 -11
  3. package/dist/advanced.js +110 -106
  4. package/dist/{analyzer-R5UBTRO2.js → analyzer-7ZGAZIE6.js} +2 -2
  5. package/dist/block.js +26 -25
  6. package/dist/{chart-meta-PbgpGwYo.d.ts → chart-meta-Bev5Ebjr.d.ts} +1 -1
  7. package/dist/chart-meta.d.ts +2 -2
  8. package/dist/chart-meta.js +11 -11
  9. package/dist/{chart-types-Db_EGf1o.d.ts → chart-types-Bf8C5QQW.d.ts} +1 -1
  10. package/dist/{charts-d3-3BZRSZV6.js → charts-d3-KEQSUWKP.js} +10 -10
  11. package/dist/{chunk-LJFXC3IP.js → chunk-2GM7N5TV.js} +10 -10
  12. package/dist/{chunk-H2GEIFUF.js → chunk-3AQJNY65.js} +8 -8
  13. package/dist/chunk-44FTCIRI.js +438 -0
  14. package/dist/{chunk-WZ23JJ7U.js → chunk-4AJKOUBO.js} +11 -11
  15. package/dist/{chunk-YK4N6TBN.js → chunk-4R6OMKXB.js} +7 -7
  16. package/dist/{chunk-HEYGGSNQ.js → chunk-5LE2CTLS.js} +2 -2
  17. package/dist/{chunk-AGO3PFGS.js → chunk-7C2RAGPT.js} +46 -31
  18. package/dist/{chunk-VJ2KROJ5.js → chunk-7KPHRTND.js} +1 -1
  19. package/dist/{chunk-LHL6HDUL.js → chunk-7SX4IY6T.js} +84 -12
  20. package/dist/{chunk-LSQGJN5H.js → chunk-7W4XLIVH.js} +15 -15
  21. package/dist/{chunk-Q2U5635V.js → chunk-ABP5BUD6.js} +9 -430
  22. package/dist/{chunk-XUDGZJTJ.js → chunk-AZ24RI5L.js} +6 -6
  23. package/dist/{chunk-UMRZPRAN.js → chunk-BB6QKWHZ.js} +15 -15
  24. package/dist/{chunk-6I5UN4FD.js → chunk-C4FRGZGX.js} +4 -4
  25. package/dist/{chunk-3DOQOXXI.js → chunk-CNUN5GO6.js} +1 -1
  26. package/dist/{chunk-5KGM44TG.js → chunk-CX6OH5WP.js} +1 -1
  27. package/dist/{chunk-D4M25W6R.js → chunk-DDPGEGHB.js} +5 -5
  28. package/dist/{chunk-B7CU2HW5.js → chunk-DZPHN2WN.js} +9 -9
  29. package/dist/{chunk-O6MMQQLF.js → chunk-ECMA6XE2.js} +10 -10
  30. package/dist/{chunk-MGBV4JEI.js → chunk-EDXGEQW3.js} +1 -1
  31. package/dist/{chunk-FBKPSU3A.js → chunk-EXKCRXPO.js} +9 -9
  32. package/dist/{chunk-HTPZDZKQ.js → chunk-FKLE6QA3.js} +13 -13
  33. package/dist/{chunk-ERNCPKD4.js → chunk-G2KHLANR.js} +1 -1
  34. package/dist/{chunk-NJIGYGZS.js → chunk-HAMF4F3P.js} +12 -7
  35. package/dist/{chunk-UY6TEJJH.js → chunk-HJRP6PXL.js} +1 -1
  36. package/dist/{chunk-LNO3ASX5.js → chunk-HUNDJTTH.js} +1 -1
  37. package/dist/{chunk-RH2PROYG.js → chunk-I6GGMCTV.js} +4 -2
  38. package/dist/{chunk-DOXBS7F5.js → chunk-ID2K3IHI.js} +4 -4
  39. package/dist/{chunk-33FQ6HNV.js → chunk-IQ6P3HDE.js} +9 -9
  40. package/dist/{chunk-BAZT6CIF.js → chunk-ITSBBQTH.js} +7 -7
  41. package/dist/{chunk-UNNJCSSQ.js → chunk-JVZ7KFAX.js} +1 -1
  42. package/dist/{chunk-AQIBKTPG.js → chunk-K5XT7NHD.js} +3 -3
  43. package/dist/{chunk-HAH5X345.js → chunk-KATED53P.js} +1 -1
  44. package/dist/{chunk-7HWY4QAJ.js → chunk-L24LESXF.js} +1 -0
  45. package/dist/{chunk-VPASQOR3.js → chunk-LFKSHDVI.js} +1 -1
  46. package/dist/{chunk-XVSJYAK7.js → chunk-LPYYZCSI.js} +2 -2
  47. package/dist/{chunk-BV6PKJUS.js → chunk-LR6RRDWN.js} +5 -5
  48. package/dist/{chunk-DAX42XVH.js → chunk-LYLNMN77.js} +8 -8
  49. package/dist/{chunk-PJQZWJ5I.js → chunk-M2BCY7H3.js} +1015 -146
  50. package/dist/{chunk-A4XPI4YN.js → chunk-MFW6P7WH.js} +27 -0
  51. package/dist/{chunk-CFBY77QJ.js → chunk-N4BBSDWI.js} +9 -9
  52. package/dist/{chunk-IDJGV6VM.js → chunk-NIUO2TNR.js} +215 -1
  53. package/dist/{chunk-PLE2432T.js → chunk-NRPELUB6.js} +2 -2
  54. package/dist/{chunk-FM3WAVB6.js → chunk-NS7L7YKH.js} +1 -1
  55. package/dist/{chunk-YMG7JDEY.js → chunk-NSR2CGV6.js} +71 -24
  56. package/dist/{chunk-LD2JSKU3.js → chunk-OOCVGX4W.js} +15 -0
  57. package/dist/{chunk-N4XHXBDQ.js → chunk-PMNITNPR.js} +4 -4
  58. package/dist/{chunk-MSXRNVHB.js → chunk-Q6SQISHT.js} +12 -11
  59. package/dist/{chunk-UNAP6O26.js → chunk-QIOYTQDZ.js} +9 -9
  60. package/dist/{chunk-BT2WH2XT.js → chunk-RGWYZR3S.js} +1 -1
  61. package/dist/{chunk-PPH6ILHL.js → chunk-RPKBWJBB.js} +4 -4
  62. package/dist/{chunk-JD4RHBNX.js → chunk-RXIKESRI.js} +7 -7
  63. package/dist/{chunk-BMUWF77V.js → chunk-S2WE7TVK.js} +4 -4
  64. package/dist/{chunk-QFIXL3OK.js → chunk-SEKNYIMO.js} +1 -1
  65. package/dist/{chunk-FPXMCGS5.js → chunk-SLQT3JP3.js} +1 -1
  66. package/dist/{chunk-LL6D3MES.js → chunk-SOPM5PLO.js} +9 -9
  67. package/dist/{chunk-J7Q4VPBJ.js → chunk-TAP2NZEU.js} +22 -16
  68. package/dist/{chunk-RE6TVIAV.js → chunk-UKJLPA7R.js} +4 -4
  69. package/dist/{chunk-RGI64U3A.js → chunk-UQLHKLF4.js} +9 -9
  70. package/dist/{chunk-LPXC4I4R.js → chunk-UWKRPQZO.js} +61 -32
  71. package/dist/{chunk-XIFK423U.js → chunk-W7QN5BC5.js} +4 -4
  72. package/dist/{chunk-XWYR5T52.js → chunk-WEF6MXFG.js} +14 -14
  73. package/dist/{chunk-P5V63L35.js → chunk-WP22MHH6.js} +17 -17
  74. package/dist/{chunk-PUVTFUNH.js → chunk-WRCAH3UO.js} +18 -18
  75. package/dist/{chunk-N7XRBWXA.js → chunk-XJ2TBXHA.js} +10 -10
  76. package/dist/{chunk-DSG6GBUQ.js → chunk-XUCQVKLQ.js} +6 -6
  77. package/dist/{chunk-NZCSVD4M.js → chunk-Y7PSAHAY.js} +8 -8
  78. package/dist/{chunk-AAMCXQPP.js → chunk-YMFQLWZ2.js} +6 -6
  79. package/dist/completion-registry.d.ts +1 -1
  80. package/dist/completion-registry.js +4 -16
  81. package/dist/countdown.js +1 -1
  82. package/dist/{dgmo-router-F2DSURTR.js → dgmo-router-7WANZOBD.js} +11 -11
  83. package/dist/{dimensions-6QAWEGIR.js → dimensions-7MF7VSGS.js} +6 -6
  84. package/dist/{flowchart-renderer-THC6Y7EH.js → flowchart-renderer-DZQZRL2F.js} +6 -5
  85. package/dist/index.d.ts +1 -1
  86. package/dist/index.js +28 -27
  87. package/dist/{layout-P6DTD4RT.js → layout-4RRC7XU7.js} +2 -2
  88. package/dist/{layout-QX5T6ZNE.js → layout-6L3BIFEZ.js} +4 -4
  89. package/dist/{layout-SOPAVXIH.js → layout-DXVAYF6W.js} +3 -3
  90. package/dist/{layout-LUQKAGGT.js → layout-EFEZ533S.js} +4 -4
  91. package/dist/{layout-EHTYSMV4.js → layout-H4K54IW3.js} +2 -2
  92. package/dist/{layout-AM57TGN5.js → layout-IGAVGDME.js} +3 -3
  93. package/dist/{layout-5NPBHV5F.js → layout-PP36LUTA.js} +2 -2
  94. package/dist/{layout-CUFA7XJD.js → layout-Q3RYSODA.js} +4 -4
  95. package/dist/layout-XUW444O5.js +1 -1
  96. package/dist/{layout-BOVTLAOT.js → layout-ZP7XYVXF.js} +2 -2
  97. package/dist/{layout-search-VKSBUCDM.js → layout-search-YKUL4VBV.js} +105 -6
  98. package/dist/{legend-constants-ZVO4FLAK.js → legend-constants-HE7FVDJP.js} +4 -2
  99. package/dist/{palettes-BIV54XLS.js → palettes-WZAIQTEG.js} +6 -4
  100. package/dist/{parser-ACW6C6OY.js → parser-337TACHB.js} +1 -1
  101. package/dist/{parser-WUK6CP5X.js → parser-GCCWMBTU.js} +3 -3
  102. package/dist/{parser-GPW4ZHPQ.js → parser-IMM2JJX3.js} +2 -1
  103. package/dist/{parser-JXS4426S.js → parser-P4TOQYNN.js} +2 -2
  104. package/dist/{parser-PVIWHVGY.js → parser-TL3JA4RI.js} +1 -1
  105. package/dist/{parser-C327BBE3.js → parser-UTXFJG4X.js} +1 -1
  106. package/dist/{renderer-RWJ45DWH.js → renderer-2ZQ6DPVD.js} +3 -3
  107. package/dist/{renderer-NHPKNNBD.js → renderer-3AD4NDF5.js} +9 -9
  108. package/dist/{renderer-2KVQGGTT.js → renderer-43ESBXVY.js} +8 -8
  109. package/dist/{renderer-A4LMOBZL.js → renderer-4JE5ORRO.js} +12 -12
  110. package/dist/{renderer-RAATRF6W.js → renderer-5GZNGZU5.js} +7 -7
  111. package/dist/{renderer-RMGN3Q7D.js → renderer-6OQM32X3.js} +3 -3
  112. package/dist/{renderer-222OTVQV.js → renderer-7HOSI6JJ.js} +4 -4
  113. package/dist/{renderer-NX4YKWCJ.js → renderer-7L7J4DHO.js} +8 -8
  114. package/dist/{renderer-DCFQDBGJ.js → renderer-7MCC6GKH.js} +2 -2
  115. package/dist/{renderer-3FF4QVGW.js → renderer-7VQOKAII.js} +8 -8
  116. package/dist/{renderer-4BHOELCE.js → renderer-BLHN3RCY.js} +3 -3
  117. package/dist/{renderer-PQYO2HCE.js → renderer-CEIX5JPA.js} +3 -3
  118. package/dist/{renderer-2OOPQ4CH.js → renderer-CHQZES6G.js} +3 -3
  119. package/dist/{renderer-36JH4OMC.js → renderer-DBNDLKPE.js} +9 -9
  120. package/dist/{renderer-KVAQE7PQ.js → renderer-DCJ4AQ3N.js} +7 -7
  121. package/dist/{renderer-LODEVN3V.js → renderer-EAORWLVK.js} +10 -10
  122. package/dist/{renderer-XRALFCIN.js → renderer-FCXRDYSJ.js} +8 -8
  123. package/dist/{renderer-YDAVCRTP.js → renderer-IR5GGAPB.js} +8 -8
  124. package/dist/{renderer-QM23SWAM.js → renderer-J4OS77PK.js} +2 -2
  125. package/dist/{renderer-4BIMRO4X.js → renderer-JR2XNZAH.js} +6 -6
  126. package/dist/{renderer-JKV2DBYP.js → renderer-JRVY7HAD.js} +6 -6
  127. package/dist/{renderer-R34GJL7U.js → renderer-NAA7D33G.js} +11 -11
  128. package/dist/{renderer-SDUSBCJI.js → renderer-P4XCRNCY.js} +7 -7
  129. package/dist/{renderer-A6ACVK4X.js → renderer-QQHQY3GT.js} +6 -6
  130. package/dist/{renderer-YIZ7G4HU.js → renderer-TJJGFQGT.js} +13 -13
  131. package/dist/{renderer-3CTUWCO7.js → renderer-VGQMJC5K.js} +12 -12
  132. package/dist/{renderer-ELYPDPNF.js → renderer-VYWCMRWA.js} +8 -7
  133. package/dist/{renderer-WH2HWE5Z.js → renderer-WB75JME5.js} +8 -8
  134. package/dist/{renderer-BICLPGAH.js → renderer-WQ654YT5.js} +2 -2
  135. package/dist/{renderer-6BUUTWVS.js → renderer-XFEZ5UBE.js} +8 -8
  136. package/dist/{renderer-4NZZ5J2F.js → renderer-XHEMXBQM.js} +7 -7
  137. package/dist/{renderer-RENDISO5.js → renderer-YTEZK3GC.js} +12 -12
  138. package/dist/{renderer-X5A5VIRD.js → renderer-ZXQXRNDR.js} +8 -8
  139. package/dist/{renderer-radial-XZ5TKUT4.js → renderer-radial-NA5DVBG4.js} +7 -7
  140. package/dist/{state-renderer-5IQ4OJUI.js → state-renderer-4S2C2CHB.js} +9 -9
  141. package/docs/ai-integration.md +5 -3
  142. package/docs/language-reference.md +2 -2
  143. package/package.json +1 -1
  144. package/dist/{chunk-3TYUXC7D.js → chunk-2SKMEL7V.js} +0 -0
  145. package/dist/{chunk-CLQIXD2C.js → chunk-7Z2VFRP5.js} +3 -3
  146. package/dist/{chunk-NF5YKFRH.js → chunk-B3S76BZO.js} +0 -0
  147. package/dist/{chunk-UIUXIDBX.js → chunk-CUYHST3B.js} +4 -4
  148. package/dist/{chunk-GUYVKGFN.js → chunk-DPSMX4EY.js} +0 -0
  149. package/dist/{chunk-2A4DQAXG.js → chunk-IIOLFAGJ.js} +3 -3
@@ -11,6 +11,9 @@ import {
11
11
  displayName,
12
12
  normalizeName
13
13
  } from "./chunk-NOTA6TEI.js";
14
+ import {
15
+ isTagBlockHeading
16
+ } from "./chunk-L5AFONQU.js";
14
17
  import {
15
18
  AliasRegistry,
16
19
  OPTION_NOCOLON_RE,
@@ -32,6 +35,10 @@ import {
32
35
  function classId(name) {
33
36
  return normalizeName(name);
34
37
  }
38
+ var INERT_OPTIONS = {
39
+ "active-tag": '"active-tag" does nothing on a class diagram \u2014 it has no tag groups. Colour a class with a trailing colour word (`User blue`).'
40
+ };
41
+ var NO_TAG_GROUPS_MESSAGE = "A class diagram has no tag groups \u2014 this block is ignored. Colour a class with a trailing colour word (`User blue`).";
35
42
  var CLASS_DECL_RE = /^(?:(abstract|interface|enum)\s+)?(?:"([^"]+)"|([A-Z][^":]*?))(?:\s+extends\s+(?:"([^"]+)"|([A-Z][^":]*?)))?(?:\s+implements\s+(?:"([^"]+)"|([A-Z][^":]*?)))?(?:\s+\[(abstract|interface|enum)\])?(?:\s+(red|orange|yellow|green|blue|purple|teal|cyan|gray|black|white))?(?:\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11}))?\s*$/;
36
43
  var INDENT_REL_ARROW_RE = /^(--\|>|\.\.\|>|\*--|o--|\.\.>|->)\s*(?:"([^"]+)"|([A-Za-z][^":]*?))(?:\s+:?\s*(.+))?$/;
37
44
  var REL_ARROW_RE = /^(?:"([^"]+)"|([A-Z][^":]*?))\s*(--\|>|\.\.\|>|\*--|o--|\.\.>|->)\s*(?:"([^"]+)"|([A-Z][^":]*?))(?:\s+:?\s*(.+))?$/;
@@ -139,6 +146,7 @@ function parseClassDiagram(content, palette) {
139
146
  }
140
147
  let currentClass = null;
141
148
  let contentStarted = false;
149
+ let swallowingTagBlock = false;
142
150
  function getOrCreateClass(name, lineNumber) {
143
151
  const key = classId(name);
144
152
  const existing = classMap.get(key);
@@ -183,6 +191,18 @@ function parseClassDiagram(content, palette) {
183
191
  continue;
184
192
  }
185
193
  if (trimmed.startsWith("//")) continue;
194
+ if (swallowingTagBlock) {
195
+ if (indent > 0) continue;
196
+ swallowingTagBlock = false;
197
+ }
198
+ if (indent === 0 && trimmed.startsWith("tag") && isTagBlockHeading(trimmed)) {
199
+ result.diagnostics.push(
200
+ makeDgmoError(lineNumber, NO_TAG_GROUPS_MESSAGE, "warning")
201
+ );
202
+ currentClass = null;
203
+ swallowingTagBlock = true;
204
+ continue;
205
+ }
186
206
  if (indent === 0) {
187
207
  const noteResult = tryCollectNote(
188
208
  lines,
@@ -227,6 +247,13 @@ function parseClassDiagram(content, palette) {
227
247
  if (optMatch) {
228
248
  const key = optMatch[1].toLowerCase();
229
249
  const value = optMatch[2].trim();
250
+ const inertMsg = INERT_OPTIONS[key];
251
+ if (inertMsg) {
252
+ result.diagnostics.push(
253
+ makeDgmoError(lineNumber, inertMsg, "warning")
254
+ );
255
+ continue;
256
+ }
230
257
  if (key !== "abstract" && key !== "interface" && key !== "enum") {
231
258
  options[key] = value;
232
259
  continue;
@@ -26,7 +26,7 @@ import {
26
26
  } from "./chunk-XCKNFFKM.js";
27
27
  import {
28
28
  layoutInlineHeader
29
- } from "./chunk-3DOQOXXI.js";
29
+ } from "./chunk-CNUN5GO6.js";
30
30
  import {
31
31
  TITLE_FONT_SIZE,
32
32
  TITLE_FONT_WEIGHT,
@@ -34,19 +34,14 @@ import {
34
34
  } from "./chunk-VLC6WNRD.js";
35
35
  import {
36
36
  renderIntegratedLegend
37
- } from "./chunk-LHL6HDUL.js";
37
+ } from "./chunk-7SX4IY6T.js";
38
38
  import {
39
39
  getLegendExtent,
40
40
  getMaxLegendReservedHeight
41
- } from "./chunk-FM3WAVB6.js";
41
+ } from "./chunk-NS7L7YKH.js";
42
42
  import {
43
43
  FONT_FAMILY
44
44
  } from "./chunk-ICLB27PZ.js";
45
- import {
46
- fitWrapped,
47
- measureText,
48
- wrapTextToWidth
49
- } from "./chunk-KAO7JL4I.js";
50
45
  import {
51
46
  UNTAGGED_TAG_COLOR,
52
47
  resolveActiveTagGroup,
@@ -54,6 +49,11 @@ import {
54
49
  resolveTagColor,
55
50
  tagAttrKey
56
51
  } from "./chunk-L5AFONQU.js";
52
+ import {
53
+ fitWrapped,
54
+ measureText,
55
+ wrapTextToWidth
56
+ } from "./chunk-KAO7JL4I.js";
57
57
  import {
58
58
  contrastText,
59
59
  groupFill,
@@ -61,7 +61,7 @@ import {
61
61
  mix,
62
62
  shapeFill,
63
63
  themeBaseBg
64
- } from "./chunk-7HWY4QAJ.js";
64
+ } from "./chunk-L24LESXF.js";
65
65
 
66
66
  // src/sketch/renderer.ts
67
67
  import * as d3 from "d3-selection";
@@ -1,3 +1,10 @@
1
+ import {
2
+ apcaContrast,
3
+ contrastRatio,
4
+ contrastText,
5
+ shapeFill
6
+ } from "./chunk-L24LESXF.js";
7
+
1
8
  // src/palettes/registry.ts
2
9
  var PALETTE_REGISTRY = /* @__PURE__ */ new Map();
3
10
  var DEFAULT_PALETTE_ID = "slate";
@@ -13,7 +20,9 @@ var COLOR_KEYS = [
13
20
  "purple",
14
21
  "teal",
15
22
  "cyan",
16
- "gray"
23
+ "gray",
24
+ "black",
25
+ "white"
17
26
  ];
18
27
  var SEMANTIC_KEYS = [
19
28
  "bg",
@@ -22,6 +31,8 @@ var SEMANTIC_KEYS = [
22
31
  "border",
23
32
  "text",
24
33
  "textMuted",
34
+ "textOnFillLight",
35
+ "textOnFillDark",
25
36
  "primary",
26
37
  "secondary",
27
38
  "accent",
@@ -772,6 +783,208 @@ var tokyoNightPalette = {
772
783
  };
773
784
  registerPalette(tokyoNightPalette);
774
785
 
786
+ // src/palettes/theme-file.ts
787
+ var CONTRAST_FLOOR = 4.5;
788
+ var SOLID_FLOOR_LC = 45;
789
+ var FILL_ACCENT_KEYS = [
790
+ "primary",
791
+ "secondary",
792
+ "accent",
793
+ "destructive"
794
+ ];
795
+ var CONTRAST_EXEMPT = /* @__PURE__ */ new Set([
796
+ "black",
797
+ "white"
798
+ ]);
799
+ var BUILT_IN_IDS = new Set(
800
+ [
801
+ atlasPalette,
802
+ blueprintPalette,
803
+ catppuccinPalette,
804
+ nordPalette,
805
+ slatePalette,
806
+ tidewaterPalette,
807
+ tokyoNightPalette
808
+ ].map((palette) => palette.id)
809
+ );
810
+ function isRecord(value) {
811
+ return typeof value === "object" && value !== null && !Array.isArray(value);
812
+ }
813
+ function collectShapeErrors(value, mode, errors) {
814
+ if (!isRecord(value)) {
815
+ errors.push(
816
+ `${mode}: expected an object of colors, got ${describe(value)}`
817
+ );
818
+ return false;
819
+ }
820
+ const before = errors.length;
821
+ const fields = /* @__PURE__ */ new Set([...SEMANTIC_KEYS, "colors"]);
822
+ for (const key of Object.keys(value)) {
823
+ if (!fields.has(key)) {
824
+ errors.push(`${mode}.${key}: not a palette field`);
825
+ }
826
+ }
827
+ for (const key of SEMANTIC_KEYS) {
828
+ const hex = value[key];
829
+ if (typeof hex !== "string" || !isValidHex(hex)) {
830
+ errors.push(`${mode}.${key}: invalid hex ${describe(hex)}`);
831
+ }
832
+ }
833
+ const named = value["colors"];
834
+ if (!isRecord(named)) {
835
+ errors.push(
836
+ `${mode}.colors: expected an object of named colors, got ${describe(named)}`
837
+ );
838
+ } else {
839
+ const names = new Set(COLOR_KEYS);
840
+ for (const key of Object.keys(named)) {
841
+ if (!names.has(key)) {
842
+ errors.push(
843
+ `${mode}.colors.${key}: not a palette color \u2014 a theme sets the existing color names and cannot add one`
844
+ );
845
+ }
846
+ }
847
+ for (const key of COLOR_KEYS) {
848
+ const hex = named[key];
849
+ if (typeof hex !== "string" || !isValidHex(hex)) {
850
+ errors.push(`${mode}.colors.${key}: invalid hex ${describe(hex)}`);
851
+ }
852
+ }
853
+ }
854
+ return errors.length === before;
855
+ }
856
+ function describe(value) {
857
+ if (value === void 0) return "nothing";
858
+ if (typeof value === "string") return `"${value}"`;
859
+ if (value === null) return "null";
860
+ return typeof value;
861
+ }
862
+ function intents(colors) {
863
+ const out = [];
864
+ for (const key of COLOR_KEYS) {
865
+ if (CONTRAST_EXEMPT.has(key)) continue;
866
+ out.push([`colors.${key}`, colors.colors[key]]);
867
+ }
868
+ for (const key of FILL_ACCENT_KEYS) out.push([key, colors[key]]);
869
+ return out;
870
+ }
871
+ function drawnToken(colors, bg) {
872
+ const drawn = contrastText(bg, colors.textOnFillLight, colors.textOnFillDark);
873
+ return drawn === colors.textOnFillDark ? "textOnFillDark" : "textOnFillLight";
874
+ }
875
+ function worstTintedFill(colors, isDark) {
876
+ let worst;
877
+ for (const [fill, intent] of intents(colors)) {
878
+ const fillHex = shapeFill(colors, intent, isDark);
879
+ const token = drawnToken(colors, fillHex);
880
+ const ratio = contrastRatio(colors[token], fillHex);
881
+ if (!worst || ratio < worst.ratio) {
882
+ worst = { ratio, token, fill, fillHex };
883
+ }
884
+ }
885
+ return worst;
886
+ }
887
+ function worstSolidFill(colors) {
888
+ let worst;
889
+ for (const [fill, intent] of intents(colors)) {
890
+ const token = drawnToken(colors, intent);
891
+ const lc = Math.abs(apcaContrast(colors[token], intent));
892
+ if (!worst || lc < worst.lc) {
893
+ worst = { lc, token, fill, fillHex: intent };
894
+ }
895
+ }
896
+ return worst;
897
+ }
898
+ function collectContrastErrors(colors, where, isDark, errors) {
899
+ const tinted = worstTintedFill(colors, isDark);
900
+ if (tinted.ratio < CONTRAST_FLOOR) {
901
+ errors.push(
902
+ `${where}: ${tinted.token} ${colors[tinted.token]} on the ${tinted.fill} fill ${tinted.fillHex} reaches only ${tinted.ratio.toFixed(2)}:1 \u2014 text on a fill needs ${CONTRAST_FLOOR.toFixed(1)}:1`
903
+ );
904
+ }
905
+ }
906
+ function collectSolidErrors(colors, where, errors) {
907
+ const solid = worstSolidFill(colors);
908
+ if (solid.lc >= SOLID_FLOOR_LC) return;
909
+ errors.push(
910
+ `${where}: ${solid.token} ${colors[solid.token]} on the solid ${solid.fill} ${solid.fillHex} reaches only Lc ${solid.lc.toFixed(1)} \u2014 text on a solid fill needs Lc ${SOLID_FLOOR_LC}`
911
+ );
912
+ }
913
+ function validateThemeFile(input) {
914
+ const errors = [];
915
+ if (!isRecord(input)) {
916
+ return {
917
+ ok: false,
918
+ errors: [`expected a theme object, got ${describe(input)}`]
919
+ };
920
+ }
921
+ const id = input["id"];
922
+ if (typeof id !== "string" || id.trim() === "") {
923
+ errors.push(`id: expected a non-empty string, got ${describe(id)}`);
924
+ } else if (BUILT_IN_IDS.has(id)) {
925
+ errors.push(
926
+ `id: "${id}" is a built-in palette \u2014 a theme file needs an id of its own`
927
+ );
928
+ }
929
+ const name = input["name"];
930
+ if (typeof name !== "string" || name.trim() === "") {
931
+ errors.push(`name: expected a non-empty string, got ${describe(name)}`);
932
+ }
933
+ const declared = input["mode"];
934
+ let mode = null;
935
+ if (declared !== void 0) {
936
+ if (declared === "light" || declared === "dark") {
937
+ mode = declared;
938
+ } else {
939
+ errors.push(
940
+ `mode: expected "light" or "dark", got ${describe(declared)}`
941
+ );
942
+ }
943
+ }
944
+ if (mode) {
945
+ const other = mode === "light" ? "dark" : "light";
946
+ if (input[other] !== void 0) {
947
+ errors.push(
948
+ `${other}: a theme declaring mode "${mode}" must not also define ${other} \u2014 drop the mode to define both`
949
+ );
950
+ }
951
+ }
952
+ const wanted = mode ? [mode] : ["light", "dark"];
953
+ const modes = {};
954
+ for (const key of wanted) {
955
+ const value = input[key];
956
+ if (value === void 0) {
957
+ errors.push(
958
+ mode ? `${key}: a theme declaring mode "${mode}" has to define ${key}` : `${key}: a theme without a mode has to define both light and dark`
959
+ );
960
+ continue;
961
+ }
962
+ if (collectShapeErrors(value, key, errors)) modes[key] = value;
963
+ }
964
+ if (errors.length === 0) {
965
+ const light2 = modes.light ?? modes.dark;
966
+ const dark2 = modes.dark ?? modes.light;
967
+ const declaredMode = mode;
968
+ const label = (render) => declaredMode !== null && render !== declaredMode ? `${render} (a theme declaring mode "${declaredMode}" is used in ${render} mode too)` : render;
969
+ collectContrastErrors(light2, label("light"), false, errors);
970
+ collectContrastErrors(dark2, label("dark"), true, errors);
971
+ if (declaredMode !== null) {
972
+ collectSolidErrors(light2, declaredMode, errors);
973
+ } else {
974
+ collectSolidErrors(light2, "light", errors);
975
+ collectSolidErrors(dark2, "dark", errors);
976
+ }
977
+ }
978
+ if (errors.length > 0) return { ok: false, errors };
979
+ const light = modes.light ?? modes.dark;
980
+ const dark = modes.dark ?? modes.light;
981
+ return {
982
+ ok: true,
983
+ palette: { id, name, light, dark },
984
+ mode
985
+ };
986
+ }
987
+
775
988
  // src/palettes/index.ts
776
989
  var palettes = {
777
990
  atlas: atlasPalette,
@@ -797,5 +1010,6 @@ export {
797
1010
  slatePalette,
798
1011
  tidewaterPalette,
799
1012
  tokyoNightPalette,
1013
+ validateThemeFile,
800
1014
  palettes
801
1015
  };
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-BDXC7MDK.js";
6
6
  import {
7
7
  renderIntegratedLegend
8
- } from "./chunk-LHL6HDUL.js";
8
+ } from "./chunk-7SX4IY6T.js";
9
9
  import {
10
10
  FONT_FAMILY
11
11
  } from "./chunk-ICLB27PZ.js";
@@ -18,7 +18,7 @@ import {
18
18
  getSeriesColors,
19
19
  mix,
20
20
  themeBaseBg
21
- } from "./chunk-7HWY4QAJ.js";
21
+ } from "./chunk-L24LESXF.js";
22
22
  import {
23
23
  resolveColor
24
24
  } from "./chunk-2M4IGSCY.js";
@@ -13,7 +13,7 @@ import {
13
13
  LEGEND_TOGGLE_DOT_R,
14
14
  measureLegendText,
15
15
  truncateLegendText
16
- } from "./chunk-RH2PROYG.js";
16
+ } from "./chunk-I6GGMCTV.js";
17
17
 
18
18
  // src/utils/number-format.ts
19
19
  function compactNumber(n) {
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-XCKNFFKM.js";
17
17
  import {
18
18
  layoutInlineHeader
19
- } from "./chunk-3DOQOXXI.js";
19
+ } from "./chunk-CNUN5GO6.js";
20
20
  import {
21
21
  TITLE_FONT_SIZE,
22
22
  TITLE_FONT_WEIGHT,
@@ -24,26 +24,19 @@ import {
24
24
  } from "./chunk-VLC6WNRD.js";
25
25
  import {
26
26
  renderIntegratedLegend
27
- } from "./chunk-LHL6HDUL.js";
27
+ } from "./chunk-7SX4IY6T.js";
28
28
  import {
29
29
  getLegendExtent,
30
30
  getMaxLegendReservedHeight
31
- } from "./chunk-FM3WAVB6.js";
31
+ } from "./chunk-NS7L7YKH.js";
32
32
  import {
33
33
  FONT_FAMILY
34
34
  } from "./chunk-ICLB27PZ.js";
35
- import {
36
- legendChromeColors
37
- } from "./chunk-RH2PROYG.js";
38
- import {
39
- measureText,
40
- truncateText
41
- } from "./chunk-KAO7JL4I.js";
42
35
  import {
43
36
  isSequenceBlock,
44
37
  isSequenceNote,
45
38
  isSequenceSection
46
- } from "./chunk-VPASQOR3.js";
39
+ } from "./chunk-LFKSHDVI.js";
47
40
  import {
48
41
  resolveActiveTagGroup,
49
42
  tagAttrKey
@@ -53,12 +46,19 @@ import {
53
46
  legendInlineRequested,
54
47
  legendSuppressed
55
48
  } from "./chunk-44GP7PD5.js";
49
+ import {
50
+ legendChromeColors
51
+ } from "./chunk-I6GGMCTV.js";
52
+ import {
53
+ measureText,
54
+ truncateText
55
+ } from "./chunk-KAO7JL4I.js";
56
56
  import {
57
57
  contrastText,
58
58
  mix,
59
59
  shapeFill,
60
60
  themeBaseBg
61
- } from "./chunk-7HWY4QAJ.js";
61
+ } from "./chunk-L24LESXF.js";
62
62
 
63
63
  // src/sequence/renderer.ts
64
64
  import * as d3Selection from "d3-selection";
@@ -284,6 +284,11 @@ var NOTE_LINE_H = 14;
284
284
  var NOTE_GAP = 15;
285
285
  var ACTIVATION_WIDTH = 10;
286
286
  var ACTIVATION_IMPLICIT_END_CLEARANCE = 8;
287
+ var ACTIVATION_LABEL_GAP = 4;
288
+ var MSG_LABEL_FONT_SIZE = 12;
289
+ var MSG_LABEL_OFFSET = 8;
290
+ var RETURN_LABEL_FONT_SIZE = 11;
291
+ var RETURN_LABEL_OFFSET = 6;
287
292
  var SELF_CALL_HEIGHT = 25;
288
293
  var SELF_CALL_WIDTH = 30;
289
294
  var ACTOR_LABEL_CLEARANCE = 22;
@@ -1152,6 +1157,55 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1152
1157
  const lifelineStartY0 = participantStartY + sBoxH;
1153
1158
  const hasActors = participants.some((p) => p.type === "actor");
1154
1159
  const messageStartOffset = sMsgStartOffset + (hasActors ? 20 : 0) + (parsed.groups.length > 0 ? groupBottomPad(0) : 0);
1160
+ const totalGaps = participants.length > 1 ? participants.length - 1 : 0;
1161
+ const numWithinGaps = totalGaps - numGroupGaps;
1162
+ let sWithinGap = sGap;
1163
+ let sBetweenGap = sGap;
1164
+ if (numGroupGaps > 0 && totalGaps > 0) {
1165
+ sWithinGap = sGap * 0.88;
1166
+ sBetweenGap = (totalGaps * sGap - numWithinGaps * sWithinGap) / numGroupGaps;
1167
+ }
1168
+ const ACTIVATION_NEST_OFFSET = ctx.structural(6);
1169
+ const labelRoomBefore = new Array(renderSteps.length).fill(0);
1170
+ {
1171
+ const relX = /* @__PURE__ */ new Map();
1172
+ let px = 0;
1173
+ participants.forEach((p, i) => {
1174
+ relX.set(p.id, px);
1175
+ if (i < participants.length - 1) {
1176
+ const nextId = participants[i + 1].id;
1177
+ px += groupBoundaryIds.has(nextId) ? sBetweenGap : sWithinGap;
1178
+ }
1179
+ });
1180
+ for (const act of activations) {
1181
+ if (!act.implicitEnd || act.endStep <= act.startStep) continue;
1182
+ const step = renderSteps[act.endStep];
1183
+ if (!step || step.from === step.to) continue;
1184
+ if (step.from === act.participantId || step.to === act.participantId) {
1185
+ continue;
1186
+ }
1187
+ const label = displayMessageLabel(step);
1188
+ const fromX = relX.get(step.from);
1189
+ const toX = relX.get(step.to);
1190
+ const barX = relX.get(act.participantId);
1191
+ if (!label || fromX === void 0 || toX === void 0) continue;
1192
+ if (barX === void 0) continue;
1193
+ const isCall = step.type === "call";
1194
+ const fontSize = isCall ? MSG_LABEL_FONT_SIZE : RETURN_LABEL_FONT_SIZE;
1195
+ const baseline = isCall ? MSG_LABEL_OFFSET : RETURN_LABEL_OFFSET;
1196
+ const halfW = measureText(label, fontSize) / 2 + sActivationWidth / 2 + 2;
1197
+ const midX = (fromX + toX) / 2;
1198
+ const left = barX - sActivationWidth / 2 + act.depth * ACTIVATION_NEST_OFFSET;
1199
+ if (midX + halfW <= left || midX - halfW >= left + sActivationWidth) {
1200
+ continue;
1201
+ }
1202
+ const room = baseline + fontSize + 2 + ACTIVATION_LABEL_GAP - ACTIVATION_IMPLICIT_END_CLEARANCE;
1203
+ labelRoomBefore[act.endStep] = Math.max(
1204
+ labelRoomBefore[act.endStep],
1205
+ room
1206
+ );
1207
+ }
1208
+ }
1155
1209
  const stepYPositions = [];
1156
1210
  const sectionYPositions = /* @__PURE__ */ new Map();
1157
1211
  let layoutEndY;
@@ -1172,6 +1226,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1172
1226
  const extra = extraBeforeMsg.get(step.messageIndex) || 0;
1173
1227
  curY += extra;
1174
1228
  }
1229
+ curY += labelRoomBefore[i];
1175
1230
  stepYPositions.push(curY);
1176
1231
  const isSelfCall = step.type === "call" && step.from === step.to;
1177
1232
  curY += isSelfCall ? sSelfCallHeight + 25 : stepSpacing;
@@ -1250,14 +1305,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1250
1305
  }
1251
1306
  const messageAreaHeight = contentBottomY - lifelineStartY0;
1252
1307
  const lifelineLength = messageAreaHeight + sLifelineTail;
1253
- const totalGaps = participants.length > 1 ? participants.length - 1 : 0;
1254
- const numWithinGaps = totalGaps - numGroupGaps;
1255
- let sWithinGap = sGap;
1256
- let sBetweenGap = sGap;
1257
- if (numGroupGaps > 0 && totalGaps > 0) {
1258
- sWithinGap = sGap * 0.88;
1259
- sBetweenGap = (totalGaps * sGap - numWithinGaps * sWithinGap) / numGroupGaps;
1260
- }
1261
1308
  const edgeProjection = (id) => {
1262
1309
  if (!id) return sBoxW / 2;
1263
1310
  const framed = parsed.groups.some(
@@ -1766,14 +1813,14 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1766
1813
  if (elements && elements.length > 0) {
1767
1814
  renderBlockFrames(elements, 0);
1768
1815
  }
1769
- const ACTIVATION_NEST_OFFSET = ctx.structural(6);
1770
1816
  activations.forEach((act) => {
1771
1817
  const px = participantX.get(act.participantId);
1772
1818
  if (px === void 0) return;
1773
1819
  const x = px - sActivationWidth / 2 + act.depth * ACTIVATION_NEST_OFFSET;
1774
1820
  const y1 = stepY(act.startStep);
1775
1821
  const rawY2 = stepY(act.endStep);
1776
- const y2 = act.implicitEnd && rawY2 - ACTIVATION_IMPLICIT_END_CLEARANCE > y1 + sActivationWidth ? rawY2 - ACTIVATION_IMPLICIT_END_CLEARANCE : rawY2;
1822
+ const implicitY2 = rawY2 - labelRoomBefore[act.endStep] - ACTIVATION_IMPLICIT_END_CLEARANCE;
1823
+ const y2 = act.implicitEnd && implicitY2 > y1 + sActivationWidth ? implicitY2 : rawY2;
1777
1824
  const coveredLines = [];
1778
1825
  for (let si = act.startStep; si <= act.endStep; si++) {
1779
1826
  const step = renderSteps[si];
@@ -1917,7 +1964,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1917
1964
  const displayLabel = displayMessageLabel(step);
1918
1965
  if (displayLabel) {
1919
1966
  const midX = (x1 + x2) / 2;
1920
- const labelEl = svg.append("text").attr("x", midX).attr("y", y - 8).attr("text-anchor", "middle").attr("fill", arrowColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", 12).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
1967
+ const labelEl = svg.append("text").attr("x", midX).attr("y", y - MSG_LABEL_OFFSET).attr("text-anchor", "middle").attr("fill", arrowColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", MSG_LABEL_FONT_SIZE).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
1921
1968
  if (tagKey && msgTagValue) {
1922
1969
  labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
1923
1970
  }
@@ -1940,7 +1987,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1940
1987
  const displayLabel = displayMessageLabel(step);
1941
1988
  if (displayLabel) {
1942
1989
  const midX = (x1 + x2) / 2;
1943
- const labelEl = svg.append("text").attr("x", midX).attr("y", y - 6).attr("text-anchor", "middle").attr("fill", returnColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", 11).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
1990
+ const labelEl = svg.append("text").attr("x", midX).attr("y", y - RETURN_LABEL_OFFSET).attr("text-anchor", "middle").attr("fill", returnColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", RETURN_LABEL_FONT_SIZE).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
1944
1991
  if (tagKey && msgTagValue) {
1945
1992
  labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
1946
1993
  }
@@ -1,3 +1,7 @@
1
+ import {
2
+ LEGEND_PILL_TOGGLE_CLASS
3
+ } from "./chunk-I6GGMCTV.js";
4
+
1
5
  // src/utils/svg-serialize.ts
2
6
  var BARE_AMPERSAND = /&(?![a-zA-Z][a-zA-Z0-9]*;|#\d+;|#[xX][0-9a-fA-F]+;)/g;
3
7
  function escapeAttributeMarkupChars(svg) {
@@ -23,7 +27,18 @@ function roundMagnitudeAttrs(svg) {
23
27
  });
24
28
  return round(ROUNDED_OPACITY_ATTRS, 4)(round(ROUNDED_ATTRS, 2)(svg));
25
29
  }
30
+ var LEGEND_PILL_BUTTON_ATTRS = [
31
+ "role",
32
+ "tabindex",
33
+ "aria-label",
34
+ "aria-pressed"
35
+ ];
26
36
  function serializeSvg(svgEl) {
37
+ for (const el of svgEl.querySelectorAll(`.${LEGEND_PILL_TOGGLE_CLASS}`)) {
38
+ el.classList.remove(LEGEND_PILL_TOGGLE_CLASS);
39
+ if (el.getAttribute("class") === "") el.removeAttribute("class");
40
+ for (const attr of LEGEND_PILL_BUTTON_ATTRS) el.removeAttribute(attr);
41
+ }
27
42
  return roundMagnitudeAttrs(escapeAttributeMarkupChars(svgEl.outerHTML));
28
43
  }
29
44
 
@@ -1,12 +1,12 @@
1
- import {
2
- measureText
3
- } from "./chunk-KAO7JL4I.js";
4
1
  import {
5
2
  formatDuration,
6
3
  formatScheduleValue,
7
4
  formatSlackValue,
8
5
  formatSprintCell
9
- } from "./chunk-3TYUXC7D.js";
6
+ } from "./chunk-2SKMEL7V.js";
7
+ import {
8
+ measureText
9
+ } from "./chunk-KAO7JL4I.js";
10
10
 
11
11
  // src/pert/layout.ts
12
12
  import dagre from "@dagrejs/dagre";