@formicoidea/labre-framework-c4 0.37.0 → 0.38.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.
@@ -0,0 +1,2 @@
1
+ import { type TemplateCategory } from '@formicoidea/labre-core/gfx/template';
2
+ export declare const c4TemplateCategory: TemplateCategory;
@@ -0,0 +1,68 @@
1
+ import { templateFromCommand, } from '@formicoidea/labre-core/gfx/template';
2
+ import { c4Commands } from './commands.js';
3
+ import { BOARD_BAND_FILL, BOARD_CARD_BORDER, BOARD_CARD_FILL, BOUNDARY_STROKE, NODE_PALETTE, } from './consts.js';
4
+ /**
5
+ * The C4 palette — DERIVED from the toolbox, one template per command.
6
+ *
7
+ * C4 was the ONE framework the Templates panel had no category for: the pack
8
+ * landed on 28/08/2026 with thirteen commands and nobody wrote the palette
9
+ * (audit of 09/09/2026, § 4.3). Writing it by hand was never an option — a C4
10
+ * component is five elements (a bodyless shape, three text tiers and the group
11
+ * that makes them one thing), created in painting order, and a hand-written
12
+ * restatement of that would have drifted from `actions.ts` the way every other
13
+ * framework's palette already had.
14
+ *
15
+ * So every entry below IS its command, run once against a recording surface, and
16
+ * `__tests__/templates-parity.unit.spec.ts` re-runs each one and compares. There
17
+ * is nothing hand-authored here to fall out of date: the day `createC4Node`
18
+ * changes, the palette changes with it.
19
+ *
20
+ * `relationshipTool` has no template on purpose — it ARMS the connector tool and
21
+ * draws nothing, so there is no artefact to record; `exportMermaid` is not an
22
+ * artefact command at all.
23
+ */
24
+ /** The command a derived template is the picture of. Throws rather than skips. */
25
+ function byId(id) {
26
+ const command = c4Commands.find(entry => entry.id === id);
27
+ if (!command)
28
+ throw new Error(`[c4] templates: no command "${id}"`);
29
+ return command;
30
+ }
31
+ const ATTRS = 'width="100%" height="100%" viewBox="0 0 135 80" xmlns="http://www.w3.org/2000/svg"';
32
+ /** The two written lines every element carries, drawn as the words they are. */
33
+ const words = (color, y) => `<g fill="${color}" opacity="0.85"><rect x="44" y="${y}" width="47" height="4" rx="2"/><rect x="52" y="${y + 8}" width="31" height="3" rx="1.5"/></g>`;
34
+ /** A kind's body, in its own stencil colours — the plain box the levels share. */
35
+ const boxPreview = (kind, extra = '') => {
36
+ const p = NODE_PALETTE[kind];
37
+ return `<svg ${ATTRS} fill="none"><rect x="30" y="20" width="75" height="40" fill="${p.fill}" stroke="${p.border}" stroke-width="2"/>${words(p.text, 32)}${extra}</svg>`;
38
+ };
39
+ /** The silhouette: a head standing clear of the same body. */
40
+ const personPreview = (kind) => {
41
+ const p = NODE_PALETTE[kind];
42
+ return `<svg ${ATTRS} fill="none"><circle cx="67" cy="18" r="10" fill="${p.fill}" stroke="${p.border}" stroke-width="2"/><rect x="34" y="32" width="67" height="32" rx="14" fill="${p.fill}" stroke="${p.border}" stroke-width="2"/>${words(p.text, 42)}</svg>`;
43
+ };
44
+ /** A dashed frame, and — one level in — a second frame inside it. */
45
+ const boundaryPreview = (inner = '') => `<svg ${ATTRS} fill="none"><rect x="14" y="12" width="107" height="56" stroke="${BOUNDARY_STROKE}" stroke-width="2" stroke-dasharray="7 4.5"/>${inner}</svg>`;
46
+ const CONTAINER = NODE_PALETTE.container;
47
+ export const c4TemplateCategory = {
48
+ name: 'C4',
49
+ templates: [
50
+ templateFromCommand(byId('c4.addBoard'), `<svg ${ATTRS} fill="none"><rect x="10" y="10" width="115" height="60" rx="6" fill="${BOARD_CARD_FILL}" stroke="${BOARD_CARD_BORDER}" stroke-width="1.5"/><path d="M10 26 H125" stroke="${BOARD_CARD_BORDER}" stroke-width="1.5"/><rect x="11" y="11" width="113" height="15" fill="${BOARD_BAND_FILL}"/><rect x="20" y="15" width="40" height="6" rx="3" fill="#262626" opacity="0.55"/><rect x="22" y="36" width="34" height="20" rx="2" fill="${NODE_PALETTE.system.fill}"/><rect x="79" y="36" width="34" height="20" rx="2" fill="${CONTAINER.fill}"/><path d="M58 46 H75" stroke="#444444" stroke-width="1.6" stroke-dasharray="4 3"/></svg>`),
51
+ templateFromCommand(byId('c4.addPerson'), personPreview('person')),
52
+ templateFromCommand(byId('c4.addPersonExt'), personPreview('person-ext')),
53
+ templateFromCommand(byId('c4.addSystem'), boxPreview('system')),
54
+ templateFromCommand(byId('c4.addSystemExt'), boxPreview('system-ext')),
55
+ templateFromCommand(byId('c4.addContainer'), boxPreview('container')),
56
+ // The UML component: the same box, with two tabs down its leading edge.
57
+ templateFromCommand(byId('c4.addComponent'), boxPreview('component', `<g fill="${NODE_PALETTE.component.fill}" stroke="${NODE_PALETTE.component.border}" stroke-width="2"><rect x="22" y="28" width="16" height="8"/><rect x="22" y="44" width="16" height="8"/></g>`)),
58
+ // A cylinder, and the stencil's own container blue: a database is a
59
+ // container drawn as a data store, never a fourth level.
60
+ templateFromCommand(byId('c4.addDatabase'), `<svg ${ATTRS} fill="none"><path d="M36 22 V58 C36 62 50 65 67 65 C84 65 99 62 99 58 V22 Z" fill="${CONTAINER.fill}" stroke="${CONTAINER.border}" stroke-width="2"/><ellipse cx="67.5" cy="22" rx="31.5" ry="7" fill="${CONTAINER.fill}" stroke="${CONTAINER.border}" stroke-width="2"/>${words(CONTAINER.text, 38)}</svg>`),
61
+ // The two decorated containers paint their BEZEL in the border colour and
62
+ // their SCREEN in the fill, which is the stencil's own pair (`consts.ts`).
63
+ templateFromCommand(byId('c4.addMobile'), `<svg ${ATTRS} fill="none"><rect x="49" y="6" width="37" height="68" rx="7" fill="${CONTAINER.border}"/><rect x="54" y="15" width="27" height="50" fill="${CONTAINER.fill}"/><rect x="61" y="10" width="13" height="2.5" rx="1.25" fill="${CONTAINER.fill}"/></svg>`),
64
+ templateFromCommand(byId('c4.addBrowser'), `<svg ${ATTRS} fill="none"><rect x="20" y="14" width="95" height="52" rx="4" fill="${CONTAINER.border}"/><rect x="24" y="28" width="87" height="34" fill="${CONTAINER.fill}"/><g fill="${CONTAINER.fill}"><circle cx="29" cy="21" r="2.4"/><circle cx="37" cy="21" r="2.4"/><circle cx="45" cy="21" r="2.4"/></g></svg>`),
65
+ templateFromCommand(byId('c4.addSystemBoundary'), boundaryPreview()),
66
+ templateFromCommand(byId('c4.addContainerBoundary'), boundaryPreview(`<rect x="34" y="26" width="67" height="30" stroke="${BOUNDARY_STROKE}" stroke-width="1.6" stroke-dasharray="5 3.5"/>`)),
67
+ ],
68
+ };
package/dist/view.d.ts CHANGED
@@ -16,8 +16,9 @@ export declare class C4RenderViewExtension extends ViewExtensionProvider {
16
16
  }
