@zenuml/core 4.7.1 → 4.8.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.
@@ -12820,7 +12820,8 @@ function renderParticipant(p) {
12820
12820
  const stereoX = icon && p.labelWidth != null ? textX + p.labelWidth / 2 : p.x;
12821
12821
  const stereoAnchor = "middle";
12822
12822
  const stereoY = textY - STEREOTYPE_VERTICAL_OFFSET;
12823
- stereotypeSvg = `<text x="${stereoX}" y="${stereoY}" text-anchor="${stereoAnchor}" dominant-baseline="central" class="stereotype-label" font-size="${STEREOTYPE_FONT_SIZE}"${participantTextStyle()}>${esc("«" + p.stereotype + "»")}</text>`;
12823
+ const { textStyle: stereoTextStyle } = colorAttrs(p.color);
12824
+ stereotypeSvg = `<text x="${stereoX}" y="${stereoY}" text-anchor="${stereoAnchor}" dominant-baseline="central" class="stereotype-label" font-size="${STEREOTYPE_FONT_SIZE}"${stereoTextStyle}>${esc("«" + p.stereotype + "»")}</text>`;
12824
12825
  }
12825
12826
  const useTextLength = p.labelWidth != null && p.name.includes(":");
12826
12827
  const textLengthAttr = useTextLength ? ` textLength="${p.labelWidth}" lengthAdjust="spacing"` : "";
