@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.
Files changed (52) hide show
  1. package/dist/actions.d.ts +213 -0
  2. package/dist/actions.js +467 -0
  3. package/dist/background.d.ts +2 -0
  4. package/dist/background.js +158 -0
  5. package/dist/commands.d.ts +4 -0
  6. package/dist/commands.js +567 -0
  7. package/dist/consts.d.ts +157 -3
  8. package/dist/consts.js +192 -3
  9. package/dist/descriptor.d.ts +8 -3
  10. package/dist/descriptor.js +6 -3
  11. package/dist/element-renderer.d.ts +10 -4
  12. package/dist/element-renderer.js +14 -55
  13. package/dist/element-view.d.ts +100 -8
  14. package/dist/element-view.js +249 -30
  15. package/dist/export.d.ts +277 -0
  16. package/dist/export.js +1802 -0
  17. package/dist/facts.d.ts +48 -0
  18. package/dist/facts.js +127 -0
  19. package/dist/import.d.ts +44 -0
  20. package/dist/import.js +1440 -0
  21. package/dist/index.d.ts +14 -1
  22. package/dist/index.js +46 -1
  23. package/dist/interchange.d.ts +109 -0
  24. package/dist/interchange.js +191 -0
  25. package/dist/morph.d.ts +61 -0
  26. package/dist/morph.js +118 -0
  27. package/dist/node/node-renderer.d.ts +0 -9
  28. package/dist/node/node-renderer.js +294 -17
  29. package/dist/pool-hit.d.ts +98 -0
  30. package/dist/pool-hit.js +130 -0
  31. package/dist/presets.d.ts +114 -0
  32. package/dist/presets.js +232 -0
  33. package/dist/profiles.d.ts +2 -0
  34. package/dist/profiles.js +189 -0
  35. package/dist/roles.d.ts +96 -0
  36. package/dist/roles.js +410 -0
  37. package/dist/rules.d.ts +199 -0
  38. package/dist/rules.js +1539 -0
  39. package/dist/templates/index.js +116 -9
  40. package/dist/toolbar/bpmn-menu.d.ts +6 -21
  41. package/dist/toolbar/bpmn-menu.js +6 -173
  42. package/dist/toolbar/bpmn-senior-button.js +8 -2
  43. package/dist/toolbar/config.d.ts +27 -2
  44. package/dist/toolbar/config.js +86 -2
  45. package/dist/toolbar/icons.d.ts +67 -0
  46. package/dist/toolbar/icons.js +141 -0
  47. package/dist/toolbar/senior-tool.js +1 -0
  48. package/dist/translations.d.ts +16 -0
  49. package/dist/translations.js +20 -0
  50. package/dist/view.d.ts +18 -0
  51. package/dist/view.js +95 -7
  52. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -1 +1,14 @@
