@formicoidea/labre-framework-bpmn 0.59.0 → 0.60.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.js CHANGED
@@ -7,12 +7,12 @@ import { downloadBlob } from '@formicoidea/labre-core/shared/utils';
7
7
  import { Bound } from '@formicoidea/labre-core/global/gfx';
8
8
  import { GfxControllerIdentifier, GfxGroupLikeElementModel, } from '@formicoidea/labre-core/std/gfx';
9
9
  import { BPMN_POOL_BACKGROUND } from './background.js';
10
- import { BPMN_EDGE_STYLE, bpmnLabelMode, LANE_NAME_FALLBACK, LANE_NAME_KEY, NODE_LABEL, nodeLabelKey, NODE_SIZE, POOL_NAME_FALLBACK, POOL_NAME_KEY, } from './consts.js';
10
+ import { BPMN_EDGE_STYLE, LANE_NAME_FALLBACK, LANE_NAME_KEY, NODE_LABEL, nodeLabelKey, NODE_SIZE, POOL_NAME_FALLBACK, POOL_NAME_KEY, POOL_REF_HEIGHT, POOL_REF_WIDTH, } from './consts.js';
11
11
  import { BPMN_FORMAT_ID, exportBpmnXmlWithWarnings, } from './export.js';
12
12
  import { bpmnLaneOf } from './facts.js';
13
13
  import { BPMN_SVG_IMPORT, BPMN_XML_EXPORT, BPMN_XML_FORMAT, BPMN_XML_IMPORT, bpmnBoardFrom, bpmnSafeFilename, } from './interchange.js';
14
- import { bpmnLabelBoxFor, bpmnLabelProps, bpmnNodeProps, bpmnPoolProps, } from './presets.js';
15
14
  import { BPMN_ROLE } from './roles.js';
15
+ import { bpmnNodeElements, bpmnPoolElement } from './toolbox.js';
16
16
  /**
17
17
  * Standalone creation/activation actions for the BPMN toolbox — lifted out of
18
18
  * `toolbar/bpmn-menu.ts` by PF3 so the menu becomes a pure renderer over the
@@ -54,30 +54,29 @@ export function createBpmnNode(std, kind) {
54
54
  return;
55
55
  const { w, h } = NODE_SIZE[kind];
56
56
  const { centerX: cx, centerY: cy } = gfx.viewport;
57
- // Translated HERE and once: the caption is document content the moment it
58
- // lands, so the host's catalogue is asked at placement and never again
59
- // (`nodeLabelKey`, and #183 on why a French board should not start in
60
- // English).
61
- const seed = NODE_LABEL[kind]
62
- ? translateKey(std, nodeLabelKey(kind), NODE_LABEL[kind])
63
- : undefined;
64
- const external = bpmnLabelMode(kind) === 'external';
65
- // What a node IS lives in one place (`./presets.ts`), because the importer
66
- // creates the same artefacts out of a `.bpmn` file and the two must not
67
- // drift: a task read from a file and a task drawn here are one element type
68
- // in the document, down to the stroke width. The gesture owns the BOX and
69
- // nothing else.
70
- const id = surface.addElement(bpmnNodeProps(kind, {
71
- xywh: new Bound(cx - w / 2, cy - h / 2, w, h).serialize(),
72
- text: external ? undefined : seed,
73
- }));
74
- if (!external || seed === undefined) {
75
- finish(gfx, id);
76
- return;
57
+ // The elements come from the ONE assembly a host with no editor also calls
58
+ // (`toolbox.ts`, `docs/adr/0045`), on the presets the importer reads too
59
+ // (`presets.ts`): a task drawn here, one read from a `.bpmn` file and one a
60
+ // host places are one element type in the document, down to the stroke
61
+ // width. What only an editor has stays here: the viewport centre, and the
62
+ // caption translated HERE and once (`nodeLabelKey`, and #183 on why a French
63
+ // board should not start in English).
64
+ const elements = bpmnNodeElements(kind, { x: cx - w / 2, y: cy - h / 2 }, { name: translateKey(std, nodeLabelKey(kind), NODE_LABEL[kind]) });
65
+ const minted = new Map();
66
+ for (const { id: local, ...props } of elements) {
67
+ if (props.type === 'group') {
68
+ // Through the native group command and not `addElement`: the group's
69
+ // seed title is numbered against the groups already on the board, and
70
+ // its user layer is its highest member's (ADR 0031) — both the editor's.
71
+ const children = Object.keys(props.children);
72
+ finish(gfx, group(gfx, children.map(child => minted.get(child) ?? child)));
73
+ return;
74
+ }
75
+ minted.set(local, surface.addElement(props));
77
76
  }
78
- const { x, y } = bpmnLabelBoxFor(kind, cx, cy);
79
- const labelId = surface.addElement(bpmnLabelProps(seed, x, y));
80
- finish(gfx, group(gfx, [id, labelId]));
77
+ const id = minted.get(`${kind}:node`);
78
+ if (id)
79
+ finish(gfx, id);
81
80
  }
82
81
  /** Create a pool (background container) centred on the viewport. */
