@diagrammo/dgmo 0.93.0 → 0.95.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 (122) hide show
  1. package/dist/advanced.d.ts +98 -21
  2. package/dist/advanced.js +79 -61
  3. package/dist/block.d.ts +6 -0
  4. package/dist/block.js +23 -20
  5. package/dist/chart-meta.js +9 -9
  6. package/dist/{charts-d3-ERYYVGP6.js → charts-d3-SZV2SFTM.js} +2 -2
  7. package/dist/{chunk-J6AEKIRQ.js → chunk-2I4UQG7W.js} +1 -1
  8. package/dist/{chunk-LDDDKWL6.js → chunk-2J2CWWWK.js} +1 -1
  9. package/dist/{chunk-QDRCWVV3.js → chunk-4EX4OKGZ.js} +71 -8
  10. package/dist/{chunk-A5WIAMCT.js → chunk-4UVCTLRH.js} +1 -1
  11. package/dist/{chunk-KCMGIYPO.js → chunk-5XBYLYYI.js} +1 -1
  12. package/dist/{chunk-XUTR7GNT.js → chunk-62GLKE6Q.js} +68 -29
  13. package/dist/{chunk-D6PVMUCX.js → chunk-67N26CER.js} +4 -4
  14. package/dist/{chunk-IIV4SMJL.js → chunk-6EFCOES2.js} +370 -285
  15. package/dist/{chunk-TNV4F5WA.js → chunk-7IALGIOI.js} +2 -2
  16. package/dist/{chunk-MB2SQF7N.js → chunk-7WEYXYLC.js} +1 -1
  17. package/dist/{chunk-4RY5D5RE.js → chunk-AM42TLSZ.js} +98 -93
  18. package/dist/{chunk-J43OCO22.js → chunk-BCV2VJTM.js} +2 -2
  19. package/dist/{chunk-7OWK5K5C.js → chunk-BH2SF4TT.js} +2 -2
  20. package/dist/{chunk-UVX3IYXF.js → chunk-BTP2BMWN.js} +4 -4
  21. package/dist/{chunk-MUJVNSEW.js → chunk-C6G36F5S.js} +1 -1
  22. package/dist/{chunk-ZTLMEBAC.js → chunk-E7F76M3U.js} +208 -26
  23. package/dist/{chunk-AUS7V54P.js → chunk-ERT7XDQW.js} +1 -1
  24. package/dist/{chunk-WK5QEYFA.js → chunk-EXHXTMVR.js} +3 -3
  25. package/dist/{chunk-YXXIRM4C.js → chunk-FWVE373X.js} +2 -2
  26. package/dist/{chunk-EQWC76GQ.js → chunk-GWQRTA5W.js} +2 -2
  27. package/dist/{chunk-GJXMG4S3.js → chunk-HHVIE45A.js} +1 -1
  28. package/dist/{chunk-4FT5KQ7H.js → chunk-IGJEKO2P.js} +1 -1
  29. package/dist/{chunk-KRU2LCIP.js → chunk-IHN6WDEY.js} +1 -1
  30. package/dist/{chunk-QT3KDDXK.js → chunk-IN7XI6NO.js} +0 -7
  31. package/dist/{chunk-NMK7KJZZ.js → chunk-IQN2NGEU.js} +4 -4
  32. package/dist/{chunk-M6ZQAFPD.js → chunk-IY62DXT2.js} +1 -1
  33. package/dist/{chunk-4WQX55VX.js → chunk-IZHGT5HD.js} +31 -5
  34. package/dist/{chunk-CYDM2XII.js → chunk-JJ7RGTAU.js} +56 -7
  35. package/dist/{chunk-NJJCTEBM.js → chunk-KLBTJEIK.js} +1 -1
  36. package/dist/{chunk-KHL652SX.js → chunk-KSZB7TIY.js} +1 -1
  37. package/dist/{chunk-KPSSNGAE.js → chunk-L5S32VZJ.js} +4 -4
  38. package/dist/{chunk-472EOHVW.js → chunk-LAXMUSGW.js} +31 -5
  39. package/dist/{chunk-M4NV5PPU.js → chunk-LJGE43SG.js} +1 -1
  40. package/dist/{chunk-VSOZZYLK.js → chunk-NERQSSYD.js} +20 -9
  41. package/dist/{chunk-UG7AQQNR.js → chunk-OSSTOSXU.js} +2 -2
  42. package/dist/{chunk-YDZIVDVR.js → chunk-P5XA627W.js} +7 -7
  43. package/dist/{chunk-DRQSB72S.js → chunk-PGBTUGDB.js} +2 -2
  44. package/dist/{chunk-65GPEV5V.js → chunk-QKPOIJBT.js} +2 -2
  45. package/dist/{chunk-QJOVZ4TC.js → chunk-QPQWY5RU.js} +1 -1
  46. package/dist/{chunk-P7TRFL4P.js → chunk-R46N5KR4.js} +2 -0
  47. package/dist/{chunk-LNVB75QU.js → chunk-RBVFNUAL.js} +1 -1
  48. package/dist/{chunk-DAHQL57W.js → chunk-RITTLIDJ.js} +1 -1
  49. package/dist/{chunk-2TFXRBCD.js → chunk-RQTDUZUH.js} +3 -3
  50. package/dist/{chunk-Q7Y6JQ3R.js → chunk-S4SJ4LLY.js} +1 -1
  51. package/dist/{chunk-LUDUDBO6.js → chunk-S5Y3OO3V.js} +2 -2
  52. package/dist/{chunk-3GCASUWA.js → chunk-TASRGDYP.js} +1 -1
  53. package/dist/{chunk-5HAYT43L.js → chunk-U6VS3T2M.js} +19 -3
  54. package/dist/{chunk-42UJ23H3.js → chunk-UIEKW4SG.js} +1 -0
  55. package/dist/{chunk-IESUM4N5.js → chunk-USE6HIOZ.js} +95 -62
  56. package/dist/{chunk-FIYW7JW4.js → chunk-USZLHYEQ.js} +1 -1
  57. package/dist/{chunk-U7U64UUN.js → chunk-V5D6GDNK.js} +4 -4
  58. package/dist/{chunk-ADVGV3P7.js → chunk-VB4VMB2I.js} +7 -5
  59. package/dist/{chunk-CQYFZOUC.js → chunk-VBMRZCMQ.js} +1 -1
  60. package/dist/{chunk-USAGHYRD.js → chunk-VF7IKIRS.js} +2 -2
  61. package/dist/{chunk-EJS3K44P.js → chunk-VGAMBOOC.js} +5 -3
  62. package/dist/{chunk-P5FUWXPW.js → chunk-VTESGA5F.js} +7 -5
  63. package/dist/chunk-WTTIODDV.js +9 -0
  64. package/dist/{chunk-5CBX66KB.js → chunk-XJQ6Z3FO.js} +2 -2
  65. package/dist/{chunk-KPGPK4SK.js → chunk-XOMIYMQ3.js} +6 -6
  66. package/dist/{chunk-KCHQVED5.js → chunk-YQMIKX54.js} +43 -7
  67. package/dist/completion-registry.js +3 -0
  68. package/dist/copy-image.d.ts +34 -0
  69. package/dist/copy-image.js +96 -0
  70. package/dist/countdown.js +1 -1
  71. package/dist/{dgmo-router-CZN36TR3.js → dgmo-router-6YLKM6WU.js} +13 -13
  72. package/dist/{dimensions-7HHKO5BS.js → dimensions-DS6FWLRY.js} +2 -2
  73. package/dist/{flowchart-parser-4MZPWYK6.js → flowchart-parser-J3VWIFWB.js} +5 -5
  74. package/dist/{flowchart-renderer-5XDN575E.js → flowchart-renderer-FECH5KK5.js} +14 -12
  75. package/dist/index.js +19 -19
  76. package/dist/layout-5SZ5A64I.js +24 -0
  77. package/dist/{layout-5GHV7HNM.js → layout-EWXHEXNS.js} +11 -10
  78. package/dist/{layout-QXGPY7KA.js → layout-TIBRMWHL.js} +7 -6
  79. package/dist/layout-VDCJOZSH.js +11 -0
  80. package/dist/layout-YBMT74MG.js +24 -0
  81. package/dist/{layout-search-EMTCDC3C.js → layout-search-AWPJWBKT.js} +9 -8
  82. package/dist/{parser-R3LPEQIT.js → parser-AR2GON37.js} +2 -2
  83. package/dist/{parser-YX72VLDZ.js → parser-BTSTKY5G.js} +5 -5
  84. package/dist/{parser-OGF2CDA6.js → parser-MA7L3XND.js} +5 -5
  85. package/dist/{parser-VKYUAT4Y.js → parser-ZRIZFDZY.js} +5 -5
  86. package/dist/{redraw-T324XAF3.js → redraw-AHW7EUUF.js} +2 -2
  87. package/dist/{redraw-MSXU4ZD2.js → redraw-STZ4WJAI.js} +3 -3
  88. package/dist/{renderer-HYGTMBHT.js → renderer-2LYX6NHN.js} +3 -3
  89. package/dist/{renderer-XJMVG2WJ.js → renderer-2QPHDBZY.js} +5 -5
  90. package/dist/{renderer-GPAVVUET.js → renderer-3NLDX7DQ.js} +3 -3
  91. package/dist/{renderer-IHCWBFPI.js → renderer-4VGO27EE.js} +14 -13
  92. package/dist/{renderer-JJ4QW3SK.js → renderer-6BDK47V6.js} +1 -1
  93. package/dist/{renderer-FL7EOSBU.js → renderer-7OGGV327.js} +3 -3
  94. package/dist/{renderer-5ITLW7MX.js → renderer-ACQQ2JXA.js} +6 -4
  95. package/dist/{renderer-37PLQHVB.js → renderer-BXD5KVSR.js} +2 -2
  96. package/dist/{renderer-TSCSZ6CL.js → renderer-HX6ICPDX.js} +2 -2
  97. package/dist/{renderer-BO73LSVT.js → renderer-IGSHD3OT.js} +4 -4
  98. package/dist/{renderer-DD6T3C4J.js → renderer-ISQJ2ELA.js} +2 -2
  99. package/dist/{renderer-CNRQFIEI.js → renderer-IVHD7ENY.js} +4 -4
  100. package/dist/{renderer-POBGKIUT.js → renderer-IXBOT6DU.js} +3 -3
  101. package/dist/{renderer-GFALLIYT.js → renderer-JYHA6R2D.js} +3 -3
  102. package/dist/{renderer-GOXAP2IE.js → renderer-KJ3V5BYP.js} +2 -2
  103. package/dist/{renderer-GFGFHYWY.js → renderer-MWZC7TMD.js} +2 -2
  104. package/dist/{renderer-3F47TPZ2.js → renderer-O6RP52CQ.js} +2 -2
  105. package/dist/{renderer-PBKTAWQV.js → renderer-P3WR7TKD.js} +14 -13
  106. package/dist/{renderer-VDBNC7A6.js → renderer-QTPWRRJ7.js} +2 -2
  107. package/dist/{renderer-J3QWK6IM.js → renderer-RUSQJFFC.js} +3 -3
  108. package/dist/{renderer-7Y3LR4R2.js → renderer-TINHO2IO.js} +2 -2
  109. package/dist/{renderer-J6H4Q3RM.js → renderer-UGW4N2W5.js} +4 -3
  110. package/dist/{renderer-EVKWGUGT.js → renderer-UTEEJDGB.js} +4 -3
  111. package/dist/{renderer-ISDKO3DI.js → renderer-WPN2SXGT.js} +2 -2
  112. package/dist/{renderer-6GJWADLO.js → renderer-XCLARXCK.js} +2 -2
  113. package/dist/{renderer-RDI2RYUP.js → renderer-XDX6S7OV.js} +3 -3
  114. package/dist/{renderer-VI34SD5V.js → renderer-Y47EM337.js} +6 -6
  115. package/dist/{renderer-HJ54YXT3.js → renderer-ZV6KCLCL.js} +14 -14
  116. package/dist/{state-parser-NPYTMRXP.js → state-parser-PMNHLHLE.js} +5 -5
  117. package/dist/{state-renderer-44K2KDX7.js → state-renderer-JQ5DS66J.js} +14 -13
  118. package/docs/language-reference.md +2 -2
  119. package/package.json +5 -1
  120. package/dist/layout-33FHGDEV.js +0 -23
  121. package/dist/layout-FTOGDNUL.js +0 -23
  122. package/dist/layout-J3AGFZZ7.js +0 -10
