@formicoidea/labre-framework-wardley 0.41.0 → 0.43.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.
@@ -1,10 +1,9 @@
1
- import { EdgelessCRUDIdentifier } from '@formicoidea/labre-core/blocks/surface';
1
+ import { EdgelessCRUDIdentifier, legendToolbarAction, validationToolbarConfig, } from '@formicoidea/labre-core/blocks/surface';
2
2
  import { WardleyBackgroundElementModel } from '@formicoidea/labre-core/model';
3
- import { BOARD_LEGEND_COMPONENTS, BOARD_RESIZE_TOGGLE, TelemetryProvider, ToolbarModuleExtension, } from '@formicoidea/labre-core/shared/services';
3
+ import { BOARD_LEGEND_COMPONENTS, BOARD_RESIZE_TOGGLE, commandMoreAction, ToolbarModuleExtension, } from '@formicoidea/labre-core/shared/services';
4
4
  import { BlockFlavourIdentifier } from '@formicoidea/labre-core/std';
5
5
  import { html } from 'lit';
6
- import { createWardleyLegend } from '../legend.js';
7
- import { wardleyLegendIcon } from './icons.js';
6
+ import { wardleyExportOwmIcon, wardleyLegendIcon } from './icons.js';
8
7
  /** The seven toolbar tooltips this file used to hard-code as English literals. */
9
8
  const EVOLUTION_AXIS_TOGGLE = [
10
9
  'com.labre.wardley.toolbar.evolution-axis',
@@ -219,29 +218,14 @@ export const wardleyToolbarConfig = {
219
218
  booleanToggle('c.2-visibility-labels', VISIBILITY_LABELS_TOGGLE, VisibilityIcon, 'showVisibilityLabels'),
220
219
  ],
221
220
  },
222
- // Generate the auto-legend from the components present inside this
223
- // background's perimeter (+ a gradient-meaning block for gradient variants).
224
- {
225
- id: 'd.legend',
226
- tooltipWording: BOARD_LEGEND_COMPONENTS,
227
- icon: wardleyLegendIcon,
228
- run(ctx) {
229
- const models = ctx.getSurfaceModelsByType(WardleyBackgroundElementModel);
230
- const bg = models[0];
231
- if (!bg)
232
- return;
233
- createWardleyLegend(ctx.std, bg);
234
- ctx.std
235
- .getOptional(TelemetryProvider)
236
- ?.track('FrameworkLegendCreated', {
237
- framework: 'wardley',
238
- element: 'legend',
239
- page: 'whiteboard editor',
240
- segment: 'element toolbar',
241
- module: 'wardley toolbar',
242
- });
243
- },
244
- },
221
+ // The OWM export, in the "⋮" — R5 of
222
+ // `docs/add-a-framework/02-framework-rules.md`, the position
223
+ // `bpmn.exportXml` and `c4.exportMermaid` already hold on their own boards.
224
+ // This module is registered ALWAYS-ON (`view.ts`) while the commands are
225
+ // flag-gated, and that needs no extra guard: the entry's `when` looks the
226
+ // command up in the registry and withdraws when the wardley flag left it
227
+ // unregistered.
228
+ commandMoreAction('z.export-owm', 'wardley.exportOwm', 'com.labre.commands.wardley.exportOwm', 'Export Wardley map (OWM)', wardleyExportOwmIcon),
245
229
  ],
246
230
  when: ctx => ctx.getSurfaceModelsByType(WardleyBackgroundElementModel).length > 0,
247
231
  };
@@ -249,3 +233,55 @@ export const wardleyToolbarExtension = ToolbarModuleExtension({
249
233
  id: BlockFlavourIdentifier('affine:surface:wardley'),
250
234
  config: wardleyToolbarConfig,
251
235
  });
