@diagrammo/dgmo 0.66.0 → 0.67.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.
package/dist/advanced.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  computeActivations,
17
17
  groupMessagesBySection,
18
18
  renderSequenceDiagram
19
- } from "./chunk-6IUL6LER.js";
19
+ } from "./chunk-WDLD5MU5.js";
20
20
  import {
21
21
  renderRing,
22
22
  renderRingForExport
@@ -79,18 +79,18 @@ import {
79
79
  import {
80
80
  renderMap,
81
81
  renderMapForExport
82
- } from "./chunk-O274UTXH.js";
82
+ } from "./chunk-QRWY5QTA.js";
83
83
  import "./chunk-FWVKPEG3.js";
84
84
  import {
85
85
  mapContentAspect,
86
86
  mapExportDimensions
87
- } from "./chunk-X26BF4T2.js";
87
+ } from "./chunk-PZOFMBF3.js";
88
88
  import {
89
89
  albersSkewFallback,
90
90
  layoutMap,
91
91
  mapBackgroundColor,
92
92
  mapNeutralLandColor
93
- } from "./chunk-R7S5542V.js";
93
+ } from "./chunk-6E5YZR4S.js";
94
94
  import {
95
95
  decodeFeatures,
96
96
  regionAt
@@ -313,7 +313,7 @@ import {
313
313
  renderSlopeChart,
314
314
  renderVenn,
315
315
  renderWordCloud
316
- } from "./chunk-3OT63FS4.js";
316
+ } from "./chunk-HJ62AO3J.js";
317
317
  import "./chunk-7L53J53J.js";
318
318
  import "./chunk-EOYPX6SF.js";
319
319
  import {
package/dist/block.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-D3K4U3ZM.js";
5
5
  import {
6
6
  render
7
- } from "./chunk-3OT63FS4.js";
7
+ } from "./chunk-HJ62AO3J.js";
8
8
  import {
9
9
  docsLink,
10
10
  renderErrorCard
@@ -1036,6 +1036,20 @@ function createLabelMetrics(size) {
1036
1036
  };
1037
1037
  }
1038
1038
 
1039
+ // src/map/layout-constants.ts
1040
+ var FIT_PAD = 24;
1041
+ var WORLD_LABEL_ANCHORS = {
1042
+ US: [-98.5, 39.5],
1043
+ // CONUS geographic centre (near Lebanon, Kansas)
1044
+ // Russia crosses the antimeridian (Chukotka at ~170°W), so on a non-global
1045
+ // (e.g. Europe) projection its geometry smears across the whole frame and the
1046
+ // area-weighted centroid lands mid-map (over Europe) — useless as a label
1047
+ // anchor. Pin it to European Russia (~Volga) so a Europe view labels visible
1048
+ // western Russia on its eastern margin; on a world view this still sits over
1049
+ // Russian land. (See the curated-anchor smear-gate bypass in context-labels.)
1050
+ RU: [45, 58]
1051
+ };
1052
+
1039
1053
  // src/map/region-labels.ts