@@ -2,7 +2,7 @@ import {
2
2
  D3_DATA_CHART_TYPES,
3
3
  renderDataChartD3,
4
4
  supportsD3DataChart
5
- } from "./chunk-KCHQVED5.js";
5
+ } from "./chunk-YQMIKX54.js";
6
6
  import "./chunk-H6BT45SN.js";
7
7
  import "./chunk-KMU65FYM.js";
8
8
  import "./chunk-EPDBWATV.js";
@@ -10,7 +10,7 @@ import "./chunk-6XLMTAEX.js";
10
10
  import "./chunk-2CW5ZTNH.js";
11
11
  import "./chunk-TOHTKLKE.js";
12
12
  import "./chunk-CYRB2JTN.js";
13
- import "./chunk-42UJ23H3.js";
13
+ import "./chunk-UIEKW4SG.js";
14
14
  import "./chunk-VLC6WNRD.js";
15
15
  import "./chunk-JILEYZ2V.js";
16
16
  import "./chunk-GXCDD6NG.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildMapProjection
3
- } from "./chunk-4RY5D5RE.js";
3
+ } from "./chunk-AM42TLSZ.js";
4
4
  import {
5
5
  TITLE_FONT_SIZE,
6
6
  TITLE_Y
@@ -4,7 +4,7 @@ import {
4
4
  countSplineCrossings,
5
5
  deroutePierces,
6
6
  searchBudget
7
- } from "./chunk-ADVGV3P7.js";
7
+ } from "./chunk-VB4VMB2I.js";
8
8
 
