@formicoidea/labre-framework-wardley 0.32.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 +49 -2
- package/dist/actions.js +113 -21
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +166 -4
- package/dist/export.d.ts +211 -0
- package/dist/export.js +655 -0
- package/dist/gradient.js +1 -1
- package/dist/import.d.ts +116 -0
- package/dist/import.js +905 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +22 -0
- package/dist/interchange.d.ts +80 -0
- package/dist/interchange.js +138 -0
- package/dist/node/node-renderer.js +1 -1
- package/dist/rules.js +16 -0
- package/dist/templates/index.js +15 -3
- package/dist/templates/maps.js +26 -6
- package/dist/toolbar/config.js +3 -1
- package/dist/toolbar/icons.d.ts +20 -0
- package/dist/toolbar/icons.js +34 -0
- package/dist/toolbar/senior-tool.js +1 -0
- package/dist/toolbar/wardley-senior-button.js +12 -6
- package/dist/view.js +13 -2
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -7,3 +7,21 @@ export { WARDLEY_PROFILES } from './profiles.js';
|
|
|
7
7
|
export { WARDLEY_NUDGES } from './nudges.js';
|
|
8
8
|
export { WARDLEY_NAMING_CONVENTIONS, WARDLEY_READING } from './reading.js';
|
|
9
9
|
export { WARDLEY_RULES } from './rules.js';
|
|
10
|
+
/**
|
|
11
|
+
* The map's own frame, declared. Public because a host that lays elements out
|
|
12
|
+
* against the plot — labre-mcp does, and so does anything that generates a map
|
|
13
|
+
* without an editor — needs the margins the renderer actually uses, and a
|
|
14
|
+
* second copy of four numbers is a copy that drifts (`templates/maps.ts` says
|
|
15
|
+
* how that went the first time). P3's packaging obligation: a value both
|
|
16
|
+
* consumers read is reachable from the index, never by deep import.
|
|
17
|
+
*/
|
|
18
|
+
export { WARDLEY_BACKGROUND } from './background.js';
|
|
19
|
+
/**
|
|
20
|
+
* The OWM DSL, both directions — pure functions of text and models, exported
|
|
21
|
+
* for the reason ADR 0012 § P3 gives: the editor command and labre-mcp call the
|
|
22
|
+
* SAME function, and no serialization logic for a Labre framework lives outside
|
|
23
|
+
* this repo. `exportWardleyOwm` is what replaces labre-mcp's own serializer.
|
|
24
|
+
*/
|
|
25
|
+
export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, type OwmPlot, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, type WardleyExportBoard, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
|
|
26
|
+
export { importWardleyOwm } from './import.js';
|
|
27
|
+
export { WARDLEY_INTERCHANGE, WARDLEY_OWM_EXPORT, WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_FORMAT, WARDLEY_SVG_IMPORT, } from './interchange.js';
|
package/dist/index.js
CHANGED
|
@@ -7,3 +7,25 @@ export { WARDLEY_PROFILES } from './profiles.js';
|
|
|
7
7
|
export { WARDLEY_NUDGES } from './nudges.js';
|
|
8
8
|
export { WARDLEY_NAMING_CONVENTIONS, WARDLEY_READING } from './reading.js';
|
|
9
9
|
export { WARDLEY_RULES } from './rules.js';
|
|
10
|
+
/**
|
|
11
|
+
* The map's own frame, declared. Public because a host that lays elements out
|
|
12
|
+
* against the plot — labre-mcp does, and so does anything that generates a map
|
|
13
|
+
* without an editor — needs the margins the renderer actually uses, and a
|
|
14
|
+
* second copy of four numbers is a copy that drifts (`templates/maps.ts` says
|
|
15
|
+
* how that went the first time). P3's packaging obligation: a value both
|
|
16
|
+
* consumers read is reachable from the index, never by deep import.
|
|
17
|
+
*/
|
|
18
|
+
export { WARDLEY_BACKGROUND } from './background.js';
|
|
19
|
+
/**
|
|
20
|
+
* The OWM DSL, both directions — pure functions of text and models, exported
|
|
21
|
+
* for the reason ADR 0012 § P3 gives: the editor command and labre-mcp call the
|
|
22
|
+
* SAME function, and no serialization logic for a Labre framework lives outside
|
|
23
|
+
* this repo. `exportWardleyOwm` is what replaces labre-mcp's own serializer.
|
|
24
|
+
*/
|
|
25
|
+
export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
|
|
26
|
+
export { importWardleyOwm } from './import.js';
|
|
27
|
+
// Wardley's entries in the interchange registry (`docs/adr/0012`) — the OWM
|
|
28
|
+
// DSL both ways, and the visual-tier SVG fallback. Exported whole so a host can
|
|
29
|
+
// ask what Wardley can read and write without mounting an editor, and call it
|
|
30
|
+
// without one either (P3).
|
|
31
|
+
export { WARDLEY_INTERCHANGE, WARDLEY_OWM_EXPORT, WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_FORMAT, WARDLEY_SVG_IMPORT, } from './interchange.js';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { InterchangeCapability, InterchangeExportCapability, InterchangeFormat, InterchangeImportCapability } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
/**
|
|
3
|
+
* Wardley's entries in the interchange registry (`docs/adr/0012`, P1).
|
|
4
|
+
*
|
|
5
|
+
* Two formats and three rows. Both directions of the OWM DSL — the export is
|
|
6
|
+
* the row the ADR records as **owed** (a Wardley serializer exists today in
|
|
7
|
+
* labre-mcp, outside this repo, and is the one violation of P3 the ADR names;
|
|
8
|
+
* it exists here now, so that repo becomes a caller and its copy is deleted),
|
|
9
|
+
* and the import is the row the ADR calls **the reference Wardley import**,
|
|
10
|
+
* because the OWM DSL is the settled Wardley vocabulary while mermaid's Wardley
|
|
11
|
+
* diagram type is still experimental upstream. Then SVG IN, the visual-tier
|
|
12
|
+
* FALLBACK, which promises recognition and nothing else.
|
|
13
|
+
*
|
|
14
|
+
* The file is laid out as one section per FORMAT, each holding its format
|
|
15
|
+
* object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
|
|
16
|
+
* collecting them. A format is added by adding a section, not by editing one.
|
|
17
|
+
*
|
|
18
|
+
* Everything here is pure. No half has ever had a `std` in sight, and this file
|
|
19
|
+
* adds no editor to any of them: it picks the artefacts the writer speaks about
|
|
20
|
+
* out of a surface's elements, and hands a reader's output straight back.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
|
|
24
|
+
* picture: a `[visibility, evolution]` pair IS a position on the value chain
|
|
25
|
+
* and on the evolution axis, so the whole preservation contract applies and the
|
|
26
|
+
* import needs no invented axis (P2, and D4's "a format that carries
|
|
27
|
+
* coordinates but no pixels").
|
|
28
|
+
*
|
|
29
|
+
* `text/plain`, because that is what a DSL is, and `.owm` first — it is the
|
|
30
|
+
* extension a download is given. `.wm` rides behind it: the same bytes are
|
|
31
|
+
* written under both in the wild, and a picker that refused one would refuse a
|
|
32
|
+
* valid map for the sake of a filename. What the file actually IS is decided by
|
|
33
|
+
* the reader.
|
|
34
|
+
*
|
|
35
|
+
* The two directions share the FORMAT object, deliberately. `owm` is the id
|
|
36
|
+
* under which foreign matter rides on an element (D2), so a reader and a writer
|
|
37
|
+
* that disagreed about it would write payloads the other could not find.
|
|
38
|
+
*/
|
|
39
|
+
export declare const WARDLEY_OWM_EXTENSION = ".owm";
|
|
40
|
+
export declare const WARDLEY_OWM_MIME = "text/plain";
|
|
41
|
+
export declare const WARDLEY_OWM_FORMAT: InterchangeFormat;
|
|
42
|
+
/** `wardley:owm:export` — the row that replaces labre-mcp's own serializer. */
|
|
43
|
+
export declare const WARDLEY_OWM_EXPORT: InterchangeExportCapability;
|
|
44
|
+
/** `wardley:owm:import` — an `.owm` file as a map. */
|
|
45
|
+
export declare const WARDLEY_OWM_IMPORT: InterchangeImportCapability;
|
|
46
|
+
/**
|
|
47
|
+
* SVG. **Visual** — the file carries a rendering, not a model, so it makes
|
|
48
|
+
* exactly one promise: the picture arrives as editable elements.
|
|
49
|
+
*
|
|
50
|
+
* Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
|
|
51
|
+
* rejects "one capability per format, with the framework inferred from the
|
|
52
|
+
* file": a `.svg` is read by several frameworks, and deciding which one a
|
|
53
|
+
* picture is a picture OF is the guess this platform refuses everywhere else.
|
|
54
|
+
* The three constants are the parser package's, so the declarations cannot
|
|
55
|
+
* drift into filtering a picker on different extensions.
|
|
56
|
+
*/
|
|
57
|
+
export declare const WARDLEY_SVG_FORMAT: InterchangeFormat;
|
|
58
|
+
/**
|
|
59
|
+
* `wardley:svg:import` — an SVG as a sketch, best effort.
|
|
60
|
+
*
|
|
61
|
+
* **The heuristics statement and the known failure modes this capability owes
|
|
62
|
+
* (ADR 0012, open question 2) are the module documentation of
|
|
63
|
+
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** Written once
|
|
64
|
+
* there because Wardley and BPMN wrap the SAME parser and therefore make the
|
|
65
|
+
* same guesses — and because the ADR's question is about what a visual
|
|
66
|
+
* capability is ALLOWED to guess, which for both of them is: geometry, and
|
|
67
|
+
* nothing else. A circle is a circle; whether it is a component is the
|
|
68
|
+
* author's sentence, not this reader's.
|
|
69
|
+
*
|
|
70
|
+
* What lands is an ADR 0007 level-1 sketch — plain shapes, brush strokes and
|
|
71
|
+
* editable free text — which the author then PROMOTES onto a map. In
|
|
72
|
+
* particular the two axes and the evolution bands are NOT recovered: a map's
|
|
73
|
+
* coordinates are its meaning, and reading them off a picture would be
|
|
74
|
+
* inventing a position and presenting it as read. {@link WARDLEY_OWM_IMPORT}
|
|
75
|
+
* beside it is the route a user should be pointed at, exactly as P2 says —
|
|
76
|
+
* this one is for the picture somebody sent you from a tool that writes no OWM.
|
|
77
|
+
*/
|
|
78
|
+
export declare const WARDLEY_SVG_IMPORT: InterchangeImportCapability;
|
|
79
|
+
/** Everything Wardley registers, in one list the view extension hands over. */
|
|
80
|
+
export declare const WARDLEY_INTERCHANGE: readonly InterchangeCapability[];
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { interchangeCapabilityId, parseSvgSketch, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { exportWardleyOwmWithWarnings, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
|
|
3
|
+
import { importWardleyOwm } from './import.js';
|
|
4
|
+
/**
|
|
5
|
+
* Wardley's entries in the interchange registry (`docs/adr/0012`, P1).
|
|
6
|
+
*
|
|
7
|
+
* Two formats and three rows. Both directions of the OWM DSL — the export is
|
|
8
|
+
* the row the ADR records as **owed** (a Wardley serializer exists today in
|
|
9
|
+
* labre-mcp, outside this repo, and is the one violation of P3 the ADR names;
|
|
10
|
+
* it exists here now, so that repo becomes a caller and its copy is deleted),
|
|
11
|
+
* and the import is the row the ADR calls **the reference Wardley import**,
|
|
12
|
+
* because the OWM DSL is the settled Wardley vocabulary while mermaid's Wardley
|
|
13
|
+
* diagram type is still experimental upstream. Then SVG IN, the visual-tier
|
|
14
|
+
* FALLBACK, which promises recognition and nothing else.
|
|
15
|
+
*
|
|
16
|
+
* The file is laid out as one section per FORMAT, each holding its format
|
|
17
|
+
* object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
|
|
18
|
+
* collecting them. A format is added by adding a section, not by editing one.
|
|
19
|
+
*
|
|
20
|
+
* Everything here is pure. No half has ever had a `std` in sight, and this file
|
|
21
|
+
* adds no editor to any of them: it picks the artefacts the writer speaks about
|
|
22
|
+
* out of a surface's elements, and hands a reader's output straight back.
|
|
23
|
+
*/
|
|
24
|
+
/* ── OWM (semantic) ───────────────────────────────────────────────────── */
|
|
25
|
+
/**
|
|
26
|
+
* The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
|
|
27
|
+
* picture: a `[visibility, evolution]` pair IS a position on the value chain
|
|
28
|
+
* and on the evolution axis, so the whole preservation contract applies and the
|
|
29
|
+
* import needs no invented axis (P2, and D4's "a format that carries
|
|
30
|
+
* coordinates but no pixels").
|
|
31
|
+
*
|
|
32
|
+
* `text/plain`, because that is what a DSL is, and `.owm` first — it is the
|
|
33
|
+
* extension a download is given. `.wm` rides behind it: the same bytes are
|
|
34
|
+
* written under both in the wild, and a picker that refused one would refuse a
|
|
35
|
+
* valid map for the sake of a filename. What the file actually IS is decided by
|
|
36
|
+
* the reader.
|
|
37
|
+
*
|
|
38
|
+
* The two directions share the FORMAT object, deliberately. `owm` is the id
|
|
39
|
+
* under which foreign matter rides on an element (D2), so a reader and a writer
|
|
40
|
+
* that disagreed about it would write payloads the other could not find.
|
|
41
|
+
*/
|
|
42
|
+
export const WARDLEY_OWM_EXTENSION = '.owm';
|
|
43
|
+
export const WARDLEY_OWM_MIME = 'text/plain';
|
|
44
|
+
export const WARDLEY_OWM_FORMAT = {
|
|
45
|
+
id: WARDLEY_OWM_FORMAT_ID,
|
|
46
|
+
tier: 'semantic',
|
|
47
|
+
extensions: [WARDLEY_OWM_EXTENSION, '.wm'],
|
|
48
|
+
mime: WARDLEY_OWM_MIME,
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* The board as an OWM document.
|
|
52
|
+
*
|
|
53
|
+
* A thin adapter and nothing else: it picks the Wardley artefacts out of the
|
|
54
|
+
* surface, names the file, and passes the writer's losses straight through.
|
|
55
|
+
* There is no second door — `wardley.exportOwm` calls THIS, so the command and
|
|
56
|
+
* the registry cannot produce different bytes, filenames or warnings.
|
|
57
|
+
*
|
|
58
|
+
* `warnings` is omitted rather than empty when the map came out whole, so a
|
|
59
|
+
* caller can ask `if (result.warnings)` and mean it.
|
|
60
|
+
*/
|
|
61
|
+
const runWardleyOwmExport = (elements, context) => {
|
|
62
|
+
const name = wardleySafeFilename(context.name);
|
|
63
|
+
const { text, warnings } = exportWardleyOwmWithWarnings(wardleyBoardFrom(elements), { name });
|
|
64
|
+
return {
|
|
65
|
+
text,
|
|
66
|
+
filename: `${name}${WARDLEY_OWM_EXTENSION}`,
|
|
67
|
+
mime: WARDLEY_OWM_MIME,
|
|
68
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
/** `wardley:owm:export` — the row that replaces labre-mcp's own serializer. */
|
|
72
|
+
export const WARDLEY_OWM_EXPORT = {
|
|
73
|
+
id: interchangeCapabilityId('wardley', WARDLEY_OWM_FORMAT.id, 'export'),
|
|
74
|
+
framework: 'wardley',
|
|
75
|
+
format: WARDLEY_OWM_FORMAT,
|
|
76
|
+
direction: 'export',
|
|
77
|
+
run: runWardleyOwmExport,
|
|
78
|
+
};
|
|
79
|
+
/** `wardley:owm:import` — an `.owm` file as a map. */
|
|
80
|
+
export const WARDLEY_OWM_IMPORT = {
|
|
81
|
+
id: interchangeCapabilityId('wardley', WARDLEY_OWM_FORMAT.id, 'import'),
|
|
82
|
+
framework: 'wardley',
|
|
83
|
+
format: WARDLEY_OWM_FORMAT,
|
|
84
|
+
direction: 'import',
|
|
85
|
+
run: importWardleyOwm,
|
|
86
|
+
};
|
|
87
|
+
/* ── SVG (visual) ─────────────────────────────────────────────────────── */
|
|
88
|
+
/**
|
|
89
|
+
* SVG. **Visual** — the file carries a rendering, not a model, so it makes
|
|
90
|
+
* exactly one promise: the picture arrives as editable elements.
|
|
91
|
+
*
|
|
92
|
+
* Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
|
|
93
|
+
* rejects "one capability per format, with the framework inferred from the
|
|
94
|
+
* file": a `.svg` is read by several frameworks, and deciding which one a
|
|
95
|
+
* picture is a picture OF is the guess this platform refuses everywhere else.
|
|
96
|
+
* The three constants are the parser package's, so the declarations cannot
|
|
97
|
+
* drift into filtering a picker on different extensions.
|
|
98
|
+
*/
|
|
99
|
+
export const WARDLEY_SVG_FORMAT = {
|
|
100
|
+
id: SVG_SKETCH_FORMAT_ID,
|
|
101
|
+
tier: 'visual',
|
|
102
|
+
extensions: [SVG_SKETCH_EXTENSION],
|
|
103
|
+
mime: SVG_SKETCH_MIME,
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* `wardley:svg:import` — an SVG as a sketch, best effort.
|
|
107
|
+
*
|
|
108
|
+
* **The heuristics statement and the known failure modes this capability owes
|
|
109
|
+
* (ADR 0012, open question 2) are the module documentation of
|
|
110
|
+
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** Written once
|
|
111
|
+
* there because Wardley and BPMN wrap the SAME parser and therefore make the
|
|
112
|
+
* same guesses — and because the ADR's question is about what a visual
|
|
113
|
+
* capability is ALLOWED to guess, which for both of them is: geometry, and
|
|
114
|
+
* nothing else. A circle is a circle; whether it is a component is the
|
|
115
|
+
* author's sentence, not this reader's.
|
|
116
|
+
*
|
|
117
|
+
* What lands is an ADR 0007 level-1 sketch — plain shapes, brush strokes and
|
|
118
|
+
* editable free text — which the author then PROMOTES onto a map. In
|
|
119
|
+
* particular the two axes and the evolution bands are NOT recovered: a map's
|
|
120
|
+
* coordinates are its meaning, and reading them off a picture would be
|
|
121
|
+
* inventing a position and presenting it as read. {@link WARDLEY_OWM_IMPORT}
|
|
122
|
+
* beside it is the route a user should be pointed at, exactly as P2 says —
|
|
123
|
+
* this one is for the picture somebody sent you from a tool that writes no OWM.
|
|
124
|
+
*/
|
|
125
|
+
export const WARDLEY_SVG_IMPORT = {
|
|
126
|
+
id: interchangeCapabilityId('wardley', WARDLEY_SVG_FORMAT.id, 'import'),
|
|
127
|
+
framework: 'wardley',
|
|
128
|
+
format: WARDLEY_SVG_FORMAT,
|
|
129
|
+
direction: 'import',
|
|
130
|
+
run: parseSvgSketch,
|
|
131
|
+
};
|
|
132
|
+
/* ── The list the view extension registers ────────────────────────────── */
|
|
133
|
+
/** Everything Wardley registers, in one list the view extension hands over. */
|
|
134
|
+
export const WARDLEY_INTERCHANGE = [
|
|
135
|
+
WARDLEY_OWM_EXPORT,
|
|
136
|
+
WARDLEY_OWM_IMPORT,
|
|
137
|
+
WARDLEY_SVG_IMPORT,
|
|
138
|
+
];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { shape as shapeRenderer } from '@formicoidea/labre-core/gfx/shape';
|
|
3
|
-
import { DefaultTheme } from '@formicoidea/labre-core/model';
|
|
3
|
+
import { DefaultTheme, } from '@formicoidea/labre-core/model';
|
|
4
4
|
import { ANCHOR, ECOSYSTEM, METHOD, NODE_FILL } from './consts.js';
|
|
5
5
|
/**
|
|
6
6
|
* Renderer for a Wardley node. The circle is drawn by REUSING the native shape
|
package/dist/rules.js
CHANGED
|
@@ -56,6 +56,10 @@ const changeArrowAgainstEvolution = {
|
|
|
56
56
|
suggestionKey: 'com.labre.wardley.validation.change-arrow-against-evolution.suggestion',
|
|
57
57
|
suggestionFallback: 'Evolution runs left to right — turn the arrow towards the commodity end, or draw a dependency instead.',
|
|
58
58
|
version: 1,
|
|
59
|
+
provenance: {
|
|
60
|
+
source: 'recommendation',
|
|
61
|
+
reference: 'Wardley mapping — the evolution axis runs left to right, and a component moves with it',
|
|
62
|
+
},
|
|
59
63
|
backgroundRole: WARDLEY_ROLE.map,
|
|
60
64
|
// The frame's own declaration, carried as data exactly like `roles` is: it is
|
|
61
65
|
// where "which way does evolution run" is written, and the engine reads it
|
|
@@ -117,6 +121,10 @@ const inertiaOffTransition = {
|
|
|
117
121
|
// 3: the carrier condition is gone and the position is judged on the bar's
|
|
118
122
|
// extent — a different verdict on the same map, so a new version.
|
|
119
123
|
version: 3,
|
|
124
|
+
provenance: {
|
|
125
|
+
source: 'labre-convention',
|
|
126
|
+
reference: 'Labre convention (PO, recette of 02/08/2026) — Wardley names the zone, not the rule',
|
|
127
|
+
},
|
|
120
128
|
backgroundRole: WARDLEY_ROLE.map,
|
|
121
129
|
background: WARDLEY_BACKGROUND,
|
|
122
130
|
attachment: {
|
|
@@ -186,6 +194,10 @@ const overlappingArtefacts = {
|
|
|
186
194
|
// calibrated with a penetration threshold — the same mistakes, fewer of the
|
|
187
195
|
// things that were never mistakes.
|
|
188
196
|
version: 2,
|
|
197
|
+
provenance: {
|
|
198
|
+
source: 'labre-convention',
|
|
199
|
+
reference: 'Labre readability convention — no Wardley mapping rule speaks of overlapping ink',
|
|
200
|
+
},
|
|
189
201
|
// Not a frame the rule measures against — an overlap is an overlap wherever
|
|
190
202
|
// it happens — but the map a finding is ATTRIBUTED to, so the arbitration
|
|
191
203
|
// "ignore this rule on the whole map" has one map to be written on.
|
|
@@ -251,6 +263,10 @@ const providerAboveConsumer = {
|
|
|
251
263
|
suggestionKey: 'com.labre.wardley.validation.provider-above-consumer.suggestion',
|
|
252
264
|
suggestionFallback: 'Needs run downwards on a Wardley map: move the provider below its consumer — or, if the link was drawn the wrong way round, reverse it.',
|
|
253
265
|
version: 1,
|
|
266
|
+
provenance: {
|
|
267
|
+
source: 'recommendation',
|
|
268
|
+
reference: 'Wardley mapping — the value-chain grammar of the map',
|
|
269
|
+
},
|
|
254
270
|
backgroundRole: WARDLEY_ROLE.map,
|
|
255
271
|
background: WARDLEY_BACKGROUND,
|
|
256
272
|
relativeOrder: {
|
package/dist/templates/index.js
CHANGED
|
@@ -27,7 +27,12 @@ const VARIANT_DEFAULTS = {
|
|
|
27
27
|
};
|
|
28
28
|
const bg = (variant, w = REF_WIDTH) => {
|
|
29
29
|
const h = Math.round((w * 9) / 16);
|
|
30
|
-
return {
|
|
30
|
+
return {
|
|
31
|
+
type: 'wardley',
|
|
32
|
+
variant,
|
|
33
|
+
...VARIANT_DEFAULTS[variant],
|
|
34
|
+
xywh: `[0,0,${w},${h}]`,
|
|
35
|
+
};
|
|
31
36
|
};
|
|
32
37
|
/** A wardley node ellipse positioned by top-left. */
|
|
33
38
|
function node(kind, x, y, d = NODE_SIZE, fill = NODE_FILL, strokeWidth = NODE_STROKE_WIDTH,
|
|
@@ -178,7 +183,9 @@ function market() {
|
|
|
178
183
|
label: label(MARKET_SIZE + 8, 2, 'Market'),
|
|
179
184
|
};
|
|
180
185
|
}
|
|
181
|
-
const single = (el) => ({
|
|
186
|
+
const single = (el) => ({
|
|
187
|
+
a: el,
|
|
188
|
+
});
|
|
182
189
|
const nodeWithLabel = (kind, d, fill, name) => ({
|
|
183
190
|
n: node(kind, 0, 0, d, fill),
|
|
184
191
|
l: label(d + 8, d / 2 - 13, name),
|
|
@@ -187,7 +194,12 @@ const ATTRS = 'width="100%" height="100%" viewBox="0 0 135 80" xmlns="http://www
|
|
|
187
194
|
const bgPreview = (extra = '') => `<svg ${ATTRS} fill="none"><path d="M22 12 V64 H120" stroke="#3b3d42" stroke-width="2"/><path d="M44 12 V64 M68 12 V64 M94 12 V64" stroke="#9aa0a6" stroke-width="0.8"/>${extra}</svg>`;
|
|
188
195
|
const dotPreview = (fill, sw = 2) => `<svg ${ATTRS} fill="none"><circle cx="67" cy="40" r="13" fill="${fill}" stroke="#1f2328" stroke-width="${sw}"/></svg>`;
|
|
189
196
|
function tpl(name, preview, elements) {
|
|
190
|
-
return {
|
|
197
|
+
return {
|
|
198
|
+
name,
|
|
199
|
+
type: 'template',
|
|
200
|
+
preview,
|
|
201
|
+
content: makeTemplateSnapshot(elements, name),
|
|
202
|
+
};
|
|
191
203
|
}
|
|
192
204
|
export const wardleyTemplateCategory = {
|
|
193
205
|
name: 'Wardley',
|
package/dist/templates/maps.js
CHANGED
|
@@ -125,7 +125,11 @@ function lbl(e, v, text, o = {}) {
|
|
|
125
125
|
color: o.color ?? NODE_STROKE,
|
|
126
126
|
fontFamily: FontFamily.Inter,
|
|
127
127
|
fontSize: o.size ?? LABEL_FONT_SIZE,
|
|
128
|
-
textAlign: align === 'right'
|
|
128
|
+
textAlign: align === 'right'
|
|
129
|
+
? TextAlign.Right
|
|
130
|
+
: align === 'center'
|
|
131
|
+
? TextAlign.Center
|
|
132
|
+
: TextAlign.Left,
|
|
129
133
|
xywh: `[${x},${cy + dy},${w},26]`,
|
|
130
134
|
};
|
|
131
135
|
}
|
|
@@ -222,7 +226,12 @@ function title(str) {
|
|
|
222
226
|
const ATTRS = 'width="100%" height="100%" viewBox="0 0 135 80" xmlns="http://www.w3.org/2000/svg"';
|
|
223
227
|
const mapPreview = (extra) => `<svg ${ATTRS} fill="none"><path d="M22 12 V64 H120" stroke="#3b3d42" stroke-width="2"/>${extra}</svg>`;
|
|
224
228
|
function tpl(name, preview, elements) {
|
|
225
|
-
return {
|
|
229
|
+
return {
|
|
230
|
+
name,
|
|
231
|
+
type: 'template',
|
|
232
|
+
preview,
|
|
233
|
+
content: makeTemplateSnapshot(elements, name),
|
|
234
|
+
};
|
|
226
235
|
}
|
|
227
236
|
function ann(e, v) {
|
|
228
237
|
const cx = ex(e);
|
|
@@ -260,7 +269,11 @@ function teaShop() {
|
|
|
260
269
|
annBox: panel(120, 200, 420, 64),
|
|
261
270
|
annText: freeText(132, 208, 400, 'Annotations:\n1. Standardising power lets kettles evolve faster\n2. Hot water is obvious and well known', 13),
|
|
262
271
|
business: stake(0.62, 0.93),
|
|
263
|
-
businessL: lbl(0.62, 0.93, 'Business', {
|
|
272
|
+
businessL: lbl(0.62, 0.93, 'Business', {
|
|
273
|
+
align: 'center',
|
|
274
|
+
dy: -28,
|
|
275
|
+
w: 120,
|
|
276
|
+
}),
|
|
264
277
|
public: stake(0.78, 0.93),
|
|
265
278
|
publicL: lbl(0.78, 0.93, 'Public', { align: 'center', dy: -28, w: 120 }),
|
|
266
279
|
cupOfTea: comp(0.62, 0.74),
|
|
@@ -284,9 +297,16 @@ function teaShop() {
|
|
|
284
297
|
// ABOVE the link it annotates, not across it. Written on the line it reads
|
|
285
298
|
// as a label nobody can read — which is the finding W3 raises, and it was
|
|
286
299
|
// raising it on the map that ships as the canonical example.
|
|
287
|
-
limitedBy: lbl(0.56, 0.43, 'limited by', {
|
|
288
|
-
|
|
289
|
-
|
|
300
|
+
limitedBy: lbl(0.56, 0.43, 'limited by', {
|
|
301
|
+
align: 'center',
|
|
302
|
+
w: 120,
|
|
303
|
+
size: 13,
|
|
304
|
+
dy: -34,
|
|
305
|
+
}),
|
|
306
|
+
ann1a: ann(0.5, 0.385),
|
|
307
|
+
ann1t: annTxt(0.5, 0.385, '1'),
|
|
308
|
+
ann2a: ann(0.84, 0.45),
|
|
309
|
+
ann2t: annTxt(0.84, 0.45, '2'),
|
|
290
310
|
l1: link('business', 'cupOfTea'),
|
|
291
311
|
l2: link('public', 'cupOfTea'),
|
|
292
312
|
l3: link('cupOfTea', 'cup'),
|
package/dist/toolbar/config.js
CHANGED
|
@@ -187,7 +187,9 @@ export const wardleyToolbarConfig = {
|
|
|
187
187
|
if (!bg)
|
|
188
188
|
return;
|
|
189
189
|
createWardleyLegend(ctx.std, bg);
|
|
190
|
-
ctx.std
|
|
190
|
+
ctx.std
|
|
191
|
+
.getOptional(TelemetryProvider)
|
|
192
|
+
?.track('FrameworkLegendCreated', {
|
|
191
193
|
framework: 'wardley',
|
|
192
194
|
element: 'legend',
|
|
193
195
|
page: 'whiteboard editor',
|
package/dist/toolbar/icons.d.ts
CHANGED
|
@@ -24,7 +24,27 @@ export declare const wardleyMethodIcon: import("lit-html").TemplateResult<2>;
|
|
|
24
24
|
export declare const wardleyLegendIcon: import("lit-html").TemplateResult<2>;
|
|
25
25
|
/** Opportunity gradient background: axes + green differential hump + red operational bump. */
|
|
26
26
|
export declare const wardleyOpportunityIcon: import("lit-html").TemplateResult<2>;
|
|
27
|
+
/**
|
|
28
|
+
* Import an SVG sketch — a framed picture with an arrow coming IN.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately the same glyph BPMN gives the same command: the two wrap ONE
|
|
31
|
+
* parser and make one promise, and a reader who has met one should recognise
|
|
32
|
+
* the other without reading its label.
|
|
33
|
+
*/
|
|
34
|
+
export declare const wardleyImportSvgIcon: import("lit-html").TemplateResult<2>;
|
|
27
35
|
/** Benefit/Investment gradient background: axes + zero line + green J-curve. */
|
|
28
36
|
export declare const wardleyBenefitIcon: import("lit-html").TemplateResult<2>;
|
|
29
37
|
/** Evolution-gradient background (Wardley's S-curve presentation): grey at both edges fading to white center. */
|
|
30
38
|
export declare const wardleyEvolutionGradientIcon: import("lit-html").TemplateResult<2>;
|
|
39
|
+
/**
|
|
40
|
+
* Export the map as an OWM document — a page with the map's own axes drawn on
|
|
41
|
+
* it, and an arrow going OUT.
|
|
42
|
+
*
|
|
43
|
+
* The page and the arrow are BPMN's, deliberately: interchange is a platform
|
|
44
|
+
* capability, and a reader who has met one framework's pair should recognise
|
|
45
|
+
* the next without reading its label. What differs is what is drawn ON the page
|
|
46
|
+
* — the value-chain corner, which is what makes it a map rather than a process.
|
|
47
|
+
*/
|
|
48
|
+
export declare const wardleyExportOwmIcon: import("lit-html").TemplateResult<2>;
|
|
49
|
+
/** Import an OWM document — the same page and the same arrow, mirrored back IN. */
|
|
50
|
+
export declare const wardleyImportOwmIcon: import("lit-html").TemplateResult<2>;
|
package/dist/toolbar/icons.js
CHANGED
|
@@ -114,6 +114,18 @@ export const wardleyOpportunityIcon = svg `<svg width="24" height="24" viewBox="
|
|
|
114
114
|
<path d="M5 12 C6 7, 8.5 7, 9.5 11 C11 17, 14 19, 18 20" stroke="${GREEN}" stroke-width="1.7" fill="none" stroke-linecap="round"/>
|
|
115
115
|
<path d="M14.5 19.5 C15.5 16.5, 17 16.5, 18 19" stroke="${RED}" stroke-width="1.7" fill="none" stroke-linecap="round"/>
|
|
116
116
|
</svg>`;
|
|
117
|
+
/**
|
|
118
|
+
* Import an SVG sketch — a framed picture with an arrow coming IN.
|
|
119
|
+
*
|
|
120
|
+
* Deliberately the same glyph BPMN gives the same command: the two wrap ONE
|
|
121
|
+
* parser and make one promise, and a reader who has met one should recognise
|
|
122
|
+
* the other without reading its label.
|
|
123
|
+
*/
|
|
124
|
+
export const wardleyImportSvgIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
125
|
+
<rect x="3" y="5" width="14" height="11" rx="1.5" stroke="currentColor" stroke-width="1.5"/>
|
|
126
|
+
<path d="M3.5 13 7 9.5l3 3 2-2 3.5 3.5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
|
127
|
+
<path d="M19 14.5v6M16.5 17l2.5-2.5 2.5 2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
128
|
+
</svg>`;
|
|
117
129
|
/** Benefit/Investment gradient background: axes + zero line + green J-curve. */
|
|
118
130
|
export const wardleyBenefitIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
119
131
|
<path d="M4 20V4M4 20h16" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
|
|
@@ -132,3 +144,25 @@ export const wardleyEvolutionGradientIcon = svg `<svg width="24" height="24" vie
|
|
|
132
144
|
</defs>
|
|
133
145
|
<rect x="4" y="4.5" width="16" height="15" rx="2" fill="url(#wardleyGreyU)" stroke="currentColor" stroke-width="1.2"/>
|
|
134
146
|
</svg>`;
|
|
147
|
+
/**
|
|
148
|
+
* Export the map as an OWM document — a page with the map's own axes drawn on
|
|
149
|
+
* it, and an arrow going OUT.
|
|
150
|
+
*
|
|
151
|
+
* The page and the arrow are BPMN's, deliberately: interchange is a platform
|
|
152
|
+
* capability, and a reader who has met one framework's pair should recognise
|
|
153
|
+
* the next without reading its label. What differs is what is drawn ON the page
|
|
154
|
+
* — the value-chain corner, which is what makes it a map rather than a process.
|
|
155
|
+
*/
|
|
156
|
+
export const wardleyExportOwmIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
157
|
+
<path d="M13.5 3.5H7a1.5 1.5 0 0 0-1.5 1.5v14A1.5 1.5 0 0 0 7 20.5h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
158
|
+
<path d="M13.5 3.5 18.5 8.5V12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
159
|
+
<path d="M8.5 7v6.5H13" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" opacity="0.6"/>
|
|
160
|
+
<path d="M16 20.5v-6M13.5 18l2.5 2.5 2.5-2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
161
|
+
</svg>`;
|
|
162
|
+
/** Import an OWM document — the same page and the same arrow, mirrored back IN. */
|
|
163
|
+
export const wardleyImportOwmIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
164
|
+
<path d="M13.5 3.5H7a1.5 1.5 0 0 0-1.5 1.5v14A1.5 1.5 0 0 0 7 20.5h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
165
|
+
<path d="M13.5 3.5 18.5 8.5V12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
166
|
+
<path d="M8.5 7v6.5H13" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" opacity="0.6"/>
|
|
167
|
+
<path d="M16 14.5v6M13.5 17l2.5-2.5 2.5 2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
168
|
+
</svg>`;
|
|
@@ -3,6 +3,7 @@ import { html } from 'lit';
|
|
|
3
3
|
export const wardleySeniorTool = SeniorToolExtension('wardley', ({ block }) => {
|
|
4
4
|
return {
|
|
5
5
|
name: 'Wardley map',
|
|
6
|
+
labelKey: 'com.labre.framework.wardley',
|
|
6
7
|
content: html `<edgeless-wardley-senior-button
|
|
7
8
|
.edgeless=${block}
|
|
8
9
|
></edgeless-wardley-senior-button>`,
|
|
@@ -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';
|
|
@@ -46,12 +47,15 @@ export class EdgelessWardleySeniorButton extends EdgelessToolbarToolMixin(Signal
|
|
|
46
47
|
bottom: 0;
|
|
47
48
|
width: 54px;
|
|
48
49
|
height: 54px;
|
|
49
|
-
transform: translateY(var(--y)) scale(var(--s));
|
|
50
|
-
translate: var(--active-x, 0) var(--active-y, 0);
|
|
50
|
+
transform: translateY(var(--y)) scale(var(--s)); /* base */
|
|
51
|
+
translate: var(--active-x, 0) var(--active-y, 0); /* actif */
|
|
51
52
|
rotate: var(--active-r, -2deg);
|
|
52
|
-
|
|
53
|
-
transition:
|
|
54
|
-
|
|
53
|
+
scale: var(--active-s, 1);
|
|
54
|
+
transition:
|
|
55
|
+
transform 0.3s ease,
|
|
56
|
+
translate 0.3s ease,
|
|
57
|
+
rotate 0.3s ease,
|
|
58
|
+
scale 0.3s ease;
|
|
55
59
|
}
|
|
56
60
|
.wardley-card svg {
|
|
57
61
|
display: block;
|
|
@@ -79,7 +83,9 @@ export class EdgelessWardleySeniorButton extends EdgelessToolbarToolMixin(Signal
|
|
|
79
83
|
render() {
|
|
80
84
|
return html `<edgeless-toolbar-button
|
|
81
85
|
class="wardley-button"
|
|
82
|
-
.tooltip=${this.popper
|
|
86
|
+
.tooltip=${this.popper
|
|
87
|
+
? ''
|
|
88
|
+
: translateKey(this.edgeless.std, 'com.labre.framework.wardley', 'Wardley map')}
|
|
83
89
|
.tooltipOffset=${4}
|
|
84
90
|
.active=${!!this.popper}
|
|
85
91
|
@click=${this._toggleMenu}
|
package/dist/view.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReadingProfileExtension, tagsToolbarConfig, validationToolbarConfig, QualityNudgeExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
1
|
+
import { InterchangeExtension, ReadingProfileExtension, tagsToolbarConfig, validationToolbarConfig, QualityNudgeExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { AuditCriterionExtension, ToolbarModuleExtension, UniverseTagDefsExtension, } from '@formicoidea/labre-core/shared/services';
|
|
3
3
|
import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
|
|
4
4
|
import { extendTemplateCategory } from '@formicoidea/labre-core/gfx/template';
|
|
@@ -7,6 +7,7 @@ import { RoleVocabularyExtension } from '@formicoidea/labre-core/std/gfx';
|
|
|
7
7
|
import { WARDLEY_AUDIT_CRITERIA } from './audit-criteria.js';
|
|
8
8
|
import { wardleyCommandIcons, wardleyCommands } from './commands.js';
|
|
9
9
|
import { effects } from './effects.js';
|
|
10
|
+
import { WARDLEY_INTERCHANGE } from './interchange.js';
|
|
10
11
|
import { WARDLEY_TAG_DEFS } from './natures.js';
|
|
11
12
|
import { WARDLEY_PROFILES } from './profiles.js';
|
|
12
13
|
import { WARDLEY_NUDGES } from './nudges.js';
|
|
@@ -75,6 +76,15 @@ export class WardleyViewExtension extends ViewExtensionProvider {
|
|
|
75
76
|
if (this.isEdgeless(context.scope)) {
|
|
76
77
|
context.register(ValidationRuleExtension(WARDLEY_RULES));
|
|
77
78
|
context.register(ValidationProfileExtension(WARDLEY_PROFILES));
|
|
79
|
+
// Both directions of the OWM DSL, and the SVG fallback that reads a
|
|
80
|
+
// picture of a map (`docs/adr/0012`, P1) — ONE registration, because the
|
|
81
|
+
// unit of declaration is the capability and `WARDLEY_INTERCHANGE` is the
|
|
82
|
+
// list of them. HERE, beside the rules, because offering to read or write
|
|
83
|
+
// a file is TOOLING: turning the wardley flag off removes the three
|
|
84
|
+
// commands and leaves every element a past import created — and every
|
|
85
|
+
// byte of `interchange` they carry — exactly where it is
|
|
86
|
+
// (`docs/adr/0009`).
|
|
87
|
+
context.register(InterchangeExtension(WARDLEY_INTERCHANGE));
|
|
78
88
|
// Map quality (PF13.9): the four nudges the tool cannot judge, and
|
|
79
89
|
// nothing else — the on-demand check-up Wardley used to expose beside
|
|
80
90
|
// them was dropped on the PO recette of 02/08/2026. The engine keeps the
|
|
@@ -132,7 +142,8 @@ export class WardleyViewExtension extends ViewExtensionProvider {
|
|
|
132
142
|
// the flag without either side naming the other.
|
|
133
143
|
context.register(ReadingProfileExtension(WARDLEY_READING));
|
|
134
144
|
context.register(wardleySeniorTool);
|
|
135
|
-
// The
|
|
145
|
+
// The Wardley commands — thirteen artefacts plus the two directions of
|
|
146
|
+
// the OWM DSL — ONE registration for both faces: the
|
|
136
147
|
// enumerable registry the sub-menu renders from, and — through
|
|
137
148
|
// `toShortcutDescriptor` — the edgeless chords (w+c, w+l, ...).
|
|
138
149
|
// Registering here inherits both the wardley flag gating and the
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formicoidea/labre-framework-wardley",
|
|
3
3
|
"description": "Labre wardley framework for @formicoidea/labre-core.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.33.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "lajola",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dist"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@formicoidea/labre-core": "0.
|
|
30
|
+
"@formicoidea/labre-core": "0.33.0",
|
|
31
31
|
"lit": "^3.2.0"
|
|
32
32
|
}
|
|
33
33
|
}
|