@diagrammo/dgmo 0.8.5 → 0.8.6
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/.claude/commands/dgmo.md +33 -0
- package/.cursorrules +20 -2
- package/.github/copilot-instructions.md +20 -2
- package/.windsurfrules +20 -2
- package/AGENTS.md +23 -3
- package/dist/cli.cjs +189 -190
- package/dist/editor.cjs +3 -18
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +3 -18
- package/dist/editor.js.map +1 -1
- package/dist/highlight.cjs +4 -21
- package/dist/highlight.cjs.map +1 -1
- package/dist/highlight.js +4 -21
- package/dist/highlight.js.map +1 -1
- package/dist/index.cjs +2785 -2996
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -56
- package/dist/index.d.ts +56 -56
- package/dist/index.js +2780 -2989
- package/dist/index.js.map +1 -1
- package/docs/ai-integration.md +1 -1
- package/docs/language-reference.md +97 -25
- package/gallery/fixtures/boxes-and-lines.dgmo +64 -0
- package/package.json +1 -1
- package/src/boxes-and-lines/collapse.ts +78 -0
- package/src/boxes-and-lines/layout.ts +319 -0
- package/src/boxes-and-lines/parser.ts +694 -0
- package/src/boxes-and-lines/renderer.ts +848 -0
- package/src/boxes-and-lines/types.ts +40 -0
- package/src/c4/parser.ts +10 -5
- package/src/c4/renderer.ts +232 -56
- package/src/chart.ts +9 -4
- package/src/cli.ts +6 -5
- package/src/completion.ts +25 -33
- package/src/d3.ts +26 -27
- package/src/dgmo-router.ts +3 -7
- package/src/echarts.ts +38 -2
- package/src/editor/keywords.ts +4 -19
- package/src/er/parser.ts +10 -4
- package/src/gantt/parser.ts +7 -4
- package/src/gantt/renderer.ts +3 -5
- package/src/index.ts +17 -26
- package/src/infra/parser.ts +7 -5
- package/src/infra/renderer.ts +2 -2
- package/src/kanban/parser.ts +7 -5
- package/src/kanban/renderer.ts +43 -18
- package/src/org/parser.ts +7 -4
- package/src/org/renderer.ts +40 -29
- package/src/sequence/parser.ts +11 -5
- package/src/sequence/renderer.ts +114 -45
- package/src/sitemap/parser.ts +8 -4
- package/src/sitemap/renderer.ts +137 -57
- package/src/utils/legend-svg.ts +44 -20
- package/src/utils/parsing.ts +1 -1
- package/src/utils/tag-groups.ts +21 -1
- package/gallery/fixtures/initiative-status-full.dgmo +0 -46
- package/gallery/fixtures/initiative-status-phases.dgmo +0 -29
- package/gallery/fixtures/initiative-status.dgmo +0 -9
- package/src/initiative-status/collapse.ts +0 -76
- package/src/initiative-status/filter.ts +0 -63
- package/src/initiative-status/layout.ts +0 -650
- package/src/initiative-status/parser.ts +0 -629
- package/src/initiative-status/renderer.ts +0 -1199
- package/src/initiative-status/types.ts +0 -57
package/src/sequence/renderer.ts
CHANGED
|
@@ -62,12 +62,12 @@ const NOTE_FONT_SIZE = 10;
|
|
|
62
62
|
const NOTE_LINE_H = 14;
|
|
63
63
|
const NOTE_GAP = 15;
|
|
64
64
|
const NOTE_CHAR_W = 6;
|
|
65
|
-
const NOTE_CHARS_PER_LINE = Math.floor(
|
|
65
|
+
const NOTE_CHARS_PER_LINE = Math.floor(
|
|
66
|
+
(NOTE_MAX_W - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W
|
|
67
|
+
);
|
|
66
68
|
const COLLAPSED_NOTE_H = 20;
|
|
67
69
|
const COLLAPSED_NOTE_W = 40;
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
71
|
function wrapTextLines(text: string, maxChars: number): string[] {
|
|
72
72
|
const rawLines = text.split('\n');
|
|
73
73
|
const wrapped: string[] = [];
|
|
@@ -97,7 +97,9 @@ function wrapTextLines(text: string, maxChars: number): string[] {
|
|
|
97
97
|
* Approximate max chars based on font-size 13 (~7.5px per char average).
|
|
98
98
|
*/
|
|
99
99
|
const LABEL_CHAR_WIDTH = 7.5;
|
|
100
|
-
const LABEL_MAX_CHARS = Math.floor(
|
|
100
|
+
const LABEL_MAX_CHARS = Math.floor(
|
|
101
|
+
(PARTICIPANT_BOX_WIDTH - 10) / LABEL_CHAR_WIDTH
|
|
102
|
+
); // ~14 chars
|
|
101
103
|
|
|
102
104
|
function splitParticipantLabel(label: string): string[] {
|
|
103
105
|
if (label.length <= LABEL_MAX_CHARS) return [label];
|
|
@@ -114,7 +116,8 @@ function splitParticipantLabel(label: string): string[] {
|
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
// Split on camelCase boundaries: "UserLookupCloudFx" → ["User", "Lookup", "Cloud", "Fx"]
|
|
117
|
-
const camelParts = label
|
|
119
|
+
const camelParts = label
|
|
120
|
+
.replace(/([a-z])([A-Z])/g, '$1\x00$2')
|
|
118
121
|
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1\x00$2')
|
|
119
122
|
.split('\x00');
|
|
120
123
|
if (camelParts.length > 1) {
|
|
@@ -142,13 +145,18 @@ function wrapLabelWords(words: string[]): string[] {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
// Shared fill/stroke helpers — accept optional color override for per-participant coloring
|
|
145
|
-
const fill = (
|
|
148
|
+
const fill = (
|
|
149
|
+
palette: PaletteColors,
|
|
150
|
+
isDark: boolean,
|
|
151
|
+
color?: string
|
|
152
|
+
): string =>
|
|
146
153
|
color
|
|
147
154
|
? mix(color, isDark ? palette.surface : palette.bg, isDark ? 30 : 40)
|
|
148
155
|
: isDark
|
|
149
156
|
? mix(palette.overlay, palette.surface, 50)
|
|
150
157
|
: mix(palette.bg, palette.surface, 50);
|
|
151
|
-
const stroke = (palette: PaletteColors, color?: string): string =>
|
|
158
|
+
const stroke = (palette: PaletteColors, color?: string): string =>
|
|
159
|
+
color || palette.border;
|
|
152
160
|
const SW = 1.5;
|
|
153
161
|
const W = PARTICIPANT_BOX_WIDTH;
|
|
154
162
|
const H = PARTICIPANT_BOX_HEIGHT;
|
|
@@ -904,11 +912,14 @@ export function renderSequenceDiagram(
|
|
|
904
912
|
const { title, messages, elements, groups, options: parsedOptions } = parsed;
|
|
905
913
|
const collapsedSections = options?.collapsedSections;
|
|
906
914
|
const expandedNoteLines = options?.expandedNoteLines;
|
|
907
|
-
const collapseNotesDisabled =
|
|
915
|
+
const collapseNotesDisabled =
|
|
916
|
+
parsedOptions['collapse-notes']?.toLowerCase() === 'no';
|
|
908
917
|
// A note is expanded if: expandedNoteLines is undefined (CLI/export),
|
|
909
918
|
// collapse-notes: no is set, or the note's lineNumber is in the set.
|
|
910
919
|
const isNoteExpanded = (note: SequenceNote): boolean =>
|
|
911
|
-
expandedNoteLines === undefined ||
|
|
920
|
+
expandedNoteLines === undefined ||
|
|
921
|
+
collapseNotesDisabled ||
|
|
922
|
+
expandedNoteLines.has(note.lineNumber);
|
|
912
923
|
const participants = applyPositionOverrides(
|
|
913
924
|
applyGroupOrdering(parsed.participants, groups, messages)
|
|
914
925
|
);
|
|
@@ -928,11 +939,14 @@ export function renderSequenceDiagram(
|
|
|
928
939
|
if (activeTagGroup) {
|
|
929
940
|
tagMap = resolveSequenceTags(parsed, activeTagGroup);
|
|
930
941
|
const tg = parsed.tagGroups.find(
|
|
931
|
-
(g) => g.name.toLowerCase() === activeTagGroup.toLowerCase()
|
|
942
|
+
(g) => g.name.toLowerCase() === activeTagGroup.toLowerCase()
|
|
932
943
|
);
|
|
933
944
|
if (tg) {
|
|
934
945
|
for (const entry of tg.entries) {
|
|
935
|
-
tagValueToColor.set(
|
|
946
|
+
tagValueToColor.set(
|
|
947
|
+
entry.value.toLowerCase(),
|
|
948
|
+
resolveColor(entry.color) ?? entry.color
|
|
949
|
+
);
|
|
936
950
|
}
|
|
937
951
|
}
|
|
938
952
|
}
|
|
@@ -962,9 +976,7 @@ export function renderSequenceDiagram(
|
|
|
962
976
|
: allRenderSteps;
|
|
963
977
|
// Drop unlabeled returns — they add visual noise without conveying information.
|
|
964
978
|
// Labeled returns (explicit <- value) are kept.
|
|
965
|
-
renderSteps = renderSteps.filter(
|
|
966
|
-
(s) => s.type === 'call' || s.label
|
|
967
|
-
);
|
|
979
|
+
renderSteps = renderSteps.filter((s) => s.type === 'call' || s.label);
|
|
968
980
|
const activations = activationsOff ? [] : computeActivations(renderSteps);
|
|
969
981
|
const stepSpacing = 35;
|
|
970
982
|
|
|
@@ -1034,7 +1046,7 @@ export function renderSequenceDiagram(
|
|
|
1034
1046
|
};
|
|
1035
1047
|
|
|
1036
1048
|
// Section layout constants
|
|
1037
|
-
const SECTION_TOP_PAD = 35;
|
|
1049
|
+
const SECTION_TOP_PAD = 35; // space above section divider line (matches stepSpacing)
|
|
1038
1050
|
const SECTION_BOTTOM_PAD = 45; // space below section divider line before next content
|
|
1039
1051
|
|
|
1040
1052
|
// Block spacing via extraBeforeMsg (sections handled separately below)
|
|
@@ -1282,11 +1294,16 @@ export function renderSequenceDiagram(
|
|
|
1282
1294
|
// Compute cumulative Y positions for each step, with section dividers as stable anchors
|
|
1283
1295
|
const titleOffset = title ? TITLE_HEIGHT : 0;
|
|
1284
1296
|
const LEGEND_FIXED_GAP = 8;
|
|
1285
|
-
const legendTopSpace =
|
|
1297
|
+
const legendTopSpace =
|
|
1298
|
+
parsed.tagGroups.length > 0 ? LEGEND_HEIGHT + LEGEND_FIXED_GAP : 0;
|
|
1286
1299
|
const groupOffset =
|
|
1287
1300
|
groups.length > 0 ? GROUP_PADDING_TOP + GROUP_LABEL_SIZE : 0;
|
|
1288
1301
|
const participantStartY =
|
|
1289
|
-
TOP_MARGIN +
|
|
1302
|
+
TOP_MARGIN +
|
|
1303
|
+
titleOffset +
|
|
1304
|
+
legendTopSpace +
|
|
1305
|
+
PARTICIPANT_Y_OFFSET +
|
|
1306
|
+
groupOffset;
|
|
1290
1307
|
const lifelineStartY0 = participantStartY + PARTICIPANT_BOX_HEIGHT;
|
|
1291
1308
|
const hasActors = participants.some((p) => p.type === 'actor');
|
|
1292
1309
|
const messageStartOffset = MESSAGE_START_OFFSET + (hasActors ? 20 : 0);
|
|
@@ -1339,7 +1356,10 @@ export function renderSequenceDiagram(
|
|
|
1339
1356
|
const si = findAssociatedLastStep(el);
|
|
1340
1357
|
if (si < 0) continue;
|
|
1341
1358
|
// Check if there's a preceding note that we should stack below
|
|
1342
|
-
const prevNote =
|
|
1359
|
+
const prevNote =
|
|
1360
|
+
i > 0 && isSequenceNote(els[i - 1])
|
|
1361
|
+
? (els[i - 1] as SequenceNote)
|
|
1362
|
+
: null;
|
|
1343
1363
|
const prevNoteY = prevNote ? noteYMap.get(prevNote) : undefined;
|
|
1344
1364
|
let noteTopY: number;
|
|
1345
1365
|
if (prevNoteY !== undefined && prevNote) {
|
|
@@ -1378,8 +1398,13 @@ export function renderSequenceDiagram(
|
|
|
1378
1398
|
)
|
|
1379
1399
|
: layoutEndY;
|
|
1380
1400
|
for (const [note, noteTopY] of noteYMap) {
|
|
1381
|
-
const noteH = isNoteExpanded(note)
|
|
1382
|
-
|
|
1401
|
+
const noteH = isNoteExpanded(note)
|
|
1402
|
+
? computeNoteHeight(note.text)
|
|
1403
|
+
: COLLAPSED_NOTE_H;
|
|
1404
|
+
contentBottomY = Math.max(
|
|
1405
|
+
contentBottomY,
|
|
1406
|
+
noteTopY + noteH + NOTE_TRAILING_GAP
|
|
1407
|
+
);
|
|
1383
1408
|
}
|
|
1384
1409
|
const messageAreaHeight = contentBottomY - lifelineStartY0;
|
|
1385
1410
|
const lifelineLength = messageAreaHeight + LIFELINE_TAIL;
|
|
@@ -1394,7 +1419,8 @@ export function renderSequenceDiagram(
|
|
|
1394
1419
|
40;
|
|
1395
1420
|
const totalHeight = contentHeight;
|
|
1396
1421
|
|
|
1397
|
-
const containerWidth =
|
|
1422
|
+
const containerWidth =
|
|
1423
|
+
options?.exportWidth ?? container.getBoundingClientRect().width;
|
|
1398
1424
|
const svgWidth = Math.max(totalWidth, containerWidth);
|
|
1399
1425
|
|
|
1400
1426
|
// Center the diagram horizontally
|
|
@@ -1528,7 +1554,7 @@ export function renderSequenceDiagram(
|
|
|
1528
1554
|
// Helper: resolve marker ref for tag-colored arrows
|
|
1529
1555
|
const coloredMarker = (
|
|
1530
1556
|
type: 'call' | 'async' | 'return',
|
|
1531
|
-
tagColor?: string
|
|
1557
|
+
tagColor?: string
|
|
1532
1558
|
): string => {
|
|
1533
1559
|
if (tagColor) {
|
|
1534
1560
|
const hex = tagColor.replace('#', '');
|
|
@@ -1578,7 +1604,7 @@ export function renderSequenceDiagram(
|
|
|
1578
1604
|
|
|
1579
1605
|
// Pre-compute pill/capsule widths for centering
|
|
1580
1606
|
const legendItems: Array<{
|
|
1581
|
-
group: typeof parsed.tagGroups[0];
|
|
1607
|
+
group: (typeof parsed.tagGroups)[0];
|
|
1582
1608
|
isActive: boolean;
|
|
1583
1609
|
pillWidth: number;
|
|
1584
1610
|
totalWidth: number;
|
|
@@ -1589,7 +1615,8 @@ export function renderSequenceDiagram(
|
|
|
1589
1615
|
const isActive =
|
|
1590
1616
|
!!activeTagGroup &&
|
|
1591
1617
|
tg.name.toLowerCase() === activeTagGroup.toLowerCase();
|
|
1592
|
-
const pillWidth =
|
|
1618
|
+
const pillWidth =
|
|
1619
|
+
measureLegendText(tg.name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
|
|
1593
1620
|
const entries = tg.entries.map((e) => ({
|
|
1594
1621
|
value: e.value,
|
|
1595
1622
|
color: resolveColor(e.color) ?? e.color,
|
|
@@ -1639,8 +1666,8 @@ export function renderSequenceDiagram(
|
|
|
1639
1666
|
}
|
|
1640
1667
|
|
|
1641
1668
|
const pillXOff = item.isActive ? LEGEND_CAPSULE_PAD : 0;
|
|
1642
|
-
const pillYOff =
|
|
1643
|
-
const pillH = LEGEND_HEIGHT -
|
|
1669
|
+
const pillYOff = LEGEND_CAPSULE_PAD;
|
|
1670
|
+
const pillH = LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2;
|
|
1644
1671
|
|
|
1645
1672
|
// Pill background
|
|
1646
1673
|
gEl
|
|
@@ -1702,7 +1729,10 @@ export function renderSequenceDiagram(
|
|
|
1702
1729
|
.attr('fill', palette.textMuted)
|
|
1703
1730
|
.text(entry.value);
|
|
1704
1731
|
|
|
1705
|
-
entryX =
|
|
1732
|
+
entryX =
|
|
1733
|
+
textX +
|
|
1734
|
+
measureLegendText(entry.value, LEGEND_ENTRY_FONT_SIZE) +
|
|
1735
|
+
LEGEND_ENTRY_TRAIL;
|
|
1706
1736
|
}
|
|
1707
1737
|
}
|
|
1708
1738
|
|
|
@@ -1732,7 +1762,11 @@ export function renderSequenceDiagram(
|
|
|
1732
1762
|
const groupTagValue = tagKey && group.metadata?.[tagKey];
|
|
1733
1763
|
const groupTagColor = getTagColor(groupTagValue || undefined);
|
|
1734
1764
|
const fillColor = groupTagColor
|
|
1735
|
-
? mix(
|
|
1765
|
+
? mix(
|
|
1766
|
+
groupTagColor,
|
|
1767
|
+
isDark ? palette.surface : palette.bg,
|
|
1768
|
+
isDark ? 15 : 20
|
|
1769
|
+
)
|
|
1736
1770
|
: isDark
|
|
1737
1771
|
? palette.surface
|
|
1738
1772
|
: palette.bg;
|
|
@@ -1778,7 +1812,16 @@ export function renderSequenceDiagram(
|
|
|
1778
1812
|
tagKey && pTagValue
|
|
1779
1813
|
? { key: tagKey, value: pTagValue.toLowerCase() }
|
|
1780
1814
|
: undefined;
|
|
1781
|
-
renderParticipant(
|
|
1815
|
+
renderParticipant(
|
|
1816
|
+
svg,
|
|
1817
|
+
participant,
|
|
1818
|
+
cx,
|
|
1819
|
+
cy,
|
|
1820
|
+
palette,
|
|
1821
|
+
isDark,
|
|
1822
|
+
pTagColor,
|
|
1823
|
+
pTagAttr
|
|
1824
|
+
);
|
|
1782
1825
|
|
|
1783
1826
|
// Render lifeline
|
|
1784
1827
|
const lifelineEl = svg
|
|
@@ -2031,7 +2074,11 @@ export function renderSequenceDiagram(
|
|
|
2031
2074
|
.attr('height', y2 - y1)
|
|
2032
2075
|
.attr('fill', isDark ? palette.surface : palette.bg);
|
|
2033
2076
|
|
|
2034
|
-
const actFill = mix(
|
|
2077
|
+
const actFill = mix(
|
|
2078
|
+
actBaseColor,
|
|
2079
|
+
isDark ? palette.surface : palette.bg,
|
|
2080
|
+
isDark ? 15 : 30
|
|
2081
|
+
);
|
|
2035
2082
|
const actRect = svg
|
|
2036
2083
|
.append('rect')
|
|
2037
2084
|
.attr('x', x)
|
|
@@ -2143,8 +2190,12 @@ export function renderSequenceDiagram(
|
|
|
2143
2190
|
const bandX = sectionLineX1 - 10;
|
|
2144
2191
|
const bandWidth = sectionLineX2 - sectionLineX1 + 20;
|
|
2145
2192
|
const bandOpacity = isCollapsed
|
|
2146
|
-
?
|
|
2147
|
-
|
|
2193
|
+
? isDark
|
|
2194
|
+
? 0.35
|
|
2195
|
+
: 0.25
|
|
2196
|
+
: isDark
|
|
2197
|
+
? 0.1
|
|
2198
|
+
: 0.08;
|
|
2148
2199
|
sectionG
|
|
2149
2200
|
.append('rect')
|
|
2150
2201
|
.attr('x', bandX)
|
|
@@ -2230,14 +2281,18 @@ export function renderSequenceDiagram(
|
|
|
2230
2281
|
const x = arrowEdgeX(step.from, i, 'right');
|
|
2231
2282
|
|
|
2232
2283
|
// Hit area for self-call
|
|
2233
|
-
svg
|
|
2284
|
+
svg
|
|
2285
|
+
.append('rect')
|
|
2234
2286
|
.attr('x', x)
|
|
2235
2287
|
.attr('y', y - 5)
|
|
2236
2288
|
.attr('width', SELF_CALL_WIDTH)
|
|
2237
2289
|
.attr('height', SELF_CALL_HEIGHT + 10)
|
|
2238
2290
|
.attr('fill', 'transparent')
|
|
2239
2291
|
.attr('class', 'message-hit-area')
|
|
2240
|
-
.attr(
|
|
2292
|
+
.attr(
|
|
2293
|
+
'data-line-number',
|
|
2294
|
+
String(messages[step.messageIndex].lineNumber)
|
|
2295
|
+
)
|
|
2241
2296
|
.attr('data-msg-index', String(step.messageIndex))
|
|
2242
2297
|
.attr('data-step-index', String(i));
|
|
2243
2298
|
|
|
@@ -2291,14 +2346,18 @@ export function renderSequenceDiagram(
|
|
|
2291
2346
|
const x2 = arrowEdgeX(step.to, i, goingRight ? 'left' : 'right');
|
|
2292
2347
|
|
|
2293
2348
|
// Hit area for call arrow
|
|
2294
|
-
svg
|
|
2349
|
+
svg
|
|
2350
|
+
.append('rect')
|
|
2295
2351
|
.attr('x', Math.min(x1, x2))
|
|
2296
2352
|
.attr('y', y - HIT_H / 2)
|
|
2297
2353
|
.attr('width', Math.abs(x2 - x1))
|
|
2298
2354
|
.attr('height', HIT_H)
|
|
2299
2355
|
.attr('fill', 'transparent')
|
|
2300
2356
|
.attr('class', 'message-hit-area')
|
|
2301
|
-
.attr(
|
|
2357
|
+
.attr(
|
|
2358
|
+
'data-line-number',
|
|
2359
|
+
String(messages[step.messageIndex].lineNumber)
|
|
2360
|
+
)
|
|
2302
2361
|
.attr('data-msg-index', String(step.messageIndex))
|
|
2303
2362
|
.attr('data-step-index', String(i));
|
|
2304
2363
|
|
|
@@ -2361,14 +2420,18 @@ export function renderSequenceDiagram(
|
|
|
2361
2420
|
const returnColor = msgTagColor || palette.textMuted;
|
|
2362
2421
|
|
|
2363
2422
|
// Hit area for return arrow
|
|
2364
|
-
svg
|
|
2423
|
+
svg
|
|
2424
|
+
.append('rect')
|
|
2365
2425
|
.attr('x', Math.min(x1, x2))
|
|
2366
2426
|
.attr('y', y - HIT_H / 2)
|
|
2367
2427
|
.attr('width', Math.abs(x2 - x1))
|
|
2368
2428
|
.attr('height', HIT_H)
|
|
2369
2429
|
.attr('fill', 'transparent')
|
|
2370
2430
|
.attr('class', 'message-hit-area')
|
|
2371
|
-
.attr(
|
|
2431
|
+
.attr(
|
|
2432
|
+
'data-line-number',
|
|
2433
|
+
String(messages[step.messageIndex].lineNumber)
|
|
2434
|
+
)
|
|
2372
2435
|
.attr('data-msg-index', String(step.messageIndex))
|
|
2373
2436
|
.attr('data-step-index', String(i));
|
|
2374
2437
|
|
|
@@ -2494,8 +2557,7 @@ export function renderSequenceDiagram(
|
|
|
2494
2557
|
|
|
2495
2558
|
// Render text with inline markdown
|
|
2496
2559
|
wrappedLines.forEach((line, li) => {
|
|
2497
|
-
const textY =
|
|
2498
|
-
noteTopY + NOTE_PAD_V + (li + 1) * NOTE_LINE_H - 3;
|
|
2560
|
+
const textY = noteTopY + NOTE_PAD_V + (li + 1) * NOTE_LINE_H - 3;
|
|
2499
2561
|
const isBullet = line.startsWith('- ');
|
|
2500
2562
|
const bulletIndent = isBullet ? 10 : 0;
|
|
2501
2563
|
const displayLine = isBullet ? line.slice(2) : line;
|
|
@@ -2602,7 +2664,9 @@ export function renderSequenceDiagram(
|
|
|
2602
2664
|
* associated message (the last message before the note in document order).
|
|
2603
2665
|
* Used by the app to expand notes when cursor is on the associated message.
|
|
2604
2666
|
*/
|
|
2605
|
-
export function buildNoteMessageMap(
|
|
2667
|
+
export function buildNoteMessageMap(
|
|
2668
|
+
elements: SequenceElement[]
|
|
2669
|
+
): Map<number, number> {
|
|
2606
2670
|
const map = new Map<number, number>();
|
|
2607
2671
|
let lastMessageLine = -1;
|
|
2608
2672
|
|
|
@@ -2639,7 +2703,7 @@ function renderParticipant(
|
|
|
2639
2703
|
palette: PaletteColors,
|
|
2640
2704
|
isDark: boolean,
|
|
2641
2705
|
color?: string,
|
|
2642
|
-
tagAttr?: { key: string; value: string }
|
|
2706
|
+
tagAttr?: { key: string; value: string }
|
|
2643
2707
|
): void {
|
|
2644
2708
|
const g = svg
|
|
2645
2709
|
.append('g')
|
|
@@ -2691,7 +2755,8 @@ function renderParticipant(
|
|
|
2691
2755
|
const labelLines = splitParticipantLabel(participant.label);
|
|
2692
2756
|
const fontSize = 13;
|
|
2693
2757
|
const lineHeight = fontSize + 2;
|
|
2694
|
-
const textEl = g
|
|
2758
|
+
const textEl = g
|
|
2759
|
+
.append('text')
|
|
2695
2760
|
.attr('x', 0)
|
|
2696
2761
|
.attr('text-anchor', 'middle')
|
|
2697
2762
|
.attr('fill', palette.text)
|
|
@@ -2700,7 +2765,10 @@ function renderParticipant(
|
|
|
2700
2765
|
|
|
2701
2766
|
if (labelLines.length === 1) {
|
|
2702
2767
|
textEl
|
|
2703
|
-
.attr(
|
|
2768
|
+
.attr(
|
|
2769
|
+
'y',
|
|
2770
|
+
isActor ? PARTICIPANT_BOX_HEIGHT + 14 : PARTICIPANT_BOX_HEIGHT / 2 + 5
|
|
2771
|
+
)
|
|
2704
2772
|
.text(participant.label);
|
|
2705
2773
|
} else {
|
|
2706
2774
|
// Multi-line: vertically center the lines within the box (or below for actors)
|
|
@@ -2710,7 +2778,8 @@ function renderParticipant(
|
|
|
2710
2778
|
: PARTICIPANT_BOX_HEIGHT / 2 + 5 - (totalHeight - lineHeight) / 2;
|
|
2711
2779
|
|
|
2712
2780
|
labelLines.forEach((line, i) => {
|
|
2713
|
-
textEl
|
|
2781
|
+
textEl
|
|
2782
|
+
.append('tspan')
|
|
2714
2783
|
.attr('x', 0)
|
|
2715
2784
|
.attr('dy', i === 0 ? `${baseY}px` : `${lineHeight}px`)
|
|
2716
2785
|
.text(line);
|
package/src/sitemap/parser.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
isTagBlockHeading,
|
|
11
11
|
matchTagBlockHeading,
|
|
12
12
|
validateTagValues,
|
|
13
|
+
stripDefaultModifier,
|
|
13
14
|
} from '../utils/tag-groups';
|
|
14
15
|
import {
|
|
15
16
|
measureIndent,
|
|
@@ -261,11 +262,13 @@ export function parseSitemap(
|
|
|
261
262
|
}
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
// Tag group entries (indented Value(color) under tag
|
|
265
|
+
// Tag group entries (indented Value(color) under tag heading)
|
|
266
|
+
// First entry is the default unless another is marked `default`
|
|
265
267
|
if (currentTagGroup && !contentStarted) {
|
|
266
268
|
const indent = measureIndent(line);
|
|
267
269
|
if (indent > 0) {
|
|
268
|
-
const {
|
|
270
|
+
const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
|
|
271
|
+
const { label, color } = extractColor(cleanEntry, palette);
|
|
269
272
|
if (!color) {
|
|
270
273
|
pushError(
|
|
271
274
|
lineNumber,
|
|
@@ -278,8 +281,9 @@ export function parseSitemap(
|
|
|
278
281
|
color,
|
|
279
282
|
lineNumber,
|
|
280
283
|
});
|
|
281
|
-
|
|
282
|
-
|
|
284
|
+
if (isDefault) {
|
|
285
|
+
currentTagGroup.defaultValue = label;
|
|
286
|
+
} else if (currentTagGroup.entries.length === 1) {
|
|
283
287
|
currentTagGroup.defaultValue = label;
|
|
284
288
|
}
|
|
285
289
|
continue;
|