236
+ /**
237
+ * The map's flag-gated row, WHOLE: the Legend button and the Validation
238
+ * dropdown, in one module.
239
+ *
240
+ * ## Why they cannot be two modules
241
+ *
242
+ * `renderToolbar` merges exactly four slots per element — `<flavour>`,
243
+ * `custom:<flavour>` and the two `affine:surface:*` wildcards — and
244
+ * `ToolbarModuleExtension` binds by DI variant, so a second module claiming
245
+ * `custom:affine:surface:wardley` would throw
246
+ * `DuplicateServiceDefinitionError` before the editor finished setting up. Two
247
+ * slots, and Wardley has three things to put on a selected map: the axis and
248
+ * label toggles (always-on, `<flavour>`, above), the legend and the level of
249
+ * requirement. The precedent is C4's `c4BoardToolingToolbarConfig`.
250
+ *
251
+ * ## Why the legend moved OUT of the always-on half
252
+ *
253
+ * Because GENERATING one is tooling, and `docs/adr/0009` gates tooling: the
254
+ * flag off takes away the gesture that writes legend elements, exactly as it
255
+ * takes away the sub-menu that draws components. What the gesture already
256
+ * wrote is document CONTENT and keeps being painted — the box is plain shapes,
257
+ * text and `wardleyNode`s with no role, all drawn by the always-on renderers.
258
+ * The axis and label toggles stay always-on for the opposite reason: a stored
259
+ * map must keep its axes whatever the flag says.
260
+ *
261
+ * Sorting keeps the row readable across the merge — `a.` … `d.legend` from the
262
+ * two modules, then `z.validation` — whatever order they were registered in.
263
+ */
264
+ export const wardleyBoardToolingToolbarConfig = {
265
+ actions: [
266
+ // `d.legend` and not the factory's default `b.legend`: the row is sorted
267
+ // lexicographically by id and the two axis groups already hold `b.` and
268
+ // `c.`, so the legend reads after the toggles it documents the map beside.
269
+ legendToolbarAction({
270
+ id: 'd.legend',
271
+ Model: WardleyBackgroundElementModel,
272
+ owner: 'wardley',
273
+ framework: 'wardley',
274
+ tooltipWording: BOARD_LEGEND_COMPONENTS,
275
+ icon: wardleyLegendIcon,
276
+ }),
277
+ // The generic dropdown, not a Wardley variant of it: the config names no
278
+ // framework — it reads the registered rules and profiles — so this is the
279
+ // very same object c4, bpmn and the context map register.
280
+ ...validationToolbarConfig.actions,
281
+ ],
282
+ when: wardleyToolbarConfig.when,
283
+ };
284
+ export const wardleyBoardToolingToolbarExtension = ToolbarModuleExtension({
285
+ id: BlockFlavourIdentifier('custom:affine:surface:wardley'),
286
+ config: wardleyBoardToolingToolbarConfig,
287
+ });
@@ -1,4 +1,4 @@
1
- import type { NamedPalette } from '@formicoidea/labre-core/components/color-picker';
1
+ import type { FrameworkPalette, NamedPalette } from '@formicoidea/labre-core/components/color-picker';
2
2
  import { type Color, type ShapeElementModel } from '@formicoidea/labre-core/model';
3
3
  import { type ChromeWording } from '@formicoidea/labre-core/shared/services';
4
4
  /**
@@ -42,4 +42,12 @@ export declare const WARDLEY_PALETTE_WORDINGS: readonly ChromeWording[];
42
42
  * colours are dropped in favour of the Wardley swatches above.
43
43
  */
44
44
  export declare const WARDLEY_PALETTE_LIST: NamedPalette[];
45
+ /**
46
+ * Wardley's page of the colour pickers' carousel (`docs/adr/0027`) — the very
47
+ * list its own node picker is seeded with, offered on every other picker too:
48
+ * a connector between two components, a free-text label, a frame drawn over
49
+ * the map. Registered from the FLAG-GATED view extension, because offering
50
+ * hues is tooling (`docs/adr/0009`).
51
+ */
52
+ export declare const WARDLEY_FRAMEWORK_PALETTE: FrameworkPalette;
45
53
  export declare const wardleyNodeToolbarExtension: import("@formicoidea/labre-core/store").ExtensionType;
