@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,149 @@
1
+ import { TextAlign, type UmlNodeKind } from '@formicoidea/labre-core/model';
2
+ import type { UmlBox } from './component.js';
3
+ /**
4
+ * What a UML shape IS, as props — the ONE description the creation site, the
5
+ * morph and the templates all read (R17).
6
+ *
7
+ * The rule exists because a kind's appearance is written by the preset of the
8
+ * kind it was created as and nothing ever rewrites it afterwards: a second table
9
+ * restating the same sizes and colours would agree with this one on the day it
10
+ * was written and drift on the first restyle. Derived, they cannot — a morphed
11
+ * classifier and one freshly drawn from the toolbox are the same element.
12
+ *
13
+ * ## No colour decisions here, and that is the notation's doing
14
+ *
15
+ * UML 2.5.1 defines no palette. Every figure in the specification is black lines
16
+ * on white paper, and what tells a class from an interface from an enumeration
17
+ * is the KEYWORD written above the name (§9.5.4), never a hue. So this file
18
+ * seeds one ink and one paper off the shared neutral scale (R33, through
19
+ * `consts.ts`) and spends its judgement on the two things the spec DOES
20
+ * legislate: which kinds are a divided rectangle, and which are a picture.
21
+ */
22
+ /**
23
+ * The kinds whose GLYPH draws the body, so the native shape underneath paints
24
+ * nothing at all.
25
+ *
26
+ * Twenty-five of thirty-eight, and the node renderer is the authority on which. A package is
27
+ * a tabbed folder (§12.2.4), a note a rectangle with a folded corner (Annex A),
28
+ * an actor a stick figure (§18.1.4) — none of which a native rect can be, so
29
+ * each is created `filled: false` with `StrokeStyle.None` and the renderer
30
+ * paints the outline and the body itself, reading `fillColor` / `strokeColor`
31
+ * off this same model. Both therefore stay editable from the ordinary shape
32
+ * toolbar, exactly like every other node's.
33
+ *
34
+ * Phase 2 added six more, and every one of them for the same reason:
35
+ *
36
+ * - `node`, `device` and `execution-environment` are the 3-D CUBE of §19.4.4 —
37
+ * three faces, two of them parallelograms, which no `shapeType` has;
38
+ * - `provided-interface` and `required-interface` are the ball and the socket
39
+ * of §10.4.4, each a curve on a stub rather than a filled area;
40
+ * - `port` is the one that looks as if a native rect would do (§11.3.4 draws a
41
+ * small square), and it is here because the square is the GLYPH: it is drawn
42
+ * to a fixed proportion of the element so that a port dragged bigger stays a
43
+ * port rather than becoming a box, and it is centred so the name written
44
+ * beside it lines up with it.
45
+ *
46
+ * The USE CASE is deliberately not on the list, and it is the one that looks as
47
+ * if it should be: an ellipse is not a rectangle either — but it is a native
48
+ * `shapeType`, so the platform draws it, fills it and hit-tests it with no glyph
49
+ * involved. Nor are `component` and `artifact`, which ARE the native filled
50
+ * rectangle with a small icon painted into the corner. A kind is on this list
51
+ * when the SHAPE LAYER cannot draw its body, not when it has a glyph.
52
+ *
53
+ * They stay hit-testable across their whole area all the same:
54
+ * `UmlNodeElementModel.includesPoint` forces the interior test regardless of
55
+ * `filled`, which is what keeps an unfilled package draggable and
56
+ * double-clickable across its body rather than along its (absent) stroke.
57
+ */
58
+ export declare const GLYPH_BODY_KINDS: ReadonlySet<UmlNodeKind>;
59
+ /**
60
+ * The kinds the native shape draws with ROUNDED corners.
61
+ *
62
+ * Two, and both by the notation's own instruction: §15.3.4 draws an Action as a
63
+ * round-cornered rectangle and §14.2.4 draws a State as one. They are the only
64
+ * places this pack departs from `radius: 0`, which is not a house style but what
65
+ * §11.4.4 draws for a classifier — so the departure is as literal as the rule.
66
+ *
67
+ * A native `radius` rather than a glyph, which is what keeps both OFF
68
+ * {@link GLYPH_BODY_KINDS}: the shape layer fills, strokes, hit-tests and
69
+ * re-themes a rounded rect for free, and a glyph-drawn one would have to
70
+ * reimplement all four.
71
+ */
72
+ export declare const ROUNDED_KINDS: ReadonlySet<UmlNodeKind>;
73
+ /**
74
+ * Every prop a UML shape is created with, for one kind and one box.
75
+ *
76
+ * `index` is deliberately NOT here: it is a layering statement the creation site
77
+ * makes about the handful of elements it is about to write in painting order,
78
+ * and it means nothing to an element that already exists.
79
+ *
80
+ * No `text` either, and that is R16 rather than an omission: a classifier's
81
+ * name, attributes and operations are canvas TEXT elements grouped with the
82
+ * shape, and the shape is a body and nothing else. Its text COLOUR and FACE are
83
+ * still seeded, because a shape's native inner text remains reachable — an
84
+ * author may type into it through the plain shape editor, and what they type
85
+ * must not arrive in some other diagram's font.
86
+ */
87
+ export declare function umlNodeProps(kind: UmlNodeKind, box: {
88
+ xywh: string;
89
+ }): Record<string, unknown> & {
90
+ type: string;
91
+ };
92
+ /**
93
+ * What a kind is worth to a shape that ALREADY EXISTS — {@link umlNodeProps}
94
+ * minus the three things a morph has no business touching.
95
+ *
96
+ * ## Why the whole preset, and not `{kind, role}`
97
+ *
98
+ * Because on this pack's own table it is visibly not enough. Morphing a class to
99
+ * a package flips `filled` and `strokeStyle` (the folder is a glyph, the class
100
+ * is a native rect); morphing either to a use case rewrites `shapeType` from
101
+ * `rect` to `ellipse`. Two keys would leave a filled rectangle painted behind a
102
+ * tabbed folder, or an ellipse's label centred in a box that is still square.
103
+ *
104
+ * Shipped in phase 1 although the morph itself is tranche D's: the preset is
105
+ * what a morph is FOR, and writing it here beside the creation props is what
106
+ * stops the two from being written by different hands against different tables.
107
+ */
108
+ export declare function umlMorphProps(kind: UmlNodeKind): Record<string, unknown>;
109
+ /**
110
+ * The fields to DELETE after morphing to `kind` — the keys some other kind
111
+ * writes and this one does not.
112
+ *
113
+ * EMPTY for every kind today, because no UML preset spreads anything
114
+ * conditionally: all thirty-eight write the same key set with different values. Kept
115
+ * anyway, and derived rather than hard-coded to `[]`, for the reason BPMN's and
116
+ * C4's equivalents exist at all — a patch cannot express absence, and the day
117
+ * one kind stops writing a key the previous kind's value would otherwise stay
118
+ * in the Y.Map, silently in force.
119
+ */
120
+ export declare function umlMorphClears(kind: UmlNodeKind): readonly string[];
121
+ /**
122
+ * Every prop a compartment's TEXT element is created with.
123
+ *
124
+ * Passing them all explicitly is not belt and braces: `surface.addElement` runs
125
+ * new props through `EditPropsStore.applyLastProps('text', …)`, which merges
126
+ * whatever the user last set on a free text element underneath — a 24px face, a
127
+ * colour from another diagram, a left alignment. Explicit props win the merge,
128
+ * so the only ones that survive it are the ones written here. An operations
129
+ * compartment inheriting the colour of the last sticky note somebody typed would
130
+ * be a notation set by accident.
131
+ *
132
+ * `hasMaxWidth` is what keeps a long signature inside the classifier instead of
133
+ * running out over the canvas: the box wraps at its own width and grows
134
+ * downward, and the group grows with it, so a component always contains its own
135
+ * words.
136
+ *
137
+ * `bold` is offered for exactly one tier — the classifier's NAME, which is the
138
+ * heading of the box and, at 16px against a 13px feature line, is not set apart
139
+ * by size alone. Everything else is Regular, because UML reserves its type
140
+ * variations for meanings the grammar reads (italics for abstract, §9.2.4) and
141
+ * a decorative weight would compete with them.
142
+ */
143
+ export declare function umlTextProps(role: string, box: UmlBox, options: {
144
+ fontSize: number;
145
+ align: TextAlign;
146
+ bold?: boolean;
147
+ }): Record<string, unknown> & {
148
+ type: string;
149
+ };
@@ -0,0 +1,302 @@
1
+ import { FontFamily, FontStyle, FontWeight, ShapeStyle, StrokeStyle, TextAlign, } from '@formicoidea/labre-core/model';
2
+ import { Bound } from '@formicoidea/labre-core/global/gfx';
3
+ import { UML_CARD, UML_INK, UML_NAME_FONT_SIZE, UML_NODE_BOX, UML_NODE_RADIUS, UML_NODE_STROKE_WIDTH, } from './consts.js';
4
+ import { UML_ROLE_OF_KIND } from './roles.js';
5
+ /**
6
+ * What a UML shape IS, as props — the ONE description the creation site, the
7
+ * morph and the templates all read (R17).
8
+ *
9
+ * The rule exists because a kind's appearance is written by the preset of the
10
+ * kind it was created as and nothing ever rewrites it afterwards: a second table
11
+ * restating the same sizes and colours would agree with this one on the day it
12
+ * was written and drift on the first restyle. Derived, they cannot — a morphed
13
+ * classifier and one freshly drawn from the toolbox are the same element.
14
+ *
15
+ * ## No colour decisions here, and that is the notation's doing
16
+ *
17
+ * UML 2.5.1 defines no palette. Every figure in the specification is black lines
18
+ * on white paper, and what tells a class from an interface from an enumeration
19
+ * is the KEYWORD written above the name (§9.5.4), never a hue. So this file
20
+ * seeds one ink and one paper off the shared neutral scale (R33, through
21
+ * `consts.ts`) and spends its judgement on the two things the spec DOES
22
+ * legislate: which kinds are a divided rectangle, and which are a picture.
23
+ */
24
+ /**
25
+ * The kinds whose GLYPH draws the body, so the native shape underneath paints
26
+ * nothing at all.
27
+ *
28
+ * Twenty-five of thirty-eight, and the node renderer is the authority on which. A package is
29
+ * a tabbed folder (§12.2.4), a note a rectangle with a folded corner (Annex A),
30
+ * an actor a stick figure (§18.1.4) — none of which a native rect can be, so
31
+ * each is created `filled: false` with `StrokeStyle.None` and the renderer
32
+ * paints the outline and the body itself, reading `fillColor` / `strokeColor`
33
+ * off this same model. Both therefore stay editable from the ordinary shape
34
+ * toolbar, exactly like every other node's.
35
+ *
36
+ * Phase 2 added six more, and every one of them for the same reason:
37
+ *
38
+ * - `node`, `device` and `execution-environment` are the 3-D CUBE of §19.4.4 —
39
+ * three faces, two of them parallelograms, which no `shapeType` has;
40
+ * - `provided-interface` and `required-interface` are the ball and the socket
41
+ * of §10.4.4, each a curve on a stub rather than a filled area;
42
+ * - `port` is the one that looks as if a native rect would do (§11.3.4 draws a
43
+ * small square), and it is here because the square is the GLYPH: it is drawn
44
+ * to a fixed proportion of the element so that a port dragged bigger stays a
45
+ * port rather than becoming a box, and it is centred so the name written
46
+ * beside it lines up with it.
47
+ *
48
+ * The USE CASE is deliberately not on the list, and it is the one that looks as
49
+ * if it should be: an ellipse is not a rectangle either — but it is a native
50
+ * `shapeType`, so the platform draws it, fills it and hit-tests it with no glyph
51
+ * involved. Nor are `component` and `artifact`, which ARE the native filled
52
+ * rectangle with a small icon painted into the corner. A kind is on this list
53
+ * when the SHAPE LAYER cannot draw its body, not when it has a glyph.
54
+ *
55
+ * They stay hit-testable across their whole area all the same:
56
+ * `UmlNodeElementModel.includesPoint` forces the interior test regardless of
57
+ * `filled`, which is what keeps an unfilled package draggable and
58
+ * double-clickable across its body rather than along its (absent) stroke.
59
+ */
60
+ export const GLYPH_BODY_KINDS = new Set([
61
+ 'package',
62
+ 'note',
63
+ 'actor',
64
+ 'port',
65
+ 'provided-interface',
66
+ 'required-interface',
67
+ 'node',
68
+ 'device',
69
+ 'execution-environment',
70
+ // Phase 2, the behaviour marks. Fourteen more, and every one of them for the
71
+ // reason the nine above are here — the shape layer cannot draw the body:
72
+ //
73
+ // - `initial`, `junction`, `activity-final`, `flow-final`, `final-state`,
74
+ // `shallow-history`, `deep-history`, `entry-point`, `exit-point` are
75
+ // CIRCLES with something inside them (a second disc, a cross, a letter) or
76
+ // a filled disc at a fixed proportion of the element — an `ellipse`
77
+ // shapeType would stretch into an egg and would carry nothing inside it;
78
+ // - `fork` is the bar of §15.3.4, drawn to a fixed proportion of the element
79
+ // so a fork dragged taller stays a bar rather than becoming a box;
80
+ // - `send-signal` and `accept-event` are the convex and concave pentagons of
81
+ // §16.3.4, which no `shapeType` has;
82
+ // - `time-event` is the hourglass of §16.10.4, two triangles meeting at a
83
+ // point;
84
+ // - `terminate` is a bare X — nothing but two strokes, and a filled
85
+ // rectangle behind it would be a box the notation does not draw.
86
+ //
87
+ // NOT on the list, and each looking as if it should be: `action` and `state`
88
+ // are the native rect with a `radius` (§15.3.4, §14.2.4 — a round-cornered
89
+ // rectangle IS a native rounded rect); `decision` and `choice` are the native
90
+ // `diamond` shapeType; `object-node` is the plain native rect of §15.4.4.
91
+ 'initial',
92
+ 'activity-final',
93
+ 'flow-final',
94
+ 'fork',
95
+ 'send-signal',
96
+ 'accept-event',
97
+ 'time-event',
98
+ 'final-state',
99
+ 'junction',
100
+ 'shallow-history',
101
+ 'deep-history',
102
+ 'entry-point',
103
+ 'exit-point',
104
+ 'terminate',
105
+ // Phase 3, the interaction marks. Two more, and again because the shape
106
+ // layer cannot draw the body:
107
+ //
108
+ // - `lifeline` is §17.3.4's head box over a DASHED SPINE, and the element is
109
+ // the 16-wide column the spine runs down — a native rect would paint a
110
+ // tall thin box where the notation draws a line, and would paint no head
111
+ // at all;
112
+ // - `destruction` is a bare X (§17.2.4), two strokes and nothing else, so a
113
+ // filled rectangle behind it would be a box the notation does not draw —
114
+ // the argument `terminate` already makes.
115
+ //
116
+ // `execution` is deliberately NOT here: §17.2.4 draws an
117
+ // ExecutionSpecification as a thin FILLED RECTANGLE on the spine, which is
118
+ // exactly what a native rect is. The shape layer fills it, strokes it,
119
+ // hit-tests it and re-themes it, and a glyph over it would reimplement all
120
+ // four — the same call `object-node` and `action` make.
121
+ 'lifeline',
122
+ 'destruction',
123
+ ]);
124
+ /**
125
+ * The kinds the native shape draws with ROUNDED corners.
126
+ *
127
+ * Two, and both by the notation's own instruction: §15.3.4 draws an Action as a
128
+ * round-cornered rectangle and §14.2.4 draws a State as one. They are the only
129
+ * places this pack departs from `radius: 0`, which is not a house style but what
130
+ * §11.4.4 draws for a classifier — so the departure is as literal as the rule.
131
+ *
132
+ * A native `radius` rather than a glyph, which is what keeps both OFF
133
+ * {@link GLYPH_BODY_KINDS}: the shape layer fills, strokes, hit-tests and
134
+ * re-themes a rounded rect for free, and a glyph-drawn one would have to
135
+ * reimplement all four.
136
+ */
137
+ export const ROUNDED_KINDS = new Set([
138
+ 'action',
139
+ 'state',
140
+ ]);
141
+ /**
142
+ * The kinds the native shape draws as a DIAMOND.
143
+ *
144
+ * §15.3.4's decision/merge node and §14.2.4's choice pseudostate — two different
145
+ * metaclasses on two different diagrams, drawn as the same diamond, which is why
146
+ * they share this line and not a role. `diamond` is a native `shapeType`, so the
147
+ * platform fills it, strokes it and hit-tests it with no glyph involved, exactly
148
+ * as it does the use case's ellipse.
149
+ */
150
+ const DIAMOND_KINDS = new Set([
151
+ 'decision',
152
+ 'choice',
153
+ ]);
154
+ /**
155
+ * Every prop a UML shape is created with, for one kind and one box.
156
+ *
157
+ * `index` is deliberately NOT here: it is a layering statement the creation site
158
+ * makes about the handful of elements it is about to write in painting order,
159
+ * and it means nothing to an element that already exists.
160
+ *
161
+ * No `text` either, and that is R16 rather than an omission: a classifier's
162
+ * name, attributes and operations are canvas TEXT elements grouped with the
163
+ * shape, and the shape is a body and nothing else. Its text COLOUR and FACE are
164
+ * still seeded, because a shape's native inner text remains reachable — an
165
+ * author may type into it through the plain shape editor, and what they type
166
+ * must not arrive in some other diagram's font.
167
+ */
168
+ export function umlNodeProps(kind, box) {
169
+ const glyphBody = GLYPH_BODY_KINDS.has(kind);
170
+ return {
171
+ type: 'umlNode',
172
+ kind,
173
+ // Semantic identity, posted next to `kind` — which stays untouched and keeps
174
+ // driving the rendering. The role is the authority on what the box MEANS,
175
+ // and it is the only thing that can say so: a class, an interface and an
176
+ // enumeration are the SAME rectangle, told apart by their keyword line
177
+ // (`./roles.ts`).
178
+ role: UML_ROLE_OF_KIND[kind],
179
+ // The kinds the platform draws for us that are not rectangles. §18.1.4
180
+ // draws a use case as an ellipse; §15.3.4 and §14.2.4 draw a decision and a
181
+ // choice as a diamond. A native `shapeType` means the platform fills it,
182
+ // strokes it and hit-tests it with no glyph involved.
183
+ shapeType: kind === 'use-case'
184
+ ? 'ellipse'
185
+ : DIAMOND_KINDS.has(kind)
186
+ ? 'diamond'
187
+ : 'rect',
188
+ filled: !glyphBody,
189
+ fillColor: UML_CARD,
190
+ strokeColor: UML_INK,
191
+ strokeWidth: UML_NODE_STROKE_WIDTH,
192
+ strokeStyle: glyphBody ? StrokeStyle.None : StrokeStyle.Solid,
193
+ shapeStyle: ShapeStyle.General,
194
+ // Zero roughness everywhere, and not a default worth revisiting: UML's
195
+ // figures are drawn with a ruler, and a hand-drawn wobble would be this
196
+ // pack inventing a house style for a notation that has one.
197
+ roughness: 0,
198
+ // The corner is a different question, and the notation answers it per
199
+ // artefact: square for a classifier (§11.4.4), ROUNDED for an action
200
+ // (§15.3.4) and a state (§14.2.4). So the zero here is the classifier's
201
+ // rule rather than a pack-wide one — see {@link ROUNDED_KINDS}.
202
+ radius: ROUNDED_KINDS.has(kind) ? UML_NODE_RADIUS : 0,
203
+ color: UML_INK,
204
+ fontFamily: FontFamily.Inter,
205
+ fontSize: UML_NAME_FONT_SIZE,
206
+ textAlign: TextAlign.Center,
207
+ xywh: box.xywh,
208
+ };
209
+ }
210
+ /**
211
+ * The box {@link umlMorphProps} hands {@link umlNodeProps} and then throws away.
212
+ * Never written to a document: a morph keeps the geometry the element already
213
+ * has, and this exists only because the one builder takes a box.
214
+ */
215
+ const DISCARDED_BOX = '[0,0,0,0]';
216
+ /** What a morph must never rewrite: identity, geometry, and the user's words. */
217
+ const NOT_A_MORPH = ['type', 'xywh', 'text'];
218
+ /**
219
+ * What a kind is worth to a shape that ALREADY EXISTS — {@link umlNodeProps}
220
+ * minus the three things a morph has no business touching.
221
+ *
222
+ * ## Why the whole preset, and not `{kind, role}`
223
+ *
224
+ * Because on this pack's own table it is visibly not enough. Morphing a class to
225
+ * a package flips `filled` and `strokeStyle` (the folder is a glyph, the class
226
+ * is a native rect); morphing either to a use case rewrites `shapeType` from
227
+ * `rect` to `ellipse`. Two keys would leave a filled rectangle painted behind a
228
+ * tabbed folder, or an ellipse's label centred in a box that is still square.
229
+ *
230
+ * Shipped in phase 1 although the morph itself is tranche D's: the preset is
231
+ * what a morph is FOR, and writing it here beside the creation props is what
232
+ * stops the two from being written by different hands against different tables.
233
+ */
234
+ export function umlMorphProps(kind) {
235
+ // Widened to the plain record on the way in: `type` is required on what the
236
+ // creation builder returns, and `delete` may only take an optional key.
237
+ const props = {
238
+ ...umlNodeProps(kind, { xywh: DISCARDED_BOX }),
239
+ };
240
+ for (const key of NOT_A_MORPH)
241
+ delete props[key];
242
+ return props;
243
+ }
244
+ /**
245
+ * Every key ANY kind's props may carry — the union over the whole pack.
246
+ *
247
+ * Computed rather than listed, so a preset that starts spreading a key
248
+ * conditionally is covered on the day it is added rather than on the day
249
+ * somebody notices.
250
+ */
251
+ const EVERY_MORPH_KEY = new Set(Object.keys(UML_NODE_BOX).flatMap(kind => Object.keys(umlMorphProps(kind))));
252
+ /**
253
+ * The fields to DELETE after morphing to `kind` — the keys some other kind
254
+ * writes and this one does not.
255
+ *
256
+ * EMPTY for every kind today, because no UML preset spreads anything
257
+ * conditionally: all thirty-eight write the same key set with different values. Kept
258
+ * anyway, and derived rather than hard-coded to `[]`, for the reason BPMN's and
259
+ * C4's equivalents exist at all — a patch cannot express absence, and the day
260
+ * one kind stops writing a key the previous kind's value would otherwise stay
261
+ * in the Y.Map, silently in force.
262
+ */
263
+ export function umlMorphClears(kind) {
264
+ const present = new Set(Object.keys(umlMorphProps(kind)));
265
+ return [...EVERY_MORPH_KEY].filter(key => !present.has(key));
266
+ }
267
+ /**
268
+ * Every prop a compartment's TEXT element is created with.
269
+ *
270
+ * Passing them all explicitly is not belt and braces: `surface.addElement` runs
271
+ * new props through `EditPropsStore.applyLastProps('text', …)`, which merges
272
+ * whatever the user last set on a free text element underneath — a 24px face, a
273
+ * colour from another diagram, a left alignment. Explicit props win the merge,
274
+ * so the only ones that survive it are the ones written here. An operations
275
+ * compartment inheriting the colour of the last sticky note somebody typed would
276
+ * be a notation set by accident.
277
+ *
278
+ * `hasMaxWidth` is what keeps a long signature inside the classifier instead of
279
+ * running out over the canvas: the box wraps at its own width and grows
280
+ * downward, and the group grows with it, so a component always contains its own
281
+ * words.
282
+ *
283
+ * `bold` is offered for exactly one tier — the classifier's NAME, which is the
284
+ * heading of the box and, at 16px against a 13px feature line, is not set apart
285
+ * by size alone. Everything else is Regular, because UML reserves its type
286
+ * variations for meanings the grammar reads (italics for abstract, §9.2.4) and
287
+ * a decorative weight would compete with them.
288
+ */
289
+ export function umlTextProps(role, box, options) {
290
+ return {
291
+ type: 'text',
292
+ role,
293
+ color: UML_INK,
294
+ fontFamily: FontFamily.Inter,
295
+ fontSize: options.fontSize,
296
+ fontWeight: options.bold ? FontWeight.SemiBold : FontWeight.Regular,
297
+ fontStyle: FontStyle.Normal,
298
+ textAlign: options.align,
299
+ hasMaxWidth: true,
300
+ xywh: new Bound(box.x, box.y, box.w, box.h).serialize(),
301
+ };
302
+ }
@@ -0,0 +1,2 @@
1
+ import type { ValidationProfile } from '@formicoidea/labre-core/blocks/surface';
2
+ export declare const UML_PROFILES: readonly ValidationProfile[];