1040
1054
  function placeRegionLabels(args) {
1041
1055
  const {
@@ -1438,7 +1452,6 @@ function placeRegionLabels(args) {
1438
1452
  }
1439
1453
 
1440
1454
  // src/map/layout.ts
1441
- var FIT_PAD = 24;
1442
1455
  var PATH_DIGITS = 1;
1443
1456
  var THIN_TOL = 0.6;
1444
1457
  var ALBERS_SKEW_MAX = 1.25;
@@ -1483,17 +1496,6 @@ var R_MIN = 4;
1483
1496
  var R_MAX = 22;
1484
1497
  var POI_FILL_OPACITY_MAX = 0.92;
1485
1498
  var POI_FILL_OPACITY_MIN = 0.55;
1486
- var WORLD_LABEL_ANCHORS = {
1487
- US: [-98.5, 39.5],
1488
- // CONUS geographic centre (near Lebanon, Kansas)
1489
- // Russia crosses the antimeridian (Chukotka at ~170°W), so on a non-global
1490
- // (e.g. Europe) projection its geometry smears across the whole frame and the
1491
- // area-weighted centroid lands mid-map (over Europe) — useless as a label
1492
- // anchor. Pin it to European Russia (~Volga) so a Europe view labels visible
1493
- // western Russia on its eastern margin; on a world view this still sits over
1494
- // Russian land. (See the curated-anchor smear-gate bypass in context-labels.)
1495
- RU: [45, 58]
1496
- };
1497
1499
  var MAX_CLUSTER_EXTENT_FACTOR = 0.18;
1498
1500
  var MAX_COLUMN_ROWS = 7;
1499
1501
  var REGION_LABEL_HALO_RATIO = 4.5;
@@ -3363,4 +3365,4 @@ export {
3363
3365
  albersSkewFallback,
3364
3366
  layoutMap
3365
3367
  };
3366
- //# sourceMappingURL=chunk-R7S5542V.js.map
3368
+ //# sourceMappingURL=chunk-6E5YZR4S.js.map
@@ -2749,8 +2749,8 @@ async function exportMap(ctx) {
2749
2749
  const { content, theme, palette, options } = ctx;
2750
2750
  const { parseMap } = await import("./parser-UKQC7N6K.js");
2751
2751
  const { resolveMap } = await import("./resolver-B3TXWNWF.js");
2752
- const { renderMapForExport } = await import("./renderer-T66477EQ.js");
2753
- const { mapExportDimensions } = await import("./dimensions-RD3Y7FCF.js");
2752
+ const { renderMapForExport } = await import("./renderer-AOFIEF2T.js");
2753
+ const { mapExportDimensions } = await import("./dimensions-ILAVBRQ3.js");
2754
2754
  const effectivePalette = await resolveExportPalette(theme, palette);
2755
2755
  const mapParsed = parseMap(content, effectivePalette);
2756
2756
  const { data: mapData, reason } = await resolveMapDataSource(
@@ -3055,7 +3055,7 @@ async function exportVisualization(ctx) {
3055
3055
  const isDark = ctx.isDark;
3056
3056
  const container = createExportContainer(ctx.width, ctx.height);
3057
3057
  const { parseSequenceDgmo } = await import("./parser-5WIZGKNE.js");
3058
- const { renderSequenceDiagram } = await import("./renderer-ALP46W2X.js");
3058
+ const { renderSequenceDiagram } = await import("./renderer-KY6PADCM.js");
3059
3059
  const seqParsed = parseSequenceDgmo(content, effectivePalette);
3060
3060
  if (seqParsed.error || seqParsed.participants.length === 0) return "";
3061
3061
  const collapsedSections = viewState?.cs ? new Set(viewState.cs) : void 0;
@@ -3718,4 +3718,4 @@ export {
3718
3718
  renderForExport,
3719
3719
  render
3720
3720
  };
3721
- //# sourceMappingURL=chunk-3OT63FS4.js.map
3721
+ //# sourceMappingURL=chunk-HJ62AO3J.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildMapProjection
3
- } from "./chunk-R7S5542V.js";
3
+ } from "./chunk-6E5YZR4S.js";
4
4
  import {
5
5
  TITLE_FONT_SIZE,
6
6
  TITLE_Y
@@ -51,4 +51,4 @@ export {
51
51
  mapContentAspect,
52
52
  mapExportDimensions
53
53
  };
54
- //# sourceMappingURL=chunk-X26BF4T2.js.map
54
+ //# sourceMappingURL=chunk-PZOFMBF3.js.map
@@ -6,7 +6,7 @@ import {
6
6
  mapLegendConfig,
7
7
  mapLegendGroups,
8
8
  parsePathRings
9
- } from "./chunk-R7S5542V.js";
9
+ } from "./chunk-6E5YZR4S.js";
10
10
  import {
11
11
  TITLE_FONT_SIZE,
12
12
  TITLE_FONT_WEIGHT,
@@ -781,4 +781,4 @@ export {
781
781
  renderMap,
782
782
  renderMapForExport
783
783
  };
784
- //# sourceMappingURL=chunk-O274UTXH.js.map
784
+ //# sourceMappingURL=chunk-QRWY5QTA.js.map
@@ -25,6 +25,9 @@ import {
25
25
  import {
26
26
  FONT_FAMILY
27
27
  } from "./chunk-UTCPNJND.js";
28
+ import {
29
+ legendChromeColors
30
+ } from "./chunk-3HOCNSPD.js";
28
31
  import {
29
32
  measureText,
30
33
  truncateText
@@ -253,6 +256,7 @@ var NOTE_FONT_SIZE = 10;
253
256
  var NOTE_LINE_H = 14;
254
257
  var NOTE_GAP = 15;
255
258
  var ACTIVATION_WIDTH = 10;
259
+ var ACTIVATION_IMPLICIT_END_CLEARANCE = 8;
256
260
  var SELF_CALL_HEIGHT = 25;
257
261
  var SELF_CALL_WIDTH = 30;
258
262
  var ACTOR_LABEL_CLEARANCE = 22;
@@ -401,6 +405,34 @@ function groupMessagesBySection(elements, messages) {
401
405
  }
402
406
  return groups;
403
407
  }
408
+ var SECTION_BAND_HEIGHT = 22;
409
+ var COLLAPSED_SECTION_BAND_HEIGHT = 36;
410
+ var COLLAPSED_SECTION_BAND_EXTRA = COLLAPSED_SECTION_BAND_HEIGHT - SECTION_BAND_HEIGHT;
411
+ var COLLAPSED_SECTION_MARK_OFFSET = 9;
412
+ var COLLAPSED_SECTION_LABEL_BASELINE = -4;
413
+ var SECTION_LABEL_CLEARANCE_X = 8;
414
+ var SECTION_LABEL_CLEARANCE_ABOVE = 12;
415
+ var SECTION_LABEL_CLEARANCE_BELOW = 5;
416
+ function summarizeSectionParticipation(messages, msgIndices) {
417
+ const summary = /* @__PURE__ */ new Map();
418
+ const bump = (id, key) => {
419
+ const entry = summary.get(id) ?? { sends: 0, receives: 0 };
420
+ entry[key] += 1;
421
+ summary.set(id, entry);
422
+ };
423
+ for (const idx of msgIndices) {
424
+ const msg = messages[idx];
425
+ if (!msg) continue;
426
+ bump(msg.from, "sends");
427
+ bump(msg.to, "receives");
428
+ }
429
+ return summary;
430
+ }
431
+ function sectionMarkRadius(touches) {
432
+ if (touches >= 4) return 6;
433
+ if (touches >= 2) return 4.5;
434
+ return 3.5;
435
+ }
404
436
  function buildRenderSequence(messages) {
405
437
  const steps = [];
406
438
  const stack = [];
@@ -732,11 +764,18 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
732
764
  }
733
765
  const lastStepIdx = Math.max(renderSteps.length - 1, 0);
734
766
  const clampStep = (i) => Math.min(Math.max(i, 0), lastStepIdx);
735
- const activations = activationsOff ? [] : computeActivations(allRenderSteps).map((a) => ({
736
- ...a,
737
- startStep: clampStep(allToFiltered[a.startStep] ?? 0),
738
- endStep: clampStep(allToFiltered[a.endStep] ?? 0)
739
- }));
767
+ const activations = activationsOff ? [] : computeActivations(allRenderSteps).map((a) => {
768
+ const closingStep = allRenderSteps[a.endStep];
769
+ return {
770
+ ...a,
771
+ startStep: clampStep(allToFiltered[a.startStep] ?? 0),
772
+ endStep: clampStep(allToFiltered[a.endStep] ?? 0),
773
+ // True when the return that closes this bar was dropped from the
774
+ // layout, so `endStep` is not the bar's own event but whatever
775
+ // happens next. The bar has to stop short of it — see the render.
776
+ implicitEnd: closingStep !== void 0 && !stepSurvives(closingStep)
777
+ };
778
+ });
740
779
  const stepSpacing = 35;
741
780
  const BLOCK_HEADER_SPACE = 30;
742
781
  const BLOCK_AFTER_SPACE = 15;
@@ -803,6 +842,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
803
842
  }
804
843
  return -1;
805
844
  };
845
+ const isSectionCollapsed = (sec) => collapsedSections?.has(sec.lineNumber) ?? false;
846
+ const collapsedBandPad = (sec) => isSectionCollapsed(sec) ? COLLAPSED_SECTION_BAND_EXTRA / 2 : 0;
806
847
  const SECTION_TOP_PAD = 35;
807
848
  const SECTION_BOTTOM_PAD = 45;
808
849
  const extraBeforeMsg = /* @__PURE__ */ new Map();
@@ -1048,9 +1089,10 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1048
1089
  const sections = sectionsBeforeStep.get(i);
1049
1090
  if (sections) {
1050
1091
  for (const sec of sections) {
1051
- curY += SECTION_TOP_PAD;
1092
+ const bandPad = collapsedBandPad(sec);
1093
+ curY += SECTION_TOP_PAD + bandPad;
1052
1094
  sectionYPositions.set(sec.lineNumber, curY);
1053
- curY += SECTION_BOTTOM_PAD;
1095
+ curY += SECTION_BOTTOM_PAD + bandPad;
1054
1096
  }
1055
1097
  }
1056
1098
  const step = renderSteps[i];
@@ -1063,9 +1105,10 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1063
1105
  curY += isSelfCall ? sSelfCallHeight + 25 : stepSpacing;
1064
1106
  }
1065
1107
  for (const sec of trailingSections) {
1066
- curY += SECTION_TOP_PAD;
1108
+ const bandPad = collapsedBandPad(sec);
1109
+ curY += SECTION_TOP_PAD + bandPad;
1067
1110
  sectionYPositions.set(sec.lineNumber, curY);
1068
- curY += SECTION_BOTTOM_PAD;
1111
+ curY += SECTION_BOTTOM_PAD + bandPad;
1069
1112
  }
1070
1113
  curY += trailingNoteSpace;
1071
1114
  layoutEndY = curY;
@@ -1324,6 +1367,13 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1324
1367
  });
