@formicoidea/labre-framework-uml 0.42.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 (114) hide show
  1. package/LICENSE +384 -0
  2. package/dist/actions.d.ts +430 -0
  3. package/dist/actions.js +724 -0
  4. package/dist/background.d.ts +153 -0
  5. package/dist/background.js +557 -0
  6. package/dist/board-hit.d.ts +137 -0
  7. package/dist/board-hit.js +191 -0
  8. package/dist/commands-manifest.d.ts +19 -0
  9. package/dist/commands-manifest.js +571 -0
  10. package/dist/commands.d.ts +4 -0
  11. package/dist/commands.js +983 -0
  12. package/dist/component.d.ts +521 -0
  13. package/dist/component.js +708 -0
  14. package/dist/consts.d.ts +365 -0
  15. package/dist/consts.js +463 -0
  16. package/dist/descriptor.d.ts +12 -0
  17. package/dist/descriptor.js +10 -0
  18. package/dist/drawio-decode.d.ts +32 -0
  19. package/dist/drawio-decode.js +96 -0
  20. package/dist/drawio-import.d.ts +133 -0
  21. package/dist/drawio-import.js +885 -0
  22. package/dist/edge-morph.d.ts +154 -0
  23. package/dist/edge-morph.js +153 -0
  24. package/dist/edge-styles.d.ts +78 -0
  25. package/dist/edge-styles.js +210 -0
  26. package/dist/effects.d.ts +9 -0
  27. package/dist/effects.js +6 -0
  28. package/dist/element-renderer.d.ts +64 -0
  29. package/dist/element-renderer.js +114 -0
  30. package/dist/element-view.d.ts +234 -0
  31. package/dist/element-view.js +430 -0
  32. package/dist/export.d.ts +61 -0
  33. package/dist/export.js +41 -0
  34. package/dist/filename.d.ts +17 -0
  35. package/dist/filename.js +26 -0
  36. package/dist/frame-tag.d.ts +70 -0
  37. package/dist/frame-tag.js +78 -0
  38. package/dist/grammar.d.ts +695 -0
  39. package/dist/grammar.js +1436 -0
  40. package/dist/import.d.ts +306 -0
  41. package/dist/import.js +1270 -0
  42. package/dist/index.d.ts +47 -0
  43. package/dist/index.js +67 -0
  44. package/dist/interchange.d.ts +125 -0
  45. package/dist/interchange.js +372 -0
  46. package/dist/keywords.d.ts +204 -0
  47. package/dist/keywords.js +361 -0
  48. package/dist/kinds.d.ts +73 -0
  49. package/dist/kinds.js +91 -0
  50. package/dist/legend.d.ts +30 -0
  51. package/dist/legend.js +255 -0
  52. package/dist/model.d.ts +862 -0
  53. package/dist/model.js +1316 -0
  54. package/dist/morph.d.ts +178 -0
  55. package/dist/morph.js +496 -0
  56. package/dist/node/act-glyphs.d.ts +30 -0
  57. package/dist/node/act-glyphs.js +142 -0
  58. package/dist/node/compartment-watcher.d.ts +107 -0
  59. package/dist/node/compartment-watcher.js +163 -0
  60. package/dist/node/fit.d.ts +85 -0
  61. package/dist/node/fit.js +129 -0
  62. package/dist/node/node-renderer.d.ts +49 -0
  63. package/dist/node/node-renderer.js +611 -0
  64. package/dist/node/node-view.d.ts +51 -0
  65. package/dist/node/node-view.js +89 -0
  66. package/dist/node/paint.d.ts +84 -0
  67. package/dist/node/paint.js +143 -0
  68. package/dist/node/sd-glyphs.d.ts +36 -0
  69. package/dist/node/sd-glyphs.js +79 -0
  70. package/dist/node/stm-glyphs.d.ts +22 -0
  71. package/dist/node/stm-glyphs.js +111 -0
  72. package/dist/node/tier-metrics.d.ts +38 -0
  73. package/dist/node/tier-metrics.js +45 -0
  74. package/dist/operators.d.ts +45 -0
  75. package/dist/operators.js +75 -0
  76. package/dist/plantuml-import.d.ts +113 -0
  77. package/dist/plantuml-import.js +1723 -0
  78. package/dist/plantuml.d.ts +94 -0
  79. package/dist/plantuml.js +985 -0
  80. package/dist/presets.d.ts +149 -0
  81. package/dist/presets.js +302 -0
  82. package/dist/profiles.d.ts +2 -0
  83. package/dist/profiles.js +358 -0
  84. package/dist/reading.d.ts +160 -0
  85. package/dist/reading.js +648 -0
  86. package/dist/roles.d.ts +257 -0
  87. package/dist/roles.js +997 -0
  88. package/dist/rules.d.ts +267 -0
  89. package/dist/rules.js +3090 -0
  90. package/dist/templates.d.ts +2 -0
  91. package/dist/templates.js +197 -0
  92. package/dist/toolbar/config.d.ts +228 -0
  93. package/dist/toolbar/config.js +833 -0
  94. package/dist/toolbar/icons.d.ts +440 -0
  95. package/dist/toolbar/icons.js +711 -0
  96. package/dist/toolbar/senior-tool.d.ts +11 -0
  97. package/dist/toolbar/senior-tool.js +21 -0
  98. package/dist/toolbar/uml-menu.d.ts +17 -0
  99. package/dist/toolbar/uml-menu.js +20 -0
  100. package/dist/toolbar/uml-senior-button.d.ts +18 -0
  101. package/dist/toolbar/uml-senior-button.js +22 -0
  102. package/dist/translations.d.ts +27 -0
  103. package/dist/translations.js +117 -0
  104. package/dist/view.d.ts +33 -0
  105. package/dist/view.js +236 -0
  106. package/dist/xmi-import.d.ts +174 -0
  107. package/dist/xmi-import.js +2268 -0
  108. package/dist/xmi.d.ts +61 -0
  109. package/dist/xmi.js +1860 -0
  110. package/dist/xml-reader.d.ts +157 -0
  111. package/dist/xml-reader.js +430 -0
  112. package/dist/xml.d.ts +72 -0
  113. package/dist/xml.js +96 -0
  114. package/package.json +38 -0