9
9
  // src/utils/placement-search.ts
10
10
  var SEARCH_RANKERS = ["tight-tree", "longest-path"];
@@ -11,6 +11,9 @@ import {
11
11
  import {
12
12
  appendArrowheadMarkers
13
13
  } from "./chunk-XBJJP2HN.js";
14
+ import {
15
+ placeEdgeLabels
16
+ } from "./chunk-IN7XI6NO.js";
14
17
  import {
15
18
  parseInfra
16
19
  } from "./chunk-UXNA2H2V.js";
@@ -19,7 +22,7 @@ import {
19
22
  } from "./chunk-24YPR5EH.js";
20
23
  import {
21
24
  layoutInlineHeader
22
- } from "./chunk-42UJ23H3.js";
25
+ } from "./chunk-UIEKW4SG.js";
23
26
  import {
24
27
  TITLE_FONT_SIZE,
25
28
  TITLE_FONT_WEIGHT,
@@ -48,7 +51,7 @@ import {
48
51
  } from "./chunk-IYULMRBE.js";
49
52
  import {
50
53
  renderInlineText
51
- } from "./chunk-65GPEV5V.js";
54
+ } from "./chunk-QKPOIJBT.js";
52
55
  import {
53
56
  FONT_FAMILY
54
57
  } from "./chunk-ICLB27PZ.js";