1325
1368
  }
1326
1369
  }
1370
+ const participantTagColor = (id) => {
1371
+ const direct = getTagColor(tagMap?.participants.get(id));
1372
+ if (direct) return direct;
1373
+ if (!collapsedGroupNames.has(id) || !tagKey) return void 0;
1374
+ const meta = collapsedGroupMeta.get(id);
1375
+ return meta?.metadata ? getTagColor(meta.metadata[tagKey]) : void 0;
1376
+ };
1327
1377
  for (const group of groups) {
1328
1378
  if (group.participantIds.length === 0) continue;
1329
1379
  const memberXs = group.participantIds.map((id) => participantX.get(id)).filter((x) => x !== void 0);
@@ -1342,21 +1392,50 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1342
1392
  groupG.append("rect").attr("x", minX).attr("y", boxY).attr("width", maxX - minX).attr("height", participantStartY - boxY).attr("fill", "transparent").attr("class", "group-label-hit");
1343
1393
  groupG.append("text").attr("x", (minX + maxX) / 2).attr("y", boxY + GROUP_LABEL_SIZE + 4).attr("text-anchor", "middle").attr("fill", strokeColor).attr("font-size", GROUP_LABEL_SIZE).attr("font-weight", "bold").attr("opacity", 0.7).attr("pointer-events", "none").attr("class", "group-label").text(group.name);
1344
1394
  }
