@formicoidea/labre-framework-ddd-event-storming 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts +29 -0
- package/dist/actions.js +78 -0
- package/dist/background.d.ts +2 -0
- package/dist/background.js +138 -0
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +103 -0
- package/dist/descriptor.d.ts +8 -3
- package/dist/descriptor.js +6 -3
- package/dist/element-renderer.d.ts +17 -0
- package/dist/element-renderer.js +15 -0
- package/dist/element-view.d.ts +18 -0
- package/dist/element-view.js +19 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -1
- package/dist/legend.d.ts +16 -0
- package/dist/legend.js +58 -0
- package/dist/nudges.d.ts +26 -0
- package/dist/nudges.js +73 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +121 -0
- package/dist/roles.d.ts +62 -0
- package/dist/roles.js +84 -0
- package/dist/rules.d.ts +20 -0
- package/dist/rules.js +241 -0
- package/dist/toolbar/board-config.d.ts +29 -0
- package/dist/toolbar/board-config.js +86 -0
- package/dist/toolbar/event-storming-menu.d.ts +15 -8
- package/dist/toolbar/event-storming-menu.js +23 -72
- 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 +16 -0
- package/dist/translations.js +22 -0
- package/dist/view.d.ts +17 -1
- package/dist/view.js +62 -1
- package/package.json +3 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { GfxController } from '@formicoidea/labre-core/std/gfx';
|
|
2
|
+
/** Create the board at the viewport centre, select it, return to the default tool. */
|
|
3
|
+
export declare function createEventStormingBoard(gfx: GfxController): void;
|
|
4
|
+
/**
|
|
5
|
+
* Activate the native connector tool, pre-styled and TYPED as a flow. The user
|
|
6
|
+
* then drags from what happens first to what follows, and the endpoints attach.
|
|
7
|
+
*
|
|
8
|
+
* ## Why this replaces the old palette entry
|
|
9
|
+
*
|
|
10
|
+
* Until WS5 the Flow entry dropped a 220-unit arrow at the viewport centre: a
|
|
11
|
+
* line between two points in mid-air, attached to nothing. It looked like the
|
|
12
|
+
* notation and said nothing — no rule could read its ends, and the user still
|
|
13
|
+
* had to drag both endpoints onto the stickies by hand.
|
|
14
|
+
*
|
|
15
|
+
* The gesture now IS the statement (`docs/adr/0010`): the tool announces which
|
|
16
|
+
* way to drag (the role's `gestureHint` — "drag from what happens first to what
|
|
17
|
+
* follows"), the drawn connector carries `es:flow`, and its endpoints are real
|
|
18
|
+
* element references. That is what makes both `es.against-timeline` and
|
|
19
|
+
* `es.forbidden-arc` possible at all.
|
|
20
|
+
*
|
|
21
|
+
* ## What the style says, and what the role says
|
|
22
|
+
*
|
|
23
|
+
* Style is presentation: a plain straight line with a rear arrowhead, which is
|
|
24
|
+
* exactly what the old drawing looked like, so a board mixing arcs drawn before
|
|
25
|
+
* and after WS5 still reads as one board. Meaning is the role, and only the
|
|
26
|
+
* role: restyling an arc never changes what it means, and an arc drawn before
|
|
27
|
+
* WS5 keeps its look and stays neutral.
|
|
28
|
+
*/
|
|
29
|
+
export declare function activateEventStormingFlow(gfx: GfxController): void;
|
package/dist/actions.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
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 { EVENT_STORMING_BACKGROUND } from './background.js';
|
|
7
|
+
import { ES_ROLE } from './roles.js';
|
|
8
|
+
/**
|
|
9
|
+
* Creation / activation actions for the Event Storming 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 FLOW_STROKE_WIDTH = 2;
|
|
16
|
+
/** Create the board at the viewport centre, select it, return to the default tool. */
|
|
17
|
+
export function createEventStormingBoard(gfx) {
|
|
18
|
+
if (!gfx.surface)
|
|
19
|
+
return;
|
|
20
|
+
const { width, height } = backgroundSize(EVENT_STORMING_BACKGROUND);
|
|
21
|
+
const { centerX, centerY } = gfx.viewport;
|
|
22
|
+
const id = gfx.surface.addElement({
|
|
23
|
+
type: EVENT_STORMING_BACKGROUND.type,
|
|
24
|
+
// The board is a first-class role: rules frame stickies against `es:board`,
|
|
25
|
+
// never against the `eventStorming` element type. The declaration owns it,
|
|
26
|
+
// so a templated board and a hand-drawn one agree.
|
|
27
|
+
role: EVENT_STORMING_BACKGROUND.role,
|
|
28
|
+
resizeEnabled: EVENT_STORMING_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 as a flow. The user
|
|
37
|
+
* then drags from what happens first to what follows, and the endpoints attach.
|
|
38
|
+
*
|
|
39
|
+
* ## Why this replaces the old palette entry
|
|
40
|
+
*
|
|
41
|
+
* Until WS5 the Flow entry dropped a 220-unit arrow at the viewport centre: a
|
|
42
|
+
* line between two points in mid-air, attached to nothing. It looked like the
|
|
43
|
+
* notation and said nothing — no rule could read its ends, and the user still
|
|
44
|
+
* had to drag both endpoints onto the stickies by hand.
|
|
45
|
+
*
|
|
46
|
+
* The gesture now IS the statement (`docs/adr/0010`): the tool announces which
|
|
47
|
+
* way to drag (the role's `gestureHint` — "drag from what happens first to what
|
|
48
|
+
* follows"), the drawn connector carries `es:flow`, and its endpoints are real
|
|
49
|
+
* element references. That is what makes both `es.against-timeline` and
|
|
50
|
+
* `es.forbidden-arc` possible at all.
|
|
51
|
+
*
|
|
52
|
+
* ## What the style says, and what the role says
|
|
53
|
+
*
|
|
54
|
+
* Style is presentation: a plain straight line with a rear arrowhead, which is
|
|
55
|
+
* exactly what the old drawing looked like, so a board mixing arcs drawn before
|
|
56
|
+
* and after WS5 still reads as one board. Meaning is the role, and only the
|
|
57
|
+
* role: restyling an arc never changes what it means, and an arc drawn before
|
|
58
|
+
* WS5 keeps its look and stays neutral.
|
|
59
|
+
*/
|
|
60
|
+
export function activateEventStormingFlow(gfx) {
|
|
61
|
+
gfx.tool.setTool(ConnectorTool, {
|
|
62
|
+
mode: ConnectorMode.Straight,
|
|
63
|
+
role: ES_ROLE.flow,
|
|
64
|
+
// The look rides on the activation, never through the last-props store:
|
|
65
|
+
// the plain connector tool must keep the user's own style (#144 M1).
|
|
66
|
+
style: {
|
|
67
|
+
stroke: LABEL_COLOR,
|
|
68
|
+
strokeStyle: StrokeStyle.Solid,
|
|
69
|
+
strokeWidth: FLOW_STROKE_WIDTH,
|
|
70
|
+
frontEndpointStyle: PointStyle.None,
|
|
71
|
+
// The arrow points at what FOLLOWS, which is the target: the role's
|
|
72
|
+
// verb is "leads to", so the source is what happens first.
|
|
73
|
+
rearEndpointStyle: PointStyle.Arrow,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
// The Event Storming palette stays open (native sub-menu behaviour): it only
|
|
77
|
+
// closes on re-click of the senior button, another senior tool, or Escape.
|
|
78
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { ES_STICKIES, FONT_FAMILY } from '@formicoidea/labre-ddd-shared';
|
|
2
|
+
import { ES_ROLE } from './roles.js';
|
|
3
|
+
/**
|
|
4
|
+
* The Event Storming board, DECLARED (the `FrameworkBackgroundDef` primitive).
|
|
5
|
+
*
|
|
6
|
+
* ## One axis, and only one
|
|
7
|
+
*
|
|
8
|
+
* Time, running left to right along the bottom. That is the entire frame of
|
|
9
|
+
* reference Event Storming has, and declaring exactly it — no second axis, no
|
|
10
|
+
* zones, no graduations — is what makes `es.against-timeline` a real rule
|
|
11
|
+
* rather than a guess: a flow whose target sits to the LEFT of its source runs
|
|
12
|
+
* against the only direction this board means anything in.
|
|
13
|
+
*
|
|
14
|
+
* The vertical is deliberately unnamed. On a real wall it is where a workshop
|
|
15
|
+
* parks what it cannot place yet — a stack of hotspots above the frieze, a row
|
|
16
|
+
* of read models below it — and a tool that quietly turned "higher" into a
|
|
17
|
+
* scale would be inventing a semantic the framework does not have and then
|
|
18
|
+
* judging people against it.
|
|
19
|
+
*
|
|
20
|
+
* ## Swimlanes: cut from v1
|
|
21
|
+
*
|
|
22
|
+
* The v2 shape is written down in `EventStormingBoardElementModel`: lanes are a
|
|
23
|
+
* variant declaration plus a rule family that measures membership per band.
|
|
24
|
+
* Painting the bands without the rule would be the vertical semantic above,
|
|
25
|
+
* arrived at by accident.
|
|
26
|
+
*
|
|
27
|
+
* ## The palette
|
|
28
|
+
*
|
|
29
|
+
* The eight sticky colours, named. Nothing here paints them — the board is a
|
|
30
|
+
* white card with an axis on it — and that is what a declared REFERENCE looks
|
|
31
|
+
* like: the same precedent as the Wardley tone convention, so the day a
|
|
32
|
+
* `tone-convention` rule asks "is this sticky drawn in one of the notation's
|
|
33
|
+
* own colours" the answer is already written down, in one place, beside the
|
|
34
|
+
* card it belongs to.
|
|
35
|
+
*/
|
|
36
|
+
/** Ink for the frame itself: the axis line and the word beside it. */
|
|
37
|
+
const AXIS_COLOR = '#6d6e71';
|
|
38
|
+
const CARD_BORDER = '#d5d9e0';
|
|
39
|
+
/**
|
|
40
|
+
* The one word this board writes on itself, and it is written BIG: 64 units
|
|
41
|
+
* (PO recette, 26/08/2026).
|
|
42
|
+
*
|
|
43
|
+
* Sixteen was chart-label size — right for a graduation, wrong for the only
|
|
44
|
+
* thing a 3200-wide roll declares. At the zoom where a whole Big Picture fits on
|
|
45
|
+
* screen the word vanished exactly like the hairline trait did before it was
|
|
46
|
+
* drawn at six; the title now reads at the same distance as the axis it names.
|
|
47
|
+
* Sized WITH the trait rather than beside it, and everything that has to make
|
|
48
|
+
* room for it — the bottom margin, the title's own offset — is derived from this
|
|
49
|
+
* number below.
|
|
50
|
+
*/
|
|
51
|
+
const AXIS_TEXT = { size: 64, color: '@axis' };
|
|
52
|
+
/** The eight sticky fills, keyed by the kind the palette creates them under. */
|
|
53
|
+
const STICKY_PALETTE = Object.fromEntries(ES_STICKIES.map(preset => [preset.kind, preset.fill]));
|
|
54
|
+
export const EVENT_STORMING_BACKGROUND = {
|
|
55
|
+
type: 'eventStorming',
|
|
56
|
+
// The board is a first-class role: rules frame stickies against `es:board`,
|
|
57
|
+
// never against the `eventStorming` element type.
|
|
58
|
+
role: ES_ROLE.board,
|
|
59
|
+
geometry: {
|
|
60
|
+
// A Big Picture is WIDE — the timeline is the point — and it grows sideways
|
|
61
|
+
// all morning as events are remembered. Neither dimension is locked to the
|
|
62
|
+
// other and the handles are offered from the start, the opposite call from
|
|
63
|
+
// the Wardley map, which is a frame you place things on rather than a roll
|
|
64
|
+
// you unspool.
|
|
65
|
+
width: 3200,
|
|
66
|
+
height: 1400,
|
|
67
|
+
lockAspectRatio: false,
|
|
68
|
+
resizable: true,
|
|
69
|
+
// Room under the plot for the axis line and its word; the same inset
|
|
70
|
+
// elsewhere, so the roll reads as paper rather than as a chart.
|
|
71
|
+
//
|
|
72
|
+
// The bottom is the exception, and it is the WORD that sets it: a 64-unit
|
|
73
|
+
// title cannot be hung under a six-unit trait inside 56 units of paper —
|
|
74
|
+
// its cap height alone eats some 47 of them and its descender wants a dozen
|
|
75
|
+
// more. 104 is the title's offset below the trait plus a descender's worth
|
|
76
|
+
// of air, so the word sits between the trait and the card edge touching
|
|
77
|
+
// neither. Nothing else reads this number: the board declares no zones, and
|
|
78
|
+
// the stickies are placed by hand.
|
|
79
|
+
margin: { top: 32, right: 32, bottom: 104, left: 32 },
|
|
80
|
+
},
|
|
81
|
+
chrome: {
|
|
82
|
+
fontFamily: FONT_FAMILY,
|
|
83
|
+
palette: {
|
|
84
|
+
card: '#ffffff',
|
|
85
|
+
cardBorder: CARD_BORDER,
|
|
86
|
+
axis: AXIS_COLOR,
|
|
87
|
+
...STICKY_PALETTE,
|
|
88
|
+
},
|
|
89
|
+
surface: {
|
|
90
|
+
fill: '@card',
|
|
91
|
+
border: { color: '@cardBorder', width: 1.5, radius: 12 },
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
axes: [
|
|
95
|
+
{
|
|
96
|
+
id: 'time',
|
|
97
|
+
orientation: 'horizontal',
|
|
98
|
+
// Along the bottom of the plot, under the frieze rather than through it.
|
|
99
|
+
at: 1,
|
|
100
|
+
// Forward is RIGHT: later. The one fact `es.against-timeline` reads.
|
|
101
|
+
arrow: 'forward',
|
|
102
|
+
// Drawn HEAVY, and deliberately heavier than any other axis in the
|
|
103
|
+
// library (PO recette, 26/08/2026). On a 3200-wide roll the timeline is
|
|
104
|
+
// not decoration beside the plot, it IS the frame of reference — the one
|
|
105
|
+
// thing the board declares and the one thing a rule measures against —
|
|
106
|
+
// and at the zoom where a whole Big Picture fits on screen a hairline
|
|
107
|
+
// simply disappears under the frieze. Six model units survive that.
|
|
108
|
+
//
|
|
109
|
+
// The head is sized WITH the line rather than left at its default: the
|
|
110
|
+
// renderer takes `arrowSize` as the head's LENGTH and spreads the base
|
|
111
|
+
// half that either side, so head width tracks head length. At 6× the
|
|
112
|
+
// stroke the triangle still reads as the end of this line and not as a
|
|
113
|
+
// separate mark — the same register as Wardley's 11-on-2, given room to
|
|
114
|
+
// scale up with the stroke.
|
|
115
|
+
arrowSize: 36,
|
|
116
|
+
stroke: { color: '@axis', width: 6 },
|
|
117
|
+
title: {
|
|
118
|
+
id: 'timeAxisTitle',
|
|
119
|
+
labelKey: 'com.labre.event-storming.background.axis.time',
|
|
120
|
+
fallback: 'Time',
|
|
121
|
+
// Pushed down with the SIZE, not just with the stroke.
|
|
122
|
+
//
|
|
123
|
+
// The renderer draws every background text on an `alphabetic`
|
|
124
|
+
// baseline, so `dy` positions the foot of the word and everything
|
|
125
|
+
// above it has to fit between the trait and that baseline: the trait
|
|
126
|
+
// grows three units below its centre (half of six) and the cap height
|
|
127
|
+
// of a 64-unit Inter is about 47. 72 clears both and leaves roughly the
|
|
128
|
+
// 23 units of air the 16-unit title used to have — the gap reads the
|
|
129
|
+
// same, it is simply no longer proportional to a word four times
|
|
130
|
+
// bigger. Below the baseline, the descender (~16) stops 16 units short
|
|
131
|
+
// of the 104-unit bottom margin, so the card edge is clear too.
|
|
132
|
+
anchor: { x: 1, y: 1, dx: -8, dy: 72 },
|
|
133
|
+
style: AXIS_TEXT,
|
|
134
|
+
align: 'right',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { addSticky, ES_HOTSPOT, ES_STICKIES, placeDddElement, STICKY_SIZE, } from '@formicoidea/labre-ddd-shared';
|
|
2
|
+
import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
+
import { svg } from 'lit';
|
|
4
|
+
import { activateEventStormingFlow, createEventStormingBoard } from './actions.js';
|
|
5
|
+
import { ES_STICKY_ROLE } from './roles.js';
|
|
6
|
+
/**
|
|
7
|
+
* The Event Storming palette as commands: the board, the eight colour-coded
|
|
8
|
+
* stickies, the hotspot and the flow. Declared once and read by the sub-menu,
|
|
9
|
+
* the keymap, Settings › Shortcuts, the catalogue and the agent
|
|
10
|
+
* (`docs/adr/0008`).
|
|
11
|
+
*
|
|
12
|
+
* Three entries changed shape in WS5 and not one telemetry value moved: the
|
|
13
|
+
* stickies now carry their role, the flow arms the connector tool instead of
|
|
14
|
+
* dropping a drawing, and the board is a new entry with a new `element` value.
|
|
15
|
+
*/
|
|
16
|
+
const squareSwatch = (color) => svg `<svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="3" fill="${color}"/></svg>`;
|
|
17
|
+
const diamondSwatch = (color) => svg `<svg viewBox="0 0 24 24"><rect x="6" y="6" width="12" height="12" transform="rotate(45 12 12)" fill="${color}"/></svg>`;
|
|
18
|
+
const flowSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><path d="M4 12 H18" stroke="currentColor" stroke-width="2"/><path d="M16 8 L20 12 L16 16" stroke="currentColor" stroke-width="2" fill="none"/></svg>`;
|
|
19
|
+
const boardSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><rect x="2.5" y="4" width="19" height="16" rx="2" fill="#ffffff" stroke="currentColor" stroke-width="1.6"/><rect x="5" y="7.5" width="4" height="4" rx="1" fill="#F5963B"/><rect x="10.5" y="7.5" width="4" height="4" rx="1" fill="#5BA3DB"/><rect x="16" y="7.5" width="4" height="4" rx="1" fill="#FAF2C9" stroke="#c9bd7f" stroke-width="0.6"/><path d="M4.5 16.5 H19.5" stroke="currentColor" stroke-width="1.2"/><path d="M17.5 14.8 L19.8 16.5 L17.5 18.2" stroke="currentColor" stroke-width="1.2"/></svg>`;
|
|
20
|
+
/**
|
|
21
|
+
* The aggregate is created BIG — 160 against the standard 120.
|
|
22
|
+
*
|
|
23
|
+
* Size is half of how the notation distinguishes it: on a real wall the
|
|
24
|
+
* aggregate is the large pale sticky a run of commands lands on, and the
|
|
25
|
+
* colour ladder in `ES_STICKIES` carries the other half. Declared here rather
|
|
26
|
+
* than in the shared palette because it is a FORMAT, not a colour: the palette
|
|
27
|
+
* says which yellow, the toolbox says how big.
|
|
28
|
+
*/
|
|
29
|
+
const AGGREGATE_SIZE = 160;
|
|
30
|
+
const SPECS = [
|
|
31
|
+
{
|
|
32
|
+
id: 'addBoard',
|
|
33
|
+
label: 'Event Storming board',
|
|
34
|
+
iconKey: 'ddd-event-storming.board',
|
|
35
|
+
// A NEW telemetry value: every other entry below keeps the `element` string
|
|
36
|
+
// it has emitted since ADR 0008.
|
|
37
|
+
element: 'board',
|
|
38
|
+
icon: boardSwatch,
|
|
39
|
+
run: std => createEventStormingBoard(std.get(GfxControllerIdentifier)),
|
|
40
|
+
},
|
|
41
|
+
...ES_STICKIES.map((preset) => ({
|
|
42
|
+
id: `add${preset.kind[0].toUpperCase()}${preset.kind.slice(1)}`,
|
|
43
|
+
label: preset.label,
|
|
44
|
+
iconKey: `ddd-event-storming.sticky.${preset.kind}`,
|
|
45
|
+
element: `sticky:${preset.kind}`,
|
|
46
|
+
icon: squareSwatch(preset.fill),
|
|
47
|
+
run: std => placeDddElement(std, (surface, cx, cy) => addSticky(surface, std, cx, cy, {
|
|
48
|
+
fill: preset.fill,
|
|
49
|
+
text: preset.text,
|
|
50
|
+
label: preset.label,
|
|
51
|
+
size: preset.kind === 'aggregate' ? AGGREGATE_SIZE : STICKY_SIZE,
|
|
52
|
+
// The role is what makes a sticky a domain EVENT rather than an
|
|
53
|
+
// orange square: every rule in `rules.ts` reads it, and a sticky
|
|
54
|
+
// placed before WS5 carries none and is never evaluated
|
|
55
|
+
// (promesse #71).
|
|
56
|
+
role: ES_STICKY_ROLE[preset.kind],
|
|
57
|
+
})),
|
|
58
|
+
})),
|
|
59
|
+
{
|
|
60
|
+
id: 'addHotspot',
|
|
61
|
+
label: ES_HOTSPOT.label,
|
|
62
|
+
iconKey: 'ddd-event-storming.sticky.hotspot',
|
|
63
|
+
element: 'sticky:hotspot',
|
|
64
|
+
icon: diamondSwatch(ES_HOTSPOT.fill),
|
|
65
|
+
run: std => placeDddElement(std, (surface, cx, cy) => addSticky(surface, std, cx, cy, {
|
|
66
|
+
fill: ES_HOTSPOT.fill,
|
|
67
|
+
text: ES_HOTSPOT.text,
|
|
68
|
+
label: ES_HOTSPOT.label,
|
|
69
|
+
shapeType: 'diamond',
|
|
70
|
+
// Typed like the rest, and cited by no grammar triplet on purpose —
|
|
71
|
+
// an arc onto a hotspot is a question being parked. See `rules.ts`.
|
|
72
|
+
role: ES_STICKY_ROLE.hotspot,
|
|
73
|
+
})),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'addFlow',
|
|
77
|
+
label: 'Flow',
|
|
78
|
+
iconKey: 'ddd-event-storming.flow',
|
|
79
|
+
element: 'flow',
|
|
80
|
+
icon: flowSwatch,
|
|
81
|
+
// No longer a placement: the entry arms the connector tool and the user
|
|
82
|
+
// DRAWS the flow between two stickies. See `activateEventStormingFlow` for
|
|
83
|
+
// why the free-floating arrow had to go. The telemetry value is untouched.
|
|
84
|
+
run: std => activateEventStormingFlow(std.get(GfxControllerIdentifier)),
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
export const eventStormingCommands = SPECS.map((spec, order) => ({
|
|
88
|
+
id: `ddd-event-storming.${spec.id}`,
|
|
89
|
+
owner: 'ddd-event-storming',
|
|
90
|
+
kind: 'artefact',
|
|
91
|
+
labelKey: `com.labre.commands.ddd-event-storming.${spec.id}`,
|
|
92
|
+
labelFallback: spec.label,
|
|
93
|
+
category: 'stickies',
|
|
94
|
+
iconKey: spec.iconKey,
|
|
95
|
+
surfaces: ['senior-menu', 'catalogue', 'palette', 'agent'],
|
|
96
|
+
order,
|
|
97
|
+
scope: 'edgeless',
|
|
98
|
+
defaultKeys: { mac: [], other: [] },
|
|
99
|
+
availability: 'always',
|
|
100
|
+
run: spec.run,
|
|
101
|
+
telemetry: { framework: 'ddd-event-storming', element: spec.element },
|
|
102
|
+
}));
|
|
103
|
+
export const eventStormingCommandIcons = Object.fromEntries(SPECS.map(spec => [spec.iconKey, spec.icon]));
|
package/dist/descriptor.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { DddEventStormingViewExtension } from './view.js';
|
|
1
|
+
import { DddEventStormingRenderViewExtension, DddEventStormingViewExtension } from './view.js';
|
|
2
2
|
/** Host wiring for the ddd-event-storming framework. */
|
|
3
3
|
export declare const dddEventStormingFramework: {
|
|
4
4
|
readonly flag: "ddd-event-storming";
|
|
5
|
-
readonly
|
|
6
|
-
readonly
|
|
5
|
+
readonly telemetryKey: "event-storming";
|
|
6
|
+
readonly extensions: readonly [{
|
|
7
|
+
readonly viewExtension: typeof DddEventStormingRenderViewExtension;
|
|
8
|
+
}, {
|
|
9
|
+
readonly flag: "ddd-event-storming";
|
|
10
|
+
readonly viewExtension: typeof DddEventStormingViewExtension;
|
|
11
|
+
}];
|
|
7
12
|
};
|
package/dist/descriptor.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { DddEventStormingViewExtension } from './view.js';
|
|
1
|
+
import { DddEventStormingRenderViewExtension, DddEventStormingViewExtension } from './view.js';
|
|
2
2
|
/** Host wiring for the ddd-event-storming framework. */
|
|
3
3
|
export const dddEventStormingFramework = {
|
|
4
4
|
flag: 'ddd-event-storming',
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
telemetryKey: 'event-storming',
|
|
6
|
+
extensions: [
|
|
7
|
+
{ viewExtension: DddEventStormingRenderViewExtension },
|
|
8
|
+
{ flag: 'ddd-event-storming', viewExtension: DddEventStormingViewExtension },
|
|
9
|
+
],
|
|
7
10
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import type { EventStormingBoardElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
+
/**
|
|
4
|
+
* Canvas renderer for the Event Storming board.
|
|
5
|
+
*
|
|
6
|
+
* There is no Event Storming drawing code: the board is an INSTANTIATION of the
|
|
7
|
+
* framework-background primitive, configured by the
|
|
8
|
+
* {@link EVENT_STORMING_BACKGROUND} declaration — a white card with one axis
|
|
9
|
+
* along the bottom.
|
|
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 eventStorming: ElementRenderer<EventStormingBoardElementModel>;
|
|
15
|
+
export declare const EventStormingRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
|
|
16
|
+
identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<EventStormingBoardElementModel>>;
|
|
17
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createFrameworkBackgroundRenderer, ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { EVENT_STORMING_BACKGROUND } from './background.js';
|
|
3
|
+
/**
|
|
4
|
+
* Canvas renderer for the Event Storming board.
|
|
5
|
+
*
|
|
6
|
+
* There is no Event Storming drawing code: the board is an INSTANTIATION of the
|
|
7
|
+
* framework-background primitive, configured by the
|
|
8
|
+
* {@link EVENT_STORMING_BACKGROUND} declaration — a white card with one axis
|
|
9
|
+
* along the bottom.
|
|
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 eventStorming = createFrameworkBackgroundRenderer(EVENT_STORMING_BACKGROUND);
|
|
15
|
+
export const EventStormingRendererExtension = ElementRendererExtension(EVENT_STORMING_BACKGROUND.type, eventStorming);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EventStormingBoardElementModel } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
+
/**
|
|
4
|
+
* View for the Event Storming 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 only text on the
|
|
8
|
+
* card is the axis word, which the declaration owns and the model carries no
|
|
9
|
+
* prop for — there is nothing here the user edits in place.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EventStormingView extends GfxElementModelView<EventStormingBoardElementModel> {
|
|
12
|
+
static type: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resize gating, from the primitive: the handles follow `resizeEnabled`, which
|
|
16
|
+
* the declaration seeds to `true` — the roll is unspooled as the morning goes.
|
|
17
|
+
*/
|
|
18
|
+
export declare const EventStormingInteraction: import("@formicoidea/labre-core/store").ExtensionType;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FrameworkBackgroundInteractionExtension } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
+
import { EVENT_STORMING_BACKGROUND } from './background.js';
|
|
4
|
+
/**
|
|
5
|
+
* View for the Event Storming 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 only text on the
|
|
9
|
+
* card is the axis word, which the declaration owns and the model carries no
|
|
10
|
+
* prop for — there is nothing here the user edits in place.
|
|
11
|
+
*/
|
|
12
|
+
export class EventStormingView extends GfxElementModelView {
|
|
13
|
+
static { this.type = 'eventStorming'; }
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resize gating, from the primitive: the handles follow `resizeEnabled`, which
|
|
17
|
+
* the declaration seeds to `true` — the roll is unspooled as the morning goes.
|
|
18
|
+
*/
|
|
19
|
+
export const EventStormingInteraction = FrameworkBackgroundInteractionExtension(EVENT_STORMING_BACKGROUND);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
export { eventStormingCommandIcons, eventStormingCommands, } from './commands.js';
|
|
2
|
+
export { EVENT_STORMING_BACKGROUND } from './background.js';
|
|
3
|
+
export { EVENT_STORMING_NUDGES } from './nudges.js';
|
|
4
|
+
export { EVENT_STORMING_PROFILES } from './profiles.js';
|
|
5
|
+
export { ES_ROLE, ES_STICKY_ROLE, EVENT_STORMING_ROLES, type EventStormingRoleId, type EventStormingStickyKind, } from './roles.js';
|
|
6
|
+
export { ES_FLOW_MATRIX, EVENT_STORMING_RULES } from './rules.js';
|
|
7
|
+
export { eventStormingTranslationEntries } from './translations.js';
|
|
1
8
|
export { eventStormingTemplateCategory } from './templates.js';
|
|
2
9
|
export { eventStormingSeniorTool } from './toolbar/senior-tool.js';
|
|
3
10
|
export { EdgelessDddEventStormingSeniorButton } from './toolbar/senior-button.js';
|
|
4
|
-
export { DddEventStormingViewExtension } from './view.js';
|
|
11
|
+
export { DddEventStormingRenderViewExtension, DddEventStormingViewExtension, } from './view.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
export { eventStormingCommandIcons, eventStormingCommands, } from './commands.js';
|
|
2
|
+
export { EVENT_STORMING_BACKGROUND } from './background.js';
|
|
3
|
+
export { EVENT_STORMING_NUDGES } from './nudges.js';
|
|
4
|
+
export { EVENT_STORMING_PROFILES } from './profiles.js';
|
|
5
|
+
export { ES_ROLE, ES_STICKY_ROLE, EVENT_STORMING_ROLES, } from './roles.js';
|
|
6
|
+
export { ES_FLOW_MATRIX, EVENT_STORMING_RULES } from './rules.js';
|
|
7
|
+
export { eventStormingTranslationEntries } from './translations.js';
|
|
1
8
|
export { eventStormingTemplateCategory } from './templates.js';
|
|
2
9
|
export { eventStormingSeniorTool } from './toolbar/senior-tool.js';
|
|
3
10
|
export { EdgelessDddEventStormingSeniorButton } from './toolbar/senior-button.js';
|
|
4
|
-
export { DddEventStormingViewExtension } from './view.js';
|
|
11
|
+
export { DddEventStormingRenderViewExtension, DddEventStormingViewExtension, } from './view.js';
|
package/dist/legend.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type AutoLegendSpec } from '@formicoidea/labre-ddd-shared';
|
|
2
|
+
/**
|
|
3
|
+
* What the Event Storming board's automatic legend can say — a TABLE, and
|
|
4
|
+
* nothing else: the scan, the placement and the box are `createAutoLegend`'s
|
|
5
|
+
* job.
|
|
6
|
+
*
|
|
7
|
+
* Every row is DERIVED from the palette the stickies are drawn with
|
|
8
|
+
* ({@link ES_STICKIES}, {@link ES_HOTSPOT}) and from the role vocabulary's own
|
|
9
|
+
* labels, never restated — so the colour ladder the legend shows is by
|
|
10
|
+
* construction the colour ladder on the wall, and a tenth sticky kind added to
|
|
11
|
+
* `ES_STICKIES` gets its legend row with no edit.
|
|
12
|
+
*
|
|
13
|
+
* The hotspot is appended for the same reason `roles.ts` appends it: it lives in
|
|
14
|
+
* its own preset (a diamond, not a square) rather than in the table.
|
|
15
|
+
*/
|
|
16
|
+
export declare const EVENT_STORMING_AUTO_LEGEND: AutoLegendSpec;
|
package/dist/legend.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ES_HOTSPOT, ES_STICKIES, LABEL_COLOR, roleLabel, } from '@formicoidea/labre-ddd-shared';
|
|
2
|
+
import { ES_ROLE, ES_STICKY_ROLE, EVENT_STORMING_ROLES } from './roles.js';
|
|
3
|
+
/**
|
|
4
|
+
* What the Event Storming board's automatic legend can say — a TABLE, and
|
|
5
|
+
* nothing else: the scan, the placement and the box are `createAutoLegend`'s
|
|
6
|
+
* job.
|
|
7
|
+
*
|
|
8
|
+
* Every row is DERIVED from the palette the stickies are drawn with
|
|
9
|
+
* ({@link ES_STICKIES}, {@link ES_HOTSPOT}) and from the role vocabulary's own
|
|
10
|
+
* labels, never restated — so the colour ladder the legend shows is by
|
|
11
|
+
* construction the colour ladder on the wall, and a tenth sticky kind added to
|
|
12
|
+
* `ES_STICKIES` gets its legend row with no edit.
|
|
13
|
+
*
|
|
14
|
+
* The hotspot is appended for the same reason `roles.ts` appends it: it lives in
|
|
15
|
+
* its own preset (a diamond, not a square) rather than in the table.
|
|
16
|
+
*/
|
|
17
|
+
export const EVENT_STORMING_AUTO_LEGEND = {
|
|
18
|
+
title: 'Legend',
|
|
19
|
+
roles: EVENT_STORMING_ROLES,
|
|
20
|
+
sections: [
|
|
21
|
+
{
|
|
22
|
+
title: 'Stickies',
|
|
23
|
+
entries: [
|
|
24
|
+
...ES_STICKIES.map(preset => ({
|
|
25
|
+
role: ES_STICKY_ROLE[preset.kind],
|
|
26
|
+
row: {
|
|
27
|
+
swatch: 'square',
|
|
28
|
+
color: preset.fill,
|
|
29
|
+
label: preset.label,
|
|
30
|
+
},
|
|
31
|
+
})),
|
|
32
|
+
{
|
|
33
|
+
role: ES_STICKY_ROLE.hotspot,
|
|
34
|
+
row: {
|
|
35
|
+
swatch: 'square',
|
|
36
|
+
color: ES_HOTSPOT.fill,
|
|
37
|
+
label: ES_HOTSPOT.label,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
title: 'Flow',
|
|
44
|
+
entries: [
|
|
45
|
+
{
|
|
46
|
+
role: ES_ROLE.flow,
|
|
47
|
+
row: {
|
|
48
|
+
swatch: 'line',
|
|
49
|
+
// The style `activateEventStormingFlow` arms the connector tool
|
|
50
|
+
// with: a solid line in the label colour.
|
|
51
|
+
color: LABEL_COLOR,
|
|
52
|
+
label: roleLabel(EVENT_STORMING_ROLES, ES_ROLE.flow),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
package/dist/nudges.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { QualityNudge } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
/**
|
|
3
|
+
* Event Storming **board quality** — the checklist (WS5, level 2).
|
|
4
|
+
*
|
|
5
|
+
* `./rules.ts` is level 1: deterministic, decidable, real time. This file is
|
|
6
|
+
* everything a board needs that no algorithm can decide. The split is the
|
|
7
|
+
* taxonomy's whole point — ticking is assuming, never verifying.
|
|
8
|
+
*
|
|
9
|
+
* ## The past tense lives HERE, and that was an arbitration
|
|
10
|
+
*
|
|
11
|
+
* "Order placed" is a domain event; "Place order" is a command. It is the first
|
|
12
|
+
* thing a facilitator corrects and the most tempting rule in the whole plan —
|
|
13
|
+
* and it is a nudge, by PO arbitration of 26/08/2026, because deciding it means
|
|
14
|
+
* parsing a human sentence. In whatever language the room speaks. Written in
|
|
15
|
+
* marker pen. By somebody who abbreviates. A regular expression over `Y.Text`
|
|
16
|
+
* would be wrong every fifth sticky, and a validation platform gets exactly one
|
|
17
|
+
* chance to be wrong about something the user can see is right.
|
|
18
|
+
*
|
|
19
|
+
* So it is a tick, and the tick is honest: it says the room LOOKED, which is
|
|
20
|
+
* what the facilitator wanted anyway.
|
|
21
|
+
*
|
|
22
|
+
* Registered from the flag-gated `DddEventStormingViewExtension`: a checklist
|
|
23
|
+
* is tooling. Switching the flag off takes it away and leaves the ticks written
|
|
24
|
+
* on the board, unread, until it comes back.
|
|
25
|
+
*/
|
|
26
|
+
export declare const EVENT_STORMING_NUDGES: readonly QualityNudge[];
|