@@ -968,17 +971,66 @@ function renderEdgePaths(svg, edges, nodes, groups, palette, _isDark, animate, d
968
971
  }
969
972
  }
970
973
  }
974
+ function placeInfraEdgeLabels(routes, edges, nodes, groups, fontSize) {
975
+ const adapted = {
976
+ nodes: nodes.map((n) => ({
977
+ label: n.id,
978
+ x: n.x,
979
+ y: n.y,
980
+ width: n.width,
981
+ height: n.height
982
+ })),
983
+ groups: groups.map((g) => ({
984
+ label: g.id,
985
+ lineNumber: g.lineNumber,
986
+ x: g.x + g.width / 2,
987
+ y: g.y + g.height / 2,
988
+ width: g.width,
989
+ height: g.height,
990
+ collapsed: false
991
+ })),
992
+ width: 0,
993
+ height: 0,
994
+ edges: edges.map((e, idx) => ({
995
+ source: e.sourceId,
996
+ target: e.targetId,
997
+ ...e.label && { label: e.label },
998
+ bidirectional: false,
999
+ lineNumber: e.lineNumber,
1000
+ points: routes[idx] ?? [],
1001
+ yOffset: 0,
1002
+ parallelCount: 1,
1003
+ metadata: {}
1004
+ }))
1005
+ };
1006
+ const blGroups = groups.map((g) => ({
1007
+ label: g.id,
1008
+ children: nodes.filter((n) => n.groupId === g.id).map((n) => n.id),
1009
+ lineNumber: g.lineNumber,
1010
+ metadata: {}
1011
+ }));
1012
+ const placed = placeEdgeLabels(adapted, {
1013
+ fontSize,
1014
+ maxWidth: Number.POSITIVE_INFINITY,
1015
+ groups: blGroups
1016
+ });
1017
+ const out = /* @__PURE__ */ new Map();
1018
+ placed.layout.edges.forEach((e, idx) => {
1019
+ if (e.labelX !== void 0 && e.labelY !== void 0)
1020
+ out.set(idx, { x: e.labelX, y: e.labelY });
1021
+ });
1022
+ return out;
1023
+ }
971
1024
  function renderEdgeLabels(svg, edges, nodes, groups, palette, _isDark, animate, direction, sc = buildScaledConstants(ScaleContext.identity())) {
972
1025
  const nodeMap = nodeMapWithGroups(nodes, groups);
973
1026
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
974
- for (const edge of edges) {
975
- if (edge.points.length === 0) continue;
976
- if (!edge.label) continue;
1027
+ const routes = edges.map((edge) => {
1028
+ if (edge.points.length === 0) return [];
977
1029
  const sourceNode = nodeMap.get(edge.sourceId);
978
1030
  const targetNode = nodeMap.get(edge.targetId);
979
- if (!sourceNode || !targetNode) continue;
1031
+ if (!sourceNode || !targetNode) return [];
980
1032
  const key = `${edge.sourceId}:${edge.targetId}`;
981
- const wps = edgeWaypoints(
1033
+ return edgeWaypoints(
982
1034
  sourceNode,
983
1035
  targetNode,
984
1036
  groups,
@@ -988,7 +1040,18 @@ function renderEdgeLabels(svg, edges, nodes, groups, palette, _isDark, animate,
988
1040
  srcPts.get(key),
989
1041
  tgtPts.get(key)
990
1042
  );
991
- const midPt = wps[Math.floor(wps.length / 2)];
1043
+ });
1044
+ const labelPts = placeInfraEdgeLabels(
1045
+ routes,
1046
+ edges,
1047
+ nodes,
1048
+ groups,
1049
+ EDGE_LABEL_FONT_SIZE
1050
+ );
1051
+ for (const [idx, edge] of edges.entries()) {
1052
+ if (!edge.label) continue;
1053
+ const wps = routes[idx];
1054
+ const midPt = labelPts.get(idx);
992
1055
  if (!midPt) continue;
993
1056
  const labelText = edge.label;
994
1057
  const g = svg.append("g").attr("class", animate ? "infra-edge-label" : "");
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  resolveNotes,
6
6
  tryCollectNote
7
- } from "./chunk-NJJCTEBM.js";
7
+ } from "./chunk-KLBTJEIK.js";
8
8
  import {
9
9
  normalizeName
10
10
  } from "./chunk-NOTA6TEI.js";
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  resolveNotes,
6
6
  tryCollectNote
7
- } from "./chunk-NJJCTEBM.js";
7
+ } from "./chunk-KLBTJEIK.js";
8
8
  import {
9
9
  displayName,
10
10
  normalizeName
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-24YPR5EH.js";
4
4
  import {
5
5
  layoutInlineHeader
6
- } from "./chunk-42UJ23H3.js";
6
+ } from "./chunk-UIEKW4SG.js";
7
7
  import {
8
8
  TITLE_FONT_SIZE,
9
9
  TITLE_FONT_WEIGHT,
@@ -30,10 +30,10 @@ import {
30
30
  } from "./chunk-VSAKEMDD.js";
31
31
  import {
32
32
  wrapDescriptionLines
33
- } from "./chunk-MB2SQF7N.js";
33
+ } from "./chunk-7WEYXYLC.js";
34
34
  import {
35
35
  renderInlineText
36
- } from "./chunk-65GPEV5V.js";
36
+ } from "./chunk-QKPOIJBT.js";
37
37
  import {
38
38
  FONT_FAMILY
39
39
  } from "./chunk-ICLB27PZ.js";