@@ -0,0 +1,2 @@
1
+ import { type TemplateCategory } from '@formicoidea/labre-core/gfx/template';
2
+ export declare const umlTemplateCategory: TemplateCategory;
@@ -0,0 +1,197 @@
1
+ import { templateFromCommand, } from '@formicoidea/labre-core/gfx/template';
2
+ import { umlCommands } from './commands.js';
3
+ import { UML_CARD, UML_DIVIDER, UML_FRAME_INK, UML_INK } from './consts.js';
4
+ /**
5
+ * The UML palette — DERIVED from the toolbox, one template per artefact
6
+ * command.
7
+ *
8
+ * Nothing here is hand-authored, and at this notation's size that is not a
9
+ * preference: a UML class is FIVE elements (a bodyless shape, three text tiers
10
+ * and the group that makes them one thing), created in painting order, with the
11
+ * compartment seeds written verbatim so the grammar can read them back. A
12
+ * hand-written restatement of that would have drifted from `actions.ts` the way
13
+ * every framework palette written before C4's already had.
14
+ *
15
+ * So every entry below IS its command, run once against a recording surface,
16
+ * and `__tests__/templates-parity.unit.spec.ts` re-runs each one and compares.
17
+ * The day `createUmlClassifier` changes, the palette changes with it.
18
+ *
19
+ * The relationship TOOLS have no template on purpose — they ARM the connector
20
+ * tool and draw nothing, so there is no artefact to record; the two exports are
21
+ * not artefact commands at all.
22
+ */
23
+ /** The command a derived template is the picture of. Throws rather than skips. */
24
+ function byId(id) {
25
+ const command = umlCommands.find(entry => entry.id === id);
26
+ if (!command)
27
+ throw new Error(`[uml] templates: no command "${id}"`);
28
+ return command;
29
+ }
30
+ const ATTRS = 'width="100%" height="100%" viewBox="0 0 135 80" xmlns="http://www.w3.org/2000/svg"';
31
+ /** A written line, drawn as the ink bar it is at this size. */
32
+ const line = (x, y, w, color = UML_FRAME_INK) => `<rect x="${x}" y="${y}" width="${w}" height="3" rx="1.5" fill="${color}" opacity="0.8"/>`;
33
+ /**
34
+ * The three-compartment box every classifier is a variation of: the body, the
35
+ * separators at the tiers `umlCompartmentBoxes` computes, and the words.
36
+ */
37
+ const classifierPreview = (options) => {
38
+ const { head = line(44, 26, 47, UML_INK), rules = 2, underline = false, splits = [0.34, 0.66], } = options;
39
+ const top = 12;
40
+ const height = 56;
41
+ const rows = Array.from({ length: rules }, (_, i) => line(40, 46 + i * 8, i === rules - 1 ? 34 : 50)).join('');
42
+ const separators = splits
43
+ .map(f => `<path d="M32 ${top + height * f} H103" stroke="${UML_INK}" stroke-width="1.6"/>`)
44
+ .join('');
45
+ return `<svg ${ATTRS} fill="none"><rect x="32" y="${top}" width="71" height="${height}" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/>${separators}${head}${underline ? `<path d="M44 31 H91" stroke="${UML_INK}" stroke-width="1.6"/>` : ''}${rows}</svg>`;
46
+ };
47
+ /**
48
+ * The 3D box every deployment target is drawn as (§19.4.4) — the back faces
49
+ * first, the front over them, and whatever mark the kind is told apart by
50
+ * INSIDE that front face, which is the only face UML writes in.
51
+ *
52
+ * One helper for the three, exactly as {@link classifierPreview} is one helper
53
+ * for four: a node, a device and an execution environment are the same drawing
54
+ * and a reader who could tell them apart by their silhouette would be reading a
55
+ * notation UML does not have.
56
+ */
57
+ const cubePreview = (mark = '') => `<svg ${ATTRS} fill="none"><path d="M24 26 L42 12 H106 V52 L88 66 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="1.6" stroke-linejoin="round"/><path d="M24 26 H88 V66 H24 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><path d="M88 26 L106 12" stroke="${UML_INK}" stroke-width="1.6"/>${line(34, 34, 44, UML_INK)}${mark}</svg>`;
58
+ /**
59
+ * The BULLSEYE — a filled disc inside a ring.
60
+ *
61
+ * One helper for two entries, and it is the same argument {@link cubePreview}
62
+ * makes for three: §15.3.4's activity final and §14.2.4's final state are ONE
63
+ * drawing, and a palette that gave them two would be teaching a distinction UML
64
+ * does not draw. What separates them is the role and the sheet each is legal
65
+ * on, which the audit reads and a preview cannot show.
66
+ */
67
+ const bullseyePreview = () => `<svg ${ATTRS} fill="none"><circle cx="67.5" cy="40" r="22" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><circle cx="67.5" cy="40" r="12" fill="${UML_INK}"/></svg>`;
68
+ /**
69
+ * The DIAMOND one token leaves by a single branch — §15.3.4's decision and
70
+ * §14.2.4's choice, which are again one drawing on two diagrams.
71
+ */
72
+ const diamondPreview = () => `<svg ${ATTRS} fill="none"><path d="M67.5 14 L98 40 L67.5 66 L37 40 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2" stroke-linejoin="round"/><path d="M12 40 H37" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/><path d="M98 40 H123" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/></svg>`;
73
+ /**
74
+ * The `H` in its circle (§14.2.4) — drawn as strokes rather than set as type,
75
+ * so the preview does not depend on a font being loaded. `mark` is the deep
76
+ * history's asterisk, and the only difference between the two.
77
+ */
78
+ const historyPreview = (mark = '') => `<svg ${ATTRS} fill="none"><circle cx="60" cy="40" r="22" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><path d="M51 29 V51 M69 29 V51 M51 40 H69" stroke="${UML_INK}" stroke-width="2.4" stroke-linecap="round"/>${mark}</svg>`;
79
+ export const umlTemplateCategory = {
80
+ name: 'UML',
81
+ // Reuses the senior button's own key — see `TemplateCategory.nameKey`.
82
+ nameKey: 'com.labre.framework.uml',
83
+ templates: [
84
+ // The sheet: the frame with its cut-corner name tag, and two classifiers
85
+ // joined by an association on it.
86
+ templateFromCommand(byId('uml.addDiagram'), `<svg ${ATTRS} fill="none"><rect x="8" y="8" width="119" height="64" fill="${UML_CARD}" stroke="${UML_FRAME_INK}" stroke-width="1.6"/><path d="M8 8 H44 L50 15 V22 H8 Z" fill="${UML_CARD}" stroke="${UML_FRAME_INK}" stroke-width="1.6" stroke-linejoin="round"/>${line(14, 13, 24, UML_FRAME_INK)}<rect x="20" y="34" width="34" height="26" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="1.6"/><path d="M20 43 H54" stroke="${UML_INK}" stroke-width="1.4"/><rect x="81" y="34" width="34" height="26" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="1.6"/><path d="M81 43 H115" stroke="${UML_INK}" stroke-width="1.4"/><path d="M54 47 H81" stroke="${UML_INK}" stroke-width="1.6"/></svg>`),
87
+ templateFromCommand(byId('uml.addClass'), classifierPreview({})),
88
+ // The keyword above the name, drawn as the guillemets it is made of.
89
+ templateFromCommand(byId('uml.addInterface'), classifierPreview({
90
+ head: `<path d="M56 22 L51 27 L56 32 M79 22 L84 27 L79 32" stroke="${UML_INK}" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>`,
91
+ })),
92
+ // The lower compartment of an enumeration is a LIST of literals.
93
+ templateFromCommand(byId('uml.addEnumeration'), classifierPreview({ rules: 3, splits: [0.34] })),
94
+ // An instance specification: the same box, name UNDERLINED, one tier of
95
+ // slots below it.
96
+ templateFromCommand(byId('uml.addObject'), classifierPreview({ underline: true, rules: 2, splits: [0.42] })),
97
+ // The folder.
98
+ templateFromCommand(byId('uml.addPackage'), `<svg ${ATTRS} fill="none"><path d="M26 16 H56 L62 26 H109 V66 H26 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2" stroke-linejoin="round"/><path d="M26 26 H62" stroke="${UML_INK}" stroke-width="1.6"/>${line(38, 40, 48, UML_INK)}</svg>`),
99
+ // The bent corner.
100
+ templateFromCommand(byId('uml.addNote'), `<svg ${ATTRS} fill="none"><path d="M32 14 H88 L103 29 V66 H32 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2" stroke-linejoin="round"/><path d="M88 14 V29 H103" stroke="${UML_INK}" stroke-width="1.6" stroke-linejoin="round"/>${line(42, 38, 42)}${line(42, 47, 34)}</svg>`),
101
+ // The stick figure.
102
+ templateFromCommand(byId('uml.addActor'), `<svg ${ATTRS} fill="none"><circle cx="67.5" cy="18" r="7" stroke="${UML_INK}" stroke-width="2" fill="${UML_CARD}"/><path d="M67.5 25 V45 M52 32 H83 M67.5 45 L56 62 M67.5 45 L79 62" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/>${line(50, 68, 35)}</svg>`),
103
+ // The ellipse, and the words centred in it.
104
+ templateFromCommand(byId('uml.addUseCase'), `<svg ${ATTRS} fill="none"><ellipse cx="67.5" cy="40" rx="45" ry="24" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/>${line(45, 38, 45, UML_INK)}</svg>`),
105
+ // The frame drawn round the use cases one system offers: a plain thin
106
+ // rectangle, its name along the top, NOT dashed — a subject is a boundary
107
+ // of ownership, and UML draws it solid (§18.1.1).
108
+ templateFromCommand(byId('uml.addSubject'), `<svg ${ATTRS} fill="none"><rect x="12" y="10" width="111" height="60" stroke="${UML_FRAME_INK}" stroke-width="1.6"/>${line(20, 17, 34, UML_FRAME_INK)}<ellipse cx="50" cy="45" rx="24" ry="13" stroke="${UML_DIVIDER}" stroke-width="1.6"/><ellipse cx="97" cy="45" rx="18" ry="11" stroke="${UML_DIVIDER}" stroke-width="1.6"/></svg>`),
109
+ /* ── Phase 2: components (§11.6.4, §11.3.4, §10.4.4) ─────────────── */
110
+ // The classifier box with the two-tab MARK in its corner — the one
111
+ // classifier UML announces without a keyword (§11.6.4).
112
+ templateFromCommand(byId('uml.addComponent'), `<svg ${ATTRS} fill="none"><rect x="30" y="14" width="75" height="52" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><path d="M30 30 H105" stroke="${UML_INK}" stroke-width="1.6"/><rect x="88" y="18" width="13" height="9" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="1.4"/><rect x="85" y="19.5" width="6" height="2.5" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="1.2"/><rect x="85" y="23.5" width="6" height="2.5" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="1.2"/>${line(38, 20, 38, UML_INK)}${line(38, 42, 50)}${line(38, 52, 34)}</svg>`),
113
+ // The filled square ON the border, and its label beside it: a port's whole
114
+ // meaning is where it sits (§11.3.4).
115
+ templateFromCommand(byId('uml.addPort'), `<svg ${ATTRS} fill="none"><rect x="18" y="16" width="56" height="48" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><rect x="66" y="32" width="16" height="16" fill="${UML_INK}"/>${line(88, 38, 30, UML_INK)}</svg>`),
116
+ // The lollipop (§10.4.4): a stub ending in the full circle.
117
+ templateFromCommand(byId('uml.addProvidedInterface'), `<svg ${ATTRS} fill="none"><path d="M22 34 H62" stroke="${UML_INK}" stroke-width="2.4" stroke-linecap="round"/><circle cx="74" cy="34" r="12" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/>${line(40, 58, 46, UML_INK)}</svg>`),
118
+ // The socket: the same stub, ending in the half circle that cups a ball.
119
+ templateFromCommand(byId('uml.addRequiredInterface'), `<svg ${ATTRS} fill="none"><path d="M22 34 H62" stroke="${UML_INK}" stroke-width="2.4" stroke-linecap="round"/><path d="M74 22 A12 12 0 0 0 74 46" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/>${line(40, 58, 46, UML_INK)}</svg>`),
120
+ /* ── Phase 2: deployment (§19.3.4, §19.4.4) ──────────────────────── */
121
+ // The document, with words written ON it — which is what tells an artifact
122
+ // from the note that shares its folded corner.
123
+ templateFromCommand(byId('uml.addArtifact'), `<svg ${ATTRS} fill="none"><path d="M38 12 H80 L97 29 V68 H38 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2" stroke-linejoin="round"/><path d="M80 12 V29 H97" stroke="${UML_INK}" stroke-width="1.6" stroke-linejoin="round"/>${line(46, 36, 40, UML_INK)}${line(46, 50, 42)}${line(46, 58, 30)}</svg>`),
124
+ templateFromCommand(byId('uml.addNode'), cubePreview()),
125
+ // The chip: this node is HARDWARE.
126
+ templateFromCommand(byId('uml.addDevice'), cubePreview(`<rect x="34" y="46" width="26" height="11" rx="1.5" fill="${UML_INK}"/>`)),
127
+ // The run mark: this node is software other software is deployed INTO.
128
+ templateFromCommand(byId('uml.addExecutionEnvironment'), cubePreview(`<path d="M34 45 L54 52.5 L34 60 Z" fill="${UML_INK}"/>`)),
129
+ /* ── Phase 2: activities (§15.2.4, §15.3.4, §15.4.4, §16) ────────── */
130
+ // The round-cornered rectangle a step is drawn as.
131
+ templateFromCommand(byId('uml.addAction'), `<svg ${ATTRS} fill="none"><rect x="26" y="22" width="83" height="36" rx="14" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/>${line(44, 38, 47, UML_INK)}</svg>`),
132
+ // The filled disc, and the first arrow out of it.
133
+ templateFromCommand(byId('uml.addInitial'), `<svg ${ATTRS} fill="none"><circle cx="42" cy="40" r="13" fill="${UML_INK}"/><path d="M58 40 H92" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/><path d="M85 34 L95 40 L85 46" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>`),
134
+ // The bullseye: every token stops.
135
+ templateFromCommand(byId('uml.addActivityFinal'), bullseyePreview()),
136
+ // The circle with the cross: THIS token stops, the activity carries on.
137
+ templateFromCommand(byId('uml.addFlowFinal'), `<svg ${ATTRS} fill="none"><circle cx="67.5" cy="40" r="22" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><path d="M57 29.5 L78 50.5 M78 29.5 L57 50.5" stroke="${UML_INK}" stroke-width="2.4" stroke-linecap="round"/></svg>`),
138
+ // One token, ONE branch.
139
+ templateFromCommand(byId('uml.addDecision'), diamondPreview()),
140
+ // One token, EVERY branch: the filled bar, with the flows through it.
141
+ templateFromCommand(byId('uml.addFork'), `<svg ${ATTRS} fill="none"><rect x="60" y="12" width="9" height="56" rx="2" fill="${UML_INK}"/><path d="M22 40 H60" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/><path d="M69 26 H112 M69 54 H112" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/></svg>`),
142
+ // Data ON a flow, which is the only thing that tells it from a class box.
143
+ templateFromCommand(byId('uml.addObjectNode'), `<svg ${ATTRS} fill="none"><rect x="45" y="26" width="45" height="28" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/>${line(54, 38, 28, UML_INK)}<path d="M14 40 H45 M90 40 H121" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/></svg>`),
144
+ // The convex pentagon: the message leaving.
145
+ templateFromCommand(byId('uml.addSendSignal'), `<svg ${ATTRS} fill="none"><path d="M24 22 H92 L110 40 L92 58 H24 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2" stroke-linejoin="round"/>${line(38, 38, 44, UML_INK)}</svg>`),
146
+ // The concave one: the cup it arrives into. Deliberately its mirror.
147
+ templateFromCommand(byId('uml.addAcceptEvent'), `<svg ${ATTRS} fill="none"><path d="M22 22 H111 V58 H22 L40 40 Z" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2" stroke-linejoin="round"/>${line(50, 38, 44, UML_INK)}</svg>`),
148
+ // The hourglass.
149
+ templateFromCommand(byId('uml.addTimeEvent'), `<svg ${ATTRS} fill="none"><path d="M50 12 H85 L50 68 H85" stroke="${UML_INK}" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"/><path d="M50 12 L85 68" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/></svg>`),
150
+ // The swimlanes, and the heading strip that makes them lanes rather than
151
+ // lines (§15.6.4).
152
+ templateFromCommand(byId('uml.addPartition'), `<svg ${ATTRS} fill="none"><rect x="12" y="10" width="111" height="60" stroke="${UML_FRAME_INK}" stroke-width="1.6"/><path d="M12 24 H123 M67.5 10 V70" stroke="${UML_FRAME_INK}" stroke-width="1.4"/>${line(22, 15, 28, UML_FRAME_INK)}${line(78, 15, 28, UML_FRAME_INK)}<rect x="24" y="36" width="34" height="18" rx="7" stroke="${UML_DIVIDER}" stroke-width="1.6"/><rect x="78" y="36" width="34" height="18" rx="7" stroke="${UML_DIVIDER}" stroke-width="1.6"/></svg>`),
153
+ /* ── Phase 2: state machines (§14.2.4) ───────────────────────────── */
154
+ // The rounded box with a name band: a name over the behaviour lines below.
155
+ templateFromCommand(byId('uml.addState'), `<svg ${ATTRS} fill="none"><rect x="26" y="14" width="83" height="52" rx="14" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><path d="M26 34 H109" stroke="${UML_INK}" stroke-width="1.6"/>${line(44, 22, 47, UML_INK)}${line(38, 42, 56)}${line(38, 52, 44)}</svg>`),
156
+ // The bullseye again: §14.2.4 and §15.3.4 draw one circle, so this pack
157
+ // draws one too — the ROLE is what says which sheet it is legal on.
158
+ templateFromCommand(byId('uml.addFinalState'), bullseyePreview()),
159
+ // The decision's diamond, on the other diagram.
160
+ templateFromCommand(byId('uml.addChoice'), diamondPreview()),
161
+ // The knot several transitions merge at.
162
+ templateFromCommand(byId('uml.addJunction'), `<svg ${ATTRS} fill="none"><circle cx="67.5" cy="40" r="11" fill="${UML_INK}"/><path d="M20 18 L58 34 M20 62 L58 46 M79 40 H116" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/></svg>`),
163
+ // `H` — come back to the sub-state this region was last in.
164
+ templateFromCommand(byId('uml.addShallowHistory'), historyPreview()),
165
+ // `H*` — come back to the whole nested configuration.
166
+ templateFromCommand(byId('uml.addDeepHistory'), historyPreview(`<path d="M104 24 V40 M97 28 L111 36 M111 28 L97 36" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/>`)),
167
+ // The named way IN, and the border it means nothing off.
168
+ templateFromCommand(byId('uml.addEntryPoint'), `<svg ${ATTRS} fill="none"><path d="M67.5 8 V72" stroke="${UML_INK}" stroke-width="2"/><path d="M22 40 H55" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/><circle cx="67.5" cy="40" r="11" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/></svg>`),
169
+ // …and the named way out, crossed.
170
+ templateFromCommand(byId('uml.addExitPoint'), `<svg ${ATTRS} fill="none"><path d="M67.5 8 V72" stroke="${UML_INK}" stroke-width="2"/><path d="M80 40 H113" stroke="${UML_INK}" stroke-width="2" stroke-linecap="round"/><circle cx="67.5" cy="40" r="11" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><path d="M60.5 33 L74.5 47 M74.5 33 L60.5 47" stroke="${UML_INK}" stroke-width="1.8" stroke-linecap="round"/></svg>`),
171
+ // The bare cross: no circle round it, which is the whole of what tells it
172
+ // from the flow final and from the exit point.
173
+ templateFromCommand(byId('uml.addTerminate'), `<svg ${ATTRS} fill="none"><path d="M46 19 L89 61 M89 19 L46 61" stroke="${UML_INK}" stroke-width="3" stroke-linecap="round"/></svg>`),
174
+ // The composite state: the container, with a sub-machine in it.
175
+ templateFromCommand(byId('uml.addRegion'), `<svg ${ATTRS} fill="none"><rect x="12" y="10" width="111" height="60" rx="10" stroke="${UML_FRAME_INK}" stroke-width="1.6"/><path d="M12 26 H123" stroke="${UML_FRAME_INK}" stroke-width="1.4"/>${line(22, 15, 32, UML_FRAME_INK)}<rect x="26" y="38" width="32" height="18" rx="7" stroke="${UML_DIVIDER}" stroke-width="1.6"/><rect x="78" y="38" width="32" height="18" rx="7" stroke="${UML_DIVIDER}" stroke-width="1.6"/><path d="M58 47 H78" stroke="${UML_DIVIDER}" stroke-width="1.6"/></svg>`),
176
+ /* ── Phase 3: sequence diagrams (§17.2.4, §17.6.4, §17.7.4) ──────── */
177
+ // The head with its name, and the DASHED spine falling out of it — the
178
+ // half a reader recognises a sequence diagram by, because time runs down
179
+ // it. Two of them, with a message between, so the preview shows what a
180
+ // lifeline is FOR rather than a box with a dotted tail.
181
+ templateFromCommand(byId('uml.addLifeline'), `<svg ${ATTRS} fill="none"><rect x="14" y="8" width="46" height="20" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/>${line(22, 16, 30, UML_INK)}<path d="M37 28 V74" stroke="${UML_INK}" stroke-width="1.6" stroke-dasharray="5 5"/><rect x="75" y="8" width="46" height="20" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/>${line(83, 16, 30, UML_INK)}<path d="M98 28 V74" stroke="${UML_INK}" stroke-width="1.6" stroke-dasharray="5 5"/><path d="M37 48 H92" stroke="${UML_DIVIDER}" stroke-width="1.6"/><path d="M92 44 L99 48 L92 52 Z" fill="${UML_DIVIDER}"/></svg>`),
182
+ // The bar ON the spine: the stretch of the conversation this participant
183
+ // spends doing something (§17.2.4). Drawn over the dashes, because a bar
184
+ // beside a lifeline states nothing.
185
+ templateFromCommand(byId('uml.addExecution'), `<svg ${ATTRS} fill="none"><path d="M67.5 6 V74" stroke="${UML_INK}" stroke-width="1.6" stroke-dasharray="5 5"/><rect x="61" y="22" width="13" height="38" fill="${UML_CARD}" stroke="${UML_INK}" stroke-width="2"/><path d="M28 30 H61" stroke="${UML_DIVIDER}" stroke-width="1.6"/><path d="M74 52 H107" stroke="${UML_DIVIDER}" stroke-width="1.6"/></svg>`),
186
+ // The cross the spine stops at: nothing happens to this participant after
187
+ // it (§17.2.4). The dashes ABOVE and none below is the whole statement.
188
+ templateFromCommand(byId('uml.addDestruction'), `<svg ${ATTRS} fill="none"><path d="M67.5 6 V40" stroke="${UML_INK}" stroke-width="1.6" stroke-dasharray="5 5"/><path d="M53 26 L82 55 M82 26 L53 55" stroke="${UML_INK}" stroke-width="3" stroke-linecap="round"/><path d="M18 40 H50" stroke="${UML_DIVIDER}" stroke-width="1.6"/><path d="M44 36 L51 40 L44 44 Z" fill="${UML_DIVIDER}"/></svg>`),
189
+ // The frame with the PENTAGON tag, and the dashed rule that separates two
190
+ // operands (§17.6.4) — the two marks nothing else in the pack draws.
191
+ templateFromCommand(byId('uml.addFragment'), `<svg ${ATTRS} fill="none"><rect x="12" y="8" width="111" height="64" stroke="${UML_FRAME_INK}" stroke-width="1.6"/><path d="M12 8 H44 L52 17 V26 H12 Z" fill="${UML_CARD}" stroke="${UML_FRAME_INK}" stroke-width="1.6" stroke-linejoin="round"/>${line(18, 14, 24, UML_FRAME_INK)}${line(60, 32, 30, UML_FRAME_INK)}<path d="M12 46 H123" stroke="${UML_FRAME_INK}" stroke-width="1.4" stroke-dasharray="5 4"/>${line(60, 56, 30, UML_DIVIDER)}</svg>`),
192
+ // The same frame with `ref` in its tag and the name of the interaction it
193
+ // points at in the middle (§17.7.4) — and NO dashed rule, which is what
194
+ // tells it from the fragment above: a `ref` has no operands.
195
+ templateFromCommand(byId('uml.addInteractionUse'), `<svg ${ATTRS} fill="none"><rect x="12" y="8" width="111" height="64" stroke="${UML_FRAME_INK}" stroke-width="1.6"/><path d="M12 8 H44 L52 17 V26 H12 Z" fill="${UML_CARD}" stroke="${UML_FRAME_INK}" stroke-width="1.6" stroke-linejoin="round"/>${line(18, 14, 24, UML_FRAME_INK)}${line(46, 42, 56, UML_INK)}</svg>`),
196
+ ],
197
+ };
@@ -0,0 +1,228 @@
1
+ import { type ToolbarContext, type ToolbarModuleConfig } from '@formicoidea/labre-core/shared/services';
2
+ /**
3
+ * The selected UML diagram frame's contextual toolbar: the resize toggle, and
4
+ * the two exports in the "⋮".
5
+ *
6
+ * ## Why the exports sit in the ALWAYS-ON half
7
+ *
8
+ * `ActionPlacement.More` partitions an entry out of the row and into the
9
+ * overflow menu, and the entries it collects come from EVERY module contributing
10
+ * to this element — so a slice adds itself there without owning this file. The
11
+ * two interchange exports are the rarest thing anybody does to a frame, and the
12
+ * `y.` / `z.` id prefixes are the sort keys that keep them last, in that order:
13
+ * PlantUML is what an architect pastes into a renderer, XMI is what they hand to
14
+ * another tool. The generic board export (`z.z-export-svg`, contributed by the
15
+ * surface's wildcard module) sorts after both.
16
+ *
17
+ * Each entry is built by the toolbar service's `commandMoreAction`, the one
18
+ * shape every framework's "⋮" shares (`docs/adr/0010` M3): it invokes the
19
+ * registered command rather than restating what it does.
20
+ *
21
+ * They are declared HERE, in the always-on module, rather than beside the legend
22
+ * in the flag-gated one — which is exactly where the C4 board puts its own
23
+ * export. The two kinds of entry look alike and are gated by different
24
+ * mechanisms, and that is the point: the legend button CALLS an action directly,
25
+ * so nothing but the module's registration can hide it, while these ask the
26
+ * registry for a command that only the flag-gated half registers and hide
27
+ * themselves when it is not there. With the `uml` button off the row is the
28
+ * resize toggle alone either way, and nothing on it can be clicked into a no-op.
29
+ *
30
+ * Declaring them in the always-on module is what makes that guard the SINGLE
31
+ * thing deciding whether an export is offered — the same rule the palette, the
32
+ * catalogue and the agent read — instead of the guard plus a second registration
33
+ * that could one day disagree with it.
34
+ *
35
+ * There is no rename entry, and there is nothing missing: both UML frames edit
36
+ * their one word in place on a double-click (`element-view.ts`).
37
+ */
38
+ export declare const umlDiagramToolbarConfig: {
39
+ readonly actions: [{
40
+ readonly id: "a.toggle-resize";
41
+ readonly tooltipWording: import("@formicoidea/labre-core/shared/services").ChromeWording;
42
+ readonly icon: import("lit-html").TemplateResult<1>;
43
+ readonly active: (ctx: ToolbarContext) => boolean;
44
+ readonly run: (ctx: ToolbarContext) => void;
45
+ }, import("@formicoidea/labre-core/shared/services").ToolbarActionGenerator, import("@formicoidea/labre-core/shared/services").ToolbarActionGenerator];
46
+ readonly when: (ctx: ToolbarContext) => boolean;
47
+ };
48
+ export declare const umlDiagramToolbarExtension: import("@formicoidea/labre-core/store/index.js").ExtensionType;
49
+ /**
50
+ * The legend button — the flag-gated half of the row.
51
+ *
52
+ * ## The legend is a BUTTON, not a command
53
+ *
54
+ * Every other UML gesture is a registered `CommandDescriptor`, which is the
55
+ * bottleneck `docs/adr/0008` asks for. The legend is the arbitrated exception,
56
+ * carried over from C4 and the Context Map (PO arbitration, 27/08/2026):
57
+ * generating one belongs to a frame you have SELECTED and to nothing else — it
58
+ * is not an artefact to pick off a palette, and an entry in a catalogue of
59
+ * things UML draws would offer it to a user with no diagram in front of them. So
60
+ * there is no `uml.legend` command, and this button is the only way to reach it.
61
+ *
62
+ * The cost is the one the bottleneck exists to avoid: the telemetry it owes is
63
+ * emitted outside `runCommand`. It is emitted ONCE, by the shared factory
64
+ * (`legend-toolbar.ts`), so the seven copies of those wire values that used to
65
+ * sit in seven files can no longer drift apart.
66
+ *
67
+ * `b.` — the factory's default — sorts it after the resize toggle, so the two
68
+ * modules render as the one row a user sees rather than in registration order.
69
+ */
70
+ export declare const umlLegendToolbarConfig: {
71
+ readonly actions: [import("@formicoidea/labre-core/shared/services").ToolbarAction];
72
+ readonly when: (ctx: ToolbarContext) => boolean;
73
+ };
74
+ /**
75
+ * The frame's flag-gated row, WHOLE: the legend button and the kind picker, in
76
+ * ONE module.
77
+ *
78
+ * ## Why they cannot be two modules
79
+ *
80
+ * `renderToolbar` merges exactly four slots per element — `<flavour>`,
81
+ * `custom:<flavour>`, and the two `affine:surface:*` wildcards — and
82
+ * `ToolbarModuleExtension` binds by DI variant, so a second module claiming
83
+ * `custom:affine:surface:umlDiagram` throws `DuplicateServiceDefinitionError`
84
+ * before the editor finishes setting up. Two slots, and UML has three things to
85
+ * put on a selected frame: the resize toggle (always-on, `<flavour>`), the
86
+ * legend and the kind.
87
+ *
88
+ * Both of the latter are gated by the same flag and appear together or not at
89
+ * all, so one module is the honest grouping rather than a workaround: `uml` off
90
+ * takes away the gesture that CREATES legend elements and the choice of which
91
+ * kind of diagram this sheet is, and leaves the stored frame its handles, its
92
+ * heading and everything already drawn on it.
93
+ *
94
+ * Sorting keeps the row readable across the merge — `b.legend`, `c.kind`, then
95
+ * `z.validation` from {@link validationToolbarConfig} — so the user sees resize,
96
+ * legend, the diagram's KIND, then the level of requirement, whatever order the
97
+ * modules were registered in.
98
+ */
99
+ export declare const umlDiagramToolingToolbarConfig: ToolbarModuleConfig;
100
+ export declare const umlDiagramToolingToolbarExtension: import("@formicoidea/labre-core/store/index.js").ExtensionType;
101
+ /**
102
+ * The ACTIVITY PARTITION's row: the resize toggle, and the one thing a swimlane
103
+ * can be said differently — which way its bands run.
104
+ *
105
+ * ## Why the orientation toggle is ALWAYS-ON
106
+ *
107
+ * It writes a stored field, so it is not obviously tooling — and that is exactly
108
+ * the question `docs/adr/0009` makes people ask. The answer is the one the
109
+ * resize toggle already gives: this is a GESTURE ON A SELECTED ELEMENT, not a
110
+ * way to put a new one on the canvas. A partition drawn while the `uml` flag was
111
+ * on must stay usable with it off — moved, stretched, renamed, and turned the
112
+ * right way round for the sheet it sits on — because every one of those is
113
+ * something the author does to a thing that is already there.
114
+ *
115
+ * The line the ADR actually draws is between the ways to CREATE and the ways to
116
+ * work with what exists. `resizeEnabled` writes content too (it is a field of
117
+ * the model, undoable like any other); so does the rename on a double-click; so
118
+ * does dragging the frame. What the flag takes away is the button that adds a
119
+ * partition in the first place, and the menu it lives in.
120
+ *
121
+ * ## Why a toggle and not a two-option dropdown
122
+ *
123
+ * §15.6.4 gives the orientation no meaning: a partition drawn in columns and the
124
+ * same partition drawn in rows say the same thing, and the choice is made
125
+ * against the sheet — a wide activity diagram wants rows, a tall one wants
126
+ * columns. Two mutually exclusive values with no semantics between them are a
127
+ * flip, and a dropdown would spend a menu on a question whose two answers are
128
+ * "this way" and "the other way". The C4 level picker is a dropdown because
129
+ * there are four levels and each MEANS something.
130
+ *
131
+ * `active` reports HORIZONTAL — the value that is not the default — so the
132
+ * button reads as pressed exactly when the author has turned the bands.
133
+ *
134
+ * ponytail: the flip writes `orientation` and nothing else. It does not swap the
135
+ * frame's width and height, so a tall partition turned horizontal is a wide band
136
+ * stack in a tall box until the author drags it — the notation has nothing to
137
+ * say about the box, and guessing a new one is a gesture the user did not ask
138
+ * for and cannot half-undo.
139
+ */
140
+ export declare const umlPartitionToolbarConfig: {
141
+ readonly actions: [{
142
+ id: string;
143
+ tooltipWording: import("@formicoidea/labre-core/shared/services").ChromeWording;
144
+ icon: import("lit-html").TemplateResult<1>;
145
+ active(ctx: ToolbarContext): boolean;
146
+ run(ctx: ToolbarContext): void;
147
+ }, {
148
+ readonly id: "b.orientation";
149
+ readonly tooltipWording: import("@formicoidea/labre-core/shared/services").ChromeWording;
150
+ readonly icon: import("lit-html").TemplateResult<1>;
151
+ readonly active: (ctx: ToolbarContext) => boolean;
152
+ readonly run: (ctx: ToolbarContext) => void;
153
+ }];
154
+ readonly when: (ctx: ToolbarContext) => boolean;
155
+ };
156
+ export declare const umlPartitionToolbarExtension: import("@formicoidea/labre-core/store/index.js").ExtensionType;
157
+ /**
158
+ * The REGION's row: the resize toggle, and nothing else.
159
+ *
160
+ * A region is a composite state's inside (§14.2.4) — one rounded rectangle with
161
+ * one name compartment and sub-states drawn in it. It has no orientation: its
162
+ * band is its name compartment, which §14.2.4 puts at the top and nowhere else,
163
+ * and there is no second reading of the same picture to flip to. So the row is
164
+ * the one entry every framework background carries, and the rename is on the
165
+ * band under a double-click (`element-view.ts`) as it is on all the others.
166
+ *
167
+ * Registered as its own module rather than folded into the partition's because
168
+ * `renderToolbar` merges BY FLAVOUR: these are two element types, so two rows.
169
+ */
170
+ export declare const umlRegionToolbarConfig: {
171
+ readonly actions: [{
172
+ id: string;
173
+ tooltipWording: import("@formicoidea/labre-core/shared/services").ChromeWording;
174
+ icon: import("lit-html").TemplateResult<1>;
175
+ active(ctx: ToolbarContext): boolean;
176
+ run(ctx: ToolbarContext): void;
177
+ }];
178
+ readonly when: (ctx: ToolbarContext) => boolean;
179
+ };
180
+ export declare const umlRegionToolbarExtension: import("@formicoidea/labre-core/store/index.js").ExtensionType;
181
+ /**
182
+ * The COMBINED FRAGMENT's always-on row: the resize toggle, and nothing else.
183
+ *
184
+ * The same argument the region's makes, and the same one entry: a fragment is a
185
+ * rectangle drawn round part of an interaction, and a document that holds one
186
+ * must keep it movable and stretchable with the UML button switched off
187
+ * (`docs/adr/0009`). What the flag takes away is the two gestures below.
188
+ */
189
+ export declare const umlFragmentToolbarConfig: {
190
+ readonly actions: [{
191
+ id: string;
192
+ tooltipWording: import("@formicoidea/labre-core/shared/services").ChromeWording;
193
+ icon: import("lit-html").TemplateResult<1>;
194
+ active(ctx: ToolbarContext): boolean;
195
+ run(ctx: ToolbarContext): void;
196
+ }];
197
+ readonly when: (ctx: ToolbarContext) => boolean;
198
+ };
199
+ export declare const umlFragmentToolbarExtension: import("@formicoidea/labre-core/store/index.js").ExtensionType;
200
+ /**
201
+ * The fragment's FLAG-GATED row: add an operand, pick the operator, and the
202
+ * generic Validation dropdown.
203
+ *
204
+ * ## Why the two gestures are here and the resize toggle is not
205
+ *
206
+ * The line `docs/adr/0009` draws is between the ways to CREATE and the ways to
207
+ * work with what already exists, and these two fall on the creating side of it:
208
+ * adding an operand puts a band on the canvas that was not there (the same
209
+ * thing `bpmn.addLane` does, and BPMN gates it with its own flag through the
210
+ * command registry), and the operator picker declares how the drawing is to be
211
+ * READ — which is what the ADR calls tooling in as many words, and where the
212
+ * diagram frame's kind picker already sits.
213
+ *
214
+ * With the `uml` flag off a stored fragment keeps its operator written, keeps
215
+ * painting its pentagon and its dashed rules, keeps every band it has and keeps
216
+ * its handles. What goes away is the button that adds a band and the menu that
217
+ * changes the word.
218
+ *
219
+ * ## One module, for the reason the diagram's row is one module
220
+ *
221
+ * `renderToolbar` merges four slots per element and `ToolbarModuleExtension`
222
+ * binds by DI variant, so a second module claiming
223
+ * `custom:affine:surface:umlFragment` throws before the editor finishes setting
224
+ * up. Both entries are gated by the same flag and appear together or not at
225
+ * all, so one module is the honest grouping rather than a workaround.
226
+ */
227
+ export declare const umlFragmentToolingToolbarConfig: ToolbarModuleConfig;
228
+ export declare const umlFragmentToolingToolbarExtension: import("@formicoidea/labre-core/store/index.js").ExtensionType;