@formicoidea/labre-framework-bpmn 0.31.0 → 0.33.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/dist/actions.d.ts +213 -0
- package/dist/actions.js +467 -0
- package/dist/background.d.ts +2 -0
- package/dist/background.js +158 -0
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +567 -0
- package/dist/consts.d.ts +157 -3
- package/dist/consts.js +192 -3
- package/dist/descriptor.d.ts +8 -3
- package/dist/descriptor.js +6 -3
- package/dist/element-renderer.d.ts +10 -4
- package/dist/element-renderer.js +14 -55
- package/dist/element-view.d.ts +100 -8
- package/dist/element-view.js +249 -30
- package/dist/export.d.ts +277 -0
- package/dist/export.js +1802 -0
- package/dist/facts.d.ts +48 -0
- package/dist/facts.js +127 -0
- package/dist/import.d.ts +44 -0
- package/dist/import.js +1440 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.js +46 -1
- package/dist/interchange.d.ts +109 -0
- package/dist/interchange.js +191 -0
- package/dist/morph.d.ts +61 -0
- package/dist/morph.js +118 -0
- package/dist/node/node-renderer.d.ts +0 -9
- package/dist/node/node-renderer.js +294 -17
- package/dist/pool-hit.d.ts +98 -0
- package/dist/pool-hit.js +130 -0
- package/dist/presets.d.ts +114 -0
- package/dist/presets.js +232 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +189 -0
- package/dist/roles.d.ts +96 -0
- package/dist/roles.js +410 -0
- package/dist/rules.d.ts +199 -0
- package/dist/rules.js +1539 -0
- package/dist/templates/index.js +116 -9
- package/dist/toolbar/bpmn-menu.d.ts +6 -21
- package/dist/toolbar/bpmn-menu.js +6 -173
- package/dist/toolbar/bpmn-senior-button.js +8 -2
- package/dist/toolbar/config.d.ts +27 -2
- package/dist/toolbar/config.js +86 -2
- package/dist/toolbar/icons.d.ts +67 -0
- package/dist/toolbar/icons.js +141 -0
- package/dist/toolbar/senior-tool.js +1 -0
- package/dist/translations.d.ts +16 -0
- package/dist/translations.js +20 -0
- package/dist/view.d.ts +18 -0
- package/dist/view.js +95 -7
- package/package.json +2 -2
package/dist/templates/index.js
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import { makeTemplateSnapshot, surfaceText, } from '@formicoidea/labre-core/gfx/template';
|
|
2
2
|
import { ConnectorMode, FontFamily, PointStyle, ShapeStyle, StrokeStyle, } from '@formicoidea/labre-core/model';
|
|
3
|
-
import { END_WIDTH, EVENT_END, EVENT_START, INNER_FONT_SIZE, NEUTRAL_STROKE, NODE_FILL, NODE_SIZE, NODE_STROKE_WIDTH, SEQUENCE_STROKE, SEQUENCE_WIDTH, START_WIDTH, TASK_RADIUS, } from '../consts.js';
|
|
4
|
-
|
|
3
|
+
import { END_WIDTH, EVENT_END, EVENT_START, INNER_FONT_SIZE, MESSAGE_STROKE, MESSAGE_WIDTH, NEUTRAL_STROKE, NODE_FILL, NODE_SIZE, NODE_STROKE_WIDTH, SEQUENCE_STROKE, SEQUENCE_WIDTH, START_WIDTH, TASK_RADIUS, } from '../consts.js';
|
|
4
|
+
import { BPMN_ROLE, BPMN_ROLE_OF_KIND } from '../roles.js';
|
|
5
|
+
/**
|
|
6
|
+
* One BPMN flow-object node, as a surface-element JSON entry.
|
|
7
|
+
*
|
|
8
|
+
* Every kind that {@link NodeKind} admits paints its own body natively, as an
|
|
9
|
+
* ellipse, a rounded rect or a diamond. The GLYPH-BODIED kinds (`dataObject`,
|
|
10
|
+
* `dataStore`, `textAnnotation`) do not: they are created unfilled and
|
|
11
|
+
* unstroked and the renderer draws their silhouette, so a card that spelled one
|
|
12
|
+
* out here would insert an invisible rectangle. `group` is out for a neighbouring
|
|
13
|
+
* reason — it is `hollow`, and the branches below all fill. When any of them
|
|
14
|
+
* earns a card, this helper reads `NODE_PRESETS` instead of branching.
|
|
15
|
+
*/
|
|
5
16
|
function node(kind, x, y, text) {
|
|
6
17
|
const { w, h } = NODE_SIZE[kind];
|
|
7
18
|
const base = {
|
|
8
19
|
type: 'bpmnNode',
|
|
9
20
|
kind,
|
|
21
|
+
// A template must produce the same typed artefacts as the toolbox, or a
|
|
22
|
+
// process started from a preset would read differently from a hand-drawn
|
|
23
|
+
// one.
|
|
24
|
+
role: BPMN_ROLE_OF_KIND[kind],
|
|
10
25
|
filled: true,
|
|
11
26
|
fillColor: NODE_FILL,
|
|
12
27
|
shapeStyle: ShapeStyle.General,
|
|
@@ -14,11 +29,26 @@ function node(kind, x, y, text) {
|
|
|
14
29
|
xywh: `[${x},${y},${w},${h}]`,
|
|
15
30
|
};
|
|
16
31
|
if (kind === 'startEvent')
|
|
17
|
-
return {
|
|
32
|
+
return {
|
|
33
|
+
...base,
|
|
34
|
+
shapeType: 'ellipse',
|
|
35
|
+
strokeColor: EVENT_START,
|
|
36
|
+
strokeWidth: START_WIDTH,
|
|
37
|
+
};
|
|
18
38
|
if (kind === 'endEvent')
|
|
19
|
-
return {
|
|
39
|
+
return {
|
|
40
|
+
...base,
|
|
41
|
+
shapeType: 'ellipse',
|
|
42
|
+
strokeColor: EVENT_END,
|
|
43
|
+
strokeWidth: END_WIDTH,
|
|
44
|
+
};
|
|
20
45
|
if (kind === 'gatewayExclusive')
|
|
21
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
...base,
|
|
48
|
+
shapeType: 'diamond',
|
|
49
|
+
strokeColor: NEUTRAL_STROKE,
|
|
50
|
+
strokeWidth: NODE_STROKE_WIDTH,
|
|
51
|
+
};
|
|
22
52
|
return {
|
|
23
53
|
...base,
|
|
24
54
|
shapeType: 'rect',
|
|
@@ -33,12 +63,21 @@ function node(kind, x, y, text) {
|
|
|
33
63
|
};
|
|
34
64
|
}
|
|
35
65
|
function pool(x, y, w, h, name = 'Pool') {
|
|
36
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
type: 'bpmnPool',
|
|
68
|
+
role: BPMN_ROLE.pool,
|
|
69
|
+
name,
|
|
70
|
+
xywh: `[${x},${y},${w},${h}]`,
|
|
71
|
+
};
|
|
37
72
|
}
|
|
38
73
|
/** A sequence-flow connector; ids are remapped on insert. */
|
|
39
74
|
function seq(source, target) {
|
|
40
75
|
return {
|
|
41
76
|
type: 'connector',
|
|
77
|
+
// Both ends are BOUND, so this arrow relates two named things and its
|
|
78
|
+
// direction is a claim the template makes: source first, target next
|
|
79
|
+
// (`docs/adr/0010`).
|
|
80
|
+
role: BPMN_ROLE.sequenceFlow,
|
|
42
81
|
mode: ConnectorMode.Orthogonal,
|
|
43
82
|
stroke: SEQUENCE_STROKE,
|
|
44
83
|
strokeWidth: SEQUENCE_WIDTH,
|
|
@@ -49,7 +88,40 @@ function seq(source, target) {
|
|
|
49
88
|
target: { id: target, position: [0.5, 0.5] },
|
|
50
89
|
};
|
|
51
90
|
}
|
|
52
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* A message-flow connector; ids are remapped on insert.
|
|
93
|
+
*
|
|
94
|
+
* The same shape as {@link seq} and the same claim — both ends are BOUND, so
|
|
95
|
+
* the arrow relates two named things — but a different sentence: "sends a
|
|
96
|
+
* message to", from the participant that sends to the one that receives
|
|
97
|
+
* (`docs/adr/0010`). Its style is the one `activateBpmnMessageFlow` arms the
|
|
98
|
+
* connector tool with, so a message flow dropped from this card and one drawn
|
|
99
|
+
* by hand are indistinguishable in the document.
|
|
100
|
+
*/
|
|
101
|
+
function msg(source, target) {
|
|
102
|
+
return {
|
|
103
|
+
type: 'connector',
|
|
104
|
+
role: BPMN_ROLE.messageFlow,
|
|
105
|
+
mode: ConnectorMode.Orthogonal,
|
|
106
|
+
stroke: MESSAGE_STROKE,
|
|
107
|
+
strokeWidth: MESSAGE_WIDTH,
|
|
108
|
+
strokeStyle: StrokeStyle.Dash,
|
|
109
|
+
frontEndpointStyle: PointStyle.Circle,
|
|
110
|
+
rearEndpointStyle: PointStyle.Arrow,
|
|
111
|
+
source: { id: source, position: [0.5, 0.5] },
|
|
112
|
+
target: { id: target, position: [0.5, 0.5] },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* A standalone (free) sequence-flow arrow for the prefab card.
|
|
117
|
+
*
|
|
118
|
+
* NEUTRAL on purpose (`docs/adr/0010` § Compatibility, and the same call the
|
|
119
|
+
* Wardley "Link" swatch makes): this is a horizontal stroke bound to nothing —
|
|
120
|
+
* a sample of a STYLE, in a palette. A typed edge claims "this is followed by
|
|
121
|
+
* that", and a stroke attached to neither end has no this and no that to say it
|
|
122
|
+
* about. Drawing it with the sequence-flow tool, or dropping this one and then
|
|
123
|
+
* attaching both of its ends, is what makes it a statement.
|
|
124
|
+
*/
|
|
53
125
|
function freeSeq() {
|
|
54
126
|
return {
|
|
55
127
|
type: 'connector',
|
|
@@ -63,7 +135,9 @@ function freeSeq() {
|
|
|
63
135
|
target: { position: [140, 0] },
|
|
64
136
|
};
|
|
65
137
|
}
|
|
66
|
-
const single = (el) => ({
|
|
138
|
+
const single = (el) => ({
|
|
139
|
+
a: el,
|
|
140
|
+
});
|
|
67
141
|
const PREVIEW_ATTRS = 'width="100%" height="100%" viewBox="0 0 135 80" xmlns="http://www.w3.org/2000/svg"';
|
|
68
142
|
const previews = {
|
|
69
143
|
process: `<svg ${PREVIEW_ATTRS} fill="none"><circle cx="16" cy="40" r="8" stroke="#43a06b" stroke-width="2"/><rect x="34" y="31" width="26" height="18" rx="3" stroke="#262626" stroke-width="1.6"/><path d="M78 31 L88 40 L78 49 L68 40 Z" stroke="#262626" stroke-width="1.4"/><path d="M73 37 L83 43 M83 37 L73 43" stroke="#262626" stroke-width="1.2"/><circle cx="118" cy="40" r="8" stroke="#cf5648" stroke-width="3"/><path d="M24 40 H34 M60 40 H68 M88 40 H110" stroke="#262626" stroke-width="1.2"/></svg>`,
|
|
@@ -73,8 +147,17 @@ const previews = {
|
|
|
73
147
|
gateway: `<svg ${PREVIEW_ATTRS} fill="none"><path d="M67 16 L92 40 L67 64 L42 40 Z" stroke="#262626" stroke-width="2.4" stroke-linejoin="round"/><path d="M58 31 L76 49 M76 31 L58 49" stroke="#262626" stroke-width="2.2" stroke-linecap="round"/></svg>`,
|
|
74
148
|
sequence: `<svg ${PREVIEW_ATTRS} fill="none"><path d="M24 40 H96" stroke="#262626" stroke-width="2.4" stroke-linecap="round"/><path d="M94 33 L108 40 L94 47 Z" fill="#262626"/></svg>`,
|
|
75
149
|
pool: `<svg ${PREVIEW_ATTRS} fill="none"><rect x="14" y="20" width="107" height="40" rx="3" stroke="#262626" stroke-width="2"/><path d="M30 20 V60" stroke="#262626" stroke-width="1.8"/><rect x="14" y="20" width="16" height="40" fill="#f4f4f5"/><path d="M30 20 V60" stroke="#262626" stroke-width="1.8"/></svg>`,
|
|
150
|
+
// Two participants stacked, and the dashed line between them is the whole
|
|
151
|
+
// point of the card: a message flow is the one arrow that crosses a pool.
|
|
152
|
+
// Its source terminator is a FILLED disc, matching what `renderCircle`
|
|
153
|
+
// actually paints rather than the hollow ring the norm asks for — a preview
|
|
154
|
+
// has one job, which is to look like what lands on the board.
|
|
155
|
+
messageExchange: `<svg ${PREVIEW_ATTRS} fill="none"><rect x="14" y="8" width="107" height="27" rx="3" stroke="#262626" stroke-width="1.6"/><rect x="14" y="8" width="11" height="27" fill="#f4f4f5"/><path d="M25 8 V35" stroke="#262626" stroke-width="1.4"/><rect x="14" y="45" width="107" height="27" rx="3" stroke="#262626" stroke-width="1.6"/><rect x="14" y="45" width="11" height="27" fill="#f4f4f5"/><path d="M25 45 V72" stroke="#262626" stroke-width="1.4"/><circle cx="36" cy="21.5" r="4.5" stroke="#43a06b" stroke-width="1.6"/><rect x="52" y="14" width="30" height="15" rx="3" stroke="#262626" stroke-width="1.6"/><rect x="52" y="51" width="30" height="15" rx="3" stroke="#262626" stroke-width="1.6"/><path d="M45 21.5 H52" stroke="#262626" stroke-width="1.4"/><circle cx="67" cy="31.5" r="2.2" fill="#262626"/><path d="M67 34 V48" stroke="#262626" stroke-width="1.4" stroke-dasharray="3 2.4"/><path d="M64 46 L67 50 L70 46" stroke="#262626" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
76
156
|
};
|
|
77
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* The BPMN basics: two worked scenes — a process end to end and a two-party
|
|
159
|
+
* message exchange — plus a prefab for each of the lean artefacts.
|
|
160
|
+
*/
|
|
78
161
|
function bpmnTemplates() {
|
|
79
162
|
const process = {
|
|
80
163
|
pool: pool(0, 0, 640, 200, 'Process'),
|
|
@@ -91,6 +174,29 @@ function bpmnTemplates() {
|
|
|
91
174
|
c5: seq('task2', 'end'),
|
|
92
175
|
c6: seq('task3', 'end'),
|
|
93
176
|
};
|
|
177
|
+
/**
|
|
178
|
+
* Two participants, and the one arrow that is allowed to cross between them.
|
|
179
|
+
*
|
|
180
|
+
* The card exists because the message flow is the piece of BPMN people get
|
|
181
|
+
* wrong first: a sequence flow may never leave its pool, and the thing that
|
|
182
|
+
* does leave is a different statement with a different line. Laying the two
|
|
183
|
+
* pools out one above the other and drawing both flows once is the shortest
|
|
184
|
+
* way to show that — the solid arrow stays home, the dashed one crosses.
|
|
185
|
+
*
|
|
186
|
+
* Stacked vertically with a 40-unit gutter, so the message flow is a straight
|
|
187
|
+
* orthogonal drop between two tasks that already line up.
|
|
188
|
+
*/
|
|
189
|
+
const messageExchange = {
|
|
190
|
+
customer: pool(0, 0, 640, 200, 'Customer'),
|
|
191
|
+
supplier: pool(0, 240, 640, 200, 'Supplier'),
|
|
192
|
+
start: node('startEvent', 40, 72),
|
|
193
|
+
ask: node('taskUser', 140, 64, 'Place order'),
|
|
194
|
+
answer: node('taskService', 140, 304, 'Confirm order'),
|
|
195
|
+
// Inside the first participant: what happens, and in what order.
|
|
196
|
+
inside: seq('start', 'ask'),
|
|
197
|
+
// Across the two: who told whom.
|
|
198
|
+
across: msg('ask', 'answer'),
|
|
199
|
+
};
|
|
94
200
|
const t = (name, preview, elements) => ({
|
|
95
201
|
name,
|
|
96
202
|
type: 'template',
|
|
@@ -99,6 +205,7 @@ function bpmnTemplates() {
|
|
|
99
205
|
});
|
|
100
206
|
return [
|
|
101
207
|
t('Simple process', previews.process, process),
|
|
208
|
+
t('Message exchange', previews.messageExchange, messageExchange),
|
|
102
209
|
t('Start event', previews.startEvent, single(node('startEvent', 0, 0))),
|
|
103
210
|
t('End event', previews.endEvent, single(node('endEvent', 0, 0))),
|
|
104
211
|
t('Task', previews.task, single(node('task', 0, 0))),
|
|
@@ -1,26 +1,11 @@
|
|
|
1
1
|
import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
|
|
2
|
-
import {
|
|
3
|
-
declare const EdgelessBpmnMenu_base: typeof LitElement & import("@formicoidea/labre-core/_pkgs/global/utils").Constructor<import("@formicoidea/labre-core/_pkgs/affine-widget-edgeless-toolbar").EdgelessToolbarToolClass>;
|
|
2
|
+
import { EdgelessCommandMenu } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
4
3
|
/**
|
|
5
|
-
* The popover above the toolbar for the BPMN toolbox.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* The popover above the toolbar for the BPMN toolbox. Since PF3 it declares
|
|
5
|
+
* nothing: {@link EdgelessCommandMenu} renders `bpmnCommands` for the
|
|
6
|
+
* `senior-menu` surface (`docs/adr/0008`).
|
|
8
7
|
*/
|
|
9
|
-
export declare class EdgelessBpmnMenu extends
|
|
10
|
-
|
|
8
|
+
export declare class EdgelessBpmnMenu extends EdgelessCommandMenu {
|
|
9
|
+
protected owner: "bpmn";
|
|
11
10
|
type: typeof EmptyTool;
|
|
12
|
-
/** Create a flow-object node (native shape) centred on the viewport. */
|
|
13
|
-
private _createNode;
|
|
14
|
-
/** Create a pool (background container) centred on the viewport. */
|
|
15
|
-
private _createPool;
|
|
16
|
-
/**
|
|
17
|
-
* Arm the native connector tool, pre-styled for a BPMN sequence flow:
|
|
18
|
-
* orthogonal, solid, with a filled triangle head. The user then draws from
|
|
19
|
-
* one node to another (endpoints attach to centers).
|
|
20
|
-
*/
|
|
21
|
-
private _activateSequenceFlow;
|
|
22
|
-
private _finish;
|
|
23
|
-
private _track;
|
|
24
|
-
render(): import("lit-html").TemplateResult<1>;
|
|
25
11
|
}
|
|
26
|
-
export {};
|
|
@@ -1,181 +1,14 @@
|
|
|
1
|
-
import { DefaultTool } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
-
import { ConnectorTool } from '@formicoidea/labre-core/gfx/connector';
|
|
3
1
|
import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
|
|
4
|
-
import {
|
|
5
|
-
import { EditPropsStore, TelemetryProvider, } from '@formicoidea/labre-core/shared/services';
|
|
6
|
-
import { EdgelessToolbarToolMixin } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
7
|
-
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
8
|
-
import { css, html, LitElement } from 'lit';
|
|
9
|
-
import { EVENT_END, EVENT_START, END_WIDTH, INNER_FONT_SIZE, NEUTRAL_STROKE, NODE_FILL, NODE_LABEL, NODE_SIZE, NODE_STROKE_WIDTH, SEQUENCE_STROKE, SEQUENCE_WIDTH, START_WIDTH, TASK_RADIUS, } from '../consts.js';
|
|
10
|
-
import { bpmnEndIcon, bpmnGatewayIcon, bpmnPoolIcon, bpmnSequenceIcon, bpmnStartIcon, bpmnTaskIcon, } from './icons.js';
|
|
11
|
-
/** Per-kind native shape + accent presets (style C). */
|
|
12
|
-
const NODE_PRESETS = {
|
|
13
|
-
startEvent: { shapeType: 'ellipse', stroke: EVENT_START, width: START_WIDTH },
|
|
14
|
-
endEvent: { shapeType: 'ellipse', stroke: EVENT_END, width: END_WIDTH },
|
|
15
|
-
task: { shapeType: 'rect', stroke: NEUTRAL_STROKE, width: NODE_STROKE_WIDTH },
|
|
16
|
-
gatewayExclusive: {
|
|
17
|
-
shapeType: 'diamond',
|
|
18
|
-
stroke: NEUTRAL_STROKE,
|
|
19
|
-
width: NODE_STROKE_WIDTH,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
2
|
+
import { EdgelessCommandMenu } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
22
3
|
/**
|
|
23
|
-
* The popover above the toolbar for the BPMN toolbox.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
4
|
+
* The popover above the toolbar for the BPMN toolbox. Since PF3 it declares
|
|
5
|
+
* nothing: {@link EdgelessCommandMenu} renders `bpmnCommands` for the
|
|
6
|
+
* `senior-menu` surface (`docs/adr/0008`).
|
|
26
7
|
*/
|
|
27
|
-
export class EdgelessBpmnMenu extends
|
|
8
|
+
export class EdgelessBpmnMenu extends EdgelessCommandMenu {
|
|
28
9
|
constructor() {
|
|
29
10
|
super(...arguments);
|
|
11
|
+
this.owner = 'bpmn';
|
|
30
12
|
this.type = EmptyTool;
|
|
31
13
|
}
|
|
32
|
-
static { this.styles = css `
|
|
33
|
-
:host {
|
|
34
|
-
display: flex;
|
|
35
|
-
z-index: -1;
|
|
36
|
-
justify-content: center;
|
|
37
|
-
}
|
|
38
|
-
.menu-content {
|
|
39
|
-
display: flex;
|
|
40
|
-
align-items: center;
|
|
41
|
-
justify-content: center;
|
|
42
|
-
}
|
|
43
|
-
.button-group-container {
|
|
44
|
-
display: flex;
|
|
45
|
-
align-items: center;
|
|
46
|
-
gap: 14px;
|
|
47
|
-
fill: var(--affine-icon-color);
|
|
48
|
-
}
|
|
49
|
-
.button-group-container svg {
|
|
50
|
-
width: 24px;
|
|
51
|
-
height: 24px;
|
|
52
|
-
}
|
|
53
|
-
`; }
|
|
54
|
-
/** Create a flow-object node (native shape) centred on the viewport. */
|
|
55
|
-
_createNode(kind) {
|
|
56
|
-
const surface = this.gfx.surface;
|
|
57
|
-
if (!surface)
|
|
58
|
-
return;
|
|
59
|
-
const { w, h } = NODE_SIZE[kind];
|
|
60
|
-
const { centerX: cx, centerY: cy } = this.gfx.viewport;
|
|
61
|
-
const preset = NODE_PRESETS[kind];
|
|
62
|
-
const id = surface.addElement({
|
|
63
|
-
type: 'bpmnNode',
|
|
64
|
-
kind,
|
|
65
|
-
shapeType: preset.shapeType,
|
|
66
|
-
filled: true,
|
|
67
|
-
fillColor: NODE_FILL,
|
|
68
|
-
strokeColor: preset.stroke,
|
|
69
|
-
strokeWidth: preset.width,
|
|
70
|
-
shapeStyle: ShapeStyle.General,
|
|
71
|
-
roughness: 0,
|
|
72
|
-
radius: kind === 'task' ? TASK_RADIUS : 0,
|
|
73
|
-
text: NODE_LABEL[kind] || undefined,
|
|
74
|
-
color: NEUTRAL_STROKE,
|
|
75
|
-
fontFamily: FontFamily.Inter,
|
|
76
|
-
fontSize: INNER_FONT_SIZE,
|
|
77
|
-
textAlign: 'center',
|
|
78
|
-
// BPMN symbols have normative sizes: a long label overflows rather
|
|
79
|
-
// than deforming the node
|
|
80
|
-
textFitMode: TextFitMode.Overflow,
|
|
81
|
-
xywh: new Bound(cx - w / 2, cy - h / 2, w, h).serialize(),
|
|
82
|
-
});
|
|
83
|
-
this._track('FrameworkElementAdded', `node:${kind}`);
|
|
84
|
-
this._finish(id);
|
|
85
|
-
}
|
|
86
|
-
/** Create a pool (background container) centred on the viewport. */
|
|
87
|
-
_createPool() {
|
|
88
|
-
const surface = this.gfx.surface;
|
|
89
|
-
if (!surface)
|
|
90
|
-
return;
|
|
91
|
-
const w = 560;
|
|
92
|
-
const h = 200;
|
|
93
|
-
const { centerX: cx, centerY: cy } = this.gfx.viewport;
|
|
94
|
-
const id = surface.addElement({
|
|
95
|
-
type: 'bpmnPool',
|
|
96
|
-
xywh: new Bound(cx - w / 2, cy - h / 2, w, h).serialize(),
|
|
97
|
-
});
|
|
98
|
-
this._track('FrameworkElementAdded', 'pool');
|
|
99
|
-
this._finish(id);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Arm the native connector tool, pre-styled for a BPMN sequence flow:
|
|
103
|
-
* orthogonal, solid, with a filled triangle head. The user then draws from
|
|
104
|
-
* one node to another (endpoints attach to centers).
|
|
105
|
-
*/
|
|
106
|
-
_activateSequenceFlow() {
|
|
107
|
-
this.edgeless.std.get(EditPropsStore).recordLastProps('connector', {
|
|
108
|
-
mode: ConnectorMode.Orthogonal,
|
|
109
|
-
stroke: SEQUENCE_STROKE,
|
|
110
|
-
strokeStyle: StrokeStyle.Solid,
|
|
111
|
-
strokeWidth: SEQUENCE_WIDTH,
|
|
112
|
-
frontEndpointStyle: PointStyle.None,
|
|
113
|
-
rearEndpointStyle: PointStyle.Triangle,
|
|
114
|
-
});
|
|
115
|
-
this._track('FrameworkToolPicked', 'connector:sequence');
|
|
116
|
-
this.gfx.tool.setTool(ConnectorTool, { mode: ConnectorMode.Orthogonal });
|
|
117
|
-
// Keep the palette open (native sub-menu behaviour).
|
|
118
|
-
}
|
|
119
|
-
_finish(id) {
|
|
120
|
-
const { gfx } = this;
|
|
121
|
-
gfx.doc.captureSync();
|
|
122
|
-
gfx.tool.setTool(DefaultTool);
|
|
123
|
-
gfx.selection.set({ elements: [id], editing: false });
|
|
124
|
-
// Keep the palette open (native sub-menu behaviour).
|
|
125
|
-
}
|
|
126
|
-
_track(event, element) {
|
|
127
|
-
this.edgeless.std.getOptional(TelemetryProvider)?.track(event, {
|
|
128
|
-
framework: 'bpmn',
|
|
129
|
-
element,
|
|
130
|
-
page: 'whiteboard editor',
|
|
131
|
-
segment: 'bpmn toolbox',
|
|
132
|
-
module: 'bpmn menu',
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
render() {
|
|
136
|
-
return html `
|
|
137
|
-
<edgeless-slide-menu>
|
|
138
|
-
<div class="menu-content">
|
|
139
|
-
<div class="button-group-container">
|
|
140
|
-
<edgeless-tool-icon-button
|
|
141
|
-
.tooltip=${'Start event'}
|
|
142
|
-
@click=${() => this._createNode('startEvent')}
|
|
143
|
-
>
|
|
144
|
-
${bpmnStartIcon}
|
|
145
|
-
</edgeless-tool-icon-button>
|
|
146
|
-
<edgeless-tool-icon-button
|
|
147
|
-
.tooltip=${'End event'}
|
|
148
|
-
@click=${() => this._createNode('endEvent')}
|
|
149
|
-
>
|
|
150
|
-
${bpmnEndIcon}
|
|
151
|
-
</edgeless-tool-icon-button>
|
|
152
|
-
<edgeless-tool-icon-button
|
|
153
|
-
.tooltip=${'Task'}
|
|
154
|
-
@click=${() => this._createNode('task')}
|
|
155
|
-
>
|
|
156
|
-
${bpmnTaskIcon}
|
|
157
|
-
</edgeless-tool-icon-button>
|
|
158
|
-
<edgeless-tool-icon-button
|
|
159
|
-
.tooltip=${'Exclusive gateway'}
|
|
160
|
-
@click=${() => this._createNode('gatewayExclusive')}
|
|
161
|
-
>
|
|
162
|
-
${bpmnGatewayIcon}
|
|
163
|
-
</edgeless-tool-icon-button>
|
|
164
|
-
<edgeless-tool-icon-button
|
|
165
|
-
.tooltip=${'Sequence flow'}
|
|
166
|
-
@click=${this._activateSequenceFlow}
|
|
167
|
-
>
|
|
168
|
-
${bpmnSequenceIcon}
|
|
169
|
-
</edgeless-tool-icon-button>
|
|
170
|
-
<edgeless-tool-icon-button
|
|
171
|
-
.tooltip=${'Pool'}
|
|
172
|
-
@click=${this._createPool}
|
|
173
|
-
>
|
|
174
|
-
${bpmnPoolIcon}
|
|
175
|
-
</edgeless-tool-icon-button>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
</edgeless-slide-menu>
|
|
179
|
-
`;
|
|
180
|
-
}
|
|
181
14
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DefaultTool } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
|
|
3
|
+
import { translateKey } from '@formicoidea/labre-core/shared/services';
|
|
3
4
|
import { EdgelessToolbarToolMixin } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
4
5
|
import { SignalWatcher } from '@formicoidea/labre-core/global/lit';
|
|
5
6
|
import { css, html, LitElement } from 'lit';
|
|
@@ -44,7 +45,10 @@ export class EdgelessBpmnSeniorButton extends EdgelessToolbarToolMixin(SignalWat
|
|
|
44
45
|
translate: var(--active-x, 0) var(--active-y, 0);
|
|
45
46
|
rotate: var(--active-r, -2deg);
|
|
46
47
|
scale: var(--active-s, 1);
|
|
47
|
-
transition:
|
|
48
|
+
transition:
|
|
49
|
+
transform 0.3s ease,
|
|
50
|
+
translate 0.3s ease,
|
|
51
|
+
rotate 0.3s ease,
|
|
48
52
|
scale 0.3s ease;
|
|
49
53
|
}
|
|
50
54
|
.bpmn-card svg {
|
|
@@ -71,7 +75,9 @@ export class EdgelessBpmnSeniorButton extends EdgelessToolbarToolMixin(SignalWat
|
|
|
71
75
|
render() {
|
|
72
76
|
return html `<edgeless-toolbar-button
|
|
73
77
|
class="bpmn-button"
|
|
74
|
-
.tooltip=${this.popper
|
|
78
|
+
.tooltip=${this.popper
|
|
79
|
+
? ''
|
|
80
|
+
: translateKey(this.edgeless.std, 'com.labre.framework.bpmn', 'BPMN')}
|
|
75
81
|
.tooltipOffset=${4}
|
|
76
82
|
.active=${!!this.popper}
|
|
77
83
|
@click=${this._toggleMenu}
|
package/dist/toolbar/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ToolbarContext } from '@formicoidea/labre-core/shared/services';
|
|
1
|
+
import { ActionPlacement, 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: [{
|
|
@@ -7,7 +7,32 @@ export declare const bpmnPoolToolbarConfig: {
|
|
|
7
7
|
icon: TemplateResult;
|
|
8
8
|
active(ctx: ToolbarContext): boolean;
|
|
9
9
|
run(ctx: ToolbarContext): void;
|
|
10
|
+
}, {
|
|
11
|
+
id: string;
|
|
12
|
+
when: (ctx: ToolbarContext) => boolean;
|
|
13
|
+
generate: (ctx: ToolbarContext) => {
|
|
14
|
+
icon: TemplateResult;
|
|
15
|
+
tooltip: string;
|
|
16
|
+
run: (runCtx: ToolbarContext) => void;
|
|
17
|
+
};
|
|
18
|
+
}, {
|
|
19
|
+
id: string;
|
|
20
|
+
when: (ctx: ToolbarContext) => boolean;
|
|
21
|
+
generate: (ctx: ToolbarContext) => {
|
|
22
|
+
icon: TemplateResult;
|
|
23
|
+
tooltip: string;
|
|
24
|
+
run: (runCtx: ToolbarContext) => void;
|
|
25
|
+
};
|
|
26
|
+
}, {
|
|
27
|
+
id: string;
|
|
28
|
+
placement: ActionPlacement;
|
|
29
|
+
when: (ctx: ToolbarContext) => boolean;
|
|
30
|
+
generate: (ctx: ToolbarContext) => {
|
|
31
|
+
icon: TemplateResult;
|
|
32
|
+
label: string;
|
|
33
|
+
run: (runCtx: ToolbarContext) => void;
|
|
34
|
+
};
|
|
10
35
|
}];
|
|
11
36
|
readonly when: (ctx: ToolbarContext) => boolean;
|
|
12
37
|
};
|
|
13
|
-
export declare const bpmnPoolToolbarExtension: import("@formicoidea/labre-core/store").ExtensionType;
|
|
38
|
+
export declare const bpmnPoolToolbarExtension: import("@formicoidea/labre-core/store/index.js").ExtensionType;
|
package/dist/toolbar/config.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { EdgelessCRUDIdentifier } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { BpmnPoolElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
-
import { ToolbarModuleExtension, } from '@formicoidea/labre-core/shared/services';
|
|
4
|
-
import { BlockFlavourIdentifier } from '@formicoidea/labre-core/std';
|
|
3
|
+
import { ActionPlacement, ToolbarModuleExtension, translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
4
|
+
import { BlockFlavourIdentifier, getRegisteredCommands, runCommand, } from '@formicoidea/labre-core/std';
|
|
5
5
|
import { html } from 'lit';
|
|
6
|
+
import { bpmnExportXmlIcon, bpmnLaneAddIcon, bpmnLaneRemoveIcon, } from './icons.js';
|
|
6
7
|
const ResizeIcon = html `<svg
|
|
7
8
|
width="24"
|
|
8
9
|
height="24"
|
|
@@ -42,9 +43,92 @@ function booleanToggle(id, tooltip, icon, prop) {
|
|
|
42
43
|
},
|
|
43
44
|
};
|
|
44
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* A toolbar entry that INVOKES a registered command instead of restating what
|
|
48
|
+
* it does — the shape `docs/adr/0010` M3 introduced for the typed-edge
|
|
49
|
+
* inversion, and the reason a lane gesture has one behaviour, one availability
|
|
50
|
+
* rule and one telemetry emission whether it is reached from here, from the
|
|
51
|
+
* palette, from Settings › Shortcuts or from the agent.
|
|
52
|
+
*
|
|
53
|
+
* `generate` rather than a static entry because the i18n seam needs `std`:
|
|
54
|
+
* `translateKey` is what reaches the host's catalogue, and a hard-coded English
|
|
55
|
+
* tooltip would be the one wording a host could not override.
|
|
56
|
+
*/
|
|
57
|
+
function commandAction(id, commandId, labelKey, labelFallback, icon) {
|
|
58
|
+
return {
|
|
59
|
+
id,
|
|
60
|
+
when: (ctx) => {
|
|
61
|
+
const command = findCommand(ctx, commandId);
|
|
62
|
+
return command !== undefined && (command.when?.(ctx.std) ?? true);
|
|
63
|
+
},
|
|
64
|
+
generate: (ctx) => {
|
|
65
|
+
const label = translateKey(ctx.std, labelKey, labelFallback);
|
|
66
|
+
return {
|
|
67
|
+
icon,
|
|
68
|
+
tooltip: label,
|
|
69
|
+
run: (runCtx) => {
|
|
70
|
+
const command = findCommand(runCtx, commandId);
|
|
71
|
+
if (!command)
|
|
72
|
+
return;
|
|
73
|
+
runCommand(runCtx.std, command, {
|
|
74
|
+
surface: 'contextual-toolbar',
|
|
75
|
+
source: 'toolbar:general',
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The same thing, for the "⋮" menu instead of the row.
|
|
84
|
+
*
|
|
85
|
+
* Two differences, and the widget imposes both: a menu line is drawn from
|
|
86
|
+
* `label` (a tooltip on a line that is already words would be a second copy of
|
|
87
|
+
* them), and `placement: ActionPlacement.More` is what partitions it out of the
|
|
88
|
+
* row in the first place — `renderToolbar` splits on exactly that flag, and the
|
|
89
|
+
* entries it collects come from every module contributing to the element,
|
|
90
|
+
* so a framework can add to the "⋮" without owning it.
|
|
91
|
+
*/
|
|
92
|
+
function commandMoreAction(id, commandId, labelKey, labelFallback, icon) {
|
|
93
|
+
return {
|
|
94
|
+
id,
|
|
95
|
+
placement: ActionPlacement.More,
|
|
96
|
+
when: (ctx) => {
|
|
97
|
+
const command = findCommand(ctx, commandId);
|
|
98
|
+
return command !== undefined && (command.when?.(ctx.std) ?? true);
|
|
99
|
+
},
|
|
100
|
+
generate: (ctx) => ({
|
|
101
|
+
icon,
|
|
102
|
+
label: translateKey(ctx.std, labelKey, labelFallback),
|
|
103
|
+
run: (runCtx) => {
|
|
104
|
+
const command = findCommand(runCtx, commandId);
|
|
105
|
+
if (!command)
|
|
106
|
+
return;
|
|
107
|
+
// The same `source` the row's own entries report: the "⋮" is a
|
|
108
|
+
// degradation of the row, not a surface of its own, and the
|
|
109
|
+
// `ElementCreationSource` union deliberately names places rather than
|
|
110
|
+
// widths (`docs/adr/0008`).
|
|
111
|
+
runCommand(runCtx.std, command, {
|
|
112
|
+
surface: 'contextual-toolbar',
|
|
113
|
+
source: 'toolbar:general',
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
}),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const findCommand = (ctx, id) => getRegisteredCommands(ctx.std).find(candidate => candidate.id === id);
|
|
45
120
|
export const bpmnPoolToolbarConfig = {
|
|
46
121
|
actions: [
|
|
47
122
|
booleanToggle('a.toggle-resize', 'Enable / lock resizing', ResizeIcon, 'resizeEnabled'),
|
|
123
|
+
// The two lane gestures, next to the resize toggle: everything on this row
|
|
124
|
+
// is about the SHAPE of the pool rather than about what is drawn in it.
|
|
125
|
+
// Add before remove, because that is the order they can be used in — a pool
|
|
126
|
+
// has no lane to remove until one has been added.
|
|
127
|
+
commandAction('b.add-lane', 'bpmn.addLane', 'com.labre.commands.bpmn.addLane', 'Add lane', bpmnLaneAddIcon),
|
|
128
|
+
commandAction('b.remove-lane', 'bpmn.removeLane', 'com.labre.commands.bpmn.removeLane', 'Remove lane', bpmnLaneRemoveIcon),
|
|
129
|
+
// …and, in the "⋮", the one thing you do to a finished process rather than
|
|
130
|
+
// to the shape of a pool: take it away as a file.
|
|
131
|
+
commandMoreAction('z.export-xml', 'bpmn.exportXml', 'com.labre.commands.bpmn.exportXml', 'Export BPMN XML', bpmnExportXmlIcon),
|
|
48
132
|
],
|
|
49
133
|
when: ctx => ctx.getSurfaceModelsByType(BpmnPoolElementModel).length > 0,
|
|
50
134
|
};
|