@@ -150,6 +150,18 @@ export const WARDLEY_PALETTE_LIST = [
150
150
  ...WARDLEY_PALETTES,
151
151
  ...neutralPalettes(),
152
152
  ];
153
+ /**
154
+ * Wardley's page of the colour pickers' carousel (`docs/adr/0027`) — the very
155
+ * list its own node picker is seeded with, offered on every other picker too:
156
+ * a connector between two components, a free-text label, a frame drawn over
157
+ * the map. Registered from the FLAG-GATED view extension, because offering
158
+ * hues is tooling (`docs/adr/0009`).
159
+ */
160
+ export const WARDLEY_FRAMEWORK_PALETTE = {
161
+ framework: 'wardley',
162
+ labelWording: ['com.labre.framework.wardley', 'Wardley map'],
163
+ palettes: WARDLEY_PALETTE_LIST,
164
+ };
153
165
  /**
154
166
  * Wardley nodes are {@link ShapeElementModel} subclasses, so the shape toolbar's
155
167
  * actions (which target `getSurfaceModelsByType(ShapeElementModel)`) operate on
@@ -12,6 +12,14 @@ export declare class EdgelessWardleySeniorButton extends EdgelessWardleySeniorBu
12
12
  enableActiveBackground: boolean;
13
13
  type: typeof EmptyTool;
14
14
  private _toggleMenu;
15
+ /**
16
+ * Lit while one of THIS framework's artefacts is armed under the cursor, as
17
+ * well as while its menu is open. The menu closes the moment the pointer goes
18
+ * to the board, so without this the ghost would be traceable to no button at
19
+ * all — and Shift+S, which walks that ghost along this framework's row, would
20
+ * read as a keystroke belonging to nothing.
21
+ */
22
+ private get _armed();
15
23
  render(): import("lit-html").TemplateResult<1>;
16
24
  }
17
25
  export {};
@@ -1,7 +1,7 @@
1
1
  import { DefaultTool } from '@formicoidea/labre-core/blocks/surface';
2
2
  import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
3
3
  import { translateKey } from '@formicoidea/labre-core/shared/services';
4
- import { EdgelessToolbarToolMixin } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
4
+ import { armedArtefact, EdgelessToolbarToolMixin, } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
5
5
  import { SignalWatcher } from '@formicoidea/labre-core/global/lit';
6
6
  import { css, html, LitElement } from 'lit';
7
7
  import { wardleyToolbarIcon } from './icons.js';
@@ -80,6 +80,16 @@ export class EdgelessWardleySeniorButton extends EdgelessToolbarToolMixin(Signal
80
80
  const menu = this.createPopper('edgeless-wardley-menu', this);
81
81
  menu.element.edgeless = this.edgeless;
82
82
  }