@@ -12919,15 +12920,15 @@ function renderSelfCall(s) {
12919
12920
  const svgY = s.y + (isAsync ? 20 : 14);
12920
12921
  const pathEnd = isAsync ? "L1,15" : "L14,15";
12921
12922
  const arrowTx = isAsync ? 0 : 7;
12922
- const arrowFill = isAsync ? "none" : "#000";
12923
+ const arrowFill = isAsync ? ' fill="none"' : "";
12923
12924
  const arrowPath = isAsync ? "M1 1.25 L6.15 4.5 L1 7.75" : "M1 1.25 L6.15 4.5 L1 7.75 Z";
12924
12925
  return `<g class="message self-call">
12925
12926
  <svg x="${svgX}" y="${svgY}" width="30" height="24">
12926
- <path d="M0,2 L26,2 Q28,2 28,4 L28,13 Q28,15 26,15 ${pathEnd}" fill="none" stroke="#000" stroke-width="1"/>
12927
+ <path d="M0,2 L26,2 Q28,2 28,4 L28,13 Q28,15 26,15 ${pathEnd}" class="self-call-line"/>
12927
12928
  <g transform="translate(${arrowTx}, 10)">
12928
- <svg height="10" width="7" viewBox="0 0 7 9">
12929
+ <svg height="10" width="7" viewBox="0 0 7 9" class="arrow-head${isAsync ? " arrow-open" : ""}">
12929
12930
  <g transform="scale(-1, 1) translate(-7, 0)">
12930
- <path d="${arrowPath}" stroke="#000" stroke-linecap="round" fill="${arrowFill}" stroke-width="1"/>
12931
+ <path d="${arrowPath}" stroke-linecap="round"${arrowFill} stroke-width="1"/>
12931
12932
  </g>
12932
12933
  </svg>
12933
12934
  </g>
@@ -12945,7 +12946,7 @@ function renderArrowHead(tipX, tipY, pointsLeft, style) {
12945
12946
  const rtlTransform = pointsLeft ? ' transform="scale(-1, 1) translate(-7, 0)"' : "";
12946
12947
  return `<svg x="${svgX}" y="${svgY}" width="7" height="10" viewBox="0 0 7 9" overflow="visible" class="arrow-head${isFilled ? "" : " arrow-open"}">
12947
12948
  <g${rtlTransform}>
12948
- <path d="${pathD}" transform="translate(1 0.5)" stroke="#000" stroke-linecap="round" stroke-width="1" fill="${fillAttr}"/>
12949
+ <path d="${pathD}" transform="translate(1 0.5)" stroke-linecap="round" stroke-width="1"${fillAttr === "none" ? ' fill="none"' : ""}/>
12949
12950
  </g>
12950
12951
  </svg>`;
12951
12952
  }
@@ -12984,7 +12985,7 @@ function renderFragment(f) {
12984
12985
  const numberX = numberBoxX + NUMBER_PAD_X;
12985
12986
  parts.push(
12986
12987
  `<rect x="${numberBoxX}" y="${headerY + (HEADER_HEIGHT - 1 - 16) / 2}" width="${numberWidth + NUMBER_PAD_X * 2}" height="16" rx="2" class="fragment-number-bg"/>`,
12987
- `<text x="${numberX}" y="${titleY - NUMBER_OPTICAL_LIFT}" dominant-baseline="central" class="seq-number">${esc(f.number)}</text>`
12988
+ `<text x="${numberX}" y="${titleY - NUMBER_OPTICAL_LIFT}" dominant-baseline="central" class="seq-number fragment-number">${esc(f.number)}</text>`
12988
12989
  );
12989
12990
  }
12990
12991
  const iconX = headerX + 4 + numberInset;
@@ -13048,7 +13049,7 @@ function renderFragment(f) {
13048
13049
  const conditionX = keywordX + keywordWidth + TEXT_PAD_X * 2;
13049
13050
  const bgWidth = keywordWidth + (section.detailWidth ?? condition.length * 7) + TEXT_PAD_X * 4;
13050
13051
  parts.push(
13051
- `<g opacity="0.65"><rect x="${keywordX - TEXT_PAD_X}" y="${lineY + 1}" width="${bgWidth}" height="20" fill="#fff"/><text x="${keywordX}" y="${labelY2}" class="fragment-section-label fragment-section-keyword" fill="#222">${esc(keyword)}</text><text x="${conditionX}" y="${labelY2}" class="fragment-section-label" fill="#222">${esc(condition)}</text></g>`
13052
+ `<g class="fragment-section-dim"><rect x="${keywordX - TEXT_PAD_X}" y="${lineY + 1}" width="${bgWidth}" height="20" class="fragment-section-bg"/><text x="${keywordX}" y="${labelY2}" class="fragment-section-label fragment-section-keyword">${esc(keyword)}</text><text x="${conditionX}" y="${labelY2}" class="fragment-section-label">${esc(condition)}</text></g>`
13052
13053
  );
13053
13054
  } else {
13054
13055
  const finallyX = f.x + 5;
@@ -13063,7 +13064,7 @@ function renderFragment(f) {
13063
13064
  const bgY = lineY + 1;
13064
13065
  const bgHeight = 20;
13065
13066
  parts.push(
13066
- `<g opacity="0.65"><rect x="${finallyX - TEXT_PAD_X}" y="${bgY}" width="${bgWidth}" height="${bgHeight}" fill="#fff"/><text x="${finallyX}" y="${finallyY}" class="fragment-section-label fragment-section-keyword">${esc(section.label)}</text></g>`
13067
+ `<g class="fragment-section-dim"><rect x="${finallyX - TEXT_PAD_X}" y="${bgY}" width="${bgWidth}" height="${bgHeight}" class="fragment-section-bg"/><text x="${finallyX}" y="${finallyY}" class="fragment-section-label fragment-section-keyword">${esc(section.label)}</text></g>`
13067
13068
  );
13068
13069
  }
13069
13070
  }
@@ -13077,48 +13078,48 @@ function renderGuardRow(x, rowY, innerText, keyword) {
13077
13078
  const baseline = rowY + 19;
13078
13079
  const textX = x + 4;
13079
13080
  const conditionX = textX + (keyword ? measureTextWithFont(keyword, "12px", "all-small-caps") + 4 : 0);
13080
- return `<g class="guard-row">` + (keyword ? `<text x="${textX}" y="${baseline}" class="guard-keyword">${esc(keyword)}</text>` : "") + (innerText ? `<text x="${conditionX}" y="${baseline}" class="fragment-condition" opacity="0.65">${esc(resolveEmojiInText(innerText))}</text>` : "") + `</g>`;
13081
+ return `<g class="guard-row">` + (keyword ? `<text x="${textX}" y="${baseline}" class="guard-keyword">${esc(keyword)}</text>` : "") + (innerText ? `<text x="${conditionX}" y="${baseline}" class="fragment-condition">${esc(resolveEmojiInText(innerText))}</text>` : "") + `</g>`;
13081
13082
  }
13082
13083
  function getFragmentIcon(kind, x, y) {
13083
13084
  const w = 20;
13084
13085
  const h = 24;
13085
13086
  switch (kind) {
13086
13087
  case "loop":
13087
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 1024 1024" fill="#000" stroke="none">
13088
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 1024 1024" class="fragment-icon" fill="currentColor" stroke="none">
13088
13089
  <path d="M960 101.84l-896.002.002c-35.344 0-64 28.656-64 64v576c0 35.36 28.656 64 64 64h160c20.496 0 32-26.32 32-31.984v-.016c0-5.824-10.88-32.416-32-32.416h-120.96c-21.376 0-38.72-17.344-38.72-38.72V206.002c0-21.391 17.328-38.72 38.72-38.72l818.272-1.007c21.376 0 38.72 17.328 38.72 38.72V702.69c0 21.376-17.344 38.72-38.72 38.72H518.142l75.984-68.912c9.344-8.944 12.369-23.408 3.025-32.336l-5.472-8.064c-9.376-8.945-24.496-8.945-33.84 0L428.111 750.53c-.192.16-.368.224-.528.368l-8.48 8.096c-4.672 4.431-7.008 10.335-6.976 16.223-.032 5.904 2.288 11.777 6.977 16.288l8.48 8.096c.16.16.368.192.528.336L555.84 915.44c9.344 8.944 24.464 8.944 33.84 0l5.472-8.065c9.344-8.944 6.32-23.44-3.025-32.368l-77.135-69.168H960c35.343 0 64-28.64 64-64v-576c0-35.344-28.657-64-64-64z"/>
13089
13090
  </svg>`;
13090
13091
  case "opt":
13091
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" fill="none">
13092
- <circle cx="12" cy="12" r="7" stroke="#000" stroke-width="1.5" stroke-dasharray="3 2" stroke-linecap="round"/>
13092
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" class="fragment-icon" fill="none">
13093
+ <circle cx="12" cy="12" r="7" stroke="currentColor" stroke-width="1.5" stroke-dasharray="3 2" stroke-linecap="round"/>
13093
13094
  </svg>`;
13094
13095
  case "par":
13095
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" fill="none">
13096
- <path d="M5 10H19" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13097
- <path d="M5 14H19" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13096
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" class="fragment-icon" fill="none">
13097
+ <path d="M5 10H19" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13098
+ <path d="M5 14H19" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13098
13099
  </svg>`;
13099
13100
  case "critical":
13100
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" fill="none">
13101
- <path d="M12 5L19 12L12 19L5 12L12 5Z" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13102
- <path d="M12 9V13" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13103
- <path d="M12 15V15.5" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13101
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" class="fragment-icon" fill="none">
13102
+ <path d="M12 5L19 12L12 19L5 12L12 5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13103
+ <path d="M12 9V13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13104
+ <path d="M12 15V15.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13104
13105
  </svg>`;
13105
13106
  case "tcf":
13106
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 3 76 76" fill="#000" stroke="none">
13107
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 3 76 76" class="fragment-icon" fill="currentColor" stroke="none">
13107
13108
  <path d="M 26,22.0001L 27,21.9998L 27,27L 26.0001,27.0003C 23.2386,27.0003 21.0001,29.2389 21.0001,32.0003L 21,46.0002C 21,48.7616 23.2386,51.0002 25.9999,51.0002L 27,51.0002L 27,47L 33.75,53.5L 27,60L 27,56L 26,56C 20.4771,56 16,51.5229 16,46L 16,32.0001C 16,26.4773 20.4771,22.0001 26,22.0001 Z M 33,27L 59,27L 59,32L 33,32L 33,27 Z M 36,35L 59,35L 59,40L 36,40L 36,35 Z M 33,43L 59,43L 59,48L 33,48L 33,43 Z"/>
13108
13109
  </svg>`;
13109
13110
  case "ref":
13110
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" fill="none">
13111
- <path d="M10 6H18C19.1046 6 20 6.89543 20 8V16C20 17.1046 19.1046 18 18 18H10" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13112
- <path d="M10 6L6 12L10 18" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13111
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" class="fragment-icon" fill="none">
13112
+ <path d="M10 6H18C19.1046 6 20 6.89543 20 8V16C20 17.1046 19.1046 18 18 18H10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13113
+ <path d="M10 6L6 12L10 18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13113
13114
  </svg>`;
13114
13115
  case "section":
13115
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 15 15" fill="#000" stroke="none">
13116
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 15 15" class="fragment-icon" fill="currentColor" stroke="none">
13116
13117
  <path fill-rule="evenodd" clip-rule="evenodd" d="M2 1.5C2 1.77614 1.77614 2 1.5 2C1.22386 2 1 1.77614 1 1.5C1 1.22386 1.22386 1 1.5 1C1.77614 1 2 1.22386 2 1.5ZM2 5L2 10H13V5H2ZM2 4C1.44772 4 1 4.44772 1 5V10C1 10.5523 1.44772 11 2 11H13C13.5523 11 14 10.5523 14 10V5C14 4.44772 13.5523 4 13 4H2ZM1.5 14C1.77614 14 2 13.7761 2 13.5C2 13.2239 1.77614 13 1.5 13C1.22386 13 1 13.2239 1 13.5C1 13.7761 1.22386 14 1.5 14ZM4 1.5C4 1.77614 3.77614 2 3.5 2C3.22386 2 3 1.77614 3 1.5C3 1.22386 3.22386 1 3.5 1C3.77614 1 4 1.22386 4 1.5ZM3.5 14C3.77614 14 4 13.7761 4 13.5C4 13.2239 3.77614 13 3.5 13C3.22386 13 3 13.2239 3 13.5C3 13.7761 3.22386 14 3.5 14ZM6 1.5C6 1.77614 5.77614 2 5.5 2C5.22386 2 5 1.77614 5 1.5C5 1.22386 5.22386 1 5.5 1C5.77614 1 6 1.22386 6 1.5ZM5.5 14C5.77614 14 6 13.7761 6 13.5C6 13.2239 5.77614 13 5.5 13C5.22386 13 5 13.2239 5 13.5C5 13.7761 5.22386 14 5.5 14ZM8 1.5C8 1.77614 7.77614 2 7.5 2C7.22386 2 7 1.77614 7 1.5C7 1.22386 7.22386 1 7.5 1C7.77614 1 8 1.22386 8 1.5ZM7.5 14C7.77614 14 8 13.7761 8 13.5C8 13.2239 7.77614 13 7.5 13C7.22386 13 7 13.2239 7 13.5C7 13.7761 7.22386 14 7.5 14ZM10 1.5C10 1.77614 9.77614 2 9.5 2C9.22386 2 9 1.77614 9 1.5C9 1.22386 9.22386 1 9.5 1C9.77614 1 10 1.22386 10 1.5ZM9.5 14C9.77614 14 10 13.7761 10 13.5C10 13.2239 9.77614 13 9.5 13C9.22386 13 9 13.2239 9 13.5C9 13.7761 9.22386 14 9.5 14ZM12 1.5C12 1.77614 11.7761 2 11.5 2C11.2239 2 11 1.77614 11 1.5C11 1.22386 11.2239 1 11.5 1C11.7761 1 12 1.22386 12 1.5ZM11.5 14C11.7761 14 12 13.7761 12 13.5C12 13.2239 11.7761 13 11.5 13C11.2239 13 11 13.2239 11 13.5C11 13.7761 11.2239 14 11.5 14ZM14 1.5C14 1.77614 13.7761 2 13.5 2C13.2239 2 13 1.77614 13 1.5C13 1.22386 13.2239 1 13.5 1C13.7761 1 14 1.22386 14 1.5ZM13.5 14C13.7761 14 14 13.7761 14 13.5C14 13.2239 13.7761 13 13.5 13C13.2239 13 13 13.2239 13 13.5C13 13.7761 13.2239 14 13.5 14Z"/>
13117
13118
  </svg>`;
13118
13119
  case "alt":
13119
13120
  default:
13120
- return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" fill="none">
13121
- <path d="M12 8L20 12L12 16L4 12L12 8Z" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13121
+ return `<svg x="${x}" y="${y}" width="${w}" height="${h}" viewBox="0 0 24 24" class="fragment-icon" fill="none">
13122
+ <path d="M12 8L20 12L12 16L4 12L12 8Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
13122
13123
  </svg>`;
13123
13124
  }