17
17
  /**
18
18
  * C4 creation tooling — flag-gated (`c4`): the senior toolbar button, its
19
- * sub-menu, the thirteen commands behind them, the board's legend button, the
20
- * component's "Change type" dropdown, and the validation rules and profiles.
19
+ * sub-menu, the thirteen commands behind them, its templates category, the
20
+ * board's legend button, the component's "Change type" dropdown, and the
21
+ * validation rules and profiles.
21
22
  *
22
23
  * All of it is tooling in the sense `docs/adr/0009` means: a diagram drawn while
23
24
  * the flag was on keeps painting, stays selectable and keeps its contextual
package/dist/view.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { FrameworkBackgroundInteractionExtension, InterchangeExtension, morphToolbarConfig, ReadingProfileExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
2
2
  import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
3
+ import { extendTemplateCategory } from '@formicoidea/labre-core/gfx/template';
3
4
  import { ToolbarModuleExtension, toolbarModuleKey, } from '@formicoidea/labre-core/shared/services';
4
5
  import { BlockFlavourIdentifier, CommandExtension } from '@formicoidea/labre-core/std';
5
6
  import { RoleVocabularyExtension } from '@formicoidea/labre-core/std/gfx';
@@ -17,6 +18,7 @@ import { C4_PROFILES } from './profiles.js';
17
18
  import { C4_READINGS } from './reading.js';
18
19
  import { C4_ROLES } from './roles.js';
19
20
  import { C4_RULES } from './rules.js';
21
+ import { c4TemplateCategory } from './templates.js';
20
22
  import { c4BoardToolbarExtension, c4BoardToolingToolbarExtension, } from './toolbar/config.js';
21
23
  import { c4SeniorTool } from './toolbar/senior-tool.js';
22
24
  /**
@@ -71,8 +73,9 @@ export class C4RenderViewExtension extends ViewExtensionProvider {
71
73
  }
72
74
  /**
73
75
  * C4 creation tooling — flag-gated (`c4`): the senior toolbar button, its
74
- * sub-menu, the thirteen commands behind them, the board's legend button, the
75
- * component's "Change type" dropdown, and the validation rules and profiles.
76
+ * sub-menu, the thirteen commands behind them, its templates category, the
77
+ * board's legend button, the component's "Change type" dropdown, and the
78
+ * validation rules and profiles.
76
79
  *
77
80
  * All of it is tooling in the sense `docs/adr/0009` means: a diagram drawn while
78
81
  * the flag was on keeps painting, stays selectable and keeps its contextual
@@ -90,6 +93,7 @@ export class C4ViewExtension extends ViewExtensionProvider {
90
93
  super.effect();
91
94
  // Defines the senior button and its menu — tooling-only custom elements.
92
95
  effects();
96
+ extendTemplateCategory(c4TemplateCategory);
93
97
  }
94
98
  setup(context) {
95
99
  super.setup(context);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formicoidea/labre-framework-c4",
3
3
  "description": "Labre c4 framework for @formicoidea/labre-core.",
4
- "version": "0.37.0",
4
+ "version": "0.38.1",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",
@@ -31,8 +31,8 @@
31
31
  "dist"
32
32
  ],
33
33
  "dependencies": {
34
- "@formicoidea/labre-core": "0.37.0",
35
- "@formicoidea/labre-ddd-shared": "0.37.0",
34
+ "@formicoidea/labre-core": "0.38.1",
35
+ "@formicoidea/labre-ddd-shared": "0.38.1",
36
36
  "lit": "^3.2.0"
37
37
  }
38
38
  }