83
+ /**
84
+ * Lit while one of THIS framework's artefacts is armed under the cursor, as
85
+ * well as while its menu is open. The menu closes the moment the pointer goes
86
+ * to the board, so without this the ghost would be traceable to no button at
87
+ * all — and Shift+S, which walks that ghost along this framework's row, would
88
+ * read as a keystroke belonging to nothing.
89
+ */
90
+ get _armed() {
91
+ return armedArtefact(this.gfx)?.owner === 'wardley';
92
+ }
83
93
  render() {
84
94
  return html `<edgeless-toolbar-button
85
95
  class="wardley-button"
@@ -87,7 +97,7 @@ export class EdgelessWardleySeniorButton extends EdgelessToolbarToolMixin(Signal
87
97
  ? ''
88
98
  : translateKey(this.edgeless.std, 'com.labre.framework.wardley', 'Wardley map')}
89
99
  .tooltipOffset=${4}
90
- .active=${!!this.popper}
100
+ .active=${!!this.popper || this._armed}
91
101
  @click=${this._toggleMenu}
92
102
  >
93
103
  <div class="wardley-root">
@@ -14,7 +14,7 @@ import { WARDLEY_READING } from './reading.js';
14
14
  import { WARDLEY_ROLES } from './roles.js';
15
15
  import { WARDLEY_RULES } from './rules.js';
16
16
  import { KODAK_INERTIA_SEED, TEA_SHOP_SEED, WARDLEY_TEMPLATE_NAME_KODAK_INERTIA, WARDLEY_TEMPLATE_NAME_TEA_SHOP, } from './templates/maps.js';
17
- import { WARDLEY_TEMPLATE_NAME_EVOLUTION_ARROW, WARDLEY_TEMPLATE_NAME_LINK, } from './templates/index.js';
17
+ import { WARDLEY_TEMPLATE_NAME_AREA_POLYGON, WARDLEY_TEMPLATE_NAME_EVOLUTION_ARROW, WARDLEY_TEMPLATE_NAME_LINK, } from './templates/index.js';
18
18
  import { WARDLEY_TOOLBAR_WORDINGS } from './toolbar/config.js';
19
19
  import { WARDLEY_PALETTE_WORDINGS } from './toolbar/node-config.js';
20
20
  /**
@@ -40,8 +40,8 @@ const exampleSeedEntries = () => [...Object.values(TEA_SHOP_SEED), ...Object.val
40
40
  /**
41
41
  * The auto-legend's own wordings — title, row captions, gradient blocks and
42
42
  * the Porter panel — derived from `legend.ts`'s own `WARDLEY_LEGEND_WORDINGS`,
43
- * the very table `createWardleyLegend` reads when it writes the group onto
44
- * the canvas.
43
+ * the very declarations the rows subscribe and the two extras write when the
44
+ * group lands on the canvas.
45
45
  */
46
46
  const legendSeedEntries = () => WARDLEY_LEGEND_WORDINGS.map(([key, fallback]) => ({
47
47
  key,
@@ -55,13 +55,14 @@ const toolbarChromeEntries = () => WARDLEY_TOOLBAR_WORDINGS.map(([key, fallback]
55
55
  source: 'chrome',
56
56
  }));
57
57
  /**
58
- * The four hand-composed cards' own tile names — chrome, not seeds: a
58
+ * The five hand-composed cards' own tile names — chrome, not seeds: a
59
59
  * `Template.nameKey`, re-resolved every time the panel opens, never written
60
60
  * into a document. See `templates/index.ts` and `templates/maps.ts`.
61
61
  */
62
62
  const templateNameEntries = () => [
63
63
  WARDLEY_TEMPLATE_NAME_LINK,
64
64
  WARDLEY_TEMPLATE_NAME_EVOLUTION_ARROW,
65
+ WARDLEY_TEMPLATE_NAME_AREA_POLYGON,
65
66
  WARDLEY_TEMPLATE_NAME_TEA_SHOP,
66
67
  WARDLEY_TEMPLATE_NAME_KODAK_INERTIA,
67
68
  ].map(([key, fallback]) => ({ key, fallback, source: 'chrome' }));
package/dist/view.js CHANGED
@@ -1,5 +1,6 @@
1
- import { InterchangeExtension, morphToolbarConfig, ReadingProfileExtension, tagsToolbarConfig, validationToolbarConfig, QualityNudgeExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
1
+ import { InterchangeExtension, morphToolbarConfig, ReadingProfileExtension, tagsToolbarConfig, QualityNudgeExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
2
2
  import { AuditCriterionExtension, ToolbarModuleExtension, toolbarModuleKey, UniverseTagDefsExtension, } from '@formicoidea/labre-core/shared/services';
3
+ import { FrameworkPaletteExtension } from '@formicoidea/labre-core/components/color-picker';
3
4
  import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
4
5
  import { TemplateCategoryExtension } from '@formicoidea/labre-core/gfx/template';
5
6
  import { BlockFlavourIdentifier, CommandExtension } from '@formicoidea/labre-core/std';
@@ -21,8 +22,8 @@ import { WardleyInteraction, WardleyView } from './element-view.js';
21
22
  import { WardleyNodeRendererExtension } from './node/node-renderer.js';
22
23
  import { WardleyNodeView } from './node/node-view.js';
23
24
  import { WardleyPorterWatcher } from './node/porter-watcher.js';
24
- import { wardleyNodeToolbarExtension } from './toolbar/node-config.js';
25
- import { wardleyToolbarExtension } from './toolbar/config.js';
25
+ import { WARDLEY_FRAMEWORK_PALETTE, wardleyNodeToolbarExtension, } from './toolbar/node-config.js';
26
+ import { wardleyBoardToolingToolbarExtension, wardleyToolbarExtension, } from './toolbar/config.js';
26
27
  import { wardleySeniorTool } from './toolbar/senior-tool.js';
27
28
  /**
28
29
  * Wardley rendering — ALWAYS registered, independent of any flag. Disabling
@@ -106,18 +107,15 @@ export class WardleyViewExtension extends ViewExtensionProvider {
106
107
  // off contributes none and `map.audit` finds nothing to ask about — while
107
108
  // `ai-audit` independently decides whether the command exists at all.
108
109
  context.register(AuditCriterionExtension(WARDLEY_AUDIT_CRITERIA));
109
- // The Validation dropdown on a selected map's contextual toolbar. A
110
- // SECOND module on the same element, through the `custom:` flavour slot
111
- // (the pattern `gfx/mindmap` uses on `custom:affine:surface:shape`):
112
- // `wardleyToolbarExtension` is registered always-on because a stored map
113
- // must keep its axes and labels, while choosing how hard to check it is
114
- // tooling and belongs here. The config itself names no framework — it
115
- // reads roles and profiles — so a second framework registers the very
116
- // same object on its own flavour.
117
- context.register(ToolbarModuleExtension({
118
- id: BlockFlavourIdentifier('custom:affine:surface:wardley'),
119
- config: validationToolbarConfig,
120
- }));
110
+ // The Legend button and the Validation dropdown on a selected map's
111
+ // contextual toolbar — ONE module, through the `custom:` flavour slot
112
+ // (the pattern `gfx/mindmap` uses on `custom:affine:surface:shape`), for
113
+ // the reason `wardleyBoardToolingToolbarConfig` states: a flavour carries
114
+ // exactly one, and a second would throw at set-up. Here and not in the
115
+ // always-on half because both are TOOLING — generating a legend and
116
+ // choosing how hard to check the map — while `wardleyToolbarExtension`
117
+ // stays always-on so a stored map keeps its axes and labels.
118
+ context.register(wardleyBoardToolingToolbarExtension);
121
119
  // The four natures — Wardley's type-3 qualification (MF3, ADR 0007).
122
120
  // Seeded on the SAME mechanism a host uses for its own taxonomy: the
123
121
  // library ships one real pack, and a client's private extension is a
@@ -179,6 +177,12 @@ export class WardleyViewExtension extends ViewExtensionProvider {
179
177
  // the flag without either side naming the other.
180
178
  context.register(ReadingProfileExtension(WARDLEY_READING));
181
179
  context.register(wardleySeniorTool);
180
+ // Wardley's page of the colour pickers' carousel (`docs/adr/0027`).
181
+ // Here, beside the senior tool, because offering hues is TOOLING: a map
182
+ // drawn while the flag was on keeps every colour it was painted with
183
+ // when the flag goes off — the shelf that offers more of them is what
184
+ // goes away (`docs/adr/0009`).
185
+ context.register(FrameworkPaletteExtension(WARDLEY_FRAMEWORK_PALETTE));
182
186
  // The Templates-panel category — tooling, so it goes with the flag (#244).
183
187
  context.register(TemplateCategoryExtension(wardleyTemplateCategory));
184
188
  // The Wardley commands — thirteen artefacts plus the two directions of
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.41.0",
4
+ "version": "0.43.1",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",
@@ -31,7 +31,7 @@
31
31
  "dist"
32
32
  ],
33
33
  "dependencies": {
34
- "@formicoidea/labre-core": "0.41.0",
34
+ "@formicoidea/labre-core": "0.43.1",
35
35
  "lit": "^3.2.0"
36
36
  }
37
37
  }