83
82
  export function createBpmnPool(std) {
@@ -85,24 +84,20 @@ export function createBpmnPool(std) {
85
84
  const surface = gfx.surface;
86
85
  if (!surface)
87
86
  return;
88
- const w = 560;
89
- const h = 200;
90
87
  const { centerX: cx, centerY: cy } = gfx.viewport;
91
- // What a pool IS lives in one place (`./presets.ts`), beside what a node is
92
- // and for the same reason: the shipped cards build their participants from it
93
- // too, so a pool laid out by a template and one dropped from the toolbox
94
- // cannot say different things. The gesture owns the BOX and nothing else.
88
+ // What a pool IS lives in one place (`bpmnPoolElement`, `toolbox.ts`, over
89
+ // `bpmnPoolProps`), beside what a node is and for the same reason: the
90
+ // shipped cards and a host build their participants from it too, so a pool
91
+ // laid out by a template, one a host places and one dropped from the toolbox
92
+ // cannot say different things. The gesture owns the centre and nothing else.
95
93
  //
96
94
  // The NAME is the one exception, and it is written HERE rather than left to
97
95
  // the model's default (`BpmnPoolElementModel.name = 'Pool'`, a red-zone
98
96
  // field: a document created before this key existed keeps its literal
99
97
  // 'Pool' verbatim). Resolved at placement and never again — content from
100
98
  // the moment it lands, exactly like a node's caption.
101
- const id = surface.addElement(bpmnPoolProps({
102
- xywh: new Bound(cx - w / 2, cy - h / 2, w, h).serialize(),
103
- name: translateKey(std, POOL_NAME_KEY, POOL_NAME_FALLBACK),
104
- }));
105
- finish(gfx, id);
99
+ const { id: _local, ...props } = bpmnPoolElement({ x: cx - POOL_REF_WIDTH / 2, y: cy - POOL_REF_HEIGHT / 2 }, { name: translateKey(std, POOL_NAME_KEY, POOL_NAME_FALLBACK) });
100
+ finish(gfx, surface.addElement(props));
106
101
  }
107
102
  /**
108
103
  * Arm the native connector tool, pre-styled for a BPMN sequence flow:
package/dist/consts.d.ts CHANGED
@@ -268,8 +268,8 @@ export declare const POOL_LANE_MIN_HEIGHT = 24;
268
268
  * participant, and a second lane that matched the first one's height would
269
269
  * claim room the process has not asked for.
270
270
  *
271
- * `actions.ts` and the templates still write these two numbers themselves; the
272
- * declaration names them so there is somewhere for them to converge.
271
+ * The toolbox draws its pool at them (`bpmnPoolElement`, which `createBpmnPool`
272
+ * calls); the templates lay their pools out at sizes of their own.
273
273
  */
274
274
  export declare const POOL_REF_WIDTH = 560;
275
275
  export declare const POOL_REF_HEIGHT = 200;
package/dist/consts.js CHANGED
@@ -329,8 +329,8 @@ export const POOL_LANE_MIN_HEIGHT = 24;
329
329
  * participant, and a second lane that matched the first one's height would
330
330
  * claim room the process has not asked for.
331
331
  *
332
- * `actions.ts` and the templates still write these two numbers themselves; the
333
- * declaration names them so there is somewhere for them to converge.
332
+ * The toolbox draws its pool at them (`bpmnPoolElement`, which `createBpmnPool`
333
+ * calls); the templates lay their pools out at sizes of their own.
334
334
  */
335
335
  export const POOL_REF_WIDTH = 560;
336
336
  export const POOL_REF_HEIGHT = 200;
package/dist/import.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { InterchangeImportError, readXmlElement, } from '@formicoidea/labre-core/interchange';
2
- import { ConnectorMode, PointStyle, StrokeStyle, } from '@formicoidea/labre-core/model/headless';
3
2
  import { Bound } from '@formicoidea/labre-core/global/gfx';
4
- import { ASSOCIATION_STROKE, ASSOCIATION_WIDTH, bpmnLabelMode, MESSAGE_STROKE, MESSAGE_WIDTH, NODE_SIZE, POOL_BAND_WIDTH, POOL_REF_HEIGHT, POOL_REF_WIDTH, SEQUENCE_STROKE, SEQUENCE_WIDTH, } from './consts.js';
3
+ import { bpmnLabelMode, NODE_SIZE, POOL_BAND_WIDTH, POOL_REF_HEIGHT, POOL_REF_WIDTH, } from './consts.js';
5
4
  import { BPMN_FORMAT_ID, BPMN_NS, BPMN_OWN_DECLARATIONS, BPMN_SCOPE, BPMN_XML_OF_KIND, escapeAttr, escapeText, } from './export.js';
6
- import { bpmnLabelBoxUnder, bpmnLabelProps, bpmnNodeProps } from './presets.js';
5
+ import { bpmnConnectorProps, bpmnLabelBoxUnder, bpmnLabelProps, bpmnNodeProps, } from './presets.js';
7
6
  import { BPMN_ROLE } from './roles.js';
8
7
  /**
9
8
  * The remarks whose wording is FIXED, as `[key, English]` pairs — one entry
@@ -637,39 +636,18 @@ const SWEEP_STEP = 200;
637
636
  const SWEEP_COLUMNS = 4;
638
637
  /** The margin between a minted pool's plot and the work inside it. */
639
638
  const MINTED_POOL_PADDING = 40;
640
- /** The connector a role is drawn as — the styles the tools arm, one table. */
639
+ /**
640
+ * The connector a role is drawn as — the styles the tools arm, one table
641
+ * (`bpmnConnectorProps`). A role this reader does not know keeps its own name
642
+ * and takes the sequence flow's line.
643
+ */
641
644
  function connectorProps(role) {
642
- const base = { type: 'connector', role, mode: ConnectorMode.Orthogonal };
643
- if (role === BPMN_ROLE.messageFlow) {
644
- return {
645
- ...base,
646
- stroke: MESSAGE_STROKE,
647
- strokeWidth: MESSAGE_WIDTH,
648
- strokeStyle: StrokeStyle.Dash,
649
- frontEndpointStyle: PointStyle.Circle,
650
- rearEndpointStyle: PointStyle.Arrow,
651
- };
652
- }
653
- if (role === BPMN_ROLE.association) {
654
- return {
655
- ...base,
656
- stroke: ASSOCIATION_STROKE,
657
- strokeWidth: ASSOCIATION_WIDTH,
658
- strokeStyle: StrokeStyle.Dash,
659
- // No head at either end: an association claims no direction, and an
660
- // arrowhead would be the picture claiming one (`docs/adr/0010`).
661
- frontEndpointStyle: PointStyle.None,
662
- rearEndpointStyle: PointStyle.None,
663
- };
664
- }
665
- return {
666
- ...base,
667
- stroke: SEQUENCE_STROKE,
668
- strokeWidth: SEQUENCE_WIDTH,
669
- strokeStyle: StrokeStyle.Solid,
670
- frontEndpointStyle: PointStyle.None,
671
- rearEndpointStyle: PointStyle.Triangle,
672
- };
645
+ const edge = role === BPMN_ROLE.messageFlow
646
+ ? 'messageFlow'
647
+ : role === BPMN_ROLE.association
648
+ ? 'association'
649
+ : 'sequenceFlow';
650
+ return { ...bpmnConnectorProps(edge), role };
673
651
  }
674
652
  /**
675
653
  * The version of the format this file declares (ADR 0012, P2 as amended).
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ 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
7
  export { bpmnLabelFit, type BpmnLabelFit, bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, type BpmnNodePreset, NODE_PRESETS, } from './presets.js';
8
+ export { BPMN_TOOLBOX, bpmnFlowElement, bpmnNodeElements, type BpmnNodeTexts, bpmnPoolElement, type BpmnPoolTexts, } from './toolbox.js';
8
9
  export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
9
10
  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
11
  export { bpmnLaneOf, bpmnPoolOf } from './facts.js';
package/dist/index.js CHANGED
@@ -30,6 +30,8 @@ export { BPMN_KIND_OF_XML, BPMN_QUARANTINE_REASON, importBpmnXml, } from './impo
30
30
  // geometry of its own — a file, a generator, another editor's board — fits their
31
31
  // labels the way the importer does, rather than reinventing the arithmetic.
32
32
  export { bpmnLabelFit, bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, NODE_PRESETS, } from './presets.js';
33
+ // The toolbar as pure builders (`docs/adr/0045`), also on `./interchange`.
34
+ export { BPMN_TOOLBOX, bpmnFlowElement, bpmnNodeElements, bpmnPoolElement, } from './toolbox.js';
33
35
  // What an artefact may BECOME: the declared families, and the spec the generic
34
36
  // morph module is registered with. Data a host can read without an editor.
35
37
  export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
@@ -72,3 +72,4 @@ export declare const BPMN_SVG_FORMAT: InterchangeFormat;
72
72
  * would be a re-render (P2).
73
73
  */
74
74
  export declare const BPMN_SVG_IMPORT: InterchangeImportCapability;
75
+ export { BPMN_TOOLBOX, bpmnFlowElement, bpmnNodeElements, type BpmnNodeTexts, bpmnPoolElement, type BpmnPoolTexts, } from './toolbox.js';
@@ -98,3 +98,6 @@ export const BPMN_SVG_IMPORT = {
98
98
  direction: 'import',
99
99
  run: parseSvgSketch,
100
100
  };
101
+ // The toolbar as pure builders (`docs/adr/0045`): what a host with no editor
102
+ // places to draw the very elements a user places from the toolbar.
103
+ export { BPMN_TOOLBOX, bpmnFlowElement, bpmnNodeElements, bpmnPoolElement, } from './toolbox.js';
package/dist/presets.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
2
2
  import { StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign } from '@formicoidea/labre-core/model/headless';
3
+ import { type BpmnEdgeKey } from './consts.js';
3
4
  /**
4
5
  * What a BPMN artefact is BORN as — the one description of a node's props, read
5
6
  * by every site that creates one.
@@ -174,6 +175,17 @@ export declare function bpmnPoolProps(box: {
174
175
  }): Record<string, unknown> & {
175
176
  type: string;
176
177
  };
178
+ /**
179
+ * One BPMN connecting object, as the props `surface.addElement` takes, ends
180
+ * left to the caller: the role, the orthogonal mode the tools arm the
181
+ * connector with, and the line {@link BPMN_EDGE_STYLE} says it looks like.
182
+ *
183
+ * The importer and the toolbox both write a flow through here, so a flow read
184
+ * out of a `.bpmn` file and one a host places are the line the tool draws.
185
+ */
186
+ export declare function bpmnConnectorProps(edge: BpmnEdgeKey): Record<string, unknown> & {
187
+ type: string;
188
+ };
177
189
  /**
178
190
  * What a node's kind is worth to an element that ALREADY EXISTS — the same
179
191
  * description as {@link bpmnNodeProps}, minus the three things a morph has no
package/dist/presets.js CHANGED
@@ -1,6 +1,6 @@
1
- import { FontFamily, SHAPE_TEXT_PADDING, SHAPE_TEXT_VERTICAL_PADDING, ShapeStyle, StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign, } from '@formicoidea/labre-core/model/headless';
1
+ import { ConnectorMode, FontFamily, SHAPE_TEXT_PADDING, SHAPE_TEXT_VERTICAL_PADDING, ShapeStyle, StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign, } from '@formicoidea/labre-core/model/headless';
2
2
  import { Bound } from '@formicoidea/labre-core/global/gfx';
3
- import { ACTIVITY_FIT_REF, BPMN_LABEL_GAP, BPMN_LABEL_H, BPMN_LABEL_W, CALL_ACTIVITY_WIDTH, END_WIDTH, EVENT_END, EVENT_START, GROUP_RADIUS, GROUP_STROKE, INNER_FONT_SIZE, isBpmnActivityKind, LABEL_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
+ import { ACTIVITY_FIT_REF, BPMN_EDGE_STYLE, BPMN_LABEL_GAP, BPMN_LABEL_H, BPMN_LABEL_W, CALL_ACTIVITY_WIDTH, END_WIDTH, EVENT_END, EVENT_START, GROUP_RADIUS, GROUP_STROKE, INNER_FONT_SIZE, isBpmnActivityKind, LABEL_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';
4
4
  import { BPMN_ROLE, BPMN_ROLE_OF_KIND } from './roles.js';
5
5
  /** Per-kind native shape + accent presets (style C). */
6
6
  export const NODE_PRESETS = {
@@ -320,6 +320,22 @@ export function bpmnPoolProps(box) {
320
320
  xywh: box.xywh,
321
321
  };
322
322
  }
323
+ /**
324
+ * One BPMN connecting object, as the props `surface.addElement` takes, ends
325
+ * left to the caller: the role, the orthogonal mode the tools arm the
326
+ * connector with, and the line {@link BPMN_EDGE_STYLE} says it looks like.
327
+ *
328
+ * The importer and the toolbox both write a flow through here, so a flow read
329
+ * out of a `.bpmn` file and one a host places are the line the tool draws.
330
+ */
331
+ export function bpmnConnectorProps(edge) {
332
+ return {
333
+ type: 'connector',
334
+ role: BPMN_ROLE[edge],
335
+ mode: ConnectorMode.Orthogonal,
336
+ ...BPMN_EDGE_STYLE[edge],
337
+ };
338
+ }
323
339
  /**
324
340
  * The box {@link bpmnMorphProps} hands {@link bpmnNodeProps} and then throws
325
341
  * away. Never written to a document: a morph keeps the geometry the element
@@ -0,0 +1,45 @@
1
+ import type { FrameworkToolbox, SerializedElementProps, ToolboxPoint } from '@formicoidea/labre-core/interchange';
2
+ import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
3
+ import { type BpmnEdgeKey } from './consts.js';
4
+ /**
5
+ * BPMN's toolbar as pure builders (`docs/adr/0045`): what `createBpmnNode`,
6
+ * `createBpmnPool`, the lane gesture and the three flow tools place, with no
7
+ * editor behind them. The actions call these, so an artefact a host places
8
+ * and one placed from the toolbar are the same elements.
9
+ */
10
+ /** The text slot of a flow object, an artefact or a data shape. */
11
+ export interface BpmnNodeTexts {
12
+ /** The name; the kind's English seed when absent. */
13
+ name?: string;
14
+ }
15
+ /**
16
+ * A BPMN artefact at `at` (its top-left), as the toolbar places it.
17
+ *
18
+ * An inscribed kind (activities, the annotation, the group) is ONE element
19
+ * carrying its name inside. An external kind (events, gateways, data shapes)
20
+ * is the bare symbol, its name as a `bpmn:label` text centred under it, and
21
+ * the group that makes the two one artefact, last (R38). The symbol's id is
22
+ * `<local>:node` either way, which is what a flow attaches to.
23
+ */
24
+ export declare function bpmnNodeElements(kind: BpmnNodeKind, at: ToolboxPoint, texts?: BpmnNodeTexts, local?: string): SerializedElementProps[];
25
+ /** The text slots of a pool. */
26
+ export interface BpmnPoolTexts {
27
+ /** The participant's name; `Pool` when absent. */
28
+ name?: string;
29
+ /** One lane name per line, top to bottom; no lane when absent. */
30
+ lanes?: string;
31
+ }
32
+ /**
33
+ * A pool at `at`, at the size the toolbar draws it, with the lanes it is
34
+ * given.
35
+ *
36
+ * Each lane is what one click on "Add lane" appends to a fresh pool: an equal
37
+ * weight of 1, and `Lane N` when its line is blank. Its id is `<local>-lane-N`
38
+ * and not a minted one: a builder mints nothing, and an id unique within the
39
+ * pool is all a lane needs (the importer's own `lane-N` fallback).
40
+ */
41
+ export declare function bpmnPoolElement(at: ToolboxPoint, texts?: BpmnPoolTexts, local?: string): SerializedElementProps;
42
+ /** The connector a flow tool is armed with, between two ends. */
43
+ export declare function bpmnFlowElement(edge: BpmnEdgeKey, from: string, to: string, label?: string): SerializedElementProps;
44
+ /** Every item of the BPMN toolbar that places elements, in the toolbar's order. */
45
+ export declare const BPMN_TOOLBOX: FrameworkToolbox;
@@ -0,0 +1,129 @@
1
+ import { Bound } from '@formicoidea/labre-core/global/gfx';
2
+ import { bpmnCommandsManifest } from './commands-manifest.js';
3
+ import { bpmnLabelMode, LANE_NAME_FALLBACK, NODE_LABEL, NODE_SIZE, POOL_NAME_FALLBACK, POOL_REF_HEIGHT, POOL_REF_WIDTH, } from './consts.js';
4
+ import { bpmnConnectorProps, bpmnLabelBoxFor, bpmnLabelProps, bpmnNodeProps, bpmnPoolProps, } from './presets.js';
5
+ /**
6
+ * A BPMN artefact at `at` (its top-left), as the toolbar places it.
7
+ *
8
+ * An inscribed kind (activities, the annotation, the group) is ONE element
9
+ * carrying its name inside. An external kind (events, gateways, data shapes)
10
+ * is the bare symbol, its name as a `bpmn:label` text centred under it, and
11
+ * the group that makes the two one artefact, last (R38). The symbol's id is
12
+ * `<local>:node` either way, which is what a flow attaches to.
13
+ */
14
+ export function bpmnNodeElements(kind, at, texts = {}, local = kind) {
15
+ const { w, h } = NODE_SIZE[kind];
16
+ const name = texts.name?.trim() || NODE_LABEL[kind];
17
+ const id = (part) => `${local}:${part}`;
18
+ const xywh = new Bound(at.x, at.y, w, h).serialize();
19
+ if (bpmnLabelMode(kind) === 'inscribed') {
20
+ return [{ ...bpmnNodeProps(kind, { xywh, text: name }), id: id('node') }];
21
+ }
22
+ const label = bpmnLabelBoxFor(kind, at.x + w / 2, at.y + h / 2);
23
+ const members = [
24
+ // `text: undefined` and not no key: the symbol is born bare exactly as the
25
+ // toolbar's is, and `bpmnNodeProps` passes the key through unchanged.
26
+ { ...bpmnNodeProps(kind, { xywh, text: undefined }), id: id('node') },
27
+ { ...bpmnLabelProps(name, label.x, label.y), id: id('label') },
28
+ ];
29
+ return [
30
+ ...members,
31
+ {
32
+ type: 'group',
33
+ id: id('group'),
34
+ children: Object.fromEntries(members.map(m => [m.id, true])),
35
+ },
36
+ ];
37
+ }
38
+ /**
39
+ * A pool at `at`, at the size the toolbar draws it, with the lanes it is
40
+ * given.
41
+ *
42
+ * Each lane is what one click on "Add lane" appends to a fresh pool: an equal
43
+ * weight of 1, and `Lane N` when its line is blank. Its id is `<local>-lane-N`
44
+ * and not a minted one: a builder mints nothing, and an id unique within the
45
+ * pool is all a lane needs (the importer's own `lane-N` fallback).
46
+ */
47
+ export function bpmnPoolElement(at, texts = {}, local = 'pool') {
48
+ const names = (texts.lanes ?? '').split('\n').map(line => line.trim());
49
+ const lanes = texts.lanes?.trim()
50
+ ? names.map((name, i) => ({
51
+ id: `${local}-lane-${i + 1}`,
52
+ name: name || LANE_NAME_FALLBACK.replace('{{n}}', String(i + 1)),
53
+ size: 1,
54
+ }))
55
+ : [];
56
+ return {
57
+ ...bpmnPoolProps({
58
+ xywh: new Bound(at.x, at.y, POOL_REF_WIDTH, POOL_REF_HEIGHT).serialize(),
59
+ name: texts.name?.trim() || POOL_NAME_FALLBACK,
60
+ }),
61
+ id: local,
62
+ // Absent until the first lane, as on a pool drawn from the toolbar.
63
+ ...(lanes.length > 0 ? { lanes } : {}),
64
+ };
65
+ }
66
+ /** The connector a flow tool is armed with, between two ends. */
67
+ export function bpmnFlowElement(edge, from, to, label) {
68
+ return {
69
+ ...bpmnConnectorProps(edge),
70
+ source: { id: from },
71
+ target: { id: to },
72
+ ...(label?.trim() ? { text: label.trim() } : {}),
73
+ };
74
+ }
75
+ /** The toolbar command's label, so a host names an item as the toolbar does. */
76
+ function label(commandId) {
77
+ const row = bpmnCommandsManifest.find(r => r.id === commandId);
78
+ return {
79
+ labelKey: row?.labelKey ?? commandId,
80
+ labelFallback: row?.labelFallback ?? commandId,
81
+ };
82
+ }
83
+ const nodeItem = (id, kind, commandId) => ({
84
+ id,
85
+ ...label(commandId),
86
+ texts: ['name'],
87
+ size: NODE_SIZE[kind],
88
+ build: (at, texts, local) => bpmnNodeElements(kind, at, texts, local),
89
+ });
90
+ const flowLink = (id, edge, commandId) => ({
91
+ id,
92
+ ...label(commandId),
93
+ build: (from, to, text) => bpmnFlowElement(edge, from, to, text),
94
+ });
95
+ /** Every item of the BPMN toolbar that places elements, in the toolbar's order. */
96
+ export const BPMN_TOOLBOX = {
97
+ framework: 'bpmn',
98
+ items: [
99
+ nodeItem('start-event', 'startEvent', 'bpmn.addStartEvent'),
100
+ nodeItem('end-event', 'endEvent', 'bpmn.addEndEvent'),
101
+ nodeItem('task', 'task', 'bpmn.addTask'),
102
+ nodeItem('exclusive-gateway', 'gatewayExclusive', 'bpmn.addExclusiveGateway'),
103
+ {
104
+ id: 'pool',
105
+ ...label('bpmn.addPool'),
106
+ texts: ['name', 'lanes'],
107
+ size: { w: POOL_REF_WIDTH, h: POOL_REF_HEIGHT },
108
+ build: (at, texts, local) => [bpmnPoolElement(at, texts, local)],
109
+ },
110
+ nodeItem('user-task', 'taskUser', 'bpmn.addUserTask'),
111
+ nodeItem('service-task', 'taskService', 'bpmn.addServiceTask'),
112
+ nodeItem('sub-process', 'subProcess', 'bpmn.addSubProcess'),
113
+ nodeItem('call-activity', 'callActivity', 'bpmn.addCallActivity'),
114
+ nodeItem('parallel-gateway', 'gatewayParallel', 'bpmn.addParallelGateway'),
115
+ nodeItem('message-start-event', 'startEventMessage', 'bpmn.addMessageStartEvent'),
116
+ nodeItem('timer-start-event', 'startEventTimer', 'bpmn.addTimerStartEvent'),
117
+ nodeItem('message-end-event', 'endEventMessage', 'bpmn.addMessageEndEvent'),
118
+ nodeItem('terminate-end-event', 'endEventTerminate', 'bpmn.addTerminateEndEvent'),
119
+ nodeItem('data-object', 'dataObject', 'bpmn.addDataObject'),
120
+ nodeItem('data-store', 'dataStore', 'bpmn.addDataStore'),
121
+ nodeItem('text-annotation', 'textAnnotation', 'bpmn.addTextAnnotation'),
122
+ nodeItem('group', 'group', 'bpmn.addGroup'),
123
+ ],
124
+ links: [
125
+ flowLink('sequence-flow', 'sequenceFlow', 'bpmn.sequenceFlowTool'),
126
+ flowLink('message-flow', 'messageFlow', 'bpmn.messageFlowTool'),
127
+ flowLink('association', 'association', 'bpmn.associationTool'),
128
+ ],
129
+ };
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.59.0",
4
+ "version": "0.60.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",
@@ -35,7 +35,7 @@
35
35
  "dist"
36
36
  ],
37
37
  "dependencies": {
38
- "@formicoidea/labre-core": "0.59.0",
38
+ "@formicoidea/labre-core": "0.60.0",
39
39
  "lit": "^3.2.0"
40
40
  }
41
41
  }