@@ -64,7 +64,17 @@ import {
64
64
  import * as d3Selection from "d3-selection";
65
65
 
66
66
  // src/sequence/collapse.ts
67
- function applyCollapseProjection(parsed, collapsedGroups) {
67
+ function isCollapsibleGroup(group) {
68
+ return group.participantIds.length > 1;
69
+ }
70
+ function collapsedGroupId(group, groups) {
71
+ const shared = groups.some((g) => g !== group && g.name === group.name);
72
+ return shared ? `${group.name}@${group.lineNumber}` : group.name;
73
+ }
74
+ function applyCollapseProjection(parsed, requestedGroups) {
75
+ const collapsedGroups = new Set(
76
+ parsed.groups.filter((g) => requestedGroups.has(g.lineNumber) && isCollapsibleGroup(g)).map((g) => g.lineNumber)
77
+ );
68
78
  if (collapsedGroups.size === 0) {
69
79
  return {
70
80
  participants: parsed.participants,
@@ -88,37 +98,37 @@ function applyCollapseProjection(parsed, collapsedGroups) {
88
98
  return false;
89
99
  };
90
100
  const memberToGroup = /* @__PURE__ */ new Map();
91
- const collapsedGroupNames = /* @__PURE__ */ new Set();
101
+ const virtualIds = /* @__PURE__ */ new Set();
102
+ const groupById = /* @__PURE__ */ new Map();
92
103
  const byDepth = [...parsed.groups].sort((a, b) => a.depth - b.depth);
93
104
  for (const group of byDepth) {
94
105
  if (!collapsedGroups.has(group.lineNumber)) continue;
95
106
  if (insideCollapsed(group)) continue;
96
- collapsedGroupNames.add(group.name);
107
+ const id = collapsedGroupId(group, parsed.groups);
108
+ virtualIds.add(id);
109
+ groupById.set(id, group);
97
110
  for (const memberId of group.participantIds) {
98
111
  if (!memberToGroup.has(memberId)) {
99
- memberToGroup.set(memberId, group.name);
112
+ memberToGroup.set(memberId, id);
100
113
  }
101
114
  }
102
115
  }
103
116
  const participants = [];
104
117
  const insertedGroups = /* @__PURE__ */ new Set();
105
118
  for (const p of parsed.participants) {
106
- const groupName = memberToGroup.get(p.id);
107
- if (groupName) {
108
- if (!insertedGroups.has(groupName)) {
109
- insertedGroups.add(groupName);
110
- const group = parsed.groups.find(
111
- (g) => g.name === groupName && collapsedGroups.has(g.lineNumber)
112
- );
119
+ const groupId = memberToGroup.get(p.id);
120
+ if (groupId) {
121
+ if (!insertedGroups.has(groupId)) {
122
+ insertedGroups.add(groupId);
123
+ const group = groupById.get(groupId);
113
124
  participants.push({
114
- id: groupName,
115
- // already ParticipantId from memberToGroup value type
116
- label: groupName,
125
+ id: groupId,
126
+ label: group.name,
117
127
  type: "default",
118
128
  lineNumber: group.lineNumber
119
129
  });
120
130
  }
121
- } else if (collapsedGroupNames.has(p.id)) {
131
+ } else if (virtualIds.has(p.id)) {
122
132
  } else {
123
133
  participants.push(p);
124
134
  }
@@ -617,6 +627,22 @@ function applyPositionOverrides(participants) {
617
627
  }
618
628
  return result;
619
629
  }
630
+ function foldCollapsedParticipants(parsed, view) {
631
+ const expanded = applyPositionOverrides(
632
+ applyGroupOrdering(parsed.participants, parsed.groups, parsed.messages)
633
+ );
634
+ const byId = new Map(view.participants.map((p) => [p.id, p]));
635
+ const result = [];
636
+ const placed = /* @__PURE__ */ new Set();
637
+ for (const p of expanded) {
638
+ const id = view.collapsedGroupIds.get(p.id) ?? p.id;
639
+ const target = byId.get(id);
640
+ if (!target || placed.has(id)) continue;
641
+ placed.add(id);
642
+ result.push(target);
643
+ }
644
+ return result;
645
+ }
620
646
  function applyGroupOrdering(participants, groups, messages = []) {
621
647
  const idToGroup = /* @__PURE__ */ new Map();
622
648
  for (const group of groups) {
@@ -720,9 +746,17 @@ function layoutSequence(parsed, containerWidth, options) {
720
746
  }
721
747
  function layoutSequencePass(parsed, containerWidth, options, fit) {
722
748
  const { title, options: parsedOptions } = parsed;
723
- const effectiveCollapsedGroups = options?.collapsedGroups ? new Set(options.collapsedGroups) : new Set(
749
+ const requestedCollapsedGroups = options?.collapsedGroups ? new Set(options.collapsedGroups) : new Set(
724
750
  parsed.groups.filter((g) => g.collapsed).map((g) => g.lineNumber)
725
751
  );
752
+ const collapsibleGroupLines = new Set(
753
+ parsed.groups.filter(isCollapsibleGroup).map((g) => g.lineNumber)
754
+ );
755
+ const effectiveCollapsedGroups = new Set(
756
+ parsed.groups.map((g) => g.lineNumber).filter(
757
+ (line) => requestedCollapsedGroups.has(line) && collapsibleGroupLines.has(line)
758
+ )
759
+ );
726
760
  const collapsed = effectiveCollapsedGroups.size > 0 ? applyCollapseProjection(parsed, effectiveCollapsedGroups) : null;
727
761
  const messages = collapsed ? collapsed.messages : parsed.messages;
728
762
  const elements = collapsed ? collapsed.elements : parsed.elements;
@@ -742,9 +776,8 @@ function layoutSequencePass(parsed, containerWidth, options, fit) {
742
776
  if (number === void 0) return step.label;
743
777
  return step.label ? `${number}. ${step.label}` : String(number);
744
778
  };
745
- const sourceParticipants = collapsed ? collapsed.participants : parsed.participants;
746
- const participants = applyPositionOverrides(
747
- applyGroupOrdering(sourceParticipants, groups, messages)
779
+ const participants = collapsed ? foldCollapsedParticipants(parsed, collapsed) : applyPositionOverrides(
780
+ applyGroupOrdering(parsed.participants, parsed.groups, parsed.messages)
748
781
  );
749
782
  if (participants.length === 0) return null;
750
783
  const groupBoundaryIds = /* @__PURE__ */ new Set();
@@ -1496,7 +1529,8 @@ function layoutSequencePass(parsed, containerWidth, options, fit) {
1496
1529
  const padBottom = hasExpandedGroup ? groupBottomPad(group.depth, maxGroupDepth) : 0;
1497
1530
  const height = sBoxH + padTop + padBottom;
1498
1531
  const barHeight = ctx.structural(COLLAPSE_BAR_HEIGHT);
1499
- collapsedGroupBoxes.set(group.name, {
1532
+ collapsedGroupBoxes.set(collapsedGroupId(group, parsed.groups), {
1533
+ name: group.name,
1500
1534
  lineNumber: group.lineNumber,
1501
1535
  depth: group.depth,
1502
1536
  participantIds: group.participantIds,
@@ -2040,7 +2074,14 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
2040
2074
  const groupTagColor = getTagColor(groupTagValue);
2041
2075
  const fillColor = groupTagColor ? mix(groupTagColor, themeBaseBg(palette, isDark), isDark ? 15 : 20) : isDark ? palette.surface : palette.bg;
2042
2076
  const strokeColor = groupTagColor ?? palette.textMuted;
2043
- const groupG = svg.append("g").attr("class", "group-box-wrapper").attr("data-group-toggle", "").attr("data-group-line", String(group.lineNumber)).attr("tabindex", "0").attr("role", "button").attr("aria-expanded", "true").attr("aria-label", groupToggleName(group.name, group.participantIds)).attr("cursor", "pointer");
2077
+ const source = parsed.groups.find((g) => g.lineNumber === group.lineNumber);
2078
+ const collapsible = source !== void 0 && isCollapsibleGroup(source);
2079
+ const groupG = svg.append("g").attr("class", "group-box-wrapper");
2080
+ if (collapsible) groupG.attr("data-group-toggle", "");
2081
+ groupG.attr("data-group-line", String(group.lineNumber));
2082
+ if (collapsible) {
2083
+ groupG.attr("data-line-number", String(group.lineNumber)).attr("role", "button").attr("aria-expanded", "true").attr("aria-label", groupToggleName(group.name, group.participantIds)).attr("cursor", "pointer");
2084
+ }
2044
2085
  groupG.append("rect").attr("x", frame.x).attr("y", frame.y).attr("width", frame.width).attr("height", frame.height).attr("rx", 6).attr("fill", fillColor).attr("stroke", strokeColor).attr("stroke-width", 1).attr("stroke-opacity", 0.5).attr("pointer-events", "none").attr("class", "group-box");
2045
2086
  groupG.append("rect").attr("x", frame.x).attr("y", frame.y).attr("width", frame.width).attr("height", frame.headerHeight).attr("fill", "transparent").attr("class", "group-label-hit");
2046
2087
  groupG.append("text").attr("x", frame.labelX).attr("y", frame.labelY).attr("text-anchor", "middle").attr("fill", strokeColor).attr("font-size", sGroupLabelSize).attr("font-weight", GROUP_LABEL_WEIGHT).attr("opacity", 0.7).attr("pointer-events", "none").attr("class", "group-label").text(group.name);
@@ -2077,10 +2118,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
2077
2118
  const participantG = svg.select(
2078
2119
  `.participant[data-participant-id="${participant.id}"]`
2079
2120
  );
2080
- participantG.attr("data-group-toggle", "").attr("data-group-line", String(meta.lineNumber)).attr("tabindex", "0").attr("role", "button").attr("aria-expanded", "false").attr(
2081
- "aria-label",
2082
- groupToggleName(participant.id, meta.participantIds)
2083
- ).attr("cursor", "pointer");
2121
+ participantG.attr("data-group-toggle", "").attr("data-group-line", String(meta.lineNumber)).attr("data-line-number", String(meta.lineNumber)).attr("role", "button").attr("aria-expanded", "false").attr("aria-label", groupToggleName(meta.name, meta.participantIds)).attr("cursor", "pointer");
2084
2122
  const pFill = effectiveTagColor ? mix(effectiveTagColor, themeBaseBg(palette, isDark), isDark ? 30 : 40) : isDark ? mix(palette.overlay, palette.surface, 50) : mix(palette.bg, palette.surface, 50);
2085
2123
  const pStroke = effectiveTagColor ?? palette.border;
2086
2124
  participantG.append("rect").attr("x", -boxW / 2).attr("y", -padTop).attr("width", boxW).attr("height", fullH).attr("rx", 6).attr("fill", pFill).attr("stroke", pStroke).attr("stroke-width", 1.5);
@@ -2146,7 +2184,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
2146
2184
  const secY = band.y;
2147
2185
  const isCollapsed = band.collapsed;
2148
2186
  const lineColor = palette.textMuted;
2149
- 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));
2187
+ const sectionG = svg.append("g").attr("data-section-toggle", "").attr("data-line-number", String(sec.lineNumber)).attr("data-section", "").attr("role", "button").attr("aria-expanded", String(!isCollapsed));
2150
2188
  const BAND_HEIGHT = band.height;
2151
2189
  const bandFill = isCollapsed ? legendChromeColors(palette, isDark).groupBg : lineColor;
2152
2190
  const bandOpacity = isCollapsed ? 1 : isDark ? 0.1 : 0.08;
@@ -2424,6 +2462,7 @@ export {
2424
2462
  buildRenderSequence,
2425
2463
  computeActivations,
2426
2464
  applyPositionOverrides,
2465
+ foldCollapsedParticipants,
2427
2466
  applyGroupOrdering,
2428
2467
  layoutSequence,
2429
2468
  renderSequenceDiagram,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  wrapDescriptionLines
3
- } from "./chunk-MB2SQF7N.js";
3
+ } from "./chunk-7WEYXYLC.js";
4
4
  import {
5
5
  renderInlineText
6
- } from "./chunk-65GPEV5V.js";
6
+ } from "./chunk-QKPOIJBT.js";
7
7
  import {
8
8
  measureText
9
9
  } from "./chunk-KAO7JL4I.js";
@@ -98,7 +98,7 @@ function renderNoteBox(parent, rect, lines, palette, opts) {
98
98
  noteG.attr("data-line-end", String(opts.endLineNumber));
99
99
  }
100
100
  if (interactive) {
101
- noteG.style("cursor", "pointer").attr("role", "button").attr("tabindex", "0").attr("aria-expanded", "true").attr("aria-label", "Collapse note");
101
+ noteG.style("cursor", "pointer").attr("role", "button").attr("aria-expanded", "true").attr("aria-label", "Collapse note");
102
102
  }
103
103
  const boxPath = noteG.append("path").attr(
104
104
  "d",
@@ -136,7 +136,7 @@ var NOTE_BADGE_OPACITY = 0.6;
136
136
  function renderNoteBadge(parent, center, palette, opts) {
137
137
  const fill = noteBoxFill(palette, opts.isDark, opts.color);
138
138
  const accent = noteAccent(palette, opts.color);
139
- const g = parent.append("g").attr("class", "note note-badge").attr("data-note-toggle", "").attr("transform", `translate(${center.x}, ${center.y})`).attr("opacity", NOTE_BADGE_OPACITY).style("cursor", "pointer").attr("role", "button").attr("tabindex", "0").attr("aria-expanded", "false").attr("aria-label", "Expand note");
139
+ const g = parent.append("g").attr("class", "note note-badge").attr("data-note-toggle", "").attr("transform", `translate(${center.x}, ${center.y})`).attr("opacity", NOTE_BADGE_OPACITY).style("cursor", "pointer").attr("role", "button").attr("aria-expanded", "false").attr("aria-label", "Expand note");
140
140
  if (opts.lineNumber !== void 0) {
141
141
  g.attr("data-line-number", String(opts.lineNumber));
142
142
  }