1395
+ const bandLeftmostX = Math.min(...Array.from(participantX.values()));
1396
+ const bandRightmostX = Math.max(...Array.from(participantX.values()));
1397
+ const sectionLineX1 = bandLeftmostX - sBoxW / 2 - 10;
1398
+ const sectionLineX2 = bandRightmostX + sBoxW / 2 + 10;
1399
+ const sectionLabelX = (sectionLineX1 + sectionLineX2) / 2;
1400
+ const sectionLabelTextFor = (sec) => {
1401
+ if (!isSectionCollapsed(sec)) return sec.label;
1402
+ const count = sectionMsgCounts.get(sec.lineNumber) ?? 0;
1403
+ return `${sec.label} (${count} ${count === 1 ? "message" : "messages"})`;
1404
+ };
1405
+ const sectionLabelBaselineFor = (sec, secY) => isSectionCollapsed(sec) ? secY + COLLAPSED_SECTION_LABEL_BASELINE : secY + 4;
1406
+ const sectionLabelBoxes = sectionRegions.map((region) => {
1407
+ const secY = sectionYPositions.get(region.section.lineNumber);
1408
+ if (secY === void 0) return null;
1409
+ const width = measureText(sectionLabelTextFor(region.section), 11, {
1410
+ bold: true
1411
+ });
1412
+ const baseline = sectionLabelBaselineFor(region.section, secY);
1413
+ return {
1414
+ x1: sectionLabelX - width / 2 - SECTION_LABEL_CLEARANCE_X,
1415
+ x2: sectionLabelX + width / 2 + SECTION_LABEL_CLEARANCE_X,
1416
+ y1: baseline - SECTION_LABEL_CLEARANCE_ABOVE,
1417
+ y2: baseline + SECTION_LABEL_CLEARANCE_BELOW
1418
+ };
1419
+ }).filter((box) => box !== null);
1420
+ const lifelineSegments = (cx, yTop, yBottom) => {
1421
+ const cuts = sectionLabelBoxes.filter((b) => cx >= b.x1 && cx <= b.x2 && b.y2 > yTop && b.y1 < yBottom).sort((a, b) => a.y1 - b.y1);
1422
+ const segments = [];
1423
+ let y = yTop;
1424
+ for (const cut of cuts) {
1425
+ if (cut.y1 > y) segments.push([y, cut.y1]);
1426
+ y = Math.max(y, cut.y2);
1427
+ }
1428
+ if (y < yBottom) segments.push([y, yBottom]);
1429
+ return segments;
1430
+ };
1345
1431
  const lifelineStartY = lifelineStartY0;
