@formicoidea/labre-framework-ddd-context-map 0.32.0 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts +38 -0
- package/dist/actions.js +84 -0
- package/dist/background.d.ts +19 -0
- package/dist/background.js +51 -0
- package/dist/commands-manifest.d.ts +18 -0
- package/dist/commands-manifest.js +114 -0
- package/dist/commands.js +37 -61
- package/dist/descriptor.d.ts +7 -2
- package/dist/descriptor.js +5 -2
- package/dist/element-renderer.d.ts +17 -0
- package/dist/element-renderer.js +15 -0
- package/dist/element-view.d.ts +17 -0
- package/dist/element-view.js +18 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/legend.d.ts +20 -0
- package/dist/legend.js +56 -0
- package/dist/nudges.d.ts +19 -0
- package/dist/nudges.js +55 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +73 -0
- package/dist/roles.d.ts +65 -0
- package/dist/roles.js +64 -0
- package/dist/rules.d.ts +2 -0
- package/dist/rules.js +264 -0
- package/dist/toolbar/board-config.d.ts +30 -0
- package/dist/toolbar/board-config.js +87 -0
- package/dist/toolbar/context-map-menu.d.ts +1 -1
- package/dist/toolbar/context-map-menu.js +1 -1
- package/dist/toolbar/senior-button.d.ts +1 -0
- package/dist/toolbar/senior-button.js +1 -0
- package/dist/toolbar/senior-tool.js +1 -0
- package/dist/translations.d.ts +9 -9
- package/dist/translations.js +22 -11
- package/dist/view.d.ts +17 -1
- package/dist/view.js +60 -2
- package/package.json +7 -3
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { GfxController } from '@formicoidea/labre-core/std/gfx';
|
|
2
|
+
import { type ContextMapPatternKind } from './roles.js';
|
|
3
|
+
/** Create the board at the viewport centre, select it, return to the default tool. */
|
|
4
|
+
export declare function createContextMapBoard(gfx: GfxController): void;
|
|
5
|
+
/**
|
|
6
|
+
* Activate the native connector tool, pre-styled and TYPED for one Context Map
|
|
7
|
+
* pattern. The user then drags from one bounded context to another and the
|
|
8
|
+
* endpoints attach.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this replaces the old palette entry
|
|
11
|
+
*
|
|
12
|
+
* Until WS2 each pattern entry dropped a free-floating GROUP at the viewport
|
|
13
|
+
* centre: a connector between two points in mid-air, an abbreviation tag and,
|
|
14
|
+
* for the U/D patterns, two letters. It looked like the notation and said
|
|
15
|
+
* nothing — the link was attached to nothing, so no rule could read its ends,
|
|
16
|
+
* and the user still had to drag both endpoints onto the contexts by hand.
|
|
17
|
+
*
|
|
18
|
+
* The gesture now IS the statement (`docs/adr/0010`): the tool announces which
|
|
19
|
+
* way to drag (the role's `gestureHint`), the drawn connector carries the
|
|
20
|
+
* pattern's role, and the endpoints are real element references — which is what
|
|
21
|
+
* makes the whole of `rules.ts` possible.
|
|
22
|
+
*
|
|
23
|
+
* ## What the style says, and what the role says
|
|
24
|
+
*
|
|
25
|
+
* Style is presentation: `dashed` for the two "no real integration" patterns
|
|
26
|
+
* (Separate Ways, Big Ball of Mud), a rear arrowhead for the five U/D ones so
|
|
27
|
+
* the sheet still reads at a glance. Meaning is the role, and only the role: a
|
|
28
|
+
* user restyling a link never changes what it means, and a link drawn before
|
|
29
|
+
* WS2 keeps its old look and stays neutral.
|
|
30
|
+
*
|
|
31
|
+
* The abbreviation TAG is not drawn any more. A label riding on the connector is
|
|
32
|
+
* `ConnectorToolOptions.label`, which was cut from v1 — the pattern reads from
|
|
33
|
+
* the hover reveal (M2) and the toolbar until it lands.
|
|
34
|
+
*/
|
|
35
|
+
export declare function activateContextMapRelationship(gfx: GfxController, kind: ContextMapPatternKind, style: {
|
|
36
|
+
upDown: boolean;
|
|
37
|
+
dashed: boolean;
|
|
38
|
+
}): void;
|
package/dist/actions.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { backgroundSize, DefaultTool } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { ConnectorTool } from '@formicoidea/labre-core/gfx/connector';
|
|
3
|
+
import { LABEL_COLOR } from '@formicoidea/labre-ddd-shared';
|
|
4
|
+
import { ConnectorMode, PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
|
|
5
|
+
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
6
|
+
import { CONTEXT_MAP_BACKGROUND } from './background.js';
|
|
7
|
+
import { CM_PATTERN_ROLE } from './roles.js';
|
|
8
|
+
/**
|
|
9
|
+
* Creation / activation actions for the Context Map toolbox — the BEHAVIOUR
|
|
10
|
+
* layer, depending on nothing but the {@link GfxController}.
|
|
11
|
+
*
|
|
12
|
+
* They emit no telemetry: since PF3 the single emission point is the command
|
|
13
|
+
* registry's `runCommand` (`docs/adr/0008`).
|
|
14
|
+
*/
|
|
15
|
+
const RELATIONSHIP_STROKE_WIDTH = 2;
|
|
16
|
+
/** Create the board at the viewport centre, select it, return to the default tool. */
|
|
17
|
+
export function createContextMapBoard(gfx) {
|
|
18
|
+
if (!gfx.surface)
|
|
19
|
+
return;
|
|
20
|
+
const { width, height } = backgroundSize(CONTEXT_MAP_BACKGROUND);
|
|
21
|
+
const { centerX, centerY } = gfx.viewport;
|
|
22
|
+
const id = gfx.surface.addElement({
|
|
23
|
+
type: CONTEXT_MAP_BACKGROUND.type,
|
|
24
|
+
// The board is a first-class role: rules frame contexts against
|
|
25
|
+
// `context-map:board`, never against the `contextMap` element type. The
|
|
26
|
+
// declaration owns it, so a templated board and a hand-drawn one agree.
|
|
27
|
+
role: CONTEXT_MAP_BACKGROUND.role,
|
|
28
|
+
resizeEnabled: CONTEXT_MAP_BACKGROUND.geometry.resizable,
|
|
29
|
+
xywh: new Bound(centerX - width / 2, centerY - height / 2, width, height).serialize(),
|
|
30
|
+
});
|
|
31
|
+
gfx.doc.captureSync();
|
|
32
|
+
gfx.tool.setTool(DefaultTool);
|
|
33
|
+
gfx.selection.set({ elements: [id], editing: false });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Activate the native connector tool, pre-styled and TYPED for one Context Map
|
|
37
|
+
* pattern. The user then drags from one bounded context to another and the
|
|
38
|
+
* endpoints attach.
|
|
39
|
+
*
|
|
40
|
+
* ## Why this replaces the old palette entry
|
|
41
|
+
*
|
|
42
|
+
* Until WS2 each pattern entry dropped a free-floating GROUP at the viewport
|
|
43
|
+
* centre: a connector between two points in mid-air, an abbreviation tag and,
|
|
44
|
+
* for the U/D patterns, two letters. It looked like the notation and said
|
|
45
|
+
* nothing — the link was attached to nothing, so no rule could read its ends,
|
|
46
|
+
* and the user still had to drag both endpoints onto the contexts by hand.
|
|
47
|
+
*
|
|
48
|
+
* The gesture now IS the statement (`docs/adr/0010`): the tool announces which
|
|
49
|
+
* way to drag (the role's `gestureHint`), the drawn connector carries the
|
|
50
|
+
* pattern's role, and the endpoints are real element references — which is what
|
|
51
|
+
* makes the whole of `rules.ts` possible.
|
|
52
|
+
*
|
|
53
|
+
* ## What the style says, and what the role says
|
|
54
|
+
*
|
|
55
|
+
* Style is presentation: `dashed` for the two "no real integration" patterns
|
|
56
|
+
* (Separate Ways, Big Ball of Mud), a rear arrowhead for the five U/D ones so
|
|
57
|
+
* the sheet still reads at a glance. Meaning is the role, and only the role: a
|
|
58
|
+
* user restyling a link never changes what it means, and a link drawn before
|
|
59
|
+
* WS2 keeps its old look and stays neutral.
|
|
60
|
+
*
|
|
61
|
+
* The abbreviation TAG is not drawn any more. A label riding on the connector is
|
|
62
|
+
* `ConnectorToolOptions.label`, which was cut from v1 — the pattern reads from
|
|
63
|
+
* the hover reveal (M2) and the toolbar until it lands.
|
|
64
|
+
*/
|
|
65
|
+
export function activateContextMapRelationship(gfx, kind, style) {
|
|
66
|
+
gfx.tool.setTool(ConnectorTool, {
|
|
67
|
+
mode: ConnectorMode.Straight,
|
|
68
|
+
role: CM_PATTERN_ROLE[kind],
|
|
69
|
+
// The look rides on the activation, never through the last-props store:
|
|
70
|
+
// the plain connector tool must keep the user's own style (#144 M1).
|
|
71
|
+
style: {
|
|
72
|
+
stroke: LABEL_COLOR,
|
|
73
|
+
strokeStyle: style.dashed ? StrokeStyle.Dash : StrokeStyle.Solid,
|
|
74
|
+
strokeWidth: RELATIONSHIP_STROKE_WIDTH,
|
|
75
|
+
frontEndpointStyle: PointStyle.None,
|
|
76
|
+
// The arrow points at the DOWNSTREAM end, which is the target: the
|
|
77
|
+
// role's verb is "is upstream of", so the source is the upstream
|
|
78
|
+
// context.
|
|
79
|
+
rearEndpointStyle: style.upDown ? PointStyle.Arrow : PointStyle.None,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
// The Context Map palette stays open (native sub-menu behaviour): it only
|
|
83
|
+
// closes on re-click of the senior button, another senior tool, or Escape.
|
|
84
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FrameworkBackgroundDef } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
/**
|
|
3
|
+
* The Context Map board, DECLARED (the `FrameworkBackgroundDef` primitive).
|
|
4
|
+
*
|
|
5
|
+
* The emptiest declaration in the library, and deliberately so: **no axes, no
|
|
6
|
+
* zones**. A Context Map is a graph, not a chart — a bounded context drawn top
|
|
7
|
+
* left says nothing more than one drawn bottom right, and graduating the card
|
|
8
|
+
* would invent a frame of reference the framework does not have. What the
|
|
9
|
+
* declaration is for here is the ROLE and the geometry: `context-map:board` is
|
|
10
|
+
* what a rule frames its subjects against, and it is what a per-map validation
|
|
11
|
+
* profile is written on.
|
|
12
|
+
*
|
|
13
|
+
* The palette carries the notation's two boundary colours even though nothing in
|
|
14
|
+
* this file paints them. Same precedent as the Wardley tone convention: a
|
|
15
|
+
* palette entry is a declared REFERENCE, so the day a `tone-convention` rule
|
|
16
|
+
* asks "is this bubble drawn in the map's own blue" the answer is already
|
|
17
|
+
* written down, in one place, beside the card it belongs to.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CONTEXT_MAP_BACKGROUND: FrameworkBackgroundDef;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CLOUD, CM_BUBBLE, FONT_FAMILY } from '@formicoidea/labre-ddd-shared';
|
|
2
|
+
import { CONTEXT_MAP_ROLE } from './roles.js';
|
|
3
|
+
/**
|
|
4
|
+
* The Context Map board, DECLARED (the `FrameworkBackgroundDef` primitive).
|
|
5
|
+
*
|
|
6
|
+
* The emptiest declaration in the library, and deliberately so: **no axes, no
|
|
7
|
+
* zones**. A Context Map is a graph, not a chart — a bounded context drawn top
|
|
8
|
+
* left says nothing more than one drawn bottom right, and graduating the card
|
|
9
|
+
* would invent a frame of reference the framework does not have. What the
|
|
10
|
+
* declaration is for here is the ROLE and the geometry: `context-map:board` is
|
|
11
|
+
* what a rule frames its subjects against, and it is what a per-map validation
|
|
12
|
+
* profile is written on.
|
|
13
|
+
*
|
|
14
|
+
* The palette carries the notation's two boundary colours even though nothing in
|
|
15
|
+
* this file paints them. Same precedent as the Wardley tone convention: a
|
|
16
|
+
* palette entry is a declared REFERENCE, so the day a `tone-convention` rule
|
|
17
|
+
* asks "is this bubble drawn in the map's own blue" the answer is already
|
|
18
|
+
* written down, in one place, beside the card it belongs to.
|
|
19
|
+
*/
|
|
20
|
+
export const CONTEXT_MAP_BACKGROUND = {
|
|
21
|
+
type: 'contextMap',
|
|
22
|
+
role: CONTEXT_MAP_ROLE.board,
|
|
23
|
+
geometry: {
|
|
24
|
+
// Wide and free: a context map grows sideways as contexts are found, so
|
|
25
|
+
// neither dimension is locked to the other and the handles are offered from
|
|
26
|
+
// the start — the opposite call from the Wardley map, which is a frame of
|
|
27
|
+
// reference you place things on rather than a sheet you spread out.
|
|
28
|
+
width: 1400,
|
|
29
|
+
height: 900,
|
|
30
|
+
lockAspectRatio: false,
|
|
31
|
+
resizable: true,
|
|
32
|
+
margin: { top: 24, right: 24, bottom: 24, left: 24 },
|
|
33
|
+
},
|
|
34
|
+
chrome: {
|
|
35
|
+
fontFamily: FONT_FAMILY,
|
|
36
|
+
palette: {
|
|
37
|
+
card: '#ffffff',
|
|
38
|
+
cardBorder: '#d5d9e0',
|
|
39
|
+
/** The bounded-context pill: the map's own blue. */
|
|
40
|
+
context: CM_BUBBLE.fill,
|
|
41
|
+
contextBorder: CM_BUBBLE.stroke,
|
|
42
|
+
/** The cloud / Big Ball of Mud: the map's own grey-violet. */
|
|
43
|
+
cloud: CLOUD.fill,
|
|
44
|
+
cloudBorder: CLOUD.stroke,
|
|
45
|
+
},
|
|
46
|
+
surface: {
|
|
47
|
+
fill: '@card',
|
|
48
|
+
border: { color: '@cardBorder', width: 1.5, radius: 12 },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ShortcutManifestEntry } from '@formicoidea/labre-core/std';
|
|
2
|
+
/**
|
|
3
|
+
* The Context Map commands as SHORTCUT-MANIFEST rows — id, label, chord, scope,
|
|
4
|
+
* owner — and nothing else.
|
|
5
|
+
*
|
|
6
|
+
* DATA ONLY, and that is the whole point (`docs/adr/0008` § Packaging). A
|
|
7
|
+
* `CommandDescriptor` carries its `run`, so a host settings pane that imports
|
|
8
|
+
* the package entry to list names and chords drags the entire action graph —
|
|
9
|
+
* the import/export machinery, the surface and gfx deep paths — into its
|
|
10
|
+
* chunk. This module has type-only imports, so the published bundle exposes it
|
|
11
|
+
* as `./commands-manifest`: a few hundred bytes that reference nothing.
|
|
12
|
+
*
|
|
13
|
+
* GENERATED-SHAPED, hand-committed: `commands-manifest.unit.spec.ts` asserts
|
|
14
|
+
* row-for-row equality with `toShortcutManifestEntry` over {@link contextMapCommands},
|
|
15
|
+
* so this file cannot drift from the commands it projects. Add a command and
|
|
16
|
+
* the test says exactly what to add here.
|
|
17
|
+
*/
|
|
18
|
+
export declare const contextMapCommandsManifest: ShortcutManifestEntry[];
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Context Map commands as SHORTCUT-MANIFEST rows — id, label, chord, scope,
|
|
3
|
+
* owner — and nothing else.
|
|
4
|
+
*
|
|
5
|
+
* DATA ONLY, and that is the whole point (`docs/adr/0008` § Packaging). A
|
|
6
|
+
* `CommandDescriptor` carries its `run`, so a host settings pane that imports
|
|
7
|
+
* the package entry to list names and chords drags the entire action graph —
|
|
8
|
+
* the import/export machinery, the surface and gfx deep paths — into its
|
|
9
|
+
* chunk. This module has type-only imports, so the published bundle exposes it
|
|
10
|
+
* as `./commands-manifest`: a few hundred bytes that reference nothing.
|
|
11
|
+
*
|
|
12
|
+
* GENERATED-SHAPED, hand-committed: `commands-manifest.unit.spec.ts` asserts
|
|
13
|
+
* row-for-row equality with `toShortcutManifestEntry` over {@link contextMapCommands},
|
|
14
|
+
* so this file cannot drift from the commands it projects. Add a command and
|
|
15
|
+
* the test says exactly what to add here.
|
|
16
|
+
*/
|
|
17
|
+
export const contextMapCommandsManifest = [
|
|
18
|
+
{
|
|
19
|
+
id: 'ddd-context-map.addBoard',
|
|
20
|
+
owner: 'ddd-context-map',
|
|
21
|
+
labelKey: 'com.labre.commands.ddd-context-map.addBoard',
|
|
22
|
+
labelFallback: 'Context Map board',
|
|
23
|
+
scope: 'edgeless',
|
|
24
|
+
defaultKeys: { mac: [], other: [] },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'ddd-context-map.addBoundedContext',
|
|
28
|
+
owner: 'ddd-context-map',
|
|
29
|
+
labelKey: 'com.labre.commands.ddd-context-map.addBoundedContext',
|
|
30
|
+
labelFallback: 'Bounded Context',
|
|
31
|
+
scope: 'edgeless',
|
|
32
|
+
defaultKeys: { mac: [], other: [] },
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'ddd-context-map.addCloud',
|
|
36
|
+
owner: 'ddd-context-map',
|
|
37
|
+
labelKey: 'com.labre.commands.ddd-context-map.addCloud',
|
|
38
|
+
labelFallback: 'Cloud / System (Big Ball of Mud)',
|
|
39
|
+
scope: 'edgeless',
|
|
40
|
+
defaultKeys: { mac: [], other: [] },
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'ddd-context-map.addPartnership',
|
|
44
|
+
owner: 'ddd-context-map',
|
|
45
|
+
labelKey: 'com.labre.commands.ddd-context-map.addPartnership',
|
|
46
|
+
labelFallback: 'Partnership',
|
|
47
|
+
scope: 'edgeless',
|
|
48
|
+
defaultKeys: { mac: [], other: [] },
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'ddd-context-map.addSharedKernel',
|
|
52
|
+
owner: 'ddd-context-map',
|
|
53
|
+
labelKey: 'com.labre.commands.ddd-context-map.addSharedKernel',
|
|
54
|
+
labelFallback: 'Shared Kernel',
|
|
55
|
+
scope: 'edgeless',
|
|
56
|
+
defaultKeys: { mac: [], other: [] },
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'ddd-context-map.addCustomerSupplier',
|
|
60
|
+
owner: 'ddd-context-map',
|
|
61
|
+
labelKey: 'com.labre.commands.ddd-context-map.addCustomerSupplier',
|
|
62
|
+
labelFallback: 'Customer / Supplier',
|
|
63
|
+
scope: 'edgeless',
|
|
64
|
+
defaultKeys: { mac: [], other: [] },
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'ddd-context-map.addConformist',
|
|
68
|
+
owner: 'ddd-context-map',
|
|
69
|
+
labelKey: 'com.labre.commands.ddd-context-map.addConformist',
|
|
70
|
+
labelFallback: 'Conformist',
|
|
71
|
+
scope: 'edgeless',
|
|
72
|
+
defaultKeys: { mac: [], other: [] },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'ddd-context-map.addAcl',
|
|
76
|
+
owner: 'ddd-context-map',
|
|
77
|
+
labelKey: 'com.labre.commands.ddd-context-map.addAcl',
|
|
78
|
+
labelFallback: 'Anticorruption Layer',
|
|
79
|
+
scope: 'edgeless',
|
|
80
|
+
defaultKeys: { mac: [], other: [] },
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'ddd-context-map.addOhs',
|
|
84
|
+
owner: 'ddd-context-map',
|
|
85
|
+
labelKey: 'com.labre.commands.ddd-context-map.addOhs',
|
|
86
|
+
labelFallback: 'Open Host Service',
|
|
87
|
+
scope: 'edgeless',
|
|
88
|
+
defaultKeys: { mac: [], other: [] },
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'ddd-context-map.addPublishedLanguage',
|
|
92
|
+
owner: 'ddd-context-map',
|
|
93
|
+
labelKey: 'com.labre.commands.ddd-context-map.addPublishedLanguage',
|
|
94
|
+
labelFallback: 'Published Language',
|
|
95
|
+
scope: 'edgeless',
|
|
96
|
+
defaultKeys: { mac: [], other: [] },
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'ddd-context-map.addSeparateWays',
|
|
100
|
+
owner: 'ddd-context-map',
|
|
101
|
+
labelKey: 'com.labre.commands.ddd-context-map.addSeparateWays',
|
|
102
|
+
labelFallback: 'Separate Ways',
|
|
103
|
+
scope: 'edgeless',
|
|
104
|
+
defaultKeys: { mac: [], other: [] },
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 'ddd-context-map.addBbom',
|
|
108
|
+
owner: 'ddd-context-map',
|
|
109
|
+
labelKey: 'com.labre.commands.ddd-context-map.addBbom',
|
|
110
|
+
labelFallback: 'Big Ball of Mud',
|
|
111
|
+
scope: 'edgeless',
|
|
112
|
+
defaultKeys: { mac: [], other: [] },
|
|
113
|
+
},
|
|
114
|
+
];
|
package/dist/commands.js
CHANGED
|
@@ -1,60 +1,48 @@
|
|
|
1
|
-
import { addBubble, addCloud,
|
|
1
|
+
import { addBubble, addCloud, CM_RELATIONSHIPS, placeDddElement, } from '@formicoidea/labre-ddd-shared';
|
|
2
|
+
import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
|
|
2
3
|
import { svg } from 'lit';
|
|
4
|
+
import { activateContextMapRelationship, createContextMapBoard, } from './actions.js';
|
|
5
|
+
import { CONTEXT_MAP_ROLE } from './roles.js';
|
|
3
6
|
/**
|
|
4
|
-
* The Context Map palette as commands: the bounded-context bubble,
|
|
5
|
-
* the
|
|
7
|
+
* The Context Map palette as commands: the board, the bounded-context bubble,
|
|
8
|
+
* the cloud and the nine relationship patterns (`docs/adr/0008`).
|
|
9
|
+
*
|
|
10
|
+
* Two entries changed shape in WS2 and neither changed its telemetry: the
|
|
11
|
+
* bubble now carries the `context-map:context` role, and the nine patterns arm
|
|
12
|
+
* the connector tool instead of dropping a drawing.
|
|
13
|
+
*
|
|
14
|
+
* The notation legend is deliberately NOT a palette entry any more (PO recette,
|
|
15
|
+
* 27/08/2026): the ONE legend is the automatic one on the selected board's
|
|
16
|
+
* contextual toolbar (`toolbar/board-config.ts`) — the same call Core Domain
|
|
17
|
+
* Chart makes. A palette that could also drop a second, static legend was two
|
|
18
|
+
* answers to one question.
|
|
6
19
|
*/
|
|
20
|
+
const boardSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><rect x="2.5" y="4.5" width="19" height="15" rx="2" fill="#ffffff" stroke="currentColor" stroke-width="1.6"/><rect x="5.5" y="8" width="6" height="3.5" rx="1.75" fill="#e6f0fa" stroke="#2f6fb0" stroke-width="1.1"/><rect x="13" y="13" width="6" height="3.5" rx="1.75" fill="#e6f0fa" stroke="#2f6fb0" stroke-width="1.1"/><path d="M11.5 10.5 L13.5 13.8" stroke="currentColor" stroke-width="1.2"/></svg>`;
|
|
7
21
|
const bubbleSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><rect x="2" y="7" width="20" height="10" rx="5" fill="#e6f0fa" stroke="#2f6fb0" stroke-width="1.6"/></svg>`;
|
|
8
22
|
const cloudSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><path d="M6 17 C3 17 2 14 4.5 12.5 C4 9 8 8 9.5 10 C11 6.5 16 7.5 16 11 C19 10.5 20.5 14 18 16 C18 17 16.5 17 15 17 Z" fill="#f0eef6" stroke="#6d6e71" stroke-width="1.4"/></svg>`;
|
|
9
|
-
const legendSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><rect x="3" y="4" width="18" height="16" rx="2" stroke="currentColor" stroke-width="1.6"/><circle cx="7" cy="9" r="1.6" fill="currentColor"/><circle cx="7" cy="14" r="1.6" fill="currentColor"/><path d="M11 9 H18 M11 14 H18" stroke="currentColor" stroke-width="1.4"/></svg>`;
|
|
10
23
|
const relationSwatch = (dashed, arrow) => svg `<svg viewBox="0 0 24 24" fill="none"><path d="M3 12 H${arrow ? 17 : 21}" stroke="currentColor" stroke-width="2" stroke-dasharray="${dashed ? '3 3' : '0'}"/>${arrow ? svg `<path d="M15 8 L21 12 L15 16" stroke="currentColor" stroke-width="2" fill="none"/>` : ''}</svg>`;
|
|
11
|
-
/** The notation legend's sections, built from the same relationship presets. */
|
|
12
|
-
function legendSections() {
|
|
13
|
-
const patRows = (kinds) => CM_RELATIONSHIPS.filter(r => kinds.includes(r.kind)).map((r) => ({
|
|
14
|
-
swatch: 'line',
|
|
15
|
-
color: '#1f2328',
|
|
16
|
-
label: `${r.abbrev} — ${r.label}`,
|
|
17
|
-
}));
|
|
18
|
-
return [
|
|
19
|
-
{
|
|
20
|
-
title: 'Boundaries',
|
|
21
|
-
rows: [
|
|
22
|
-
{ swatch: 'square', color: CM_BUBBLE.fill, label: 'Bounded Context' },
|
|
23
|
-
{
|
|
24
|
-
swatch: 'square',
|
|
25
|
-
color: CLOUD.fill,
|
|
26
|
-
label: 'System / Big Ball of Mud',
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
title: 'Mutually dependent',
|
|
32
|
-
rows: patRows(['partnership', 'sharedKernel']),
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
title: 'Upstream → Downstream (U/D)',
|
|
36
|
-
rows: patRows([
|
|
37
|
-
'customerSupplier',
|
|
38
|
-
'conformist',
|
|
39
|
-
'acl',
|
|
40
|
-
'ohs',
|
|
41
|
-
'publishedLanguage',
|
|
42
|
-
]),
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
title: 'Separate / no integration',
|
|
46
|
-
rows: patRows(['separateWays', 'bbom']),
|
|
47
|
-
},
|
|
48
|
-
];
|
|
49
|
-
}
|
|
50
24
|
const SPECS = [
|
|
25
|
+
{
|
|
26
|
+
id: 'addBoard',
|
|
27
|
+
label: 'Context Map board',
|
|
28
|
+
iconKey: 'ddd-context-map.board',
|
|
29
|
+
// A NEW telemetry value, and the only one in this file: every other entry
|
|
30
|
+
// below keeps the `element` string it has emitted since ADR 0008.
|
|
31
|
+
element: 'board',
|
|
32
|
+
icon: boardSwatch,
|
|
33
|
+
run: std => createContextMapBoard(std.get(GfxControllerIdentifier)),
|
|
34
|
+
},
|
|
51
35
|
{
|
|
52
36
|
id: 'addBoundedContext',
|
|
53
37
|
label: 'Bounded Context',
|
|
54
38
|
iconKey: 'ddd-context-map.bubble',
|
|
55
39
|
element: 'bounded-context',
|
|
56
40
|
icon: bubbleSwatch,
|
|
57
|
-
run: std => placeDddElement(std, (surface, cx, cy) =>
|
|
41
|
+
run: std => placeDddElement(std, (surface, cx, cy) =>
|
|
42
|
+
// The role is what makes a bubble a bounded CONTEXT rather than a blue
|
|
43
|
+
// pill: every rule in `rules.ts` reads it, and a pill drawn before WS2
|
|
44
|
+
// carries none and is never evaluated (promesse #71).
|
|
45
|
+
addBubble(surface, cx, cy, 'Bounded Context', CONTEXT_MAP_ROLE.context)),
|
|
58
46
|
},
|
|
59
47
|
{
|
|
60
48
|
id: 'addCloud',
|
|
@@ -70,24 +58,12 @@ const SPECS = [
|
|
|
70
58
|
iconKey: `ddd-context-map.relationship.${preset.kind}`,
|
|
71
59
|
element: `relationship:${preset.kind}`,
|
|
72
60
|
icon: relationSwatch(preset.dashed, preset.upDown),
|
|
73
|
-
|
|
61
|
+
// No longer a placement: the nine patterns arm the connector tool and the
|
|
62
|
+
// user DRAWS the relation between two contexts. See
|
|
63
|
+
// `activateContextMapRelationship` for why the free-floating group had to
|
|
64
|
+
// go. The telemetry `element` value is untouched.
|
|
65
|
+
run: std => activateContextMapRelationship(std.get(GfxControllerIdentifier), preset.kind, { upDown: preset.upDown, dashed: preset.dashed }),
|
|
74
66
|
})),
|
|
75
|
-
{
|
|
76
|
-
id: 'addLegend',
|
|
77
|
-
label: 'Legend',
|
|
78
|
-
iconKey: 'ddd-context-map.legend',
|
|
79
|
-
// Deliberately NOT `kind: 'legend'`: this palette entry has always emitted
|
|
80
|
-
// `FrameworkElementAdded` with element `'legend'`, and ADR 0008's
|
|
81
|
-
// no-analytics-breakage rule outranks the taxonomy tidy-up. Promoting it
|
|
82
|
-
// to `FrameworkLegendCreated` is a telemetry change, not a refactor.
|
|
83
|
-
element: 'legend',
|
|
84
|
-
icon: legendSwatch,
|
|
85
|
-
run: std => placeDddElement(std, (surface, cx, cy) => addLegend(surface, std, cx - 140, cy - 210, {
|
|
86
|
-
title: 'Légende',
|
|
87
|
-
sections: legendSections(),
|
|
88
|
-
width: 290,
|
|
89
|
-
})),
|
|
90
|
-
},
|
|
91
67
|
];
|
|
92
68
|
export const contextMapCommands = SPECS.map((spec, order) => ({
|
|
93
69
|
id: `ddd-context-map.${spec.id}`,
|
package/dist/descriptor.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { DddContextMapViewExtension } from './view.js';
|
|
1
|
+
import { DddContextMapRenderViewExtension, DddContextMapViewExtension } from './view.js';
|
|
2
2
|
/** Host wiring for the ddd-context-map framework. */
|
|
3
3
|
export declare const dddContextMapFramework: {
|
|
4
4
|
readonly flag: "ddd-context-map";
|
|
5
5
|
readonly telemetryKey: "context-map";
|
|
6
|
-
readonly
|
|
6
|
+
readonly extensions: readonly [{
|
|
7
|
+
readonly viewExtension: typeof DddContextMapRenderViewExtension;
|
|
8
|
+
}, {
|
|
9
|
+
readonly flag: "ddd-context-map";
|
|
10
|
+
readonly viewExtension: typeof DddContextMapViewExtension;
|
|
11
|
+
}];
|
|
7
12
|
};
|
package/dist/descriptor.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { DddContextMapViewExtension } from './view.js';
|
|
1
|
+
import { DddContextMapRenderViewExtension, DddContextMapViewExtension } from './view.js';
|
|
2
2
|
/** Host wiring for the ddd-context-map framework. */
|
|
3
3
|
export const dddContextMapFramework = {
|
|
4
4
|
flag: 'ddd-context-map',
|
|
5
5
|
telemetryKey: 'context-map',
|
|
6
|
-
|
|
6
|
+
extensions: [
|
|
7
|
+
{ viewExtension: DddContextMapRenderViewExtension },
|
|
8
|
+
{ flag: 'ddd-context-map', viewExtension: DddContextMapViewExtension },
|
|
9
|
+
],
|
|
7
10
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import type { ContextMapBoardElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
+
/**
|
|
4
|
+
* Canvas renderer for the Context Map board.
|
|
5
|
+
*
|
|
6
|
+
* There is no Context Map drawing code: the board is an INSTANTIATION of the
|
|
7
|
+
* framework-background primitive, configured by the `CONTEXT_MAP_BACKGROUND`
|
|
8
|
+
* declaration — which, having no axes and no zones, paints the primitive's own
|
|
9
|
+
* default: a white card with a hairline border.
|
|
10
|
+
*
|
|
11
|
+
* Exported as a function as well as an extension so a test can drive it with a
|
|
12
|
+
* canvas stub.
|
|
13
|
+
*/
|
|
14
|
+
export declare const contextMap: ElementRenderer<ContextMapBoardElementModel>;
|
|
15
|
+
export declare const ContextMapRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
|
|
16
|
+
identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<ContextMapBoardElementModel>>;
|
|
17
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createFrameworkBackgroundRenderer, ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { CONTEXT_MAP_BACKGROUND } from './background.js';
|
|
3
|
+
/**
|
|
4
|
+
* Canvas renderer for the Context Map board.
|
|
5
|
+
*
|
|
6
|
+
* There is no Context Map drawing code: the board is an INSTANTIATION of the
|
|
7
|
+
* framework-background primitive, configured by the `CONTEXT_MAP_BACKGROUND`
|
|
8
|
+
* declaration — which, having no axes and no zones, paints the primitive's own
|
|
9
|
+
* default: a white card with a hairline border.
|
|
10
|
+
*
|
|
11
|
+
* Exported as a function as well as an extension so a test can drive it with a
|
|
12
|
+
* canvas stub.
|
|
13
|
+
*/
|
|
14
|
+
export const contextMap = createFrameworkBackgroundRenderer(CONTEXT_MAP_BACKGROUND);
|
|
15
|
+
export const ContextMapRendererExtension = ElementRendererExtension(CONTEXT_MAP_BACKGROUND.type, contextMap);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ContextMapBoardElementModel } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
+
/**
|
|
4
|
+
* View for the Context Map board. Registering it ensures `gfx.view.get(model)`
|
|
5
|
+
* returns a view (required so move / select interactions work).
|
|
6
|
+
*
|
|
7
|
+
* No double-click label editor, unlike the Wardley map: the declaration carries
|
|
8
|
+
* no text at all, so there is nothing on the card to hit-test.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ContextMapView extends GfxElementModelView<ContextMapBoardElementModel> {
|
|
11
|
+
static type: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resize gating, from the primitive: the handles follow `resizeEnabled`, which
|
|
15
|
+
* the declaration seeds to `true` — a board is a sheet you spread out.
|
|
16
|
+
*/
|
|
17
|
+
export declare const ContextMapInteraction: import("@formicoidea/labre-core/store").ExtensionType;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FrameworkBackgroundInteractionExtension } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
+
import { CONTEXT_MAP_BACKGROUND } from './background.js';
|
|
4
|
+
/**
|
|
5
|
+
* View for the Context Map board. Registering it ensures `gfx.view.get(model)`
|
|
6
|
+
* returns a view (required so move / select interactions work).
|
|
7
|
+
*
|
|
8
|
+
* No double-click label editor, unlike the Wardley map: the declaration carries
|
|
9
|
+
* no text at all, so there is nothing on the card to hit-test.
|
|
10
|
+
*/
|
|
11
|
+
export class ContextMapView extends GfxElementModelView {
|
|
12
|
+
static { this.type = 'contextMap'; }
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resize gating, from the primitive: the handles follow `resizeEnabled`, which
|
|
16
|
+
* the declaration seeds to `true` — a board is a sheet you spread out.
|
|
17
|
+
*/
|
|
18
|
+
export const ContextMapInteraction = FrameworkBackgroundInteractionExtension(CONTEXT_MAP_BACKGROUND);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export { contextMapCommandIcons, contextMapCommands } from './commands.js';
|
|
2
|
+
export { CONTEXT_MAP_BACKGROUND } from './background.js';
|
|
3
|
+
export { CONTEXT_MAP_NUDGES } from './nudges.js';
|
|
4
|
+
export { CONTEXT_MAP_PROFILES } from './profiles.js';
|
|
5
|
+
export { CM_PATTERN_ROLE, CONTEXT_MAP_ROLE, CONTEXT_MAP_ROLES, type ContextMapPatternKind, type ContextMapRoleId, } from './roles.js';
|
|
6
|
+
export { CONTEXT_MAP_RULES } from './rules.js';
|
|
2
7
|
export { contextMapTranslationEntries } from './translations.js';
|
|
3
8
|
export { contextMapTemplateCategory } from './templates.js';
|
|
4
9
|
export { contextMapSeniorTool } from './toolbar/senior-tool.js';
|
|
5
10
|
export { EdgelessDddContextMapSeniorButton } from './toolbar/senior-button.js';
|
|
6
|
-
export { DddContextMapViewExtension } from './view.js';
|
|
11
|
+
export { DddContextMapRenderViewExtension, DddContextMapViewExtension, } from './view.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export { contextMapCommandIcons, contextMapCommands } from './commands.js';
|
|
2
|
+
export { CONTEXT_MAP_BACKGROUND } from './background.js';
|
|
3
|
+
export { CONTEXT_MAP_NUDGES } from './nudges.js';
|
|
4
|
+
export { CONTEXT_MAP_PROFILES } from './profiles.js';
|
|
5
|
+
export { CM_PATTERN_ROLE, CONTEXT_MAP_ROLE, CONTEXT_MAP_ROLES, } from './roles.js';
|
|
6
|
+
export { CONTEXT_MAP_RULES } from './rules.js';
|
|
2
7
|
export { contextMapTranslationEntries } from './translations.js';
|
|
3
8
|
export { contextMapTemplateCategory } from './templates.js';
|
|
4
9
|
export { contextMapSeniorTool } from './toolbar/senior-tool.js';
|
|
5
10
|
export { EdgelessDddContextMapSeniorButton } from './toolbar/senior-button.js';
|
|
6
|
-
export { DddContextMapViewExtension } from './view.js';
|
|
11
|
+
export { DddContextMapRenderViewExtension, DddContextMapViewExtension, } from './view.js';
|
package/dist/legend.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AutoLegendSpec } from '@formicoidea/labre-ddd-shared';
|
|
2
|
+
/**
|
|
3
|
+
* What the Context Map board's automatic legend can say — a TABLE, and nothing
|
|
4
|
+
* else: the scan, the placement and the box are `createAutoLegend`'s job.
|
|
5
|
+
*
|
|
6
|
+
* Every row is DERIVED from the presets the palette itself draws from
|
|
7
|
+
* ({@link CM_RELATIONSHIPS}, {@link CM_BUBBLE}) and from the role vocabulary's
|
|
8
|
+
* own labels, never restated. A tenth pattern added to `CM_RELATIONSHIPS` gets
|
|
9
|
+
* its legend row here with no edit, the same way it gets its role.
|
|
10
|
+
*
|
|
11
|
+
* ## What is missing, and why
|
|
12
|
+
*
|
|
13
|
+
* The **cloud** (the "System / Big Ball of Mud" blob) carries no role: it is
|
|
14
|
+
* created neutral by `commands.ts`, deliberately — the endpoint grammar treats a
|
|
15
|
+
* relationship drawn onto a cloud as a sketch and stays silent on it. Detection
|
|
16
|
+
* is by role and only by role, so the automatic legend cannot list the cloud and
|
|
17
|
+
* does not pretend to. The palette's static Legend entry still documents it, and
|
|
18
|
+
* the day the cloud earns a role its row lands here in one line.
|
|
19
|
+
*/
|
|
20
|
+
export declare const CONTEXT_MAP_AUTO_LEGEND: AutoLegendSpec;
|