@formicoidea/labre-framework-bpmn 0.33.0 → 0.34.1
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/dist/actions.js +8 -2
- package/dist/commands-manifest.d.ts +18 -0
- package/dist/commands-manifest.js +226 -0
- package/dist/consts.d.ts +51 -14
- package/dist/consts.js +51 -14
- package/dist/element-view.d.ts +19 -0
- package/dist/element-view.js +25 -0
- package/dist/import.d.ts +25 -0
- package/dist/import.js +45 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -1
- package/dist/presets.d.ts +55 -1
- package/dist/presets.js +100 -5
- package/dist/toolbar/config.d.ts +2 -1
- package/dist/toolbar/config.js +8 -3
- package/dist/translations.js +32 -2
- package/package.json +6 -2
package/dist/actions.js
CHANGED
|
@@ -5,7 +5,7 @@ import { NotificationProvider, translateKey, } from '@formicoidea/labre-core/sha
|
|
|
5
5
|
import { downloadBlob } from '@formicoidea/labre-core/shared/utils';
|
|
6
6
|
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
7
7
|
import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
|
|
8
|
-
import { ASSOCIATION_STROKE, ASSOCIATION_WIDTH, MESSAGE_STROKE, MESSAGE_WIDTH, NODE_LABEL, NODE_SIZE, SEQUENCE_STROKE, SEQUENCE_WIDTH, } from './consts.js';
|
|
8
|
+
import { ASSOCIATION_STROKE, ASSOCIATION_WIDTH, MESSAGE_STROKE, MESSAGE_WIDTH, NODE_LABEL, nodeLabelKey, NODE_SIZE, SEQUENCE_STROKE, SEQUENCE_WIDTH, } from './consts.js';
|
|
9
9
|
import { BPMN_FORMAT_ID } from './export.js';
|
|
10
10
|
import { BPMN_SVG_IMPORT, BPMN_XML_EXPORT, BPMN_XML_FORMAT, BPMN_XML_IMPORT, bpmnBoardFrom, bpmnSafeFilename, } from './interchange.js';
|
|
11
11
|
import { bpmnNodeProps } from './presets.js';
|
|
@@ -37,7 +37,13 @@ export function createBpmnNode(std, kind) {
|
|
|
37
37
|
// nothing else.
|
|
38
38
|
const id = surface.addElement(bpmnNodeProps(kind, {
|
|
39
39
|
xywh: new Bound(cx - w / 2, cy - h / 2, w, h).serialize(),
|
|
40
|
-
|
|
40
|
+
// Translated HERE and once: the caption is document content the moment
|
|
41
|
+
// it lands, so the host's catalogue is asked at placement and never
|
|
42
|
+
// again (`nodeLabelKey`, and #183 on why a French board should not
|
|
43
|
+
// start in English).
|
|
44
|
+
text: NODE_LABEL[kind]
|
|
45
|
+
? translateKey(std, nodeLabelKey(kind), NODE_LABEL[kind])
|
|
46
|
+
: undefined,
|
|
41
47
|
}));
|
|
42
48
|
finish(gfx, id);
|
|
43
49
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ShortcutManifestEntry } from '@formicoidea/labre-core/std';
|
|
2
|
+
/**
|
|
3
|
+
* The BPMN commands as SHORTCUT-MANIFEST rows — id, label, chord, scope,
|
|
4
|
+
* owner — and nothing else.
|
|
5
|
+
*
|
|
6
|
+
* DATA ONLY, and that is the whole point (`docs/adr/0008` § Packaging). A
|
|
7
|
+
* `CommandDescriptor` carries its `run`, so a host settings pane that imports
|
|
8
|
+
* the package entry to list names and chords drags the entire action graph —
|
|
9
|
+
* the import/export machinery, the surface and gfx deep paths — into its
|
|
10
|
+
* chunk. This module has type-only imports, so the published bundle exposes it
|
|
11
|
+
* as `./commands-manifest`: a few hundred bytes that reference nothing.
|
|
12
|
+
*
|
|
13
|
+
* GENERATED-SHAPED, hand-committed: `commands-manifest.unit.spec.ts` asserts
|
|
14
|
+
* row-for-row equality with `toShortcutManifestEntry` over {@link bpmnCommands},
|
|
15
|
+
* so this file cannot drift from the commands it projects. Add a command and
|
|
16
|
+
* the test says exactly what to add here.
|
|
17
|
+
*/
|
|
18
|
+
export declare const bpmnCommandsManifest: ShortcutManifestEntry[];
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The BPMN commands as SHORTCUT-MANIFEST rows — id, label, chord, scope,
|
|
3
|
+
* owner — and nothing else.
|
|
4
|
+
*
|
|
5
|
+
* DATA ONLY, and that is the whole point (`docs/adr/0008` § Packaging). A
|
|
6
|
+
* `CommandDescriptor` carries its `run`, so a host settings pane that imports
|
|
7
|
+
* the package entry to list names and chords drags the entire action graph —
|
|
8
|
+
* the import/export machinery, the surface and gfx deep paths — into its
|
|
9
|
+
* chunk. This module has type-only imports, so the published bundle exposes it
|
|
10
|
+
* as `./commands-manifest`: a few hundred bytes that reference nothing.
|
|
11
|
+
*
|
|
12
|
+
* GENERATED-SHAPED, hand-committed: `commands-manifest.unit.spec.ts` asserts
|
|
13
|
+
* row-for-row equality with `toShortcutManifestEntry` over {@link bpmnCommands},
|
|
14
|
+
* so this file cannot drift from the commands it projects. Add a command and
|
|
15
|
+
* the test says exactly what to add here.
|
|
16
|
+
*/
|
|
17
|
+
export const bpmnCommandsManifest = [
|
|
18
|
+
{
|
|
19
|
+
id: 'bpmn.addStartEvent',
|
|
20
|
+
owner: 'bpmn',
|
|
21
|
+
labelKey: 'com.labre.commands.bpmn.addStartEvent',
|
|
22
|
+
labelFallback: 'Start event',
|
|
23
|
+
scope: 'edgeless',
|
|
24
|
+
defaultKeys: { mac: [], other: [] },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'bpmn.addEndEvent',
|
|
28
|
+
owner: 'bpmn',
|
|
29
|
+
labelKey: 'com.labre.commands.bpmn.addEndEvent',
|
|
30
|
+
labelFallback: 'End event',
|
|
31
|
+
scope: 'edgeless',
|
|
32
|
+
defaultKeys: { mac: [], other: [] },
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'bpmn.addTask',
|
|
36
|
+
owner: 'bpmn',
|
|
37
|
+
labelKey: 'com.labre.commands.bpmn.addTask',
|
|
38
|
+
labelFallback: 'Task',
|
|
39
|
+
scope: 'edgeless',
|
|
40
|
+
defaultKeys: { mac: [], other: [] },
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'bpmn.addExclusiveGateway',
|
|
44
|
+
owner: 'bpmn',
|
|
45
|
+
labelKey: 'com.labre.commands.bpmn.addExclusiveGateway',
|
|
46
|
+
labelFallback: 'Exclusive gateway',
|
|
47
|
+
scope: 'edgeless',
|
|
48
|
+
defaultKeys: { mac: [], other: [] },
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'bpmn.sequenceFlowTool',
|
|
52
|
+
owner: 'bpmn',
|
|
53
|
+
labelKey: 'com.labre.commands.bpmn.sequenceFlowTool',
|
|
54
|
+
labelFallback: 'Sequence flow',
|
|
55
|
+
scope: 'edgeless',
|
|
56
|
+
defaultKeys: { mac: [], other: [] },
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'bpmn.addPool',
|
|
60
|
+
owner: 'bpmn',
|
|
61
|
+
labelKey: 'com.labre.commands.bpmn.addPool',
|
|
62
|
+
labelFallback: 'Pool',
|
|
63
|
+
scope: 'edgeless',
|
|
64
|
+
defaultKeys: { mac: [], other: [] },
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'bpmn.messageFlowTool',
|
|
68
|
+
owner: 'bpmn',
|
|
69
|
+
labelKey: 'com.labre.commands.bpmn.messageFlowTool',
|
|
70
|
+
labelFallback: 'Message flow',
|
|
71
|
+
scope: 'edgeless',
|
|
72
|
+
defaultKeys: { mac: [], other: [] },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'bpmn.addUserTask',
|
|
76
|
+
owner: 'bpmn',
|
|
77
|
+
labelKey: 'com.labre.commands.bpmn.addUserTask',
|
|
78
|
+
labelFallback: 'User task',
|
|
79
|
+
scope: 'edgeless',
|
|
80
|
+
defaultKeys: { mac: [], other: [] },
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'bpmn.addServiceTask',
|
|
84
|
+
owner: 'bpmn',
|
|
85
|
+
labelKey: 'com.labre.commands.bpmn.addServiceTask',
|
|
86
|
+
labelFallback: 'Service task',
|
|
87
|
+
scope: 'edgeless',
|
|
88
|
+
defaultKeys: { mac: [], other: [] },
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'bpmn.addSubProcess',
|
|
92
|
+
owner: 'bpmn',
|
|
93
|
+
labelKey: 'com.labre.commands.bpmn.addSubProcess',
|
|
94
|
+
labelFallback: 'Sub-process',
|
|
95
|
+
scope: 'edgeless',
|
|
96
|
+
defaultKeys: { mac: [], other: [] },
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'bpmn.addCallActivity',
|
|
100
|
+
owner: 'bpmn',
|
|
101
|
+
labelKey: 'com.labre.commands.bpmn.addCallActivity',
|
|
102
|
+
labelFallback: 'Call activity',
|
|
103
|
+
scope: 'edgeless',
|
|
104
|
+
defaultKeys: { mac: [], other: [] },
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 'bpmn.addParallelGateway',
|
|
108
|
+
owner: 'bpmn',
|
|
109
|
+
labelKey: 'com.labre.commands.bpmn.addParallelGateway',
|
|
110
|
+
labelFallback: 'Parallel gateway',
|
|
111
|
+
scope: 'edgeless',
|
|
112
|
+
defaultKeys: { mac: [], other: [] },
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'bpmn.addMessageStartEvent',
|
|
116
|
+
owner: 'bpmn',
|
|
117
|
+
labelKey: 'com.labre.commands.bpmn.addMessageStartEvent',
|
|
118
|
+
labelFallback: 'Message start event',
|
|
119
|
+
scope: 'edgeless',
|
|
120
|
+
defaultKeys: { mac: [], other: [] },
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'bpmn.addTimerStartEvent',
|
|
124
|
+
owner: 'bpmn',
|
|
125
|
+
labelKey: 'com.labre.commands.bpmn.addTimerStartEvent',
|
|
126
|
+
labelFallback: 'Timer start event',
|
|
127
|
+
scope: 'edgeless',
|
|
128
|
+
defaultKeys: { mac: [], other: [] },
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'bpmn.addMessageEndEvent',
|
|
132
|
+
owner: 'bpmn',
|
|
133
|
+
labelKey: 'com.labre.commands.bpmn.addMessageEndEvent',
|
|
134
|
+
labelFallback: 'Message end event',
|
|
135
|
+
scope: 'edgeless',
|
|
136
|
+
defaultKeys: { mac: [], other: [] },
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: 'bpmn.addTerminateEndEvent',
|
|
140
|
+
owner: 'bpmn',
|
|
141
|
+
labelKey: 'com.labre.commands.bpmn.addTerminateEndEvent',
|
|
142
|
+
labelFallback: 'Terminate end event',
|
|
143
|
+
scope: 'edgeless',
|
|
144
|
+
defaultKeys: { mac: [], other: [] },
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'bpmn.associationTool',
|
|
148
|
+
owner: 'bpmn',
|
|
149
|
+
labelKey: 'com.labre.commands.bpmn.associationTool',
|
|
150
|
+
labelFallback: 'Association',
|
|
151
|
+
scope: 'edgeless',
|
|
152
|
+
defaultKeys: { mac: [], other: [] },
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: 'bpmn.addDataObject',
|
|
156
|
+
owner: 'bpmn',
|
|
157
|
+
labelKey: 'com.labre.commands.bpmn.addDataObject',
|
|
158
|
+
labelFallback: 'Data object',
|
|
159
|
+
scope: 'edgeless',
|
|
160
|
+
defaultKeys: { mac: [], other: [] },
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: 'bpmn.addDataStore',
|
|
164
|
+
owner: 'bpmn',
|
|
165
|
+
labelKey: 'com.labre.commands.bpmn.addDataStore',
|
|
166
|
+
labelFallback: 'Data store',
|
|
167
|
+
scope: 'edgeless',
|
|
168
|
+
defaultKeys: { mac: [], other: [] },
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'bpmn.addTextAnnotation',
|
|
172
|
+
owner: 'bpmn',
|
|
173
|
+
labelKey: 'com.labre.commands.bpmn.addTextAnnotation',
|
|
174
|
+
labelFallback: 'Text annotation',
|
|
175
|
+
scope: 'edgeless',
|
|
176
|
+
defaultKeys: { mac: [], other: [] },
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: 'bpmn.addGroup',
|
|
180
|
+
owner: 'bpmn',
|
|
181
|
+
labelKey: 'com.labre.commands.bpmn.addGroup',
|
|
182
|
+
labelFallback: 'Group',
|
|
183
|
+
scope: 'edgeless',
|
|
184
|
+
defaultKeys: { mac: [], other: [] },
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: 'bpmn.addLane',
|
|
188
|
+
owner: 'bpmn',
|
|
189
|
+
labelKey: 'com.labre.commands.bpmn.addLane',
|
|
190
|
+
labelFallback: 'Add lane',
|
|
191
|
+
scope: 'edgeless',
|
|
192
|
+
defaultKeys: { mac: [], other: [] },
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: 'bpmn.removeLane',
|
|
196
|
+
owner: 'bpmn',
|
|
197
|
+
labelKey: 'com.labre.commands.bpmn.removeLane',
|
|
198
|
+
labelFallback: 'Remove lane',
|
|
199
|
+
scope: 'edgeless',
|
|
200
|
+
defaultKeys: { mac: [], other: [] },
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: 'bpmn.exportXml',
|
|
204
|
+
owner: 'bpmn',
|
|
205
|
+
labelKey: 'com.labre.commands.bpmn.exportXml',
|
|
206
|
+
labelFallback: 'Export BPMN XML',
|
|
207
|
+
scope: 'edgeless',
|
|
208
|
+
defaultKeys: { mac: [], other: [] },
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: 'bpmn.importXml',
|
|
212
|
+
owner: 'bpmn',
|
|
213
|
+
labelKey: 'com.labre.commands.bpmn.importXml',
|
|
214
|
+
labelFallback: 'Import BPMN XML',
|
|
215
|
+
scope: 'edgeless',
|
|
216
|
+
defaultKeys: { mac: [], other: [] },
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: 'bpmn.importSvg',
|
|
220
|
+
owner: 'bpmn',
|
|
221
|
+
labelKey: 'com.labre.commands.bpmn.importSvg',
|
|
222
|
+
labelFallback: 'Import SVG sketch',
|
|
223
|
+
scope: 'edgeless',
|
|
224
|
+
defaultKeys: { mac: [], other: [] },
|
|
225
|
+
},
|
|
226
|
+
];
|
package/dist/consts.d.ts
CHANGED
|
@@ -45,6 +45,38 @@ export declare const GROUP_RADIUS = 20;
|
|
|
45
45
|
export declare const GROUP_STROKE = "#8e8d91";
|
|
46
46
|
/** Inner-text font for the task label. */
|
|
47
47
|
export declare const INNER_FONT_SIZE = 18;
|
|
48
|
+
/**
|
|
49
|
+
* The smallest font a FITTED label is asked for — the importer's floor, and
|
|
50
|
+
* only its (`bpmnLabelFit` in `presets.ts`).
|
|
51
|
+
*
|
|
52
|
+
* A file draws its artefacts at whatever scale its author's tool uses, and
|
|
53
|
+
* bpmn.io's normative sizes are about six tenths of this pack's: a 36-unit
|
|
54
|
+
* event against a 56-unit one, a 100×72 task against a 120×72. The label of an
|
|
55
|
+
* imported artefact is therefore asked for at a size proportional to the box
|
|
56
|
+
* the FILE gave, and 10 is where that shrinking stops — under it a label is no
|
|
57
|
+
* longer read, it is guessed at.
|
|
58
|
+
*
|
|
59
|
+
* It is a floor on what is ASKED for, not on what is painted: the shape
|
|
60
|
+
* renderer's own `TextFitMode.Contained` pass shrinks further, to its own floor
|
|
61
|
+
* of 8 (`MIN_CONTAINED_FONT_SIZE`), when even this does not fit. Kept here as a
|
|
62
|
+
* number of our own rather than imported from `@labre/affine-gfx-shape`, so the
|
|
63
|
+
* reader stays a pure function of a string with no renderer behind it (ADR
|
|
64
|
+
* 0012, P3).
|
|
65
|
+
*/
|
|
66
|
+
export declare const LABEL_MIN_FONT_SIZE = 10;
|
|
67
|
+
/**
|
|
68
|
+
* How much of a box a fitted label gives up to its margin, per side.
|
|
69
|
+
*
|
|
70
|
+
* A shape's native inset is a FIXED 20 units horizontally
|
|
71
|
+
* (`SHAPE_TEXT_PADDING`), which is a sixth of this pack's 120-unit task and
|
|
72
|
+
* therefore invisible on a drawn board — and more than the whole width of a
|
|
73
|
+
* 36-unit event, which leaves NEGATIVE room for the text and is why an imported
|
|
74
|
+
* label breaks in the middle of a word. Expressed as a ratio, the margin
|
|
75
|
+
* follows the artefact down: it is exactly the native inset at the pack's own
|
|
76
|
+
* task width and it never grows past it, so a drawn node is untouched and a
|
|
77
|
+
* small one keeps a usable line.
|
|
78
|
+
*/
|
|
79
|
+
export declare const LABEL_INSET_RATIO: number;
|
|
48
80
|
/**
|
|
49
81
|
* Default node sizes (model units) per kind.
|
|
50
82
|
*
|
|
@@ -83,13 +115,25 @@ export declare const NODE_SIZE: Record<BpmnNodeKind, {
|
|
|
83
115
|
* go inside it, and inside is where the folded page and the cylinder already
|
|
84
116
|
* are. The user can still type — the text simply overflows, which is the
|
|
85
117
|
* honest failure rather than a label painted over the glyph.
|
|
118
|
+
*
|
|
119
|
+
* The caption is asked of the host's catalogue under {@link nodeLabelKey} when
|
|
120
|
+
* the artefact is placed, with the entry below as the English default.
|
|
86
121
|
*/
|
|
87
122
|
export declare const NODE_LABEL: Record<BpmnNodeKind, string>;
|
|
123
|
+
/**
|
|
124
|
+
* The i18n key {@link NODE_LABEL} is the English default of.
|
|
125
|
+
*
|
|
126
|
+
* Resolved AT PLACEMENT (`createBpmnNode`) and never afterwards: what a gesture
|
|
127
|
+
* writes into the document is content the author owns from that moment on, and
|
|
128
|
+
* a renderer that re-translated it on every paint would silently overwrite a
|
|
129
|
+
* name somebody typed. The kinds with an empty label ask for nothing — there is
|
|
130
|
+
* no word to translate, and BPMN puts an event's name outside its glyph anyway.
|
|
131
|
+
*/
|
|
132
|
+
export declare const nodeLabelKey: (kind: BpmnNodeKind) => string;
|
|
88
133
|
/**
|
|
89
134
|
* Pool (background container) defaults — read by the `BPMN_POOL_BACKGROUND`
|
|
90
135
|
* declaration (`background.ts`), which is the only thing that draws a pool.
|
|
91
136
|
*/
|
|
92
|
-
export declare const POOL_BAND_WIDTH = 28;
|
|
93
137
|
export declare const POOL_FRAME_COLOR = "#262626";
|
|
94
138
|
/**
|
|
95
139
|
* The card. The same white every framework background paints — it is what
|
|
@@ -113,20 +157,13 @@ export declare const POOL_FONT_FAMILY = "Inter, sans-serif";
|
|
|
113
157
|
*/
|
|
114
158
|
export declare const POOL_LANE_NAME_FONT_SIZE = 13;
|
|
115
159
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* subordinate one has to say so. Identical widths read as a single 56-unit
|
|
122
|
-
* gutter rather than as a participant containing lanes, which is exactly the
|
|
123
|
-
* relationship the picture has to carry.
|
|
124
|
-
*
|
|
125
|
-
* NO fill, divider only — what bpmn.io, Camunda and Visio all draw. A second
|
|
126
|
-
* grey strip beside the pool's own would double the furniture and leave the
|
|
127
|
-
* flow area looking inset by two margins.
|
|
160
|
+
* The two band widths live in `@labre/affine-model`, beside the pool model that
|
|
161
|
+
* hit-tests against them (a pool is clickable by its title bands as well as by
|
|
162
|
+
* its border — the bpmn.io convention, issue #194). They are re-exported here
|
|
163
|
+
* so this file stays the one place a reader looks for a pool's metrics, and so
|
|
164
|
+
* the declaration keeps reading them from where it always did.
|
|
128
165
|
*/
|
|
129
|
-
export
|
|
166
|
+
export { POOL_BAND_WIDTH, POOL_LANE_BAND_WIDTH } from '@formicoidea/labre-core/model';
|
|
130
167
|
/**
|
|
131
168
|
* How close to an internal lane boundary a pointer has to be, in MODEL units,
|
|
132
169
|
* for the gesture to be a separator drag rather than a click on the pool.
|
package/dist/consts.js
CHANGED
|
@@ -44,6 +44,38 @@ export const GROUP_RADIUS = 20;
|
|
|
44
44
|
export const GROUP_STROKE = '#8e8d91';
|
|
45
45
|
/** Inner-text font for the task label. */
|
|
46
46
|
export const INNER_FONT_SIZE = 18;
|
|
47
|
+
/**
|
|
48
|
+
* The smallest font a FITTED label is asked for — the importer's floor, and
|
|
49
|
+
* only its (`bpmnLabelFit` in `presets.ts`).
|
|
50
|
+
*
|
|
51
|
+
* A file draws its artefacts at whatever scale its author's tool uses, and
|
|
52
|
+
* bpmn.io's normative sizes are about six tenths of this pack's: a 36-unit
|
|
53
|
+
* event against a 56-unit one, a 100×72 task against a 120×72. The label of an
|
|
54
|
+
* imported artefact is therefore asked for at a size proportional to the box
|
|
55
|
+
* the FILE gave, and 10 is where that shrinking stops — under it a label is no
|
|
56
|
+
* longer read, it is guessed at.
|
|
57
|
+
*
|
|
58
|
+
* It is a floor on what is ASKED for, not on what is painted: the shape
|
|
59
|
+
* renderer's own `TextFitMode.Contained` pass shrinks further, to its own floor
|
|
60
|
+
* of 8 (`MIN_CONTAINED_FONT_SIZE`), when even this does not fit. Kept here as a
|
|
61
|
+
* number of our own rather than imported from `@labre/affine-gfx-shape`, so the
|
|
62
|
+
* reader stays a pure function of a string with no renderer behind it (ADR
|
|
63
|
+
* 0012, P3).
|
|
64
|
+
*/
|
|
65
|
+
export const LABEL_MIN_FONT_SIZE = 10;
|
|
66
|
+
/**
|
|
67
|
+
* How much of a box a fitted label gives up to its margin, per side.
|
|
68
|
+
*
|
|
69
|
+
* A shape's native inset is a FIXED 20 units horizontally
|
|
70
|
+
* (`SHAPE_TEXT_PADDING`), which is a sixth of this pack's 120-unit task and
|
|
71
|
+
* therefore invisible on a drawn board — and more than the whole width of a
|
|
72
|
+
* 36-unit event, which leaves NEGATIVE room for the text and is why an imported
|
|
73
|
+
* label breaks in the middle of a word. Expressed as a ratio, the margin
|
|
74
|
+
* follows the artefact down: it is exactly the native inset at the pack's own
|
|
75
|
+
* task width and it never grows past it, so a drawn node is untouched and a
|
|
76
|
+
* small one keeps a usable line.
|
|
77
|
+
*/
|
|
78
|
+
export const LABEL_INSET_RATIO = 1 / 6;
|
|
47
79
|
/**
|
|
48
80
|
* Default node sizes (model units) per kind.
|
|
49
81
|
*
|
|
@@ -97,6 +129,9 @@ export const NODE_SIZE = {
|
|
|
97
129
|
* go inside it, and inside is where the folded page and the cylinder already
|
|
98
130
|
* are. The user can still type — the text simply overflows, which is the
|
|
99
131
|
* honest failure rather than a label painted over the glyph.
|
|
132
|
+
*
|
|
133
|
+
* The caption is asked of the host's catalogue under {@link nodeLabelKey} when
|
|
134
|
+
* the artefact is placed, with the entry below as the English default.
|
|
100
135
|
*/
|
|
101
136
|
export const NODE_LABEL = {
|
|
102
137
|
startEvent: '',
|
|
@@ -121,11 +156,20 @@ export const NODE_LABEL = {
|
|
|
121
156
|
// centred so it does not float over whatever the group encloses.
|
|
122
157
|
group: 'Group',
|
|
123
158
|
};
|
|
159
|
+
/**
|
|
160
|
+
* The i18n key {@link NODE_LABEL} is the English default of.
|
|
161
|
+
*
|
|
162
|
+
* Resolved AT PLACEMENT (`createBpmnNode`) and never afterwards: what a gesture
|
|
163
|
+
* writes into the document is content the author owns from that moment on, and
|
|
164
|
+
* a renderer that re-translated it on every paint would silently overwrite a
|
|
165
|
+
* name somebody typed. The kinds with an empty label ask for nothing — there is
|
|
166
|
+
* no word to translate, and BPMN puts an event's name outside its glyph anyway.
|
|
167
|
+
*/
|
|
168
|
+
export const nodeLabelKey = (kind) => `com.labre.bpmn.seed.${kind}`;
|
|
124
169
|
/**
|
|
125
170
|
* Pool (background container) defaults — read by the `BPMN_POOL_BACKGROUND`
|
|
126
171
|
* declaration (`background.ts`), which is the only thing that draws a pool.
|
|
127
172
|
*/
|
|
128
|
-
export const POOL_BAND_WIDTH = 28;
|
|
129
173
|
export const POOL_FRAME_COLOR = '#262626';
|
|
130
174
|
/**
|
|
131
175
|
* The card. The same white every framework background paints — it is what
|
|
@@ -149,20 +193,13 @@ export const POOL_FONT_FAMILY = 'Inter, sans-serif';
|
|
|
149
193
|
*/
|
|
150
194
|
export const POOL_LANE_NAME_FONT_SIZE = 13;
|
|
151
195
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* subordinate one has to say so. Identical widths read as a single 56-unit
|
|
158
|
-
* gutter rather than as a participant containing lanes, which is exactly the
|
|
159
|
-
* relationship the picture has to carry.
|
|
160
|
-
*
|
|
161
|
-
* NO fill, divider only — what bpmn.io, Camunda and Visio all draw. A second
|
|
162
|
-
* grey strip beside the pool's own would double the furniture and leave the
|
|
163
|
-
* flow area looking inset by two margins.
|
|
196
|
+
* The two band widths live in `@labre/affine-model`, beside the pool model that
|
|
197
|
+
* hit-tests against them (a pool is clickable by its title bands as well as by
|
|
198
|
+
* its border — the bpmn.io convention, issue #194). They are re-exported here
|
|
199
|
+
* so this file stays the one place a reader looks for a pool's metrics, and so
|
|
200
|
+
* the declaration keeps reading them from where it always did.
|
|
164
201
|
*/
|
|
165
|
-
export
|
|
202
|
+
export { POOL_BAND_WIDTH, POOL_LANE_BAND_WIDTH } from '@formicoidea/labre-core/model';
|
|
166
203
|
/**
|
|
167
204
|
* How close to an internal lane boundary a pointer has to be, in MODEL units,
|
|
168
205
|
* for the gesture to be a separator drag rather than a click on the pool.
|
package/dist/element-view.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { BpmnPoolElementModel } from '@formicoidea/labre-core/model';
|
|
2
|
+
import type { EditorHost } from '@formicoidea/labre-core/std';
|
|
3
|
+
import type { PointTestOptions } from '@formicoidea/labre-core/std/gfx';
|
|
2
4
|
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
3
5
|
/**
|
|
4
6
|
* View for a BPMN pool. Three direct gestures live here:
|
|
@@ -80,6 +82,23 @@ export declare class BpmnPoolView extends GfxElementModelView<BpmnPoolElementMod
|
|
|
80
82
|
/** Which name this point aims at, if any — lane strip first, see `pool-hit`. */
|
|
81
83
|
private _targetAt;
|
|
82
84
|
private get _editable();
|
|
85
|
+
/**
|
|
86
|
+
* A pool is SELECTED by its border and its painted title bands
|
|
87
|
+
* (`BpmnPoolElementModel.includesPoint`) — but two of this view's gestures
|
|
88
|
+
* live elsewhere on it and must still receive their pointer events:
|
|
89
|
+
*
|
|
90
|
+
* - the internal LANE SEPARATORS, twelve-unit strips in the middle of the
|
|
91
|
+
* flow area, which arm the drag that moves them;
|
|
92
|
+
* - the zoom-GROWN rename targets, which reach past the painted bands when
|
|
93
|
+
* the board is small on screen so a fingertip can still land on one.
|
|
94
|
+
*
|
|
95
|
+
* Neither is a selection zone — a click in the flow area still goes to
|
|
96
|
+
* whatever the user dropped there, because picking asks the MODEL. This
|
|
97
|
+
* override only decides where the pool's own gestures are heard, which is why
|
|
98
|
+
* it is declared here, beside the code that draws and handles them, rather
|
|
99
|
+
* than in `affine-model` where none of this geometry is reachable.
|
|
100
|
+
*/
|
|
101
|
+
includesPoint(x: number, y: number, options: PointTestOptions, host: EditorHost): boolean;
|
|
83
102
|
/**
|
|
84
103
|
* One pass over the pointer, deciding both the cursor and whether a
|
|
85
104
|
* separator drag is armed.
|
package/dist/element-view.js
CHANGED
|
@@ -113,6 +113,31 @@ export class BpmnPoolView extends GfxElementModelView {
|
|
|
113
113
|
get _editable() {
|
|
114
114
|
return !this.gfx.std.store.readonly && !this.model.isLocked();
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* A pool is SELECTED by its border and its painted title bands
|
|
118
|
+
* (`BpmnPoolElementModel.includesPoint`) — but two of this view's gestures
|
|
119
|
+
* live elsewhere on it and must still receive their pointer events:
|
|
120
|
+
*
|
|
121
|
+
* - the internal LANE SEPARATORS, twelve-unit strips in the middle of the
|
|
122
|
+
* flow area, which arm the drag that moves them;
|
|
123
|
+
* - the zoom-GROWN rename targets, which reach past the painted bands when
|
|
124
|
+
* the board is small on screen so a fingertip can still land on one.
|
|
125
|
+
*
|
|
126
|
+
* Neither is a selection zone — a click in the flow area still goes to
|
|
127
|
+
* whatever the user dropped there, because picking asks the MODEL. This
|
|
128
|
+
* override only decides where the pool's own gestures are heard, which is why
|
|
129
|
+
* it is declared here, beside the code that draws and handles them, rather
|
|
130
|
+
* than in `affine-model` where none of this geometry is reachable.
|
|
131
|
+
*/
|
|
132
|
+
includesPoint(x, y, options, host) {
|
|
133
|
+
if (super.includesPoint(x, y, options, host))
|
|
134
|
+
return true;
|
|
135
|
+
// Element-local by subtraction, like every other box in this view — see the
|
|
136
|
+
// rotation reserve in the class comment.
|
|
137
|
+
const [ex, ey] = this.model.deserializedXYWH;
|
|
138
|
+
const local = [x - ex, y - ey];
|
|
139
|
+
return this._boundaryAt(local) !== null || this._targetAt(local) !== null;
|
|
140
|
+
}
|
|
116
141
|
/* ── Hover: what this point would do ───────────────────────────────── */
|
|
117
142
|
/**
|
|
118
143
|
* One pass over the pointer, deciding both the cursor and whether a
|
package/dist/import.d.ts
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
import type { InterchangeImportContext, InterchangeImportResult } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
3
3
|
import { BPMN_SCOPE } from './export.js';
|
|
4
|
+
/**
|
|
5
|
+
* The remarks whose wording is FIXED, as `[key, English]` pairs.
|
|
6
|
+
*
|
|
7
|
+
* A reader is a pure function of text (`docs/adr/0012`, P3) and has no `std`,
|
|
8
|
+
* so it cannot ask the host's catalogue for anything: it declares the key on
|
|
9
|
+
* the note and `reportInterchangeImport` resolves it when it draws the report
|
|
10
|
+
* (`InterchangeNote.messageKey`). The English string stays here and stays the
|
|
11
|
+
* fallback, so the console table and a playground with no catalogue read
|
|
12
|
+
* exactly what they read before.
|
|
13
|
+
*
|
|
14
|
+
* These three and no others, and the line is not arbitrary: every remaining
|
|
15
|
+
* remark NAMES something out of the file — `<boundaryEvent>`, an id, a count of
|
|
16
|
+
* lanes — and the seam has neither interpolation nor pluralisation. A key for
|
|
17
|
+
* one of those would be a sentence with holes in it that a translator cannot
|
|
18
|
+
* see the shape of, which is the same refusal the interchange count labels
|
|
19
|
+
* already make (`interchange-import.ts`).
|
|
20
|
+
*
|
|
21
|
+
* They are contributed to the manifest by `./translations.ts`, with the
|
|
22
|
+
* framework, because they ship in the BPMN bundle rather than in core.
|
|
23
|
+
*/
|
|
24
|
+
export declare const BPMN_IMPORT_REMARKS: {
|
|
25
|
+
readonly inventedPool: readonly ["com.labre.bpmn.import.remark.invented-pool", "This file names no participant, so its process was drawn in a pool of Labre's own. The pool is not the file's: exporting writes the process back without one."];
|
|
26
|
+
readonly laneGap: readonly ["com.labre.bpmn.import.remark.lane-gap", "The lanes of this pool are drawn with a gap or an overlap between them. Labre lays its bands end to end, so their heights were kept in proportion and the space between them was closed."];
|
|
27
|
+
readonly mustUnderstand: readonly ["com.labre.bpmn.import.remark.must-understand", "The file declares an extension that it says MUST be understood to read the model correctly. Labre does not understand it: the import went ahead, and this reading of the process may be wrong."];
|
|
28
|
+
};
|
|
4
29
|
/**
|
|
5
30
|
* `startEvent` + `messageEventDefinition` → `startEventMessage`, and the
|
|
6
31
|
* sixteen other answers.
|
package/dist/import.js
CHANGED
|
@@ -4,6 +4,40 @@ import { ASSOCIATION_STROKE, ASSOCIATION_WIDTH, MESSAGE_STROKE, MESSAGE_WIDTH, N
|
|
|
4
4
|
import { BPMN_FORMAT_ID, BPMN_NS, BPMN_OWN_DECLARATIONS, BPMN_SCOPE, BPMN_XML_OF_KIND, escapeAttr, escapeText, } from './export.js';
|
|
5
5
|
import { bpmnNodeProps } from './presets.js';
|
|
6
6
|
import { BPMN_ROLE } from './roles.js';
|
|
7
|
+
/**
|
|
8
|
+
* The remarks whose wording is FIXED, as `[key, English]` pairs.
|
|
9
|
+
*
|
|
10
|
+
* A reader is a pure function of text (`docs/adr/0012`, P3) and has no `std`,
|
|
11
|
+
* so it cannot ask the host's catalogue for anything: it declares the key on
|
|
12
|
+
* the note and `reportInterchangeImport` resolves it when it draws the report
|
|
13
|
+
* (`InterchangeNote.messageKey`). The English string stays here and stays the
|
|
14
|
+
* fallback, so the console table and a playground with no catalogue read
|
|
15
|
+
* exactly what they read before.
|
|
16
|
+
*
|
|
17
|
+
* These three and no others, and the line is not arbitrary: every remaining
|
|
18
|
+
* remark NAMES something out of the file — `<boundaryEvent>`, an id, a count of
|
|
19
|
+
* lanes — and the seam has neither interpolation nor pluralisation. A key for
|
|
20
|
+
* one of those would be a sentence with holes in it that a translator cannot
|
|
21
|
+
* see the shape of, which is the same refusal the interchange count labels
|
|
22
|
+
* already make (`interchange-import.ts`).
|
|
23
|
+
*
|
|
24
|
+
* They are contributed to the manifest by `./translations.ts`, with the
|
|
25
|
+
* framework, because they ship in the BPMN bundle rather than in core.
|
|
26
|
+
*/
|
|
27
|
+
export const BPMN_IMPORT_REMARKS = {
|
|
28
|
+
inventedPool: [
|
|
29
|
+
'com.labre.bpmn.import.remark.invented-pool',
|
|
30
|
+
"This file names no participant, so its process was drawn in a pool of Labre's own. The pool is not the file's: exporting writes the process back without one.",
|
|
31
|
+
],
|
|
32
|
+
laneGap: [
|
|
33
|
+
'com.labre.bpmn.import.remark.lane-gap',
|
|
34
|
+
'The lanes of this pool are drawn with a gap or an overlap between them. Labre lays its bands end to end, so their heights were kept in proportion and the space between them was closed.',
|
|
35
|
+
],
|
|
36
|
+
mustUnderstand: [
|
|
37
|
+
'com.labre.bpmn.import.remark.must-understand',
|
|
38
|
+
'The file declares an extension that it says MUST be understood to read the model correctly. Labre does not understand it: the import went ahead, and this reading of the process may be wrong.',
|
|
39
|
+
],
|
|
40
|
+
};
|
|
7
41
|
/**
|
|
8
42
|
* A BPMN 2.0 interchange document, read as a board — the inverse of `export.ts`
|
|
9
43
|
* on the vocabulary Labre draws, and an honest accounting of everything else
|
|
@@ -814,9 +848,8 @@ export function importBpmnXml(source, context = {}) {
|
|
|
814
848
|
kind: 'invented-layout',
|
|
815
849
|
sourceId,
|
|
816
850
|
element: 'process',
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
`back without one.`,
|
|
851
|
+
messageKey: BPMN_IMPORT_REMARKS.inventedPool[0],
|
|
852
|
+
message: BPMN_IMPORT_REMARKS.inventedPool[1],
|
|
820
853
|
});
|
|
821
854
|
}
|
|
822
855
|
/**
|
|
@@ -945,9 +978,8 @@ export function importBpmnXml(source, context = {}) {
|
|
|
945
978
|
kind: 'invented-layout',
|
|
946
979
|
sourceId: attrOf(laneSet, 'id'),
|
|
947
980
|
element: 'laneSet',
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
`in proportion and the space between them was closed.`,
|
|
981
|
+
messageKey: BPMN_IMPORT_REMARKS.laneGap[0],
|
|
982
|
+
message: BPMN_IMPORT_REMARKS.laneGap[1],
|
|
951
983
|
});
|
|
952
984
|
}
|
|
953
985
|
}
|
|
@@ -1102,6 +1134,11 @@ export function importBpmnXml(source, context = {}) {
|
|
|
1102
1134
|
? new Bound(bounds.x, bounds.y, bounds.w, bounds.h)
|
|
1103
1135
|
: new Bound(0, 0, size.w, size.h)).serialize(),
|
|
1104
1136
|
text: text || undefined,
|
|
1137
|
+
// The file's own box, which this reader may not rewrite — so the label
|
|
1138
|
+
// is fitted to it rather than painted past it (#184). A shape the file
|
|
1139
|
+
// did not draw is laid out at the pack's own size below, and wants the
|
|
1140
|
+
// pack's own type: no fit, and an element identical to a drawn one.
|
|
1141
|
+
...(bounds ? { fitLabel: true } : {}),
|
|
1105
1142
|
}),
|
|
1106
1143
|
payload,
|
|
1107
1144
|
order: shape?.index ?? Number.POSITIVE_INFINITY,
|
|
@@ -1314,9 +1351,8 @@ export function importBpmnXml(source, context = {}) {
|
|
|
1314
1351
|
note({
|
|
1315
1352
|
kind: 'warning',
|
|
1316
1353
|
element: 'extension',
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
`went ahead, and this reading of the process may be wrong.`,
|
|
1354
|
+
messageKey: BPMN_IMPORT_REMARKS.mustUnderstand[0],
|
|
1355
|
+
message: BPMN_IMPORT_REMARKS.mustUnderstand[1],
|
|
1320
1356
|
});
|
|
1321
1357
|
}
|
|
1322
1358
|
carryChild(host.payload, BPMN_SCOPE.definitions, root, attrOf(definitions, 'id'));
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { materializeBpmnImport, reportBpmnImport } from './actions.js';
|
|
|
4
4
|
export { bpmnCommandIcons, bpmnCommands } from './commands.js';
|
|
5
5
|
export { BPMN_FORMAT_ID, BPMN_NS, BPMN_XML_OF_KIND, type BpmnExportBoard, type BpmnExportOptions, type BpmnExportOutcome, type BpmnXmlMapping, exportBpmnXml, exportBpmnXmlWithWarnings, isNcName, toNcName, } from './export.js';
|
|
6
6
|
export { BPMN_KIND_OF_XML, BPMN_QUARANTINE_REASON, importBpmnXml, } from './import.js';
|
|
7
|
-
export { bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, type BpmnNodePreset, NODE_PRESETS, } from './presets.js';
|
|
7
|
+
export { bpmnLabelFit, type BpmnLabelFit, bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, type BpmnNodePreset, NODE_PRESETS, } from './presets.js';
|
|
8
8
|
export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
|
|
9
9
|
export { BPMN_INTERCHANGE, BPMN_SVG_FORMAT, BPMN_SVG_IMPORT, BPMN_XML_EXPORT, BPMN_XML_EXTENSION, BPMN_XML_IMPORT, BPMN_XML_FORMAT, BPMN_XML_MIME, bpmnBoardFrom, bpmnSafeFilename, } from './interchange.js';
|
|
10
10
|
export { bpmnLaneOf, bpmnPoolOf } from './facts.js';
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,10 @@ export { BPMN_KIND_OF_XML, BPMN_QUARANTINE_REASON, importBpmnXml, } from './impo
|
|
|
26
26
|
// What an artefact is BORN as, shared by the palette and the importer so a task
|
|
27
27
|
// read out of a file and a task drawn by hand are one element in the document —
|
|
28
28
|
// and, since the morph, by the toolbar that says one artefact more precisely.
|
|
29
|
-
|
|
29
|
+
// `bpmnLabelFit` rides along with it: a host that materializes artefacts from a
|
|
30
|
+
// geometry of its own — a file, a generator, another editor's board — fits their
|
|
31
|
+
// labels the way the importer does, rather than reinventing the arithmetic.
|
|
32
|
+
export { bpmnLabelFit, bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, NODE_PRESETS, } from './presets.js';
|
|
30
33
|
// What an artefact may BECOME: the declared families, and the spec the generic
|
|
31
34
|
// morph module is registered with. Data a host can read without an editor.
|
|
32
35
|
export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
|
package/dist/presets.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
2
|
-
import { StrokeStyle, TextAlign, TextVerticalAlign } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign } from '@formicoidea/labre-core/model';
|
|
3
3
|
/**
|
|
4
4
|
* What a BPMN artefact is BORN as — the one description of a node's props, read
|
|
5
5
|
* by every site that creates one.
|
|
@@ -52,6 +52,51 @@ export interface BpmnNodePreset {
|
|
|
52
52
|
}
|
|
53
53
|
/** Per-kind native shape + accent presets (style C). */
|
|
54
54
|
export declare const NODE_PRESETS: Record<BpmnNodeKind, BpmnNodePreset>;
|
|
55
|
+
/** The label typography a foreign box asks for. See {@link bpmnLabelFit}. */
|
|
56
|
+
export interface BpmnLabelFit {
|
|
57
|
+
fontSize: number;
|
|
58
|
+
/** `[vertical, horizontal]`, as `ShapeElementModel.padding` is written. */
|
|
59
|
+
padding: [number, number];
|
|
60
|
+
textFitMode: TextFitMode;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The typography a label needs to sit INSIDE a box this pack did not choose —
|
|
64
|
+
* which in practice means a box an interchange file chose (`import.ts`).
|
|
65
|
+
*
|
|
66
|
+
* ## Why an imported label misbehaves and a drawn one does not
|
|
67
|
+
*
|
|
68
|
+
* Every value the creation builder writes is calibrated against
|
|
69
|
+
* {@link NODE_SIZE}: an 18-unit font and the shape's native 20-unit horizontal
|
|
70
|
+
* inset are comfortable in a 120-unit task, which is what the palette draws.
|
|
71
|
+
* A file draws to its author's scale, and bpmn.io's normative sizes — the ones
|
|
72
|
+
* nearly every `.bpmn` in the wild carries — are a 100×80 task and a 36-unit
|
|
73
|
+
* event. In a 100-unit task the native inset leaves 60 units of line, which is
|
|
74
|
+
* less than the word "Étudier" is wide at 18 units, so the label breaks in the
|
|
75
|
+
* middle of a word; in a 36-unit event it leaves NEGATIVE room, and the name
|
|
76
|
+
* sprawls across the canvas. Both are issue #184, and neither is reachable from
|
|
77
|
+
* the palette.
|
|
78
|
+
*
|
|
79
|
+
* So the three props that decide how a label sits are derived from the box:
|
|
80
|
+
*
|
|
81
|
+
* - **`fontSize`** shrinks with the box, proportionally, and never grows past
|
|
82
|
+
* {@link INNER_FONT_SIZE} — a file that draws BIGGER than this pack gets the
|
|
83
|
+
* pack's own type, not inflated type — with {@link LABEL_MIN_FONT_SIZE} as
|
|
84
|
+
* the floor;
|
|
85
|
+
* - **`padding`** becomes {@link LABEL_INSET_RATIO} of the box, capped at the
|
|
86
|
+
* shape's native inset, so the margin follows the artefact down instead of
|
|
87
|
+
* eating it;
|
|
88
|
+
* - **`textFitMode`** becomes `Contained`, which is the honest statement of
|
|
89
|
+
* what an imported artefact IS: the file fixed the box — re-exporting a
|
|
90
|
+
* different one would rewrite the author's diagram — so the TEXT is what
|
|
91
|
+
* yields. The renderer then shrinks the font further, per frame, whenever a
|
|
92
|
+
* long name still does not fit.
|
|
93
|
+
*
|
|
94
|
+
* Pure arithmetic on two numbers: no measuring, no canvas, no renderer. The
|
|
95
|
+
* fit does not have to be exact, because `Contained` finishes it at paint time
|
|
96
|
+
* with the real font metrics; what this has to do is stop asking for type the
|
|
97
|
+
* box was never going to hold.
|
|
98
|
+
*/
|
|
99
|
+
export declare function bpmnLabelFit(kind: BpmnNodeKind, w: number, h: number): BpmnLabelFit;
|
|
55
100
|
/**
|
|
56
101
|
* One BPMN node, as the props `surface.addElement` takes.
|
|
57
102
|
*
|
|
@@ -63,10 +108,19 @@ export declare const NODE_PRESETS: Record<BpmnNodeKind, BpmnNodePreset>;
|
|
|
63
108
|
* label the source left empty gets no `text` key at all rather than an empty
|
|
64
109
|
* one, which is what keeps an imported node byte-comparable with a drawn one
|
|
65
110
|
* that was never typed into.
|
|
111
|
+
*
|
|
112
|
+
* `fitLabel` says the box is NOT the pack's own — the caller took it from a
|
|
113
|
+
* file it may not rewrite — so the label is fitted to it
|
|
114
|
+
* ({@link bpmnLabelFit}). It is asked for explicitly rather than inferred from
|
|
115
|
+
* the box's size for two reasons: an importer knows whether it read a
|
|
116
|
+
* `dc:Bounds` and a guess never would, and {@link bpmnMorphProps} calls this
|
|
117
|
+
* builder with a throwaway box whose numbers must not be allowed to mean
|
|
118
|
+
* anything.
|
|
66
119
|
*/
|
|
67
120
|
export declare function bpmnNodeProps(kind: BpmnNodeKind, box: {
|
|
68
121
|
xywh: string;
|
|
69
122
|
text?: string;
|
|
123
|
+
fitLabel?: boolean;
|
|
70
124
|
}): Record<string, unknown> & {
|
|
71
125
|
type: string;
|
|
72
126
|
};
|
package/dist/presets.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { FontFamily, ShapeStyle, StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign, } from '@formicoidea/labre-core/model';
|
|
2
|
-
import {
|
|
1
|
+
import { FontFamily, SHAPE_TEXT_PADDING, SHAPE_TEXT_VERTICAL_PADDING, ShapeStyle, StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign, } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
3
|
+
import { CALL_ACTIVITY_WIDTH, END_WIDTH, EVENT_END, EVENT_START, GROUP_RADIUS, GROUP_STROKE, INNER_FONT_SIZE, LABEL_INSET_RATIO, LABEL_MIN_FONT_SIZE, NEUTRAL_STROKE, NODE_FILL, NODE_SIZE, NODE_STROKE_WIDTH, START_WIDTH, TASK_RADIUS, } from './consts.js';
|
|
3
4
|
import { BPMN_ROLE_OF_KIND } from './roles.js';
|
|
4
5
|
/** Per-kind native shape + accent presets (style C). */
|
|
5
6
|
export const NODE_PRESETS = {
|
|
@@ -105,6 +106,81 @@ export const NODE_PRESETS = {
|
|
|
105
106
|
textVerticalAlign: TextVerticalAlign.Top,
|
|
106
107
|
},
|
|
107
108
|
};
|
|
109
|
+
/**
|
|
110
|
+
* `[w, h]` off a serialized box.
|
|
111
|
+
*
|
|
112
|
+
* A `Bound` and not a hand-rolled `split(',')`: the same deserializer the store
|
|
113
|
+
* reads an element's geometry with, so a box this builder measures and a box
|
|
114
|
+
* the canvas draws can never be two different rectangles.
|
|
115
|
+
*/
|
|
116
|
+
function boxExtent(xywh) {
|
|
117
|
+
const bound = Bound.deserialize(xywh);
|
|
118
|
+
return [bound.w, bound.h];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* How big a box is against the pack's own — and `1`, meaning "the pack's own",
|
|
122
|
+
* for an extent that says nothing.
|
|
123
|
+
*
|
|
124
|
+
* A `dc:Bounds` of zeros, of negatives or of `NaN` (which is what a
|
|
125
|
+
* non-numeric attribute parses to) reaches an importer on its first afternoon
|
|
126
|
+
* in the wild. The answer for a box that says nothing is the DRAWN artefact's
|
|
127
|
+
* type, not a shrunken guess at a size nobody gave — and never `NaN`, which is
|
|
128
|
+
* not a number the store can hold.
|
|
129
|
+
*/
|
|
130
|
+
const ratioOf = (extent, standard) => Number.isFinite(extent) && extent > 0 ? extent / standard : 1;
|
|
131
|
+
/** One side's margin: the ratio of the extent, never more than the native inset. */
|
|
132
|
+
const insetOf = (extent, native) => Number.isFinite(extent) && extent > 0
|
|
133
|
+
? Math.round(Math.min(native, extent * LABEL_INSET_RATIO))
|
|
134
|
+
: native;
|
|
135
|
+
/**
|
|
136
|
+
* The typography a label needs to sit INSIDE a box this pack did not choose —
|
|
137
|
+
* which in practice means a box an interchange file chose (`import.ts`).
|
|
138
|
+
*
|
|
139
|
+
* ## Why an imported label misbehaves and a drawn one does not
|
|
140
|
+
*
|
|
141
|
+
* Every value the creation builder writes is calibrated against
|
|
142
|
+
* {@link NODE_SIZE}: an 18-unit font and the shape's native 20-unit horizontal
|
|
143
|
+
* inset are comfortable in a 120-unit task, which is what the palette draws.
|
|
144
|
+
* A file draws to its author's scale, and bpmn.io's normative sizes — the ones
|
|
145
|
+
* nearly every `.bpmn` in the wild carries — are a 100×80 task and a 36-unit
|
|
146
|
+
* event. In a 100-unit task the native inset leaves 60 units of line, which is
|
|
147
|
+
* less than the word "Étudier" is wide at 18 units, so the label breaks in the
|
|
148
|
+
* middle of a word; in a 36-unit event it leaves NEGATIVE room, and the name
|
|
149
|
+
* sprawls across the canvas. Both are issue #184, and neither is reachable from
|
|
150
|
+
* the palette.
|
|
151
|
+
*
|
|
152
|
+
* So the three props that decide how a label sits are derived from the box:
|
|
153
|
+
*
|
|
154
|
+
* - **`fontSize`** shrinks with the box, proportionally, and never grows past
|
|
155
|
+
* {@link INNER_FONT_SIZE} — a file that draws BIGGER than this pack gets the
|
|
156
|
+
* pack's own type, not inflated type — with {@link LABEL_MIN_FONT_SIZE} as
|
|
157
|
+
* the floor;
|
|
158
|
+
* - **`padding`** becomes {@link LABEL_INSET_RATIO} of the box, capped at the
|
|
159
|
+
* shape's native inset, so the margin follows the artefact down instead of
|
|
160
|
+
* eating it;
|
|
161
|
+
* - **`textFitMode`** becomes `Contained`, which is the honest statement of
|
|
162
|
+
* what an imported artefact IS: the file fixed the box — re-exporting a
|
|
163
|
+
* different one would rewrite the author's diagram — so the TEXT is what
|
|
164
|
+
* yields. The renderer then shrinks the font further, per frame, whenever a
|
|
165
|
+
* long name still does not fit.
|
|
166
|
+
*
|
|
167
|
+
* Pure arithmetic on two numbers: no measuring, no canvas, no renderer. The
|
|
168
|
+
* fit does not have to be exact, because `Contained` finishes it at paint time
|
|
169
|
+
* with the real font metrics; what this has to do is stop asking for type the
|
|
170
|
+
* box was never going to hold.
|
|
171
|
+
*/
|
|
172
|
+
export function bpmnLabelFit(kind, w, h) {
|
|
173
|
+
const size = NODE_SIZE[kind];
|
|
174
|
+
const scale = Math.min(1, ratioOf(w, size.w), ratioOf(h, size.h));
|
|
175
|
+
return {
|
|
176
|
+
fontSize: Math.max(LABEL_MIN_FONT_SIZE, Math.round(INNER_FONT_SIZE * scale)),
|
|
177
|
+
padding: [
|
|
178
|
+
insetOf(h, SHAPE_TEXT_VERTICAL_PADDING),
|
|
179
|
+
insetOf(w, SHAPE_TEXT_PADDING),
|
|
180
|
+
],
|
|
181
|
+
textFitMode: TextFitMode.Contained,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
108
184
|
/**
|
|
109
185
|
* One BPMN node, as the props `surface.addElement` takes.
|
|
110
186
|
*
|
|
@@ -116,9 +192,22 @@ export const NODE_PRESETS = {
|
|
|
116
192
|
* label the source left empty gets no `text` key at all rather than an empty
|
|
117
193
|
* one, which is what keeps an imported node byte-comparable with a drawn one
|
|
118
194
|
* that was never typed into.
|
|
195
|
+
*
|
|
196
|
+
* `fitLabel` says the box is NOT the pack's own — the caller took it from a
|
|
197
|
+
* file it may not rewrite — so the label is fitted to it
|
|
198
|
+
* ({@link bpmnLabelFit}). It is asked for explicitly rather than inferred from
|
|
199
|
+
* the box's size for two reasons: an importer knows whether it read a
|
|
200
|
+
* `dc:Bounds` and a guess never would, and {@link bpmnMorphProps} calls this
|
|
201
|
+
* builder with a throwaway box whose numbers must not be allowed to mean
|
|
202
|
+
* anything.
|
|
119
203
|
*/
|
|
120
204
|
export function bpmnNodeProps(kind, box) {
|
|
121
205
|
const preset = NODE_PRESETS[kind];
|
|
206
|
+
// Nothing to fit without a label: an artefact whose name the file left empty
|
|
207
|
+
// stays byte-identical to a drawn one, which is what `presets.ts` is for.
|
|
208
|
+
const fit = box.fitLabel && box.text
|
|
209
|
+
? bpmnLabelFit(kind, ...boxExtent(box.xywh))
|
|
210
|
+
: undefined;
|
|
122
211
|
return {
|
|
123
212
|
type: 'bpmnNode',
|
|
124
213
|
kind,
|
|
@@ -145,7 +234,7 @@ export function bpmnNodeProps(kind, box) {
|
|
|
145
234
|
text: box.text,
|
|
146
235
|
color: NEUTRAL_STROKE,
|
|
147
236
|
fontFamily: FontFamily.Inter,
|
|
148
|
-
fontSize: INNER_FONT_SIZE,
|
|
237
|
+
fontSize: fit?.fontSize ?? INNER_FONT_SIZE,
|
|
149
238
|
textAlign: preset.textAlign ?? TextAlign.Center,
|
|
150
239
|
// Spread, never a defaulted key: the model's own default is already
|
|
151
240
|
// `Center`, so writing it here would put a new key in the Y.Map of every
|
|
@@ -155,8 +244,14 @@ export function bpmnNodeProps(kind, box) {
|
|
|
155
244
|
? { textVerticalAlign: preset.textVerticalAlign }
|
|
156
245
|
: {}),
|
|
157
246
|
// BPMN symbols have normative sizes: a long label overflows rather
|
|
158
|
-
// than deforming the node
|
|
159
|
-
|
|
247
|
+
// than deforming the node. An imported artefact is the one case where that
|
|
248
|
+
// is not enough — its box is the FILE's and its label is the file's too, so
|
|
249
|
+
// the text is fitted to the box instead of painted past it (#184).
|
|
250
|
+
textFitMode: fit?.textFitMode ?? TextFitMode.Overflow,
|
|
251
|
+
// Spread, never a defaulted key, for the reason `textVerticalAlign` is: a
|
|
252
|
+
// drawn artefact keeps the shape's own inset and puts nothing of its own in
|
|
253
|
+
// the Y.Map.
|
|
254
|
+
...(fit ? { padding: fit.padding } : {}),
|
|
160
255
|
xywh: box.xywh,
|
|
161
256
|
};
|
|
162
257
|
}
|
package/dist/toolbar/config.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { ActionPlacement, type ToolbarContext } from '@formicoidea/labre-core/shared/services';
|
|
1
|
+
import { ActionPlacement, type ChromeWording, type ToolbarContext } from '@formicoidea/labre-core/shared/services';
|
|
2
2
|
import { type TemplateResult } from 'lit';
|
|
3
3
|
export declare const bpmnPoolToolbarConfig: {
|
|
4
4
|
readonly actions: [{
|
|
5
5
|
id: string;
|
|
6
6
|
tooltip: string;
|
|
7
|
+
tooltipWording: ChromeWording | undefined;
|
|
7
8
|
icon: TemplateResult;
|
|
8
9
|
active(ctx: ToolbarContext): boolean;
|
|
9
10
|
run(ctx: ToolbarContext): void;
|
package/dist/toolbar/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EdgelessCRUDIdentifier } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { BpmnPoolElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
-
import { ActionPlacement, ToolbarModuleExtension, translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
3
|
+
import { ActionPlacement, BOARD_RESIZE_TOGGLE, ToolbarModuleExtension, translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
4
4
|
import { BlockFlavourIdentifier, getRegisteredCommands, runCommand, } from '@formicoidea/labre-core/std';
|
|
5
5
|
import { html } from 'lit';
|
|
6
6
|
import { bpmnExportXmlIcon, bpmnLaneAddIcon, bpmnLaneRemoveIcon, } from './icons.js';
|
|
@@ -24,7 +24,12 @@ const ResizeIcon = html `<svg
|
|
|
24
24
|
function booleanToggle(id, tooltip, icon, prop) {
|
|
25
25
|
return {
|
|
26
26
|
id,
|
|
27
|
-
tooltip,
|
|
27
|
+
tooltip: typeof tooltip === 'string' ? tooltip : tooltip[1],
|
|
28
|
+
// The declared wording, when the caller gave one instead of a literal:
|
|
29
|
+
// `combine` resolves it against the host's catalogue and writes it over
|
|
30
|
+
// the English default above, so a playground with no catalogue reads
|
|
31
|
+
// exactly what it read before (#183).
|
|
32
|
+
tooltipWording: typeof tooltip === 'string' ? undefined : tooltip,
|
|
28
33
|
icon,
|
|
29
34
|
active(ctx) {
|
|
30
35
|
const models = ctx.getSurfaceModelsByType(BpmnPoolElementModel);
|
|
@@ -119,7 +124,7 @@ function commandMoreAction(id, commandId, labelKey, labelFallback, icon) {
|
|
|
119
124
|
const findCommand = (ctx, id) => getRegisteredCommands(ctx.std).find(candidate => candidate.id === id);
|
|
120
125
|
export const bpmnPoolToolbarConfig = {
|
|
121
126
|
actions: [
|
|
122
|
-
booleanToggle('a.toggle-resize',
|
|
127
|
+
booleanToggle('a.toggle-resize', BOARD_RESIZE_TOGGLE, ResizeIcon, 'resizeEnabled'),
|
|
123
128
|
// The two lane gestures, next to the resize toggle: everything on this row
|
|
124
129
|
// is about the SHAPE of the pool rather than about what is drawn in it.
|
|
125
130
|
// Add before remove, because that is the order they can be used in — a pool
|
package/dist/translations.js
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
|
-
import { collectTranslationKeys, commandTranslationEntries, mergeTranslationEntries, } from '@formicoidea/labre-core/std';
|
|
1
|
+
import { collectTranslationKeys, commandCategoryTranslationEntries, commandTranslationEntries, mergeTranslationEntries, } from '@formicoidea/labre-core/std';
|
|
2
2
|
import { bpmnCommands } from './commands.js';
|
|
3
|
+
import { NODE_LABEL, nodeLabelKey } from './consts.js';
|
|
4
|
+
import { BPMN_IMPORT_REMARKS } from './import.js';
|
|
3
5
|
import { BPMN_PROFILES } from './profiles.js';
|
|
4
6
|
import { BPMN_ROLES } from './roles.js';
|
|
5
7
|
import { BPMN_RULES } from './rules.js';
|
|
8
|
+
/**
|
|
9
|
+
* The captions a placed artefact is seeded with, and the fixed-wording remarks
|
|
10
|
+
* an import can produce — the two families of BPMN prose that live in tables
|
|
11
|
+
* rather than in a declaration the walker can reach.
|
|
12
|
+
*
|
|
13
|
+
* Derived from those tables, never restated: the fallback IS `NODE_LABEL[kind]`
|
|
14
|
+
* and `BPMN_IMPORT_REMARKS[…][1]`, so the wording a host is offered and the
|
|
15
|
+
* wording the library writes cannot drift. The kinds with no caption
|
|
16
|
+
* contribute no key — there is nothing to translate.
|
|
17
|
+
*/
|
|
18
|
+
const seedEntries = () => Object.entries(NODE_LABEL)
|
|
19
|
+
.filter(([, label]) => label !== '')
|
|
20
|
+
.map(([kind, label]) => ({
|
|
21
|
+
key: nodeLabelKey(kind),
|
|
22
|
+
fallback: label,
|
|
23
|
+
source: 'seed',
|
|
24
|
+
}));
|
|
25
|
+
const importRemarkEntries = () => Object.values(BPMN_IMPORT_REMARKS).map(([key, english]) => ({
|
|
26
|
+
key,
|
|
27
|
+
fallback: english,
|
|
28
|
+
source: 'chrome',
|
|
29
|
+
}));
|
|
6
30
|
/**
|
|
7
31
|
* THIS framework's contribution to the translation-key manifest — every
|
|
8
32
|
* `com.labre.*` key BPMN can hand to `TranslationProvider.t`, derived from the
|
|
@@ -17,4 +41,10 @@ import { BPMN_RULES } from './rules.js';
|
|
|
17
41
|
* `bpmnCommands` into the command registry. See
|
|
18
42
|
* `packages/affine/all/src/translations.ts`.
|
|
19
43
|
*/
|
|
20
|
-
export const bpmnTranslationEntries = mergeTranslationEntries(commandTranslationEntries(bpmnCommands),
|
|
44
|
+
export const bpmnTranslationEntries = mergeTranslationEntries(commandTranslationEntries(bpmnCommands),
|
|
45
|
+
// The catalogue's own group headers, derived from the very categories
|
|
46
|
+
// these commands declare. They ship WITH the framework because core's
|
|
47
|
+
// registry names no framework category in the bundled distribution, so a
|
|
48
|
+
// host that composed core's manifest alone drew translated entries under
|
|
49
|
+
// English headers (#183).
|
|
50
|
+
commandCategoryTranslationEntries(bpmnCommands), collectTranslationKeys('role', BPMN_ROLES), collectTranslationKeys('rule', BPMN_RULES), collectTranslationKeys('profile', BPMN_PROFILES), seedEntries(), importRemarkEntries());
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formicoidea/labre-framework-bpmn",
|
|
3
3
|
"description": "Labre bpmn framework for @formicoidea/labre-core.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.34.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "lajola",
|
|
@@ -21,13 +21,17 @@
|
|
|
21
21
|
"./descriptor": {
|
|
22
22
|
"types": "./dist/descriptor.d.ts",
|
|
23
23
|
"import": "./dist/descriptor.js"
|
|
24
|
+
},
|
|
25
|
+
"./commands-manifest": {
|
|
26
|
+
"types": "./dist/commands-manifest.d.ts",
|
|
27
|
+
"import": "./dist/commands-manifest.js"
|
|
24
28
|
}
|
|
25
29
|
},
|
|
26
30
|
"files": [
|
|
27
31
|
"dist"
|
|
28
32
|
],
|
|
29
33
|
"dependencies": {
|
|
30
|
-
"@formicoidea/labre-core": "0.
|
|
34
|
+
"@formicoidea/labre-core": "0.34.1",
|
|
31
35
|
"lit": "^3.2.0"
|
|
32
36
|
}
|
|
33
37
|
}
|