1346
1432
  participants.forEach((participant) => {
1347
1433
  const cx = participantX.get(participant.id);
1348
1434
  const cy = participantStartY;
1349
1435
  const pTagValue = tagMap?.participants.get(participant.id);
1350
- const pTagColor = getTagColor(pTagValue);
1351
1436
  const pTagAttr = tagKey && pTagValue ? { key: tagKey, value: pTagValue.toLowerCase() } : void 0;
1352
1437
  const isCollapsedGroup = collapsedGroupNames.has(participant.id);
1353
- let effectiveTagColor = pTagColor;
1354
- if (isCollapsedGroup && !effectiveTagColor) {
1355
- const meta = collapsedGroupMeta.get(participant.id);
1356
- if (meta?.metadata && tagKey) {
1357
- effectiveTagColor = getTagColor(meta.metadata[tagKey]);
1358
- }
1359
- }
1438
+ const effectiveTagColor = participantTagColor(participant.id);
1360
1439
  renderParticipant(
1361
1440
  svg,
1362
1441
  participant,
@@ -1392,10 +1471,16 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1392
1471
  participantG.append("rect").attr("class", "sequence-drill-bar").attr("x", -boxW / 2).attr("y", -GROUP_PADDING_TOP + fullH - drillBarH).attr("width", boxW).attr("height", drillBarH).attr("fill", drillColor).attr("clip-path", `url(#${clipId})`);
1393
1472
  }
1394
1473
  const llY = isCollapsedGroup ? lifelineStartY + GROUP_PADDING_BOTTOM : participant.type === "actor" ? lifelineStartY + ACTOR_LABEL_CLEARANCE : lifelineStartY;
1395
- const llColor = isCollapsedGroup ? effectiveTagColor || palette.textMuted : pTagColor || palette.textMuted;
1396
- const lifelineEl = svg.append("line").attr("x1", cx).attr("y1", llY).attr("x2", cx).attr("y2", lifelineStartY + lifelineLength).attr("stroke", llColor).attr("stroke-width", 1).attr("stroke-dasharray", "6 4").attr("class", "lifeline").attr("data-participant-id", participant.id);
1397
- if (tagKey && pTagValue) {
1398
- lifelineEl.attr(`data-tag-${tagKey}`, pTagValue.toLowerCase());
1474
+ const llColor = effectiveTagColor || palette.textMuted;
1475
+ for (const [segTop, segBottom] of lifelineSegments(
1476
+ cx,
1477
+ llY,
1478
+ lifelineStartY + lifelineLength
1479
+ )) {
1480
+ const lifelineEl = svg.append("line").attr("x1", cx).attr("y1", segTop).attr("x2", cx).attr("y2", segBottom).attr("stroke", llColor).attr("stroke-width", 1).attr("stroke-dasharray", "6 4").attr("class", "lifeline").attr("data-participant-id", participant.id);
1481
+ if (tagKey && pTagValue) {
1482
+ lifelineEl.attr(`data-tag-${tagKey}`, pTagValue.toLowerCase());
1483
+ }
1399
1484
  }
1400
1485
  });
1401
1486
  const FRAME_PADDING_X = 30;
@@ -1403,7 +1488,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1403
1488
  const FRAME_LABEL_HEIGHT = 18;
1404
1489
  const SELF_ARROW_PROJECTION = sActivationWidth / 2 + sSelfCallWidth;
1405
1490
  const SELF_ARROW_FRAME_PAD = 10;
1406
- const frameRightmostX = Math.max(...Array.from(participantX.values()));
1407
1491
  const collectMsgIndices = (els) => {
1408
1492
  const indices = [];
1409
1493
  for (const el of els) {
@@ -1576,7 +1660,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1576
1660
  if (px === void 0) return;
1577
1661
  const x = px - sActivationWidth / 2 + act.depth * ACTIVATION_NEST_OFFSET;
1578
1662
  const y1 = stepY(act.startStep);
1579
- const y2 = stepY(act.endStep);
1663
+ const rawY2 = stepY(act.endStep);
1664
+ const y2 = act.implicitEnd && rawY2 - ACTIVATION_IMPLICIT_END_CLEARANCE > y1 + sActivationWidth ? rawY2 - ACTIVATION_IMPLICIT_END_CLEARANCE : rawY2;
1580
1665
  const coveredLines = [];
1581
1666
  for (let si = act.startStep; si <= act.endStep; si++) {
1582
1667
  const step = renderSteps[si];
@@ -1626,31 +1711,57 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1626
1711
  const offset = depth * ACTIVATION_NEST_OFFSET;
1627
1712
  return side === "right" ? px + sActivationWidth / 2 + offset : px - sActivationWidth / 2 + offset;
1628
1713
  };
1629
- const leftmostX = Math.min(...Array.from(participantX.values()));
1630
- const rightmostX = frameRightmostX;
1631
- const sectionLineX1 = leftmostX - sBoxW / 2 - 10;
1632
- const sectionLineX2 = rightmostX + sBoxW / 2 + 10;
1633
1714
  for (const region of sectionRegions) {
1634
1715
  const sec = region.section;
1635
1716
  const secY = sectionYPositions.get(sec.lineNumber);
1636
1717
  if (secY === void 0) continue;
1637
- const isCollapsed = collapsedSections?.has(sec.lineNumber) ?? false;
1718
+ const isCollapsed = isSectionCollapsed(sec);
1638
1719
  const lineColor = palette.textMuted;
1639
1720
  const sectionG = svg.append("g").attr("data-section-toggle", "").attr("data-line-number", String(sec.lineNumber)).attr("data-section", "").attr("tabindex", "0").attr("role", "button").attr("aria-expanded", String(!isCollapsed));
1640
- const BAND_HEIGHT = 22;
1721
+ const BAND_HEIGHT = isCollapsed ? COLLAPSED_SECTION_BAND_HEIGHT : SECTION_BAND_HEIGHT;
1641
1722
  const bandX = sectionLineX1 - 10;
1642
1723
  const bandWidth = sectionLineX2 - sectionLineX1 + 20;
1643
- const bandOpacity = isCollapsed ? isDark ? 0.35 : 0.25 : isDark ? 0.1 : 0.08;
1644
- sectionG.append("rect").attr("x", bandX).attr("y", secY - BAND_HEIGHT / 2).attr("width", bandWidth).attr("height", BAND_HEIGHT).attr("fill", lineColor).attr("opacity", bandOpacity).attr("rx", 2).attr("pointer-events", "none").attr("class", "section-divider");
1645
- const msgCount = sectionMsgCounts.get(sec.lineNumber) ?? 0;
1646
- const labelText = isCollapsed ? `${sec.label} (${msgCount} ${msgCount === 1 ? "message" : "messages"})` : sec.label;
1647
- const labelX = (sectionLineX1 + sectionLineX2) / 2;
1648
- const labelHitW = Math.max(
1649
- 80,
1650
- measureText(labelText, 11, { bold: true }) + 24
1651
- );
1724
+ const bandFill = isCollapsed ? legendChromeColors(palette, isDark).groupBg : lineColor;
1725
+ const bandOpacity = isCollapsed ? 1 : isDark ? 0.1 : 0.08;
1726
+ sectionG.append("rect").attr("x", bandX).attr("y", secY - BAND_HEIGHT / 2).attr("width", bandWidth).attr("height", BAND_HEIGHT).attr("fill", bandFill).attr("opacity", bandOpacity).attr("rx", 2).attr("pointer-events", "none").attr("class", "section-divider");
1727
+ const labelText = sectionLabelTextFor(sec);
1728
+ const labelWidth = measureText(labelText, 11, { bold: true });
1729
+ const labelX = sectionLabelX;
1730
+ const labelBaseline = sectionLabelBaselineFor(sec, secY);
1731
+ const labelHitW = Math.max(80, labelWidth + 24);
1652
1732
  sectionG.append("rect").attr("x", labelX - labelHitW / 2).attr("y", secY - BAND_HEIGHT / 2).attr("width", labelHitW).attr("height", BAND_HEIGHT).attr("fill", "transparent").attr("class", "section-label-hit");
1653
- sectionG.append("text").attr("x", labelX).attr("y", secY + 4).attr("text-anchor", "middle").attr("fill", lineColor).attr("font-size", 11).attr("font-weight", "bold").attr("class", "section-label").text(labelText);
1733
+ sectionG.append("text").attr("x", labelX).attr("y", labelBaseline).attr("text-anchor", "middle").attr("fill", lineColor).attr("font-size", 11).attr("font-weight", "bold").attr("class", "section-label").text(labelText);
1734
+ if (!isCollapsed) continue;
1735
+ const participation = summarizeSectionParticipation(
1736
+ messages,
1737
+ region.msgIndices
1738
+ );
1739
+ const markY = secY + COLLAPSED_SECTION_MARK_OFFSET;
1740
+ const involvedXs = participants.filter((p) => participation.has(p.id)).map((p) => participantX.get(p.id)).filter((x) => x !== void 0);
1741
+ if (involvedXs.length > 1) {
1742
+ sectionG.append("line").attr("x1", Math.min(...involvedXs)).attr("x2", Math.max(...involvedXs)).attr("y1", markY).attr("y2", markY).attr("stroke", lineColor).attr("stroke-width", 1).attr("stroke-dasharray", "2 3").attr("opacity", 0.5).attr("pointer-events", "none").attr("class", "section-reach");
1743
+ }
1744
+ for (const participant of participants) {
1745
+ const markX = participantX.get(participant.id);
1746
+ if (markX === void 0) continue;
1747
+ const part = participation.get(participant.id);
1748
+ const mark = sectionG.append("circle").attr("cx", markX).attr("cy", markY).attr("pointer-events", "none").attr("data-participant-id", participant.id);
1749
+ if (!part) {
1750
+ mark.attr("r", 2.5).attr("fill", "none").attr("stroke", lineColor).attr("stroke-width", 1).attr("opacity", 0.5).attr("class", "section-mark section-mark-absent");
1751
+ continue;
1752
+ }
1753
+ const markColor = participantTagColor(participant.id) ?? palette.text;
1754
+ const radius = sectionMarkRadius(part.sends + part.receives);
1755
+ if (part.sends === 0) {
1756
+ mark.attr("r", radius).attr("fill", bandFill).attr("stroke", markColor).attr("stroke-width", 1.6).attr("class", "section-mark section-mark-receives");
1757
+ } else {
1758
+ mark.attr("r", radius).attr("fill", markColor).attr("class", "section-mark section-mark-sends");
1759
+ }
1760
+ }
1761
+ const involvedLabels = participants.filter((p) => participation.has(p.id)).map((p) => p.label);
1762
+ if (involvedLabels.length > 0) {
1763
+ sectionG.attr("aria-label", `${labelText}, ${involvedLabels.join(", ")}`);
1764
+ }
1654
1765
  }
1655
1766
  renderSteps.forEach((step, i) => {
1656
1767
  const fromX = participantX.get(step.from);
@@ -1903,6 +2014,7 @@ function renderParticipant(svg, participant, cx, cy, palette, isDark, color, tag
1903
2014
  export {
1904
2015
  applyCollapseProjection,
1905
2016
  groupMessagesBySection,
2017
+ summarizeSectionParticipation,
1906
2018
  buildRenderSequence,
1907
2019
  computeActivations,
1908
2020
  applyPositionOverrides,
@@ -1910,4 +2022,4 @@ export {
1910
2022
  renderSequenceDiagram,
1911
2023
  buildNoteMessageMap
1912
2024
  };
1913
- //# sourceMappingURL=chunk-6IUL6LER.js.map
2025
+ //# sourceMappingURL=chunk-WDLD5MU5.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  mapContentAspect,
3
3
  mapExportDimensions
4
- } from "./chunk-X26BF4T2.js";
5
- import "./chunk-R7S5542V.js";
4
+ } from "./chunk-PZOFMBF3.js";
5
+ import "./chunk-6E5YZR4S.js";
6
6
  import "./chunk-4QV26TEG.js";
7
7
  import "./chunk-L65WI4HO.js";
8
8
  import "./chunk-A4GOY3PE.js";
@@ -19,4 +19,4 @@ export {
19
19
  mapContentAspect,
20
20
  mapExportDimensions
21
21
  };
22
- //# sourceMappingURL=dimensions-RD3Y7FCF.js.map
22
+ //# sourceMappingURL=dimensions-ILAVBRQ3.js.map
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-SQAG3UXH.js";
12
12
  import {
13
13
  render
14
- } from "./chunk-3OT63FS4.js";
14
+ } from "./chunk-HJ62AO3J.js";
15
15
  import {
16
16
  renderErrorCard
17
17
  } from "./chunk-7L53J53J.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  renderMap,
3
3
  renderMapForExport
4
- } from "./chunk-O274UTXH.js";
4
+ } from "./chunk-QRWY5QTA.js";
5
5
  import "./chunk-FWVKPEG3.js";
6
- import "./chunk-R7S5542V.js";
6
+ import "./chunk-6E5YZR4S.js";
7
7
  import "./chunk-4QV26TEG.js";
8
8
  import "./chunk-L65WI4HO.js";
9
9
  import "./chunk-A4GOY3PE.js";
@@ -24,4 +24,4 @@ export {
24
24
  renderMap,
25
25
  renderMapForExport
26
26
  };
27
- //# sourceMappingURL=renderer-T66477EQ.js.map
27
+ //# sourceMappingURL=renderer-AOFIEF2T.js.map
@@ -5,8 +5,9 @@ import {
5
5
  buildRenderSequence,
6
6
  computeActivations,
7
7
  groupMessagesBySection,
8
- renderSequenceDiagram
9
- } from "./chunk-6IUL6LER.js";
8
+ renderSequenceDiagram,
9
+ summarizeSectionParticipation
10
+ } from "./chunk-WDLD5MU5.js";
10
11
  import "./chunk-NCT22MOD.js";
11
12
  import {
12
13
  parseInlineMarkdown,
@@ -39,6 +40,7 @@ export {
39
40
  groupMessagesBySection,
40
41
  parseInlineMarkdown,
41
42
  renderSequenceDiagram,
43
+ summarizeSectionParticipation,
42
44
  truncateBareUrl
43
45
  };
44
- //# sourceMappingURL=renderer-ALP46W2X.js.map
46
+ //# sourceMappingURL=renderer-KY6PADCM.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagrammo/dgmo",
3
- "version": "0.66.0",
3
+ "version": "0.67.0",
4
4
  "description": "DGMO diagram markup language — parser, renderer, and color system",
5
5
  "license": "MIT",
6
6
  "author": "Diagrammo LLC",