@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.
- package/LICENSE +384 -0
- package/dist/actions.d.ts +430 -0
- package/dist/actions.js +724 -0
- package/dist/background.d.ts +153 -0
- package/dist/background.js +557 -0
- package/dist/board-hit.d.ts +137 -0
- package/dist/board-hit.js +191 -0
- package/dist/commands-manifest.d.ts +19 -0
- package/dist/commands-manifest.js +571 -0
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +983 -0
- package/dist/component.d.ts +521 -0
- package/dist/component.js +708 -0
- package/dist/consts.d.ts +365 -0
- package/dist/consts.js +463 -0
- package/dist/descriptor.d.ts +12 -0
- package/dist/descriptor.js +10 -0
- package/dist/drawio-decode.d.ts +32 -0
- package/dist/drawio-decode.js +96 -0
- package/dist/drawio-import.d.ts +133 -0
- package/dist/drawio-import.js +885 -0
- package/dist/edge-morph.d.ts +154 -0
- package/dist/edge-morph.js +153 -0
- package/dist/edge-styles.d.ts +78 -0
- package/dist/edge-styles.js +210 -0
- package/dist/effects.d.ts +9 -0
- package/dist/effects.js +6 -0
- package/dist/element-renderer.d.ts +64 -0
- package/dist/element-renderer.js +114 -0
- package/dist/element-view.d.ts +234 -0
- package/dist/element-view.js +430 -0
- package/dist/export.d.ts +61 -0
- package/dist/export.js +41 -0
- package/dist/filename.d.ts +17 -0
- package/dist/filename.js +26 -0
- package/dist/frame-tag.d.ts +70 -0
- package/dist/frame-tag.js +78 -0
- package/dist/grammar.d.ts +695 -0
- package/dist/grammar.js +1436 -0
- package/dist/import.d.ts +306 -0
- package/dist/import.js +1270 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +67 -0
- package/dist/interchange.d.ts +125 -0
- package/dist/interchange.js +372 -0
- package/dist/keywords.d.ts +204 -0
- package/dist/keywords.js +361 -0
- package/dist/kinds.d.ts +73 -0
- package/dist/kinds.js +91 -0
- package/dist/legend.d.ts +30 -0
- package/dist/legend.js +255 -0
- package/dist/model.d.ts +862 -0
- package/dist/model.js +1316 -0
- package/dist/morph.d.ts +178 -0
- package/dist/morph.js +496 -0
- package/dist/node/act-glyphs.d.ts +30 -0
- package/dist/node/act-glyphs.js +142 -0
- package/dist/node/compartment-watcher.d.ts +107 -0
- package/dist/node/compartment-watcher.js +163 -0
- package/dist/node/fit.d.ts +85 -0
- package/dist/node/fit.js +129 -0
- package/dist/node/node-renderer.d.ts +49 -0
- package/dist/node/node-renderer.js +611 -0
- package/dist/node/node-view.d.ts +51 -0
- package/dist/node/node-view.js +89 -0
- package/dist/node/paint.d.ts +84 -0
- package/dist/node/paint.js +143 -0
- package/dist/node/sd-glyphs.d.ts +36 -0
- package/dist/node/sd-glyphs.js +79 -0
- package/dist/node/stm-glyphs.d.ts +22 -0
- package/dist/node/stm-glyphs.js +111 -0
- package/dist/node/tier-metrics.d.ts +38 -0
- package/dist/node/tier-metrics.js +45 -0
- package/dist/operators.d.ts +45 -0
- package/dist/operators.js +75 -0
- package/dist/plantuml-import.d.ts +113 -0
- package/dist/plantuml-import.js +1723 -0
- package/dist/plantuml.d.ts +94 -0
- package/dist/plantuml.js +985 -0
- package/dist/presets.d.ts +149 -0
- package/dist/presets.js +302 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +358 -0
- package/dist/reading.d.ts +160 -0
- package/dist/reading.js +648 -0
- package/dist/roles.d.ts +257 -0
- package/dist/roles.js +997 -0
- package/dist/rules.d.ts +267 -0
- package/dist/rules.js +3090 -0
- package/dist/templates.d.ts +2 -0
- package/dist/templates.js +197 -0
- package/dist/toolbar/config.d.ts +228 -0
- package/dist/toolbar/config.js +833 -0
- package/dist/toolbar/icons.d.ts +440 -0
- package/dist/toolbar/icons.js +711 -0
- package/dist/toolbar/senior-tool.d.ts +11 -0
- package/dist/toolbar/senior-tool.js +21 -0
- package/dist/toolbar/uml-menu.d.ts +17 -0
- package/dist/toolbar/uml-menu.js +20 -0
- package/dist/toolbar/uml-senior-button.d.ts +18 -0
- package/dist/toolbar/uml-senior-button.js +22 -0
- package/dist/translations.d.ts +27 -0
- package/dist/translations.js +117 -0
- package/dist/view.d.ts +33 -0
- package/dist/view.js +236 -0
- package/dist/xmi-import.d.ts +174 -0
- package/dist/xmi-import.js +2268 -0
- package/dist/xmi.d.ts +61 -0
- package/dist/xmi.js +1860 -0
- package/dist/xml-reader.d.ts +157 -0
- package/dist/xml-reader.js +430 -0
- package/dist/xml.d.ts +72 -0
- package/dist/xml.js +96 -0
- package/package.json +38 -0
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
import { UML_CARD, UML_DIAGRAM_BOX, UML_DIAGRAM_MARGIN, UML_DIVIDER, UML_FONT_FAMILY, UML_FRAGMENT_BAND, UML_FRAGMENT_BORDER_WIDTH, UML_FRAGMENT_BOX, UML_FRAGMENT_GUARD_FONT_SIZE, UML_FRAGMENT_GUARD_INSET, UML_FRAGMENT_MARGIN, UML_FRAGMENT_OPERAND_DASH, UML_FRAME_BAND_HEIGHT, UML_FRAME_BORDER_WIDTH, UML_FRAME_HEADING_FONT_SIZE, UML_FRAME_INK, UML_NAME_FONT_SIZE, UML_PARTITION_BAND, UML_PARTITION_BORDER_WIDTH, UML_PARTITION_BOX, UML_PARTITION_MARGIN, UML_REGION_BAND, UML_REGION_BORDER_WIDTH, UML_REGION_BOX, UML_REGION_MARGIN, UML_REGION_RADIUS, UML_SUBJECT_BORDER_WIDTH, UML_SUBJECT_BOX, UML_SUBJECT_MARGIN, } from './consts.js';
|
|
2
|
+
import { UML_ROLE } from './roles.js';
|
|
3
|
+
/**
|
|
4
|
+
* The four UML frames, DECLARED (the `FrameworkBackgroundDef` primitive): the
|
|
5
|
+
* diagram sheet of Annex A, the use case subject of §18.1.4, the activity
|
|
6
|
+
* partition of §15.6.4 (in its two orientations) and the composite state of
|
|
7
|
+
* §14.2.4.
|
|
8
|
+
*
|
|
9
|
+
* There is no UML drawing code for either of them: the primitive paints these
|
|
10
|
+
* declarations, and would paint any other framework's the same way
|
|
11
|
+
* (`docs/adr/0009` on why a framework declares rather than draws). The ONE thing
|
|
12
|
+
* UML asks for that the primitive has no vocabulary for — the cut-corner heading
|
|
13
|
+
* tag of Annex A — is a decorator over the renderer these produce, and it lives
|
|
14
|
+
* in `frame-tag.ts` rather than in a new field of the declaration language.
|
|
15
|
+
*/
|
|
16
|
+
/* ── The diagram frame ─────────────────────────────────────────────────── */
|
|
17
|
+
/**
|
|
18
|
+
* The UML diagram frame: a white card with a square border and a heading band
|
|
19
|
+
* across its top.
|
|
20
|
+
*
|
|
21
|
+
* **No axes and no zones**, like the C4 board this is modelled on and for the
|
|
22
|
+
* same reason: a UML diagram is a GRAPH. A class drawn top left says nothing
|
|
23
|
+
* more than one drawn bottom right, and graduating the card would invent a frame
|
|
24
|
+
* of reference UML does not have — and then judge people against it.
|
|
25
|
+
*
|
|
26
|
+
* ## The heading is `heading`, not `name` — and that is the whole difference
|
|
27
|
+
*
|
|
28
|
+
* A C4 board writes its title, which is free text. Annex A writes `<kind>
|
|
29
|
+
* <name>`: a class diagram called Orders reads `class Orders`, and only the
|
|
30
|
+
* second word is the author's. So the label binds the model's DERIVED
|
|
31
|
+
* {@link UmlDiagramElementModel.heading} — the two halves joined — and the
|
|
32
|
+
* rename gesture writes `name` alone (`element-view.ts`). Binding `heading`
|
|
33
|
+
* directly would let an editor write the joined string back into a getter, which
|
|
34
|
+
* would either throw or, worse, re-prefix the kind on every rename.
|
|
35
|
+
*
|
|
36
|
+
* ## Why the band paints NOTHING
|
|
37
|
+
*
|
|
38
|
+
* It declares no fill and no divider, which is not an oversight: Annex A draws a
|
|
39
|
+
* frame as one rectangle with a tag in its corner, and a rule ruled across the
|
|
40
|
+
* sheet under the heading would be a line the notation does not have. The band
|
|
41
|
+
* exists to place the words and to reserve the top margin; what a reader SEES
|
|
42
|
+
* there is the tag, and what a user AIMS at is the tag — which is the affordance
|
|
43
|
+
* the C4 board needed its painted strip for.
|
|
44
|
+
*
|
|
45
|
+
* The model's own carve-out (`UmlDiagramElementModel.includesPoint`) still picks
|
|
46
|
+
* the whole band, so a click anywhere along the top margin selects the sheet
|
|
47
|
+
* rather than falling through to the canvas. That is deliberately WIDER than
|
|
48
|
+
* what is painted, and it is the one place the two disagree: the alternative is
|
|
49
|
+
* a frame whose corner tag is the only selectable part of a 44-unit strip that
|
|
50
|
+
* is plainly part of the sheet.
|
|
51
|
+
*/
|
|
52
|
+
export const UML_DIAGRAM_FRAME = {
|
|
53
|
+
type: 'umlDiagram',
|
|
54
|
+
role: UML_ROLE.diagram,
|
|
55
|
+
geometry: {
|
|
56
|
+
// Wide and free: a diagram grows sideways as the model is discovered, so
|
|
57
|
+
// neither dimension is locked to the other and the handles are offered from
|
|
58
|
+
// the start.
|
|
59
|
+
width: UML_DIAGRAM_BOX.w,
|
|
60
|
+
height: UML_DIAGRAM_BOX.h,
|
|
61
|
+
lockAspectRatio: false,
|
|
62
|
+
resizable: true,
|
|
63
|
+
// Only the top margin is deep: it IS the heading band, and the band's height
|
|
64
|
+
// is the margin it covers rather than a second number beside it. Declared in
|
|
65
|
+
// `@labre/affine-model` because the frame's hit test reads it too.
|
|
66
|
+
margin: {
|
|
67
|
+
top: UML_FRAME_BAND_HEIGHT,
|
|
68
|
+
right: UML_DIAGRAM_MARGIN,
|
|
69
|
+
bottom: UML_DIAGRAM_MARGIN,
|
|
70
|
+
left: UML_DIAGRAM_MARGIN,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
chrome: {
|
|
74
|
+
fontFamily: UML_FONT_FAMILY,
|
|
75
|
+
palette: {
|
|
76
|
+
card: UML_CARD,
|
|
77
|
+
frame: UML_FRAME_INK,
|
|
78
|
+
},
|
|
79
|
+
surface: {
|
|
80
|
+
fill: '@card',
|
|
81
|
+
border: {
|
|
82
|
+
color: '@frame',
|
|
83
|
+
width: UML_FRAME_BORDER_WIDTH,
|
|
84
|
+
// Square: Annex A's frame is a plain rectangle, and a rounded one would
|
|
85
|
+
// read as a note or a card rather than as the sheet's own edge.
|
|
86
|
+
radius: 0,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
sideBands: [
|
|
90
|
+
{
|
|
91
|
+
// No `fill` and no `divider` — see the note above. The band is where the
|
|
92
|
+
// heading goes, and the tag drawn round it is what a reader sees.
|
|
93
|
+
side: 'top',
|
|
94
|
+
label: {
|
|
95
|
+
id: 'heading',
|
|
96
|
+
// The DERIVED `<kind> <name>`, so the frame says what it is before it
|
|
97
|
+
// says what it is called. The rename writes `name`; see the view.
|
|
98
|
+
prop: 'heading',
|
|
99
|
+
// `y: 0` is the top of the plot, i.e. the band's INNER edge; a
|
|
100
|
+
// negative `dy` walks back UP into the band, where the words go. A
|
|
101
|
+
// third of the band leaves the baseline low enough for the tag drawn
|
|
102
|
+
// round it to clear the descenders.
|
|
103
|
+
anchor: { x: 0, y: 0, dy: -UML_FRAME_BAND_HEIGHT / 3 },
|
|
104
|
+
style: {
|
|
105
|
+
size: UML_FRAME_HEADING_FONT_SIZE,
|
|
106
|
+
weight: 600,
|
|
107
|
+
color: '@frame',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
/* ── The subject ───────────────────────────────────────────────────────── */
|
|
115
|
+
/**
|
|
116
|
+
* The use case SUBJECT (§18.1.4): a plain rectangle with its name written inside
|
|
117
|
+
* the top-left corner, drawn round the use cases a system offers.
|
|
118
|
+
*
|
|
119
|
+
* TRANSPARENT, like the C4 boundary and for the same reason: it is drawn OVER a
|
|
120
|
+
* diagram, round elements that are already there, and an opaque card would hide
|
|
121
|
+
* the very thing it is pointing at. So it declares a border and no fill, which
|
|
122
|
+
* the primitive paints as an unfilled frame — and the consequence is the reverse
|
|
123
|
+
* of the usual one: a subject dropped over existing use cases does NOT cover
|
|
124
|
+
* them, and is hit nowhere but on its own frame band and its name.
|
|
125
|
+
*
|
|
126
|
+
* SOLID, unlike that boundary, and this is where the two notations part company:
|
|
127
|
+
* C4's stencil dashes its boundary, §18.1.4 draws one unbroken rectangle. A dash
|
|
128
|
+
* here would say "logical grouping" in a notation where a subject is a
|
|
129
|
+
* SYSTEM — the thing whose behaviour the use cases are, with the actors
|
|
130
|
+
* deliberately outside it.
|
|
131
|
+
*
|
|
132
|
+
* The name is written TOP-left rather than the boundary's bottom-left: that is
|
|
133
|
+
* where the specification's figures put it, and it is also the corner a use case
|
|
134
|
+
* ellipse is least likely to reach into, ellipses having no corners of their own.
|
|
135
|
+
*
|
|
136
|
+
* No variant and no second tier: §18.1.4 gives the subject one rectangle and one
|
|
137
|
+
* name — no dashed flavour, no keyword line — so there is nothing here for a
|
|
138
|
+
* variant to select between.
|
|
139
|
+
*/
|
|
140
|
+
export const UML_SUBJECT_FRAME = {
|
|
141
|
+
type: 'umlSubject',
|
|
142
|
+
role: UML_ROLE.subject,
|
|
143
|
+
geometry: {
|
|
144
|
+
width: UML_SUBJECT_BOX.w,
|
|
145
|
+
height: UML_SUBJECT_BOX.h,
|
|
146
|
+
// A subject is stretched round whatever it has been drawn about, which is
|
|
147
|
+
// never the same shape twice.
|
|
148
|
+
lockAspectRatio: false,
|
|
149
|
+
resizable: true,
|
|
150
|
+
margin: {
|
|
151
|
+
top: UML_SUBJECT_MARGIN,
|
|
152
|
+
right: UML_SUBJECT_MARGIN,
|
|
153
|
+
bottom: UML_SUBJECT_MARGIN,
|
|
154
|
+
left: UML_SUBJECT_MARGIN,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
zones: [
|
|
158
|
+
{
|
|
159
|
+
id: 'name',
|
|
160
|
+
rect: { x: 0, y: 0, w: 1, h: 1 },
|
|
161
|
+
label: {
|
|
162
|
+
id: 'name',
|
|
163
|
+
// The author's own words, and only those: a subject is named by whoever
|
|
164
|
+
// draws it, so there is no vocabulary to fall back to.
|
|
165
|
+
prop: 'name',
|
|
166
|
+
// Top-left INSIDE the plot. The anchor is a BASELINE, so `dy` is one
|
|
167
|
+
// line down from the plot's top edge — written at the size the name
|
|
168
|
+
// compartment of a classifier uses, because it is the same kind of word.
|
|
169
|
+
anchor: { x: 0, y: 0, dy: UML_NAME_FONT_SIZE },
|
|
170
|
+
style: {
|
|
171
|
+
size: UML_NAME_FONT_SIZE,
|
|
172
|
+
weight: 600,
|
|
173
|
+
color: '@frame',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
chrome: {
|
|
179
|
+
fontFamily: UML_FONT_FAMILY,
|
|
180
|
+
palette: {
|
|
181
|
+
frame: UML_FRAME_INK,
|
|
182
|
+
},
|
|
183
|
+
surface: {
|
|
184
|
+
// NO fill — see the note above. This is the transparent one.
|
|
185
|
+
border: {
|
|
186
|
+
color: '@frame',
|
|
187
|
+
width: UML_SUBJECT_BORDER_WIDTH,
|
|
188
|
+
radius: 0,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
/* ── The partition ─────────────────────────────────────────────────────── */
|
|
194
|
+
/**
|
|
195
|
+
* The activity PARTITION (§15.6.4): the swimlane drawn across an activity
|
|
196
|
+
* diagram saying who is responsible for the actions inside it.
|
|
197
|
+
*
|
|
198
|
+
* TRANSPARENT, like the subject and for exactly the same reason: it is drawn
|
|
199
|
+
* over a flow that is already there, and an opaque card would hide the very
|
|
200
|
+
* actions it is attributing. Membership is geometry at read time (R11) — an
|
|
201
|
+
* action belongs to the lane its centre is in.
|
|
202
|
+
*
|
|
203
|
+
* ## Two declarations rather than one with a variant
|
|
204
|
+
*
|
|
205
|
+
* `FrameworkBackgroundDef.variantProp` exists and would look like the answer,
|
|
206
|
+
* but it does not reach the two things an orientation has to change here. A
|
|
207
|
+
* variant selects which WASHES and which ZONES are painted (`BackgroundWashDef
|
|
208
|
+
* .variants`, `BackgroundZoneDef.variants`); a side band declares no variants
|
|
209
|
+
* at all, and the band's THICKNESS is the geometry's margin on that side, which
|
|
210
|
+
* is a single fixed inset per declaration. So a vertical lane and a horizontal
|
|
211
|
+
* one differ in two fields the variant mechanism cannot vary —
|
|
212
|
+
* `sideBands[0].side` and which of `margin.top` / `margin.left` is deep — and
|
|
213
|
+
* the honest way to say that is two declarations, picked in the renderer by the
|
|
214
|
+
* element's own `orientation`.
|
|
215
|
+
*
|
|
216
|
+
* The alternative — teaching `variants` to side bands and margins — is a change
|
|
217
|
+
* to the declaration LANGUAGE for one framework's convenience, and the language
|
|
218
|
+
* grows when a second framework asks (`BackgroundSideBandDef`'s own note on why
|
|
219
|
+
* it offers only `left` and `top`).
|
|
220
|
+
*
|
|
221
|
+
* ## The band is painted, unlike the diagram frame's
|
|
222
|
+
*
|
|
223
|
+
* The sheet's heading band paints nothing because Annex A draws a tag in the
|
|
224
|
+
* corner and no rule across the page. A swimlane's header is the opposite:
|
|
225
|
+
* §15.6.4 draws it as a titled strip ruled off from the lane below it, and that
|
|
226
|
+
* rule is what makes a column of actions read as belonging to somebody. So both
|
|
227
|
+
* declarations below carry a `divider` — the lighter of the two frame inks, so
|
|
228
|
+
* the strip reads as part of the same lane rather than as a second frame drawn
|
|
229
|
+
* inside the first. Still no `fill`: a tint would be a colour code UML does not
|
|
230
|
+
* have (R33), and it would tint whatever the lane is drawn over.
|
|
231
|
+
*/
|
|
232
|
+
function partitionFrame(side, margin) {
|
|
233
|
+
return {
|
|
234
|
+
type: 'umlPartition',
|
|
235
|
+
role: UML_ROLE.partition,
|
|
236
|
+
geometry: {
|
|
237
|
+
width: UML_PARTITION_BOX.w,
|
|
238
|
+
height: UML_PARTITION_BOX.h,
|
|
239
|
+
// A lane is stretched round whatever it has been drawn about, in
|
|
240
|
+
// whichever direction the flow runs.
|
|
241
|
+
lockAspectRatio: false,
|
|
242
|
+
resizable: true,
|
|
243
|
+
margin,
|
|
244
|
+
},
|
|
245
|
+
chrome: {
|
|
246
|
+
fontFamily: UML_FONT_FAMILY,
|
|
247
|
+
palette: {
|
|
248
|
+
frame: UML_FRAME_INK,
|
|
249
|
+
divider: UML_DIVIDER,
|
|
250
|
+
},
|
|
251
|
+
surface: {
|
|
252
|
+
// NO fill: see the header. This is a transparent frame.
|
|
253
|
+
border: {
|
|
254
|
+
color: '@frame',
|
|
255
|
+
width: UML_PARTITION_BORDER_WIDTH,
|
|
256
|
+
// Square: §15.6.4 draws a partition as a plain rectangle, and a
|
|
257
|
+
// rounded one would read as a composite state.
|
|
258
|
+
radius: 0,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
sideBands: [
|
|
262
|
+
{
|
|
263
|
+
side,
|
|
264
|
+
divider: { color: '@divider', width: UML_PARTITION_BORDER_WIDTH },
|
|
265
|
+
label: {
|
|
266
|
+
id: 'name',
|
|
267
|
+
// The author's own words: a lane is named after whoever owns it,
|
|
268
|
+
// so there is no vocabulary to fall back to.
|
|
269
|
+
prop: 'name',
|
|
270
|
+
// The plot's top-left corner is the band's INNER corner, so a
|
|
271
|
+
// negative delta walks back into the band, where the words go. A
|
|
272
|
+
// third of the band leaves the baseline clear of the descenders —
|
|
273
|
+
// the diagram frame's own arithmetic, on whichever edge the band
|
|
274
|
+
// is. The horizontal lane also needs a `dy`, because its anchor is
|
|
275
|
+
// a BASELINE and the plot's top is the top of the words.
|
|
276
|
+
anchor: side === 'top'
|
|
277
|
+
? { x: 0, y: 0, dy: -UML_PARTITION_BAND / 3 }
|
|
278
|
+
: {
|
|
279
|
+
x: 0,
|
|
280
|
+
y: 0,
|
|
281
|
+
dx: -UML_PARTITION_BAND + UML_PARTITION_BAND / 4,
|
|
282
|
+
dy: UML_NAME_FONT_SIZE,
|
|
283
|
+
},
|
|
284
|
+
style: {
|
|
285
|
+
size: UML_NAME_FONT_SIZE,
|
|
286
|
+
weight: 600,
|
|
287
|
+
color: '@frame',
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/** A VERTICAL partition — a column, its name written across the top. */
|
|
296
|
+
export const UML_PARTITION_FRAME_V = partitionFrame('top', {
|
|
297
|
+
top: UML_PARTITION_BAND,
|
|
298
|
+
right: UML_PARTITION_MARGIN,
|
|
299
|
+
bottom: UML_PARTITION_MARGIN,
|
|
300
|
+
left: UML_PARTITION_MARGIN,
|
|
301
|
+
});
|
|
302
|
+
/** A HORIZONTAL partition — a row, its name written down the left edge. */
|
|
303
|
+
export const UML_PARTITION_FRAME_H = partitionFrame('left', {
|
|
304
|
+
top: UML_PARTITION_MARGIN,
|
|
305
|
+
right: UML_PARTITION_MARGIN,
|
|
306
|
+
bottom: UML_PARTITION_MARGIN,
|
|
307
|
+
left: UML_PARTITION_BAND,
|
|
308
|
+
});
|
|
309
|
+
/**
|
|
310
|
+
* The declaration a partition element is painted and hit-tested by — the one
|
|
311
|
+
* place the `orientation` prop is turned into a picture.
|
|
312
|
+
*
|
|
313
|
+
* A function rather than a lookup repeated at each call site, so the renderer,
|
|
314
|
+
* the view and the band helpers cannot disagree about which of the two a lane
|
|
315
|
+
* is: all three ask this.
|
|
316
|
+
*
|
|
317
|
+
* An orientation this build has never heard of falls back to the VERTICAL
|
|
318
|
+
* declaration rather than painting nothing — the same promise
|
|
319
|
+
* `UmlDiagramElementModel.heading` makes about an unknown kind: a document
|
|
320
|
+
* written by a newer build still draws a lane.
|
|
321
|
+
*/
|
|
322
|
+
export function umlPartitionFrame(model) {
|
|
323
|
+
return model.orientation === 'horizontal'
|
|
324
|
+
? UML_PARTITION_FRAME_H
|
|
325
|
+
: UML_PARTITION_FRAME_V;
|
|
326
|
+
}
|
|
327
|
+
/* ── The composite state ───────────────────────────────────────────────── */
|
|
328
|
+
/**
|
|
329
|
+
* The COMPOSITE STATE (§14.2.4): the round-cornered rectangle drawn round the
|
|
330
|
+
* sub-states of a state that has a machine of its own inside it.
|
|
331
|
+
*
|
|
332
|
+
* Transparent, band on the top, and ROUNDED — which is the whole point of it.
|
|
333
|
+
* §14.2.4 draws every state with rounded corners, simple or composite, and a
|
|
334
|
+
* square frame round a sub-machine would read as a partition or as a subject.
|
|
335
|
+
* `surface.border.radius` is in MODEL UNITS here (the primitive draws the card
|
|
336
|
+
* in the units the element is), unlike the node preset's fractional `radius`,
|
|
337
|
+
* so the number comes from `UML_REGION_RADIUS` rather than from
|
|
338
|
+
* `UML_NODE_RADIUS`.
|
|
339
|
+
*
|
|
340
|
+
* ## One region, and the ceiling stated
|
|
341
|
+
*
|
|
342
|
+
* ORTHOGONAL regions — a composite state cut into concurrent regions by dashed
|
|
343
|
+
* separators (§14.2.4, Figure 14.8) — are not drawn. That is an INSTANCE
|
|
344
|
+
* PARTITION in the declaration language (`instanceZones`, the mechanism the
|
|
345
|
+
* BPMN pool's lanes use), and it arrives the day the notation is asked for
|
|
346
|
+
* rather than as a field added here in a hurry. See `UmlRegionElementModel`.
|
|
347
|
+
*/
|
|
348
|
+
export const UML_REGION_FRAME = {
|
|
349
|
+
type: 'umlRegion',
|
|
350
|
+
role: UML_ROLE.region,
|
|
351
|
+
geometry: {
|
|
352
|
+
width: UML_REGION_BOX.w,
|
|
353
|
+
height: UML_REGION_BOX.h,
|
|
354
|
+
lockAspectRatio: false,
|
|
355
|
+
resizable: true,
|
|
356
|
+
margin: {
|
|
357
|
+
top: UML_REGION_BAND,
|
|
358
|
+
right: UML_REGION_MARGIN,
|
|
359
|
+
bottom: UML_REGION_MARGIN,
|
|
360
|
+
left: UML_REGION_MARGIN,
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
chrome: {
|
|
364
|
+
fontFamily: UML_FONT_FAMILY,
|
|
365
|
+
palette: {
|
|
366
|
+
frame: UML_FRAME_INK,
|
|
367
|
+
divider: UML_DIVIDER,
|
|
368
|
+
},
|
|
369
|
+
surface: {
|
|
370
|
+
// NO fill: a composite state is drawn over the sub-machine it holds.
|
|
371
|
+
border: {
|
|
372
|
+
color: '@frame',
|
|
373
|
+
width: UML_REGION_BORDER_WIDTH,
|
|
374
|
+
radius: UML_REGION_RADIUS,
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
sideBands: [
|
|
378
|
+
{
|
|
379
|
+
side: 'top',
|
|
380
|
+
// The rule under the name is §14.2.4's own: a composite state's name
|
|
381
|
+
// compartment is ruled off from the region below it, exactly as a
|
|
382
|
+
// simple state's name is ruled off from its internal activities.
|
|
383
|
+
divider: { color: '@divider', width: UML_REGION_BORDER_WIDTH },
|
|
384
|
+
label: {
|
|
385
|
+
id: 'name',
|
|
386
|
+
prop: 'name',
|
|
387
|
+
anchor: { x: 0, y: 0, dy: -UML_REGION_BAND / 3 },
|
|
388
|
+
style: {
|
|
389
|
+
size: UML_NAME_FONT_SIZE,
|
|
390
|
+
weight: 600,
|
|
391
|
+
color: '@frame',
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
/* ── The combined fragment ─────────────────────────────────────────────── */
|
|
399
|
+
/**
|
|
400
|
+
* The COMBINED FRAGMENT (§17.6.4): the rectangle drawn round part of a
|
|
401
|
+
* conversation with `alt`, `loop` or `opt` in its corner — and, under the `ref`
|
|
402
|
+
* operator, §17.7.4's InteractionUse.
|
|
403
|
+
*
|
|
404
|
+
* TRANSPARENT, like the subject and the partition and for exactly the same
|
|
405
|
+
* reason: it is drawn over lifelines and messages that are already there, and
|
|
406
|
+
* an opaque card would hide the conversation it is qualifying. SOLID border,
|
|
407
|
+
* because §17.6.4 draws one unbroken rectangle — the only dashed lines in the
|
|
408
|
+
* picture are the ones BETWEEN the operands.
|
|
409
|
+
*
|
|
410
|
+
* ## The band paints nothing, like the diagram frame's
|
|
411
|
+
*
|
|
412
|
+
* And for the same reason: §17.6.4 draws the operator in Annex A's own
|
|
413
|
+
* cut-corner pentagon, and a rule ruled right across the fragment under it
|
|
414
|
+
* would be a line the notation does not have. The band exists to place the word
|
|
415
|
+
* and to reserve the top margin; what a reader sees is the pentagon, drawn by
|
|
416
|
+
* `withUmlFrameTag` over this declaration's own label — which is why the label
|
|
417
|
+
* binds `operator` and why the tag carries no words of its own.
|
|
418
|
+
*
|
|
419
|
+
* ## The guard, and the one contract the operands keep
|
|
420
|
+
*
|
|
421
|
+
* `name` is the guard of the fragment's FIRST operand — `[x > 0]`, `[else]` —
|
|
422
|
+
* or, under `ref`, the name of the interaction referred to. It is written in
|
|
423
|
+
* the plot's top-left corner, which is where §17.6.4 puts an operand's guard,
|
|
424
|
+
* and it is a declared ZONE label so the frame view's rename gesture reaches
|
|
425
|
+
* it exactly as it reaches the subject's name.
|
|
426
|
+
*
|
|
427
|
+
* Once the fragment is SPLIT, the guards live in `operands` and nowhere else:
|
|
428
|
+
* the instance-zone label below writes each operand's own, and the first of
|
|
429
|
+
* them occupies the very corner `name` is written in. The contract the "add
|
|
430
|
+
* operand" action keeps (`actions.ts`) is therefore that splitting a fragment
|
|
431
|
+
* MOVES `name` into `operands[0].name` and clears it — one guard, one place,
|
|
432
|
+
* and no corner with two strings in it.
|
|
433
|
+
*/
|
|
434
|
+
export const UML_FRAGMENT_FRAME = {
|
|
435
|
+
type: 'umlFragment',
|
|
436
|
+
role: UML_ROLE.fragment,
|
|
437
|
+
geometry: {
|
|
438
|
+
width: UML_FRAGMENT_BOX.w,
|
|
439
|
+
height: UML_FRAGMENT_BOX.h,
|
|
440
|
+
// Stretched round whatever part of the conversation it has been drawn
|
|
441
|
+
// about, which is never the same shape twice.
|
|
442
|
+
lockAspectRatio: false,
|
|
443
|
+
resizable: true,
|
|
444
|
+
// Only the top margin is deep: it IS the operator band, the diagram
|
|
445
|
+
// frame's own arrangement.
|
|
446
|
+
margin: {
|
|
447
|
+
top: UML_FRAGMENT_BAND,
|
|
448
|
+
right: UML_FRAGMENT_MARGIN,
|
|
449
|
+
bottom: UML_FRAGMENT_MARGIN,
|
|
450
|
+
left: UML_FRAGMENT_MARGIN,
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
zones: [
|
|
454
|
+
{
|
|
455
|
+
id: 'guard',
|
|
456
|
+
rect: { x: 0, y: 0, w: 1, h: 1 },
|
|
457
|
+
label: {
|
|
458
|
+
id: 'guard',
|
|
459
|
+
// The author's own words, and only those — there is no vocabulary to
|
|
460
|
+
// fall back to for a condition somebody has not written yet.
|
|
461
|
+
prop: 'name',
|
|
462
|
+
// Top-left INSIDE the plot, one line down: the anchor is a BASELINE,
|
|
463
|
+
// and §17.6.4 writes a guard in the operand's own corner.
|
|
464
|
+
anchor: {
|
|
465
|
+
x: 0,
|
|
466
|
+
y: 0,
|
|
467
|
+
dx: UML_FRAGMENT_GUARD_INSET,
|
|
468
|
+
dy: UML_FRAGMENT_GUARD_FONT_SIZE + UML_FRAGMENT_GUARD_INSET,
|
|
469
|
+
},
|
|
470
|
+
style: {
|
|
471
|
+
size: UML_FRAGMENT_GUARD_FONT_SIZE,
|
|
472
|
+
weight: 600,
|
|
473
|
+
color: '@frame',
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
],
|
|
478
|
+
/**
|
|
479
|
+
* The OPERANDS — the bands §17.6.4 cuts an `alt` or a `par` into, separated
|
|
480
|
+
* by dashed lines.
|
|
481
|
+
*
|
|
482
|
+
* The BPMN pool's lanes, to the letter: an instance partition on the
|
|
483
|
+
* declaration, weights rather than heights so a fragment dragged taller
|
|
484
|
+
* redistributes instead of leaving a gap, and the CORNER placement for the
|
|
485
|
+
* guard because that is where §17.6.4 writes one. A pool's lanes take the
|
|
486
|
+
* band placement instead, and the difference is the notation's: a lane name
|
|
487
|
+
* is a title written down a strip, an operand's guard is a condition written
|
|
488
|
+
* in a corner over the messages it governs.
|
|
489
|
+
*/
|
|
490
|
+
instanceZones: {
|
|
491
|
+
prop: 'operands',
|
|
492
|
+
// Horizontal bands, top to bottom in array order: time runs down a
|
|
493
|
+
// sequence diagram, and an operand is a stretch of it.
|
|
494
|
+
stack: 'y',
|
|
495
|
+
// A namespace, so an operand a user guards `else` can never shadow the
|
|
496
|
+
// declared `guard` zone above.
|
|
497
|
+
idPrefix: 'operand',
|
|
498
|
+
// DASHED, and the one dashed line in the fragment: §17.6.4 rules its
|
|
499
|
+
// operands off with a broken line precisely so the rectangle round them
|
|
500
|
+
// stays a single unbroken frame.
|
|
501
|
+
divider: {
|
|
502
|
+
color: '@divider',
|
|
503
|
+
width: UML_FRAGMENT_BORDER_WIDTH,
|
|
504
|
+
dash: [...UML_FRAGMENT_OPERAND_DASH],
|
|
505
|
+
},
|
|
506
|
+
label: {
|
|
507
|
+
// The corner placement — no `band`. See the note above.
|
|
508
|
+
dx: UML_FRAGMENT_GUARD_INSET,
|
|
509
|
+
dy: UML_FRAGMENT_GUARD_FONT_SIZE + UML_FRAGMENT_GUARD_INSET,
|
|
510
|
+
style: {
|
|
511
|
+
size: UML_FRAGMENT_GUARD_FONT_SIZE,
|
|
512
|
+
weight: 600,
|
|
513
|
+
color: '@frame',
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
chrome: {
|
|
518
|
+
fontFamily: UML_FONT_FAMILY,
|
|
519
|
+
palette: {
|
|
520
|
+
frame: UML_FRAME_INK,
|
|
521
|
+
divider: UML_DIVIDER,
|
|
522
|
+
},
|
|
523
|
+
surface: {
|
|
524
|
+
// NO fill — this is the transparent one.
|
|
525
|
+
border: {
|
|
526
|
+
color: '@frame',
|
|
527
|
+
width: UML_FRAGMENT_BORDER_WIDTH,
|
|
528
|
+
// Square: §17.6.4 draws a plain rectangle, and a rounded one would
|
|
529
|
+
// read as a composite state.
|
|
530
|
+
radius: 0,
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
sideBands: [
|
|
534
|
+
{
|
|
535
|
+
// No `fill` and no `divider`, exactly as the diagram frame's heading
|
|
536
|
+
// band declares none: what a reader sees is the pentagon.
|
|
537
|
+
side: 'top',
|
|
538
|
+
label: {
|
|
539
|
+
id: 'operator',
|
|
540
|
+
// The word itself — `alt`, `loop`, `ref`. NOT a derived heading: a
|
|
541
|
+
// fragment has one word in its tag, and the guard is written in the
|
|
542
|
+
// operand rather than beside the operator.
|
|
543
|
+
prop: 'operator',
|
|
544
|
+
// `y: 0` is the band's INNER edge; a negative `dy` walks back up into
|
|
545
|
+
// it. A third of the band clears the descenders, which is the
|
|
546
|
+
// diagram frame's own arithmetic.
|
|
547
|
+
anchor: { x: 0, y: 0, dy: -UML_FRAGMENT_BAND / 3 },
|
|
548
|
+
style: {
|
|
549
|
+
size: UML_FRAME_HEADING_FONT_SIZE,
|
|
550
|
+
weight: 600,
|
|
551
|
+
color: '@frame',
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
},
|
|
557
|
+
};
|