13124
13125
  }
@@ -13331,6 +13332,7 @@ const DEFAULT_PALETTE = {
13331
13332
  titleText: "#222",
13332
13333
  participantBg: "#ffffff",
13333
13334
  participantBorder: "#666",
13335
+ lifeline: "#666",
13334
13336
  participantText: "#222",
13335
13337
  messageArrow: "#000",
13336
13338
  messageText: "#222",
@@ -13339,57 +13341,116 @@ const DEFAULT_PALETTE = {
13339
13341
  fragmentBorder: "#666",
13340
13342
  fragmentHeaderBg: "#dedede",
13341
13343
  fragmentHeaderOpacity: "0.498",
13344
+ fragmentHeaderText: "#000",
13342
13345
  fragmentText: "#000",
13346
+ guardOpacity: "0.65",
13343
13347
  fragmentSeparator: "#e5e7eb",
13344
13348
  commentText: "#333",
13349
+ commentOpacity: "0.5",
13350
+ groupOutline: "#666",
13351
+ dividerLine: "#aaaa33",
13352
+ dividerBg: "#fff5ad",
13353
+ dividerText: "#333",
13354
+ numberText: "#6b7280",
13355
+ fragmentNumberText: "#6b7280",
13356
+ numberBg: "#6b7280",
13357
+ numberBgOpacity: "0.1",
13358
+ guardText: "#6b7280",
13359
+ fontFamily: DIAGRAM_FONT_STACK
13360
+ };
13361
+ const DARK_PALETTE = {
13362
+ frameBorder: "#e1e1e1",
13363
+ frameBg: "#1f1f1f",
13364
+ titleText: "#fbfbfb",
13365
+ participantBg: "#1f1f1f",
13366
+ participantBorder: "#e1e1e1",
13367
+ lifeline: "#e1e1e1",
13368
+ participantText: "#fbfbfb",
13369
+ messageArrow: "#ffffff",
13370
+ messageText: "#fbfbfb",
13371
+ occurrenceBg: "#818181",
13372
+ occurrenceBorder: "#e1e1e1",
13373
+ fragmentBorder: "#e1e1e1",
13374
+ fragmentHeaderBg: "#e9e9e9",
13375
+ fragmentHeaderOpacity: "1",
13376
+ fragmentHeaderText: "#000000",
13377
+ fragmentText: "#d4d4d4",
13378
+ guardOpacity: "1",
13379
+ fragmentSeparator: "#9f9f9f",
13380
+ commentText: "#d4d4d4",
13381
+ commentOpacity: "1",
13382
+ groupOutline: "#e1e1e1",
13383
+ dividerLine: "#9f9f9f",
13384
+ dividerBg: "#cfcfcf",
13385
+ dividerText: "#000000",
13386
+ numberText: "#ededed",
13387
+ fragmentNumberText: "#000000",
13388
+ // No badge: the slot is transparent, so the fill colour is irrelevant at opacity 0.
13389
+ numberBg: "#ededed",
13390
+ numberBgOpacity: "0",
13391
+ guardText: "#ececec",
13345
13392
  fontFamily: DIAGRAM_FONT_STACK
13346
13393
  };
13347
13394
  const THEME_PALETTES = {
13348
13395
  "theme-default": DEFAULT_PALETTE,
13349
- // `.theme-mermaid` sets only base/text/border/occurrence, and hides the
13350
- // footer — chrome the SVG output does not draw. Every slot it leaves unset
13351
- // matches theme-default, so the two render identically.
13352
- "theme-mermaid": DEFAULT_PALETTE,
13353
- // src/assets/tailwind.css `.theme-clean-light`.
13396
+ // `.theme-mermaid` sets only base/text/border/occurrence (and hides the
13397
+ // footer, which the SVG does not draw). Two slots it leaves unset fall back
13398
+ // differently from theme-default in the DOM: the message arrow resolves to
13399
+ // the border colour and the fragment header to the frame (no band). The
13400
+ // palette follows the DOM (themes.spec.ts).
13401
+ "theme-mermaid": {
13402
+ ...DEFAULT_PALETTE,
13403
+ messageArrow: "#666",
13404
+ fragmentHeaderBg: "#ffffff",
13405
+ fragmentHeaderOpacity: "1"
13406
+ },
13407
+ // src/assets/tailwind.css `.theme-clean-light`, resolved through the DOM
13408
+ // chains (themes.spec.ts): the title, fragment border, separator and comment
13409
+ // used to carry values the DOM never showed.
13354
13410
  "theme-clean-light": {
13355
13411
  frameBorder: "#e5e9f0",
13356
13412
  frameBg: "#ffffff",
13357
- titleText: "#353748",
13413
+ titleText: "#368eff",
13358
13414
  participantBg: "#edf4fe",
13359
13415
  participantBorder: "#368eff",
13416
+ // The DOM lifeline is --color-border-base, not the participant border.
13417
+ lifeline: "#c8c9c9",
13360
13418
  participantText: "#368eff",
13361
13419
  messageArrow: "#368eff",
13362
13420
  messageText: "#368eff",
13363
13421
  occurrenceBg: "#ffffff",
13364
13422
  occurrenceBorder: "#368eff",
13365
- fragmentBorder: "#c8c9c9",
13423
+ fragmentBorder: "#e5e9f0",
13366
13424
  fragmentHeaderBg: "#edf4fe",
13367
13425
  fragmentHeaderOpacity: "1",
13426
+ fragmentHeaderText: "#368eff",
13368
13427
  fragmentText: "#368eff",
13369
- fragmentSeparator: "#e5e9f0",
13370
- commentText: "#353748",
13371
- fontFamily: DIAGRAM_FONT_STACK
13372
- },
13373
- // src/assets/tailwind.css `.theme-clean-dark`.
13374
- "theme-clean-dark": {
13375
- frameBorder: "#cecfd2",
13376
- frameBg: "#111628",
13377
- titleText: "#cecfd2",
13378
- participantBg: "#5964f2",
13379
- participantBorder: "#cecfd2",
13380
- participantText: "#536fff",
13381
- messageArrow: "#536fff",
13382
- messageText: "#cecfd2",
13383
- occurrenceBg: "#5964f2",
13384
- occurrenceBorder: "#cecfd2",
13385
- fragmentBorder: "#cecfd2",
13386
- fragmentHeaderBg: "#5964f2",
13387
- fragmentHeaderOpacity: "1",
13388
- fragmentText: "#cecfd2",
13389
- fragmentSeparator: "#cecfd2",
13390
- commentText: "#cecfd2",
13428
+ guardOpacity: "0.65",
13429
+ fragmentSeparator: "#e5e7eb",
13430
+ commentText: "#333",
13431
+ commentOpacity: "0.5",
13432
+ // Slots every DOM theme still renders with the theme-default literals
13433
+ // (their CSS chains fall back to these values; only a theme that sets the
13434
+ // slot changes them).
13435
+ groupOutline: "#666",
13436
+ dividerLine: "#aaaa33",
13437
+ dividerBg: "#fff5ad",
13438
+ dividerText: "#333",
13439
+ numberText: "#6b7280",
13440
+ fragmentNumberText: "#6b7280",
13441
+ numberBg: "#6b7280",
13442
+ numberBgOpacity: "0.1",
13443
+ guardText: "#6b7280",
13391
13444
  fontFamily: DIAGRAM_FONT_STACK
13392
13445
  },
13446
+ // The one dark theme (ADR 0004); theme-clean-dark and theme-darcula are
13447
+ // aliases of it. Values are the derived tokens in
13448
+ // docs/ux-research/evidence/theme-dark/derive-dark.json, transcribed from
13449
+ // the `.theme-dark` block in src/assets/tailwind.css; themes.spec.ts
13450
+ // resolves every slot through tailwind.config.js and checks them.
13451
+ "theme-dark": DARK_PALETTE,
13452
+ "theme-clean-dark": DARK_PALETTE,
13453
+ "theme-darcula": DARK_PALETTE,
13393
13454
  // src/assets/tailwind.css `.theme-neon`. The DOM theme also swaps in the
13394
13455
  // MS Sans Serif webfont (`.zenuml .theme-neon`); the SVG names it first and
13395
13456
  // keeps the Helvetica stack behind it, since a consumer embedding the SVG
@@ -13400,6 +13461,7 @@ const THEME_PALETTES = {
13400
13461
  titleText: "#8ffc5b",
13401
13462
  participantBg: "#000000",
13402
13463
  participantBorder: "#8ffc5b",
13464
+ lifeline: "#60ff33",
13403
13465
  participantText: "#8ffc5b",
13404
13466
  messageArrow: "#8ffc5b",
13405
13467
  messageText: "#8ffc5b",
@@ -13408,9 +13470,25 @@ const THEME_PALETTES = {
13408
13470
  fragmentBorder: "#60ff33",
13409
13471
  fragmentHeaderBg: "#000000",
13410
13472
  fragmentHeaderOpacity: "1",
13473
+ fragmentHeaderText: "#8ffc5b",
13411
13474
  fragmentText: "#8ffc5b",
13412
- fragmentSeparator: "#60ff33",
13413
- commentText: "#8ffc5b",
13475
+ guardOpacity: "0.65",
13476
+ // Neither slot is set by `.theme-neon`; the DOM shows the defaults.
13477
+ fragmentSeparator: "#e5e7eb",
13478
+ commentText: "#333",
13479
+ commentOpacity: "0.5",
13480
+ // Slots every DOM theme still renders with the theme-default literals
13481
+ // (their CSS chains fall back to these values; only a theme that sets the
13482
+ // slot changes them).
13483
+ groupOutline: "#666",
13484
+ dividerLine: "#aaaa33",
13485
+ dividerBg: "#fff5ad",
13486
+ dividerText: "#333",
13487
+ numberText: "#6b7280",
13488
+ fragmentNumberText: "#6b7280",
13489
+ numberBg: "#6b7280",
13490
+ numberBgOpacity: "0.1",
13491
+ guardText: "#6b7280",
13414
13492
  fontFamily: `"MS Sans Serif", ${DIAGRAM_FONT_STACK}`
13415
13493
  }
13416
13494
  };
@@ -13430,20 +13508,25 @@ function buildThemeStyles(p) {
13430
13508
  .frame-title { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 400; fill: ${p.titleText}; }
13431
13509
  .participant-box { fill: ${p.participantBg}; stroke: ${p.participantBorder}; stroke-width: 1; }
13432
13510
  .participant-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.participantText}; }
13511
+ .stereotype-label { fill: ${p.participantText}; }
13433
13512
  .participant-icon { color: ${p.participantText}; }
13434
13513
  .participant-icon [fill="currentColor"]:not([stroke]) { stroke: ${p.participantBorder}; stroke-width: 1; }
13435
- .lifeline { stroke: ${p.participantBorder}; stroke-width: 1; }
13514
+ .lifeline { stroke: ${p.lifeline}; stroke-width: 1; }
13436
13515
  .message-line { stroke: ${p.messageArrow}; stroke-width: 1; shape-rendering: crispEdges; }
13437
13516
  .message-label { font-family: ${p.fontFamily}; font-size: 15px; fill: ${p.messageText}; }
13438
13517
  .arrow-head { fill: ${p.messageArrow}; stroke: ${p.messageArrow}; stroke-width: 1; }
13439
13518
  .arrow-open { fill: none; }
13519
+ .self-call-line { stroke: ${p.messageArrow}; stroke-width: 1; fill: none; }
13440
13520
  .occurrence { fill: ${p.occurrenceBg}; stroke: ${p.occurrenceBorder}; stroke-width: 1; shape-rendering: crispEdges; }
13441
13521
  .fragment-border { fill: none; stroke: ${p.fragmentBorder}; stroke-width: 1; }
13442
13522
  .fragment-header { fill: ${p.fragmentHeaderBg}; fill-opacity: ${p.fragmentHeaderOpacity}; stroke: none; shape-rendering: crispEdges; }
13443
- .fragment-number-bg { fill: #6b7280; fill-opacity: 0.1; stroke: none; }
13444
- .message-number-bg { fill: #6b7280; fill-opacity: 0.1; stroke: none; }
13445
- .fragment-label { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 400; font-variant-caps: all-small-caps; fill: ${p.fragmentText}; }
13446
- .fragment-condition { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; }
13523
+ .fragment-number-bg { fill: ${p.numberBg}; fill-opacity: ${p.numberBgOpacity}; stroke: none; }
13524
+ .message-number-bg { fill: ${p.numberBg}; fill-opacity: ${p.numberBgOpacity}; stroke: none; }
13525
+ .fragment-label { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 400; font-variant-caps: all-small-caps; fill: ${p.fragmentHeaderText}; }
13526
+ .fragment-condition { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; opacity: ${p.guardOpacity}; }
13527
+ .fragment-section-dim { opacity: ${p.guardOpacity}; }
13528
+ .fragment-section-bg { fill: ${p.frameBg}; }
13529
+ .fragment-icon { color: ${p.fragmentHeaderText}; }
13447
13530
  .fragment-separator { stroke: ${p.fragmentSeparator}; stroke-width: 1; shape-rendering: crispEdges; }
13448
13531
  .fragment-section-keyword { font-variant-caps: all-small-caps; }
13449
13532
  .fragment-section-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; }
@@ -13451,13 +13534,14 @@ function buildThemeStyles(p) {
13451
13534
  .return-arrow { stroke: ${p.messageArrow}; stroke-width: 1; fill: none; }
13452
13535
  .return-label { font-family: ${p.fontFamily}; font-size: 15px; fill: ${p.messageText}; }
13453
13536
  .return-icon { fill: ${p.messageText}; }
13454
- .divider-line { stroke: #aaaa33; stroke-width: 1; }
13455
- .divider-bg { fill: #fff5ad; stroke: #aaaa33; stroke-width: 1; }
13456
- .divider-label { font-family: ${p.fontFamily}; font-size: 14px; fill: #333; }
13457
- .comment-text { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.commentText}; opacity: 0.5; }
13458
- .guard-keyword { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; font-variant-caps: all-small-caps; fill: #6b7280; }
13459
- .seq-number { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; fill: #6b7280; }
13460
- .group-outline { fill: none; stroke: ${p.participantBorder}; }
13537
+ .divider-line { stroke: ${p.dividerLine}; stroke-width: 1; }
13538
+ .divider-bg { fill: ${p.dividerBg}; stroke: ${p.dividerLine}; stroke-width: 1; }
13539
+ .divider-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.dividerText}; }
13540
+ .comment-text { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.commentText}; opacity: ${p.commentOpacity}; }
13541
+ .guard-keyword { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; font-variant-caps: all-small-caps; fill: ${p.guardText}; }
13542
+ .seq-number { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; fill: ${p.numberText}; }
13543
+ .fragment-number { fill: ${p.fragmentNumberText}; }
13544
+ .group-outline { fill: none; stroke: ${p.groupOutline}; }
13461
13545
  .group-title-bg { fill: ${p.frameBg}; stroke: none; }
13462
13546
  .group-title-text { font-family: ${p.fontFamily}; font-size: 13px; font-weight: 400; fill: ${p.participantText}; }
13463
13547
  `;
@@ -13614,8 +13698,9 @@ Rendering:
13614
13698
  -o, --output <file> Output file (use "-" for stdout; default: <input>.svg)
13615
13699
  -e, --outputFormat <format> Output format: "svg" (default) or "png"
13616
13700
  -s, --scale <factor> Pixel scale factor for PNG (default: 2; ignored for SVG)
13617
- -t, --theme <name> Theme: default, mermaid, clean-light, clean-dark,
13618
- neon (prefix "theme-"; unknown names use default)
13701
+ -t, --theme <name> Theme: default, mermaid, clean-light, dark, neon
13702
+ (clean-dark and darcula are aliases of dark;
13703
+ prefix "theme-"; unknown names use default)
13619
13704
  -c, --configFile <file> JSON config file with { theme, scale, outputFormat }
13620
13705
  --md Markdown mode: render zenuml code blocks and produce output Markdown
13621
13706