1
- export {};
1
+ export { BPMN_POOL_BACKGROUND } from './background.js';
2
+ export { bpmnBoardOf } from './actions.js';
3
+ export { materializeBpmnImport, reportBpmnImport } from './actions.js';
4
+ export { bpmnCommandIcons, bpmnCommands } from './commands.js';
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
+ export { BPMN_KIND_OF_XML, BPMN_QUARANTINE_REASON, importBpmnXml, } from './import.js';
7
+ export { bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, type BpmnNodePreset, NODE_PRESETS, } from './presets.js';
8
+ export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
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
+ export { bpmnLaneOf, bpmnPoolOf } from './facts.js';
11
+ export { BPMN_PROFILES } from './profiles.js';
12
+ export { BPMN_ROLE, BPMN_ROLE_OF_KIND, BPMN_ROLES, type BpmnRole, type BpmnRoleId, } from './roles.js';
13
+ export { BPMN_RULES, BPMN_SEQUENCE_MATRIX } from './rules.js';
14
+ export { bpmnTranslationEntries } from './translations.js';
package/dist/index.js CHANGED
@@ -1 +1,46 @@
1
- export {};
1
+ // The declaration IS the pool: what it looks like, where its plot is and how
2
+ // its lanes divide that plot are all read off this one value (`docs/adr/0009`
3
+ // on why a framework declares rather than draws). Exported so a host — and the
4
+ // audit's own consumers — can answer those questions without a canvas.
5
+ export { BPMN_POOL_BACKGROUND } from './background.js';
6
+ // Everything on the surface the exporter speaks about, in document order — the
7
+ // half of the export that needs an editor, kept apart from the half that does
8
+ // not so a host can substitute either.
9
+ export { bpmnBoardOf } from './actions.js';
10
+ // …and the mirror half of the import: the reader is pure, and THIS is the one
11
+ // thing its caller owes it — the surface mints ids, so a connector's endpoints
12
+ // arrive naming the source file's and are rewritten from the map the returned
13
+ // array already carries (`docs/adr/0012`, D3). Exported so the command, the
14
+ // chromium round trip and a host embedding the reader all write a board the
15
+ // same way.
16
+ export { materializeBpmnImport, reportBpmnImport } from './actions.js';
17
+ export { bpmnCommandIcons, bpmnCommands } from './commands.js';
18
+ // The board as a BPMN 2.0 interchange document. A pure function — element
19
+ // models in, XML out — so a host can export a board it never rendered, and the
20
+ // kind → element table it is built on is readable without running it.
21
+ export { BPMN_FORMAT_ID, BPMN_NS, BPMN_XML_OF_KIND, exportBpmnXml, exportBpmnXmlWithWarnings, isNcName, toNcName, } from './export.js';
22
+ // …and the same file, back as a board. A pure function too — text in, element
23
+ // PROPS out, never live models — so labre-mcp reads a `.bpmn` through the one
24
+ // implementation the editor reads it through (`docs/adr/0012`, P3).
25
+ export { BPMN_KIND_OF_XML, BPMN_QUARANTINE_REASON, importBpmnXml, } from './import.js';
26
+ // What an artefact is BORN as, shared by the palette and the importer so a task
27
+ // read out of a file and a task drawn by hand are one element in the document —
28
+ // and, since the morph, by the toolbar that says one artefact more precisely.
29
+ export { bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, NODE_PRESETS, } from './presets.js';
30
+ // What an artefact may BECOME: the declared families, and the spec the generic
31
+ // morph module is registered with. Data a host can read without an editor.
32
+ export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
33
+ // BPMN's entries in the interchange registry (`docs/adr/0012`) — `.bpmn` out,
34
+ // `.bpmn` in, and the visual-tier SVG fallback. Exported whole so a host can
35
+ // ask what BPMN can read and write without mounting an editor, and call it
36
+ // without one either.
37
+ 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';
38
+ // Where an artefact sits, without a `BlockStdScope`: the same pool and lane
39
+ // attribution the audit computes, answerable by a rule, a host or a test.
40
+ export { bpmnLaneOf, bpmnPoolOf } from './facts.js';
41
+ // The levels of requirement, and the rules they arbitrate: DATA a host can read,
42
+ // ship and reason about without an editor.
43
+ export { BPMN_PROFILES } from './profiles.js';
44
+ export { BPMN_ROLE, BPMN_ROLE_OF_KIND, BPMN_ROLES, } from './roles.js';
45
+ export { BPMN_RULES, BPMN_SEQUENCE_MATRIX } from './rules.js';
46
+ export { bpmnTranslationEntries } from './translations.js';
@@ -0,0 +1,109 @@
1
+ import type { InterchangeCapability, InterchangeExportCapability, InterchangeFormat, InterchangeImportCapability } from '@formicoidea/labre-core/blocks/surface';
2
+ import type { GfxPrimitiveElementModel } from '@formicoidea/labre-core/std/gfx';
3
+ import { type BpmnExportBoard } from './export.js';
4
+ /**
5
+ * BPMN's entries in the interchange registry (`docs/adr/0012`, P1).
6
+ *
7
+ * Both directions of one format, declared as two capabilities and not as one
8
+ * symmetric thing: `.bpmn` OUT shipped in #149, `.bpmn` IN is the worked
9
+ * example D1–D6 specifies, and each makes its own promises. The registry says
10
+ * so in the only way it can — a row per triple.
11
+ *
12
+ * They share the FORMAT object, deliberately. `bpmn` is the id under which
13
+ * foreign matter rides on an element (D2), so a reader and a writer that
14
+ * disagreed about it would write payloads the other could not find; there is
15
+ * one `BPMN_XML_FORMAT` and both point at it.
16
+ *
17
+ * Everything here is pure. Neither serializer nor parser has ever had a `std`
18
+ * in sight, and this file adds no editor to either: it picks the artefacts the
19
+ * writer speaks about out of a surface's elements, and hands the reader's
20
+ * output straight back to whoever asked for it.
21
+ */
22
+ /**
23
+ * BPMN 2.0 XML. **Semantic** — the file carries a model, not a picture, so it
24
+ * takes the whole preservation contract the day an importer is written.
25
+ *
26
+ * `application/xml` and not `text/xml`: the file is not meant to be read as
27
+ * text by whatever opens it, and `.bpmn` is the extension every BPMN tool
28
+ * watches for.
29
+ *
30
+ * `.xml` rides along BEHIND it, and the order is the whole of the difference:
31
+ * the first extension is the one a download is given, so Labre still writes
32
+ * `.bpmn`, and the rest are what a picker offers and what an auto-detecting
33
+ * host indexes on. Half the tools in the wild write the same bytes under the
34
+ * generic extension, and a filter that refused them would refuse a valid
35
+ * process for the sake of a filename — the same argument the shared `FileTypes`
36
+ * table made when this filter lived there, kept now that the filter is built
37
+ * from the format itself. What the file actually IS is decided by the reader,
38
+ * which throws on anything that is not a BPMN `<definitions>`.
39
+ */
40
+ export declare const BPMN_XML_EXTENSION = ".bpmn";
41
+ export declare const BPMN_XML_MIME = "application/xml";
42
+ export declare const BPMN_XML_FORMAT: InterchangeFormat;
43
+ /**
44
+ * The artefacts the exporter speaks about, picked out of a surface's elements
45
+ * and kept in the order they were given.
46
+ *
47
+ * Document order matters twice and both times for the same reason: `bpmnPoolOf`
48
+ * gives a centre inside two overlapping pools to the FIRST one, and the audit's
49
+ * `attribute()` does the same. Sorting here would make the export disagree with
50
+ * the badge the user can see.
51
+ */
52
+ export declare function bpmnBoardFrom(elements: readonly GfxPrimitiveElementModel[]): BpmnExportBoard;
53
+ /**
54
+ * A name a file system will accept, minus the extension.
55
+ *
56
+ * Every character a file system reserves becomes `-`, whitespace runs collapse,
57
+ * and the result is capped: `process` is a better download than one a browser
58
+ * silently refuses.
59
+ *
60
+ * The trailing `[. ]` trim is the Windows tail case and it is not decorative: a
61
+ * board called "Order to cash." would otherwise download as
62
+ * `Order to cash..bpmn`, and Windows strips trailing dots and spaces from a
63
+ * name anyway — so the extension is what would get eaten. Trimmed AFTER the
64
+ * cap, because the cap can create one.
65
+ */
66
+ export declare function bpmnSafeFilename(raw: string | undefined): string;
67
+ /** `bpmn:bpmn:export` — the registry's first capability. */
68
+ export declare const BPMN_XML_EXPORT: InterchangeExportCapability;
69
+ /**
70
+ * `bpmn:bpmn:import` — a `.bpmn` file as a board.
71
+ *
72
+ * A thin adapter over {@link importBpmnXml} and nothing else, which is the
73
+ * whole of what a capability is: the parser is a pure function of a string, so
74
+ * the registry entry has nothing to add to it and deliberately adds nothing.
75
+ * A reader that threw its arms around a surface here would be a reader
76
+ * labre-mcp could not call.
77
+ */
78
+ export declare const BPMN_XML_IMPORT: InterchangeImportCapability;
79
+ /**
80
+ * SVG. **Visual** — the file carries a rendering, not a model.
81
+ *
82
+ * A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
83
+ * singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
84
+ * explicitly rejects "one capability per format, with the framework inferred
85
+ * from the file" — a `.svg` is read by several frameworks and the inference is
86
+ * exactly the guess the ADR forbids everywhere else. The three constants come
87
+ * from the parser's own package so the two declarations cannot drift into
88
+ * disagreeing about the extension or the mime a picker filters on.
89
+ */
90
+ export declare const BPMN_SVG_FORMAT: InterchangeFormat;
91
+ /**
92
+ * `bpmn:svg:import` — an SVG as a sketch, best effort.
93
+ *
94
+ * **The heuristics statement and the known failure modes this capability owes
95
+ * (ADR 0012, open question 2) are the module documentation of
96
+ * `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
97
+ * written once, there, because BPMN and Wardley wrap the SAME parser and
98
+ * therefore make the same guesses; a framework that ever wants narrower or
99
+ * wider recognition writes its own parser and its own paragraph beside it.
100
+ *
101
+ * What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
102
+ * editable free text — that the author then PROMOTES into BPMN artefacts.
103
+ * Nothing here decides that a rounded rectangle in somebody's picture was a
104
+ * task, and no `interchange` payload is written, because a visual round-trip
105
+ * would be a re-render (P2).
106
+ */
107
+ export declare const BPMN_SVG_IMPORT: InterchangeImportCapability;
108
+ /** Everything BPMN registers, in one list the view extension can hand over. */
109
+ export declare const BPMN_INTERCHANGE: readonly InterchangeCapability[];
@@ -0,0 +1,191 @@
1
+ import { interchangeCapabilityId, parseSvgSketch, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { BpmnNodeElementModel, BpmnPoolElementModel, ConnectorElementModel, } from '@formicoidea/labre-core/model';
3
+ import { BPMN_FORMAT_ID, exportBpmnXmlWithWarnings, } from './export.js';
4
+ import { importBpmnXml } from './import.js';
5
+ /**
6
+ * BPMN's entries in the interchange registry (`docs/adr/0012`, P1).
7
+ *
8
+ * Both directions of one format, declared as two capabilities and not as one
9
+ * symmetric thing: `.bpmn` OUT shipped in #149, `.bpmn` IN is the worked
10
+ * example D1–D6 specifies, and each makes its own promises. The registry says
11
+ * so in the only way it can — a row per triple.
12
+ *
13
+ * They share the FORMAT object, deliberately. `bpmn` is the id under which
14
+ * foreign matter rides on an element (D2), so a reader and a writer that
15
+ * disagreed about it would write payloads the other could not find; there is
16
+ * one `BPMN_XML_FORMAT` and both point at it.
17
+ *
18
+ * Everything here is pure. Neither serializer nor parser has ever had a `std`
19
+ * in sight, and this file adds no editor to either: it picks the artefacts the
20
+ * writer speaks about out of a surface's elements, and hands the reader's
21
+ * output straight back to whoever asked for it.
22
+ */
23
+ /* ── The format ───────────────────────────────────────────────────────── */
24
+ /**
25
+ * BPMN 2.0 XML. **Semantic** — the file carries a model, not a picture, so it
26
+ * takes the whole preservation contract the day an importer is written.
27
+ *
28
+ * `application/xml` and not `text/xml`: the file is not meant to be read as
29
+ * text by whatever opens it, and `.bpmn` is the extension every BPMN tool
30
+ * watches for.
31
+ *
32
+ * `.xml` rides along BEHIND it, and the order is the whole of the difference:
33
+ * the first extension is the one a download is given, so Labre still writes
34
+ * `.bpmn`, and the rest are what a picker offers and what an auto-detecting
35
+ * host indexes on. Half the tools in the wild write the same bytes under the
36
+ * generic extension, and a filter that refused them would refuse a valid
37
+ * process for the sake of a filename — the same argument the shared `FileTypes`
38
+ * table made when this filter lived there, kept now that the filter is built
39
+ * from the format itself. What the file actually IS is decided by the reader,
40
+ * which throws on anything that is not a BPMN `<definitions>`.
41
+ */
42
+ export const BPMN_XML_EXTENSION = '.bpmn';
43
+ export const BPMN_XML_MIME = 'application/xml';
44
+ export const BPMN_XML_FORMAT = {
45
+ id: BPMN_FORMAT_ID,
46
+ tier: 'semantic',
47
+ extensions: [BPMN_XML_EXTENSION, '.xml'],
48
+ mime: BPMN_XML_MIME,
49
+ };
50
+ /* ── Pure board helpers ───────────────────────────────────────────────── */
51
+ /**
52
+ * The artefacts the exporter speaks about, picked out of a surface's elements
53
+ * and kept in the order they were given.
54
+ *
55
+ * Document order matters twice and both times for the same reason: `bpmnPoolOf`
56
+ * gives a centre inside two overlapping pools to the FIRST one, and the audit's
57
+ * `attribute()` does the same. Sorting here would make the export disagree with
58
+ * the badge the user can see.
59
+ */
60
+ export function bpmnBoardFrom(elements) {
61
+ const pools = [];
62
+ const nodes = [];
63
+ const connectors = [];
64
+ for (const element of elements) {
65
+ if (element instanceof BpmnPoolElementModel)
66
+ pools.push(element);
67
+ else if (element instanceof BpmnNodeElementModel)
68
+ nodes.push(element);
69
+ else if (element instanceof ConnectorElementModel)
70
+ connectors.push(element);
71
+ }
72
+ return { pools, nodes, connectors };
73
+ }
74
+ /**
75
+ * A name a file system will accept, minus the extension.
76
+ *
77
+ * Every character a file system reserves becomes `-`, whitespace runs collapse,
78
+ * and the result is capped: `process` is a better download than one a browser
79
+ * silently refuses.
80
+ *
81
+ * The trailing `[. ]` trim is the Windows tail case and it is not decorative: a
82
+ * board called "Order to cash." would otherwise download as
83
+ * `Order to cash..bpmn`, and Windows strips trailing dots and spaces from a
84
+ * name anyway — so the extension is what would get eaten. Trimmed AFTER the
85
+ * cap, because the cap can create one.
86
+ */
87
+ export function bpmnSafeFilename(raw) {
88
+ const safe = (raw ?? '')
89
+ .trim()
90
+ .replaceAll(/[\\/:*?"<>|]/g, '-')
91
+ .replaceAll(/\s+/g, ' ')
92
+ .trim()
93
+ .slice(0, 120)
94
+ .replace(/[. ]+$/, '');
95
+ return safe || 'process';
96
+ }
97
+ /* ── The capability ───────────────────────────────────────────────────── */
98
+ /**
99
+ * The board as a BPMN 2.0 interchange document.
100
+ *
101
+ * A thin adapter and nothing else: it splits the surface into the three lists
102
+ * {@link exportBpmnXmlWithWarnings} takes, names the file, and passes the
103
+ * writer's losses straight through. There is no second door — `bpmn.exportXml`
104
+ * calls THIS, so the command and the registry cannot produce different bytes,
105
+ * different filenames or different warnings: there is nowhere for them to
106
+ * differ.
107
+ *
108
+ * `warnings` is omitted rather than empty when the board came out whole, so a
109
+ * caller can ask `if (result.warnings)` and mean it.
110
+ */
111
+ const runBpmnXmlExport = (elements, context) => {
112
+ const name = bpmnSafeFilename(context.name);
113
+ const { text, warnings } = exportBpmnXmlWithWarnings(bpmnBoardFrom(elements), { name });
114
+ return {
115
+ text,
116
+ filename: `${name}${BPMN_XML_EXTENSION}`,
117
+ mime: BPMN_XML_MIME,
118
+ ...(warnings.length > 0 ? { warnings } : {}),
119
+ };
120
+ };
121
+ /** `bpmn:bpmn:export` — the registry's first capability. */
122
+ export const BPMN_XML_EXPORT = {
123
+ id: interchangeCapabilityId('bpmn', BPMN_XML_FORMAT.id, 'export'),
124
+ framework: 'bpmn',
125
+ format: BPMN_XML_FORMAT,
126
+ direction: 'export',
127
+ run: runBpmnXmlExport,
128
+ };
129
+ /**
130
+ * `bpmn:bpmn:import` — a `.bpmn` file as a board.
131
+ *
132
+ * A thin adapter over {@link importBpmnXml} and nothing else, which is the
133
+ * whole of what a capability is: the parser is a pure function of a string, so
134
+ * the registry entry has nothing to add to it and deliberately adds nothing.
135
+ * A reader that threw its arms around a surface here would be a reader
136
+ * labre-mcp could not call.
137
+ */
138
+ export const BPMN_XML_IMPORT = {
139
+ id: interchangeCapabilityId('bpmn', BPMN_XML_FORMAT.id, 'import'),
140
+ framework: 'bpmn',
141
+ format: BPMN_XML_FORMAT,
142
+ direction: 'import',
143
+ run: importBpmnXml,
144
+ };
145
+ /* ── The visual tier ──────────────────────────────────────────────────── */
146
+ /**
147
+ * SVG. **Visual** — the file carries a rendering, not a model.
148
+ *
149
+ * A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
150
+ * singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
151
+ * explicitly rejects "one capability per format, with the framework inferred
152
+ * from the file" — a `.svg` is read by several frameworks and the inference is
153
+ * exactly the guess the ADR forbids everywhere else. The three constants come
154
+ * from the parser's own package so the two declarations cannot drift into
155
+ * disagreeing about the extension or the mime a picker filters on.
156
+ */
157
+ export const BPMN_SVG_FORMAT = {
158
+ id: SVG_SKETCH_FORMAT_ID,
159
+ tier: 'visual',
160
+ extensions: [SVG_SKETCH_EXTENSION],
161
+ mime: SVG_SKETCH_MIME,
162
+ };
163
+ /**
164
+ * `bpmn:svg:import` — an SVG as a sketch, best effort.
165
+ *
166
+ * **The heuristics statement and the known failure modes this capability owes
167
+ * (ADR 0012, open question 2) are the module documentation of
168
+ * `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
169
+ * written once, there, because BPMN and Wardley wrap the SAME parser and
170
+ * therefore make the same guesses; a framework that ever wants narrower or
171
+ * wider recognition writes its own parser and its own paragraph beside it.
172
+ *
173
+ * What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
174
+ * editable free text — that the author then PROMOTES into BPMN artefacts.
175
+ * Nothing here decides that a rounded rectangle in somebody's picture was a
176
+ * task, and no `interchange` payload is written, because a visual round-trip
177
+ * would be a re-render (P2).
178
+ */
179
+ export const BPMN_SVG_IMPORT = {
180
+ id: interchangeCapabilityId('bpmn', BPMN_SVG_FORMAT.id, 'import'),
181
+ framework: 'bpmn',
182
+ format: BPMN_SVG_FORMAT,
183
+ direction: 'import',
184
+ run: parseSvgSketch,
185
+ };
186
+ /** Everything BPMN registers, in one list the view extension can hand over. */
187
+ export const BPMN_INTERCHANGE = [
188
+ BPMN_XML_EXPORT,
189
+ BPMN_XML_IMPORT,
190
+ BPMN_SVG_IMPORT,
191
+ ];
@@ -0,0 +1,61 @@
1
+ import { type MorphSpec } from '@formicoidea/labre-core/blocks/surface';
2
+ import { type BpmnNodeKind } from '@formicoidea/labre-core/model';
3
+ /**
4
+ * What a BPMN artefact may BECOME — the declaration behind the "Change type"
5
+ * dropdown on a selected node's contextual toolbar.
6
+ *
7
+ * ## Families, and why they are a table
8
+ *
9
+ * A user task IS a task, said more precisely; a timer start IS a start event
10
+ * that names its trigger. Realising halfway through a draft that the rectangle
11
+ * should have been a user task is modelling, not a mistake — but the only way
12
+ * through it today is delete, re-draw, re-connect and re-type the label, which
13
+ * loses every sequence flow attached to the node.
14
+ *
15
+ * The six families below are DATA and nothing derives them. The role tree would
16
+ * have been the obvious source and it is the wrong one: `roleIsA` makes
17
+ * `bpmn:task` and `bpmn:sub-process` both `bpmn:activity`, so a derivation
18
+ * would offer "turn this task into a sub-process" — a swap between an atomic
19
+ * unit of work and a stand-in for a whole process, which is not the same
20
+ * artefact said more precisely but a different claim about the process. A
21
+ * reader has to accept the pair, and only a human knows which pairs a reader
22
+ * accepts.
23
+ *
24
+ * Each family is closed under "the same thing, more or less specific":
25
+ *
26
+ * - the three tasks — plain, and the two that say WHO performs the work;
27
+ * - the three starts and the three ends — plain, and the variants that say what
28
+ * triggers the one and what the other does on the way out;
29
+ * - the two gateways — the same diamond, and the marker is the whole difference;
30
+ * - the two data artefacts — a data object dies with the process instance, a
31
+ * data store outlives it, and both are the paperwork rather than the work;
32
+ * - the sub-process and the call activity — the two ways of standing for a
33
+ * whole process, one defined inline and one defined elsewhere. They are each
34
+ * other's neighbour and neither is a task.
35
+ *
36
+ * ## The two kinds with no family, deliberately
37
+ *
38
+ * `textAnnotation` and `group` are what the author drew ON the picture rather
39
+ * than IN it (BPMN 2.0.2 §10.4), and there is nothing either of them could
40
+ * become without ceasing to be commentary. They are in no family, so a
41
+ * selection holding one offers no menu at all — which is the same isolation
42
+ * `roles.ts` already gives them in the role tree.
43
+ */
44
+ export declare const BPMN_MORPH_FAMILIES: readonly (readonly BpmnNodeKind[])[];
45
+ /**
46
+ * BPMN's morph declaration, handed to the generic `morphToolbarConfig`.
47
+ *
48
+ * `propsOf` is the shipped creation builder minus `type` / `xywh` / `text`
49
+ * ({@link bpmnMorphProps}) and `clearOf` the keys the target does not write
50
+ * ({@link bpmnMorphClears}) — both live in `presets.ts`, beside the one
51
+ * description of what a BPMN node IS, precisely so that a morph and a creation
52
+ * can never disagree about what a `callActivity` looks like.
53
+ *
54
+ * That pair is the one place the FULL preset earns its keep on today's table:
55
+ * `subProcess` and `callActivity` differ only in `strokeWidth` (2 ⇄ 4), and the
56
+ * thick border is the whole distinction. Every other family here shares one
57
+ * preset across its members, so the rest of the patch is inert — kept anyway,
58
+ * because a family grows by DECLARATION and nobody would be prompted to check
59
+ * the presets on the day one gains a member that styles itself differently.
60
+ */
61
+ export declare const BPMN_MORPH_SPEC: MorphSpec<BpmnNodeKind>;
package/dist/morph.js ADDED
@@ -0,0 +1,118 @@
1
+ import { morphLabel, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { BpmnNodeElementModel } from '@formicoidea/labre-core/model';
3
+ import { bpmnCommandIcons, bpmnCommands } from './commands.js';
4
+ import { bpmnMorphClears, bpmnMorphProps } from './presets.js';
5
+ import { BPMN_ROLE_OF_KIND } from './roles.js';
6
+ /**
7
+ * What a BPMN artefact may BECOME — the declaration behind the "Change type"
8
+ * dropdown on a selected node's contextual toolbar.
9
+ *
10
+ * ## Families, and why they are a table
11
+ *
12
+ * A user task IS a task, said more precisely; a timer start IS a start event
13
+ * that names its trigger. Realising halfway through a draft that the rectangle
14
+ * should have been a user task is modelling, not a mistake — but the only way
15
+ * through it today is delete, re-draw, re-connect and re-type the label, which
16
+ * loses every sequence flow attached to the node.
17
+ *
18
+ * The six families below are DATA and nothing derives them. The role tree would
19
+ * have been the obvious source and it is the wrong one: `roleIsA` makes
20
+ * `bpmn:task` and `bpmn:sub-process` both `bpmn:activity`, so a derivation
21
+ * would offer "turn this task into a sub-process" — a swap between an atomic
22
+ * unit of work and a stand-in for a whole process, which is not the same
23
+ * artefact said more precisely but a different claim about the process. A
24
+ * reader has to accept the pair, and only a human knows which pairs a reader
25
+ * accepts.
26
+ *
27
+ * Each family is closed under "the same thing, more or less specific":
28
+ *
29
+ * - the three tasks — plain, and the two that say WHO performs the work;
30
+ * - the three starts and the three ends — plain, and the variants that say what
31
+ * triggers the one and what the other does on the way out;
32
+ * - the two gateways — the same diamond, and the marker is the whole difference;
33
+ * - the two data artefacts — a data object dies with the process instance, a
34
+ * data store outlives it, and both are the paperwork rather than the work;
35
+ * - the sub-process and the call activity — the two ways of standing for a
36
+ * whole process, one defined inline and one defined elsewhere. They are each
37
+ * other's neighbour and neither is a task.
38
+ *
39
+ * ## The two kinds with no family, deliberately
40
+ *
41
+ * `textAnnotation` and `group` are what the author drew ON the picture rather
42
+ * than IN it (BPMN 2.0.2 §10.4), and there is nothing either of them could
43
+ * become without ceasing to be commentary. They are in no family, so a
44
+ * selection holding one offers no menu at all — which is the same isolation
45
+ * `roles.ts` already gives them in the role tree.
46
+ */
47
+ export const BPMN_MORPH_FAMILIES = [
48
+ // Declaration order is menu order, and it opens on the plain member of each
49
+ // family: the undecorated artefact is the honest first draft, and the variant
50
+ // is the refinement — the same call `commands.ts` makes about the senior row.
51
+ ['task', 'taskUser', 'taskService'],
52
+ ['startEvent', 'startEventMessage', 'startEventTimer'],
53
+ ['endEvent', 'endEventMessage', 'endEventTerminate'],
54
+ ['gatewayExclusive', 'gatewayParallel'],
55
+ ['dataObject', 'dataStore'],
56
+ ['subProcess', 'callActivity'],
57
+ ];
58
+ /**
59
+ * The creation command that draws each kind, keyed BY that kind.
60
+ *
61
+ * Derived from `telemetry.element`, which is where the kind is already written
62
+ * down (`node:taskUser`) and is documented as a historical value that must not
63
+ * be renamed. Deriving rather than restating is what stops a second table of
64
+ * labels and icons drifting from the one the palette and the catalogue read: a
65
+ * kind whose command is renamed, re-iconed or re-worded changes here for free,
66
+ * and a kind with no creation command at all simply falls back to its own name.
67
+ */
68
+ const NODE_COMMANDS = new Map(bpmnCommands.flatMap(command => {
69
+ const element = command.telemetry?.element;
70
+ return element?.startsWith('node:')
71
+ ? [[element.slice('node:'.length), command]]
72
+ : [];
73
+ }));
74
+ /**
75
+ * A kind's wording: the creation command's own key and English, so the dropdown
76
+ * says "User task" in whatever the host's catalogue says it in, and says
77
+ * exactly what the palette entry that draws one says.
78
+ */
79
+ function labelOf(kind) {
80
+ const command = NODE_COMMANDS.get(kind);
81
+ return {
82
+ key: command?.labelKey,
83
+ fallback: command?.labelFallback ?? kind,
84
+ };
85
+ }
86
+ /** A kind's icon: the creation command's own, reused rather than redrawn. */
87
+ function iconOf(kind) {
88
+ const iconKey = NODE_COMMANDS.get(kind)?.iconKey;
89
+ return ((iconKey && bpmnCommandIcons[iconKey]) || bpmnCommandIcons['bpmn.task']);
90
+ }
91
+ /**
92
+ * BPMN's morph declaration, handed to the generic `morphToolbarConfig`.
93
+ *
94
+ * `propsOf` is the shipped creation builder minus `type` / `xywh` / `text`
95
+ * ({@link bpmnMorphProps}) and `clearOf` the keys the target does not write
96
+ * ({@link bpmnMorphClears}) — both live in `presets.ts`, beside the one
97
+ * description of what a BPMN node IS, precisely so that a morph and a creation
98
+ * can never disagree about what a `callActivity` looks like.
99
+ *
100
+ * That pair is the one place the FULL preset earns its keep on today's table:
101
+ * `subProcess` and `callActivity` differ only in `strokeWidth` (2 ⇄ 4), and the
102
+ * thick border is the whole distinction. Every other family here shares one
103
+ * preset across its members, so the rest of the patch is inert — kept anyway,
104
+ * because a family grows by DECLARATION and nobody would be prompted to check
105
+ * the presets on the day one gains a member that styles itself differently.
106
+ */
107
+ export const BPMN_MORPH_SPEC = {
108
+ framework: 'bpmn',
109
+ families: BPMN_MORPH_FAMILIES,
110
+ modelType: BpmnNodeElementModel,
111
+ kindOf: (model) => model instanceof BpmnNodeElementModel ? model.kind : undefined,
112
+ roleOf: kind => BPMN_ROLE_OF_KIND[kind],
113
+ propsOf: bpmnMorphProps,
114
+ clearOf: bpmnMorphClears,
115
+ labelOf,
116
+ iconOf,
117
+ label: morphLabel('com.labre.morph.toolbar.label', 'Change type'),
118
+ };
@@ -1,14 +1,5 @@
1
1
  import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
2
2
  import { type BpmnNodeElementModel } from '@formicoidea/labre-core/model';
3
- /**
4
- * Renderer for a BPMN flow-object node. The shape body (ellipse / rounded rect
5
- * / diamond) is drawn by REUSING the native shape renderer — so stroke width,
6
- * colors, inner text and theme behave exactly like a native shape. Only
7
- * `gatewayExclusive` is decorated: an X drawn on top in the node's (editable)
8
- * stroke color. Events and task are plain native shapes.
9
- *
10
- * Mirrors the EDGY node renderer.
11
- */
12
3
  export declare const bpmnNode: ElementRenderer<BpmnNodeElementModel>;
13
4
  export declare const BpmnNodeRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
14
5
  identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<BpmnNodeElementModel>>;