@formicoidea/labre-framework-c4 0.39.3 → 0.41.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.js CHANGED
@@ -7,12 +7,12 @@ import { downloadBlob } from '@formicoidea/labre-core/shared/utils';
7
7
  import { Bound } from '@formicoidea/labre-core/global/gfx';
8
8
  import { GfxControllerIdentifier, } from '@formicoidea/labre-core/std/gfx';
9
9
  import { c4TierBoxes } from './component.js';
10
- import { BOARD_REF_HEIGHT, BOARD_REF_WIDTH, BOUNDARY_LABEL, BOUNDARY_REF_HEIGHT, BOUNDARY_REF_WIDTH, DESCRIPTION_FONT_SIZE, DESCRIPTION_PLACEHOLDER, NODE_LABEL, NODE_PALETTE, NODE_SIZE, RELATIONSHIP_STROKE, RELATIONSHIP_WIDTH, TITLE_FONT_SIZE, TYPE_FONT_SIZE, } from './consts.js';
10
+ import { BOARD_REF_HEIGHT, BOARD_REF_WIDTH, BOUNDARY_LABEL, boundaryLabelKey, BOUNDARY_REF_HEIGHT, BOUNDARY_REF_WIDTH, DESCRIPTION_FONT_SIZE, DESCRIPTION_PLACEHOLDER, DESCRIPTION_PLACEHOLDER_KEY, NODE_LABEL, nodeLabelKey, NODE_PALETTE, NODE_SIZE, RELATIONSHIP_STROKE, RELATIONSHIP_WIDTH, TITLE_FONT_SIZE, TYPE_FONT_SIZE, } from './consts.js';
11
11
  import { C4_MERMAID_EXPORT, c4BoardFrom, c4SafeFilename } from './interchange.js';
12
12
  import { C4_AUTO_LEGEND } from './legend.js';
13
13
  import { c4NodeProps } from './presets.js';
14
14
  import { C4_BOUNDARY_ROLE, C4_ROLE, c4BoardRoleKey } from './roles.js';
15
- import { C4_TYPE_PLACEHOLDER } from './type-line.js';
15
+ import { c4TypePlaceholder } from './type-line.js';
16
16
  /**
17
17
  * Standalone creation/activation actions for the C4 toolbox — the same shape
18
18
  * BPMN's `actions.ts` has, and for the same reason: the menu is a pure renderer
@@ -126,13 +126,34 @@ export function createC4Node(std, kind) {
126
126
  const boxes = c4TierBoxes(kind, x, y, w, h);
127
127
  const titleId = addTier(surface, gfx.layer.generateIndex(), C4_ROLE.title,
128
128
  // The kind's own label — `Person`, `Web app`. A name and a prompt at once,
129
- // which is why the exporter writes it through unchanged.
130
- NODE_LABEL[kind], TITLE_FONT_SIZE,
129
+ // which is why the exporter writes it through unchanged. Resolved HERE,
130
+ // once, exactly like a BPMN node's caption (`nodeLabelKey`): content from
131
+ // the moment it lands, so a component drawn in a translated host starts in
132
+ // that language.
133
+ translateKey(std, nodeLabelKey(kind), NODE_LABEL[kind]), TITLE_FONT_SIZE,
131
134
  // The one tier with weight on it: it is the heading of the box, and at 20px
132
135
  // against a 16px sentence the size alone does not carry that.
133
136
  FontWeight.SemiBold, paint.text, boxes.title);
134
- const typeLineId = addTier(surface, gfx.layer.generateIndex(), C4_ROLE['type-line'], C4_TYPE_PLACEHOLDER[kind], TYPE_FONT_SIZE, FontWeight.Regular, paint.text, boxes.typeLine);
135
- const descriptionId = addTier(surface, gfx.layer.generateIndex(), C4_ROLE.description, DESCRIPTION_PLACEHOLDER, DESCRIPTION_FONT_SIZE, FontWeight.Regular, paint.text, boxes.description);
137
+ const typeLineId = addTier(surface, gfx.layer.generateIndex(), C4_ROLE['type-line'],
138
+ // Resolved at placement, like the title above: `c4TypePlaceholder` reads
139
+ // through the host's catalogue for both halves of the prompt (the
140
+ // bracketed word AND the technology slot), and `C4TypeLineWatcher`
141
+ // (`node/type-line-watcher.ts`) now recomputes the canonical line the same
142
+ // way on every edit commit, so a translated seed here is no longer
143
+ // reverted to English the first time an author opens and closes the
144
+ // tier's editor without typing anything. `technologyOfTypeLine` and
145
+ // `c4StatedTechnology` (`component.ts`) recognise EITHER the English
146
+ // literal or the host's own resolved word (`type-line.ts`).
147
+ c4TypePlaceholder(kind, std), TYPE_FONT_SIZE, FontWeight.Regular, paint.text, boxes.typeLine);
148
+ const descriptionId = addTier(surface, gfx.layer.generateIndex(), C4_ROLE.description,
149
+ // Resolved at placement like the title above. `c4StatedDescription`
150
+ // (`component.ts`) still compares the stored text against the ENGLISH
151
+ // `DESCRIPTION_PLACEHOLDER` to read "nothing stated yet" — this lot's own
152
+ // French proposal for this key is the identical word ('description'), so
153
+ // the shipped catalogue keeps that comparison true; a host catalogue that
154
+ // chose a different wording would regain the same residual risk the type
155
+ // line carries permanently (see `notes`).
156
+ translateKey(std, DESCRIPTION_PLACEHOLDER_KEY, DESCRIPTION_PLACEHOLDER), DESCRIPTION_FONT_SIZE, FontWeight.Regular, paint.text, boxes.description);
136
157
  const groupId = surface.addElement({
137
158
  type: 'group',
138
159
  index: gfx.layer.generateIndex(),
@@ -209,7 +230,10 @@ export function createC4Boundary(std, variant) {
209
230
  // role of a boundary drawn before the split and of nothing this editor
210
231
  // creates. See the note above.
211
232
  role: C4_BOUNDARY_ROLE[variant],
212
- name: BOUNDARY_LABEL[variant],
233
+ // Resolved HERE, once — the boundary's name is exported verbatim
234
+ // (`export.ts`) with no placeholder comparison, so it is as safe to
235
+ // translate as a component's title.
236
+ name: translateKey(std, boundaryLabelKey(variant), BOUNDARY_LABEL[variant]),
213
237
  variant,
214
238
  xywh: new Bound(cx - BOUNDARY_REF_WIDTH / 2, cy - BOUNDARY_REF_HEIGHT / 2, BOUNDARY_REF_WIDTH, BOUNDARY_REF_HEIGHT).serialize(),
215
239
  });
package/dist/consts.d.ts CHANGED
@@ -246,24 +246,42 @@ export declare const NODE_SIZE: Record<C4NodeKind, {
246
246
  * nothing at all: the words are the artefact.
247
247
  */
248
248
  export declare const NODE_LABEL: Record<C4NodeKind, string>;
249
+ /**
250
+ * The i18n key {@link NODE_LABEL} is the English default of — mirrors BPMN's
251
+ * {@link nodeLabelKey} exactly, one package over: resolved at placement
252
+ * (`createC4Node`, the NAME tier) and never afterwards, since the title is
253
+ * content from the moment it lands and an author is free to retype it.
254
+ *
255
+ * Safe to translate where the type line is not: the exporter reads a
256
+ * component's NAME verbatim (`c4StatedName`) with no placeholder suppression,
257
+ * so nothing downstream compares this text against the English literal.
258
+ */
259
+ export declare const nodeLabelKey: (kind: C4NodeKind) => string;
260
+ /**
261
+ * The prompt a fresh description tier carries, resolved at placement exactly
262
+ * like {@link DESCRIPTION_PLACEHOLDER} below is the English default of.
263
+ */
264
+ export declare const DESCRIPTION_PLACEHOLDER_KEY = "com.labre.c4.seed.description-placeholder";
249
265
  export declare const FONT_FAMILY = "Inter, sans-serif";
250
- /** The card — the same white every framework background paints. */
251
- export declare const BOARD_CARD_FILL = "#ffffff";
252
- export declare const BOARD_CARD_BORDER = "#d5d9e0";
266
+ /**
267
+ * The card — the same white every framework background paints, framed and
268
+ * titled in the shared notation scale. The board is Labre's furniture, not
269
+ * the stencil's, so its neutrals are the scale's; the stencil greys are kept
270
+ * where the stencil draws them (the boundary, the relationship).
271
+ */
272
+ export declare const BOARD_CARD_FILL: string;
273
+ export declare const BOARD_CARD_BORDER: string;
253
274
  export declare const BOARD_BORDER_WIDTH = 1.5;
254
275
  export declare const BOARD_CORNER_RADIUS = 12;
255
276
  export declare const BOARD_TITLE_FONT_SIZE = 20;
256
- export declare const BOARD_TITLE_COLOR = "#262626";
277
+ export declare const BOARD_TITLE_COLOR: string;
257
278
  /**
258
- * The header strip's own tint — a shade of the card, not a colour of its own.
259
- *
260
- * Sober on purpose, and the same intent as the pool's participant band
261
- * (`POOL_BAND_FILL`, `#f4f4f5`): the band has to be SEEN, because a strip a user
262
- * cannot see is a target they cannot aim at, and it must not read as a second
263
- * object sitting on the sheet. A hair lighter than the pool's, which is what it
264
- * takes to stay quiet under a 20-unit title rather than under a 13-unit one.
279
+ * The header strip's fill: plain card white, like the pool's participant band
280
+ * (`POOL_BAND_FILL`), painted at render time. The strip stays visible, and so
281
+ * aimable, through the divider drawn under it in `BOARD_CARD_BORDER`, not
282
+ * through a tint (PO, 11/09/2026: no tinted bands).
265
283
  */
266
- export declare const BOARD_BAND_FILL = "#f7f8fa";
284
+ export declare const BOARD_BAND_FILL: string;
267
285
  /**
268
286
  * The size a fresh board is created at, and the room its furniture takes.
269
287
  *
@@ -334,6 +352,14 @@ export declare const BOUNDARY_MARGIN = 12;
334
352
  * on the canvas keeps its words whatever its variant.
335
353
  */
336
354
  export declare const BOUNDARY_LABEL: Record<C4BoundaryVariant, string>;
355
+ /**
356
+ * The i18n key {@link BOUNDARY_LABEL} is the English default of — resolved at
357
+ * placement (`createC4Boundary`) exactly like {@link nodeLabelKey}: the name
358
+ * is exported verbatim (`export.ts`, `boundary.name`) with no comparison
359
+ * against the English literal, so translating it is as safe as a component's
360
+ * title.
361
+ */
362
+ export declare const boundaryLabelKey: (variant: C4BoundaryVariant) => string;
337
363
  /**
338
364
  * Relationship connector preset — the dashed arrow C4 draws between elements.
339
365
  *
package/dist/consts.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/consts';
1
2
  /**
2
3
  * Visual constants for the C4 pack.
3
4
  *
@@ -290,25 +291,43 @@ export const NODE_LABEL = {
290
291
  browser: 'Web app',
291
292
  component: 'Component',
292
293
  };
294
+ /**
295
+ * The i18n key {@link NODE_LABEL} is the English default of — mirrors BPMN's
296
+ * {@link nodeLabelKey} exactly, one package over: resolved at placement
297
+ * (`createC4Node`, the NAME tier) and never afterwards, since the title is
298
+ * content from the moment it lands and an author is free to retype it.
299
+ *
300
+ * Safe to translate where the type line is not: the exporter reads a
301
+ * component's NAME verbatim (`c4StatedName`) with no placeholder suppression,
302
+ * so nothing downstream compares this text against the English literal.
303
+ */
304
+ export const nodeLabelKey = (kind) => `com.labre.c4.seed.${kind}`;
305
+ /**
306
+ * The prompt a fresh description tier carries, resolved at placement exactly
307
+ * like {@link DESCRIPTION_PLACEHOLDER} below is the English default of.
308
+ */
309
+ export const DESCRIPTION_PLACEHOLDER_KEY = 'com.labre.c4.seed.description-placeholder';
293
310
  /* ── The board ─────────────────────────────────────────────────────────── */
294
311
  export const FONT_FAMILY = 'Inter, sans-serif';
295
- /** The card — the same white every framework background paints. */
296
- export const BOARD_CARD_FILL = '#ffffff';
297
- export const BOARD_CARD_BORDER = '#d5d9e0';
312
+ /**
313
+ * The card — the same white every framework background paints, framed and
314
+ * titled in the shared notation scale. The board is Labre's furniture, not
315
+ * the stencil's, so its neutrals are the scale's; the stencil greys are kept
316
+ * where the stencil draws them (the boundary, the relationship).
317
+ */
318
+ export const BOARD_CARD_FILL = NOTATION_NEUTRALS.cardFill;
319
+ export const BOARD_CARD_BORDER = NOTATION_NEUTRALS.cardBorder;
298
320
  export const BOARD_BORDER_WIDTH = 1.5;
299
321
  export const BOARD_CORNER_RADIUS = 12;
300
322
  export const BOARD_TITLE_FONT_SIZE = 20;
301
- export const BOARD_TITLE_COLOR = '#262626';
323
+ export const BOARD_TITLE_COLOR = NOTATION_NEUTRALS.frameInk;
302
324
  /**
303
- * The header strip's own tint — a shade of the card, not a colour of its own.
304
- *
305
- * Sober on purpose, and the same intent as the pool's participant band
306
- * (`POOL_BAND_FILL`, `#f4f4f5`): the band has to be SEEN, because a strip a user
307
- * cannot see is a target they cannot aim at, and it must not read as a second
308
- * object sitting on the sheet. A hair lighter than the pool's, which is what it
309
- * takes to stay quiet under a 20-unit title rather than under a 13-unit one.
325
+ * The header strip's fill: plain card white, like the pool's participant band
326
+ * (`POOL_BAND_FILL`), painted at render time. The strip stays visible, and so
327
+ * aimable, through the divider drawn under it in `BOARD_CARD_BORDER`, not
328
+ * through a tint (PO, 11/09/2026: no tinted bands).
310
329
  */
311
- export const BOARD_BAND_FILL = '#f7f8fa';
330
+ export const BOARD_BAND_FILL = NOTATION_NEUTRALS.cardFill;
312
331
  /**
313
332
  * The size a fresh board is created at, and the room its furniture takes.
314
333
  *
@@ -386,6 +405,14 @@ export const BOUNDARY_LABEL = {
386
405
  system: 'System boundary',
387
406
  container: 'Container boundary',
388
407
  };
408
+ /**
409
+ * The i18n key {@link BOUNDARY_LABEL} is the English default of — resolved at
410
+ * placement (`createC4Boundary`) exactly like {@link nodeLabelKey}: the name
411
+ * is exported verbatim (`export.ts`, `boundary.name`) with no comparison
412
+ * against the English literal, so translating it is as safe as a component's
413
+ * title.
414
+ */
415
+ export const boundaryLabelKey = (variant) => `com.labre.c4.seed.boundary-${variant}`;
389
416
  /* ── The relationship ──────────────────────────────────────────────────── */
390
417
  /**
391
418
  * Relationship connector preset — the dashed arrow C4 draws between elements.
package/dist/legend.d.ts CHANGED
@@ -1,37 +1,5 @@
1
1
  import { type AutoLegendSpec } from '@formicoidea/labre-ddd-shared';
2
- /**
3
- * What the C4 board's automatic legend can say — a TABLE, and nothing else: the
4
- * scan, the placement and the box are `createAutoLegend`'s job, shared with the
5
- * three DDD boards.
6
- *
7
- * Every row is DERIVED twice over: its WORDING from the role vocabulary's own
8
- * `labelFallback` ({@link roleLabel}), and its COLOUR from the very palette the
9
- * creation site paints with ({@link NODE_PALETTE}). Neither is restated here, so
10
- * renaming a role renames its legend row and restyling the pack restyles its
11
- * swatches — which is what keeps a legend a description of the board rather than
12
- * a second opinion about it.
13
- *
14
- * ## Why `exact` on the container, and only there
15
- *
16
- * `c4:database` specialises `c4:container`, so an inclusive entry on the parent
17
- * would put a "Container" row — with the container's blue square — on a board
18
- * carrying nothing but cylinders. The row would name a shape that is nowhere on
19
- * the diagram. EDGY's four base kinds hit this first and `AutoLegendEntry.exact`
20
- * exists for it: base and specialisation become two separate statements, each
21
- * listed when it is the thing the user actually drew.
22
- *
23
- * The other four element roles are childless, so `exact` would change nothing
24
- * for them and is left off — the flag marks the places where the distinction is
25
- * real.
26
- *
27
- * ## What is missing, and why
28
- *
29
- * `mobile` and `browser` get no row of their own: they carry `c4:container`,
30
- * because a phone app and a single-page app are containers with a picture
31
- * (`roles.ts`). Detection is by role and only by role, so a board of nothing but
32
- * mobile apps lists "Container" — which is the honest answer about what the
33
- * boxes MEAN. `person-ext` and `system-ext` collapse the same way onto person
34
- * and system, for the same reason: the grey says "out of scope", not "a
35
- * different sort of thing".
36
- */
2
+ import { type ChromeWording } from '@formicoidea/labre-core/shared/services';
3
+ /** Every section `titleKey` above, for `translations.ts`'s manifest. */
4
+ export declare const C4_LEGEND_SECTION_WORDINGS: readonly ChromeWording[];
37
5
  export declare const C4_AUTO_LEGEND: AutoLegendSpec;
package/dist/legend.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { roleLabel } from '@formicoidea/labre-ddd-shared';
2
+ import { BOARD_LEGEND_TITLE, } from '@formicoidea/labre-core/shared/services';
2
3
  import { BOUNDARY_STROKE, NODE_PALETTE, RELATIONSHIP_STROKE } from './consts.js';
3
4
  import { C4_ROLE, C4_ROLES } from './roles.js';
4
5
  /**
@@ -36,13 +37,36 @@ import { C4_ROLE, C4_ROLES } from './roles.js';
36
37
  * and system, for the same reason: the grey says "out of scope", not "a
37
38
  * different sort of thing".
38
39
  */
40
+ /** This section's own keys. */
41
+ const SECTION_ELEMENTS = [
42
+ 'com.labre.c4.legend.section.elements',
43
+ 'Elements',
44
+ ];
45
+ const SECTION_FRAMES = [
46
+ 'com.labre.c4.legend.section.frames',
47
+ 'Frames',
48
+ ];
49
+ const SECTION_RELATIONS = [
50
+ 'com.labre.c4.legend.section.relations',
51
+ 'Relations',
52
+ ];
53
+ /** Every section `titleKey` above, for `translations.ts`'s manifest. */
54
+ export const C4_LEGEND_SECTION_WORDINGS = [
55
+ SECTION_ELEMENTS,
56
+ SECTION_FRAMES,
57
+ SECTION_RELATIONS,
58
+ ];
39
59
  export const C4_AUTO_LEGEND = {
40
- title: 'Legend',
60
+ // The shared DDD auto-legend box's own generic chrome, resolved through
61
+ // the same key every board that has one reuses — see `AutoLegendSpec.title`.
62
+ title: BOARD_LEGEND_TITLE[1],
63
+ titleKey: BOARD_LEGEND_TITLE[0],
41
64
  width: 290,
42
65
  roles: C4_ROLES,
43
66
  sections: [
44
67
  {
45
68
  title: 'Elements',
69
+ titleKey: SECTION_ELEMENTS[0],
46
70
  entries: [
47
71
  {
48
72
  role: C4_ROLE.person,
@@ -90,6 +114,7 @@ export const C4_AUTO_LEGEND = {
90
114
  },
91
115
  {
92
116
  title: 'Frames',
117
+ titleKey: SECTION_FRAMES[0],
93
118
  entries: [
94
119
  {
95
120
  role: C4_ROLE.boundary,
@@ -107,6 +132,7 @@ export const C4_AUTO_LEGEND = {
107
132
  },
108
133
  {
109
134
  title: 'Relations',
135
+ titleKey: SECTION_RELATIONS[0],
110
136
  entries: [
111
137
  {
112
138
  role: C4_ROLE.relationship,
package/dist/morph.js CHANGED
@@ -167,8 +167,8 @@ function rewriteTier(model, role, decide) {
167
167
  * "Customer database" keeps that name whatever it becomes, which is the PO's
168
168
  * "the label is intact" for every title that is real content.
169
169
  */
170
- function rewriteTiers(model, from, to) {
171
- rewriteTier(model, C4_ROLE['type-line'], text => c4MorphedTypeLine(from, to, text));
170
+ function rewriteTiers(model, from, to, std) {
171
+ rewriteTier(model, C4_ROLE['type-line'], text => c4MorphedTypeLine(from, to, text, std));
172
172
  rewriteTier(model, C4_ROLE.title, text => c4MorphedTitle(from, to, text));
173
173
  }
174
174
  /**
@@ -103,7 +103,12 @@ export class C4TypeLineWatcher extends InteractivityExtension {
103
103
  if (!kind)
104
104
  return;
105
105
  const raw = element.text.toString();
106
- const canonical = normalizeC4TypeLine(kind, raw);
106
+ // `this.std` resolves the canonical line through the host's catalogue —
107
+ // both halves of the prompt, and the technology round-trip
108
+ // (`technologyOfTypeLine`) recognising the host's own resolved word —
109
+ // so a translated document's type line stays in that language across a
110
+ // commit instead of being silently reverted to English (`type-line.ts`).
111
+ const canonical = normalizeC4TypeLine(kind, raw, this.std);
107
112
  if (canonical === raw)
108
113
  return;
109
114
  this.std.store.captureSync();
package/dist/templates.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { templateFromCommand, } from '@formicoidea/labre-core/gfx/template';
2
2
  import { c4Commands } from './commands.js';
3
- import { BOARD_BAND_FILL, BOARD_CARD_BORDER, BOARD_CARD_FILL, BOUNDARY_STROKE, NODE_PALETTE, } from './consts.js';
3
+ import { BOARD_BAND_FILL, BOARD_CARD_BORDER, BOARD_CARD_FILL, BOARD_TITLE_COLOR, BOUNDARY_STROKE, NODE_PALETTE, RELATIONSHIP_STROKE, } from './consts.js';
4
4
  /**
5
5
  * The C4 palette — DERIVED from the toolbox, one template per command.
6
6
  *
@@ -46,8 +46,10 @@ const boundaryPreview = (inner = '') => `<svg ${ATTRS} fill="none"><rect x="14"
46
46
  const CONTAINER = NODE_PALETTE.container;
47
47
  export const c4TemplateCategory = {
48
48
  name: 'C4',
49
+ // Reuses the senior button's own key — see `TemplateCategory.nameKey`.
50
+ nameKey: 'com.labre.framework.c4',
49
51
  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>`),
52
+ 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="${BOARD_TITLE_COLOR}" 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="${RELATIONSHIP_STROKE}" stroke-width="1.6" stroke-dasharray="4 3"/></svg>`),
51
53
  templateFromCommand(byId('c4.addPerson'), personPreview('person')),
52
54
  templateFromCommand(byId('c4.addPersonExt'), personPreview('person-ext')),
53
55
  templateFromCommand(byId('c4.addSystem'), boxPreview('system')),
@@ -1,11 +1,50 @@
1
1
  import { collectTranslationKeys, commandCategoryTranslationEntries, commandTranslationEntries, mergeTranslationEntries, } from '@formicoidea/labre-core/std';
2
2
  import { C4_BOARD_BACKGROUND, C4_BOUNDARY_BACKGROUND } from './background.js';
3
3
  import { c4Commands } from './commands.js';
4
+ import { BOUNDARY_LABEL, boundaryLabelKey, DESCRIPTION_PLACEHOLDER, DESCRIPTION_PLACEHOLDER_KEY, NODE_LABEL, nodeLabelKey, } from './consts.js';
5
+ import { C4_LEGEND_SECTION_WORDINGS } from './legend.js';
4
6
  import { C4_BOARD_LEVEL_MENU } from './levels.js';
5
7
  import { C4_PROFILES } from './profiles.js';
6
8
  import { C4_READINGS } from './reading.js';
7
9
  import { C4_ROLES } from './roles.js';
8
10
  import { C4_RULES } from './rules.js';
11
+ import { C4_TYPE_LINE_WORDINGS } from './type-line.js';
12
+ /**
13
+ * The captions a placed component and a placed boundary are seeded with — the
14
+ * fallback IS `NODE_LABEL[kind]` / `BOUNDARY_LABEL[variant]`, never restated,
15
+ * mirroring BPMN's `seedEntries` exactly. The type line's own bracketed word
16
+ * and the technology placeholder ARE here too (`C4_TYPE_LINE_WORDINGS`),
17
+ * resolved at placement (`createC4Node`, `actions.ts`) and rebuilt through the
18
+ * same seam on every edit commit (`C4TypeLineWatcher`).
19
+ */
20
+ const seedEntries = () => [
21
+ ...Object.entries(NODE_LABEL).map(([kind, label]) => ({
22
+ key: nodeLabelKey(kind),
23
+ fallback: label,
24
+ source: 'seed',
25
+ })),
26
+ ...Object.entries(BOUNDARY_LABEL).map(([variant, label]) => ({
27
+ key: boundaryLabelKey(variant),
28
+ fallback: label,
29
+ source: 'seed',
30
+ })),
31
+ {
32
+ key: DESCRIPTION_PLACEHOLDER_KEY,
33
+ fallback: DESCRIPTION_PLACEHOLDER,
34
+ source: 'seed',
35
+ },
36
+ ...C4_TYPE_LINE_WORDINGS.map(([key, fallback]) => ({
37
+ key,
38
+ fallback,
39
+ source: 'seed',
40
+ })),
41
+ ];
42
+ /** The auto-legend's own section titles ({@link C4_LEGEND_SECTION_WORDINGS}). */
43
+ const legendSectionEntries = () => C4_LEGEND_SECTION_WORDINGS.map(([key, fallback]) => ({
44
+ key,
45
+ fallback,
46
+ source: 'chrome',
47
+ }));
9
48
  /**
10
49
  * THIS framework's contribution to the translation-key manifest — every
11
50
  * `com.labre.*` key C4 can hand to `TranslationProvider.t`, derived from the
@@ -40,7 +79,7 @@ commandCategoryTranslationEntries(c4Commands), collectTranslationKeys('role', C4
40
79
  // nothing is restated in `affine/all`, so a key added to the picker
41
80
  // reaches a host's catalogue by construction.
42
81
  C4_BOARD_LEVEL_MENU,
43
- ]),
82
+ ]), seedEntries(), legendSectionEntries(),
44
83
  // AFTER the two above, and the order is load-bearing: a rule carries its
45
84
  // framework's `roles` and, for `c4.person-in-boundary`, the boundary's own
46
85
  // declaration, so walking the rules reaches keys those two lists already
@@ -1,4 +1,6 @@
1
1
  import type { C4NodeKind } from '@formicoidea/labre-core/model';
2
+ import { type ChromeWording } from '@formicoidea/labre-core/shared/services';
3
+ import type { BlockStdScope } from '@formicoidea/labre-core/std';
2
4
  /**
3
5
  * The middle tier of a C4 element's label — `[Person]`, `[Software System]`,
4
6
  * `[Container: Java]` — SEMI-DERIVED: the word comes from the kind, the
@@ -41,6 +43,7 @@ import type { C4NodeKind } from '@formicoidea/labre-core/model';
41
43
  * without a word to announce it fails the build here.
42
44
  */
43
45
  export declare const C4_TYPE_WORD: Record<C4NodeKind, string>;
46
+ export declare const C4_TYPE_WORD_KEY: Record<C4NodeKind, string>;
44
47
  /**
45
48
  * The type line as it is drawn, brackets included.
46
49
  *
@@ -49,10 +52,12 @@ export declare const C4_TYPE_WORD: Record<C4NodeKind, string>;
49
52
  * produce a dangling `[Container: ]`. Whitespace runs collapse for the same
50
53
  * reason they do in the mermaid sanitizer: the line is one line.
51
54
  *
52
- * Pure, total and `std`-free, so the renderer, the exporter and a test can all
53
- * ask the same question and get the same answer.
55
+ * Pure and total; `std` is OPTIONAL and, when given, resolves the bracketed
56
+ * word through the host's catalogue ({@link typeWord}) — the renderer, the
57
+ * exporter and a test can all still ask the same question with no `std` at
58
+ * all and get the same English answer they always have.
54
59
  */
55
- export declare function c4TypeLine(kind: C4NodeKind, technology?: string): string;
60
+ export declare function c4TypeLine(kind: C4NodeKind, technology?: string, std?: BlockStdScope): string;
56
61
  /**
57
62
  * The technology an author stated in a type line, whatever shape they left it
58
63
  * in — `''` when they stated none.
@@ -70,8 +75,12 @@ export declare function c4TypeLine(kind: C4NodeKind, technology?: string): strin
70
75
  * https://x/docs → https://x/docs a colon that is NOT a prefix
71
76
  * ```
72
77
  *
73
- * Pure and `std`-free, so the commit hook, the exporter and a test all read the
74
- * same line the same way.
78
+ * Pure and total; `std` is OPTIONAL, exactly like {@link c4TypeLine} —
79
+ * without it this reads a line the same way it always has, and with it the
80
+ * vocabulary the `<word>:` prefix is matched against ALSO recognises the
81
+ * host's own resolved word ({@link knownTypeWords}), so a line seeded or
82
+ * normalized in a translated host still gives back the right technology
83
+ * rather than the whole line.
75
84
  *
76
85
  * It deliberately does NOT know about the creation placeholder: a node created
77
86
  * and never touched carries `[Container: technology]`, and reading that as "no
@@ -80,7 +89,7 @@ export declare function c4TypeLine(kind: C4NodeKind, technology?: string): strin
80
89
  * placeholder is a question for whoever asks what the element STATES, which is
81
90
  * the exporter, and it is answered there.
82
91
  */
83
- export declare function technologyOfTypeLine(text: string | null | undefined): string;
92
+ export declare function technologyOfTypeLine(text: string | null | undefined, std?: BlockStdScope): string;
84
93
  /**
85
94
  * A type line as it must be STORED, whatever was typed into it.
86
95
  *
@@ -91,8 +100,14 @@ export declare function technologyOfTypeLine(text: string | null | undefined): s
91
100
  *
92
101
  * Idempotent by construction — `normalize(normalize(x)) === normalize(x)` —
93
102
  * which is what lets it run on every commit without a guard.
103
+ *
104
+ * `std` is OPTIONAL and, when given, is threaded to both halves: the
105
+ * technology is read back recognising the host's own word
106
+ * ({@link technologyOfTypeLine}) and the line is rebuilt with it
107
+ * ({@link c4TypeLine}) — see `C4TypeLineWatcher`, the one real caller that
108
+ * has an `std` to give it.
94
109
  */
95
- export declare function normalizeC4TypeLine(kind: C4NodeKind, rawText: string | null | undefined): string;
110
+ export declare function normalizeC4TypeLine(kind: C4NodeKind, rawText: string | null | undefined, std?: BlockStdScope): string;
96
111
  /**
97
112
  * The word a fresh type line prompts the author with, in the technology's slot.
98
113
  *
@@ -101,6 +116,19 @@ export declare function normalizeC4TypeLine(kind: C4NodeKind, rawText: string |
101
116
  * {@link C4_TYPE_PLACEHOLDER}.
102
117
  */
103
118
  export declare const TYPE_TECHNOLOGY_PLACEHOLDER = "technology";
119
+ /**
120
+ * {@link TYPE_TECHNOLOGY_PLACEHOLDER}'s own key — see the long comment on
121
+ * {@link C4_TYPE_WORD_KEY} for why this lot's shipped French proposal keeps
122
+ * it identical to English.
123
+ */
124
+ export declare const C4_TECHNOLOGY_PLACEHOLDER_KEY = "com.labre.c4.type.technology-placeholder";
125
+ /**
126
+ * Every wording this file writes onto the canvas, for `translations.ts`'s
127
+ * manifest contribution — the four distinct type words plus the technology
128
+ * prompt, all `seed` (written into the document once, at placement or at a
129
+ * commit the watcher normalizes).
130
+ */
131
+ export declare const C4_TYPE_LINE_WORDINGS: readonly ChromeWording[];
104
132
  /**
105
133
  * Which kinds announce a technology in their type line AT ALL.
106
134
  *
@@ -131,6 +159,15 @@ export declare const C4_TYPE_TAKES_TECHNOLOGY: Record<C4NodeKind, boolean>;
131
159
  * with a technology literally called "technology".
132
160
  */
133
161
  export declare const C4_TYPE_PLACEHOLDER: Record<C4NodeKind, string>;
162
+ /**
163
+ * {@link C4_TYPE_PLACEHOLDER}, resolved through `std` when given — the
164
+ * placement site (`createC4Node`, `actions.ts`) seeds a fresh element with
165
+ * this rather than the English-only constant, so a component drawn in a
166
+ * translated host starts in that language, like every other seed
167
+ * (`docs/adr/0016`). With no `std` this returns exactly
168
+ * `C4_TYPE_PLACEHOLDER[kind]`.
169
+ */
170
+ export declare function c4TypePlaceholder(kind: C4NodeKind, std?: BlockStdScope): string;
134
171
  /**
135
172
  * The type line a component should carry once its shape has morphed from `from`
136
173
  * to `to` — or `null` when the line is the AUTHOR's and must not be touched.
@@ -172,4 +209,4 @@ export declare const C4_TYPE_PLACEHOLDER: Record<C4NodeKind, string>;
172
209
  *
173
210
  * Pure, total and `std`-free, like everything else in this file.
174
211
  */
175
- export declare function c4MorphedTypeLine(from: C4NodeKind, to: C4NodeKind, rawText: string | null | undefined): string | null;
212
+ export declare function c4MorphedTypeLine(from: C4NodeKind, to: C4NodeKind, rawText: string | null | undefined, std?: BlockStdScope): string | null;
package/dist/type-line.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { translateKey, } from '@formicoidea/labre-core/shared/services';
1
2
  /**
2
3
  * The middle tier of a C4 element's label — `[Person]`, `[Software System]`,
3
4
  * `[Container: Java]` — SEMI-DERIVED: the word comes from the kind, the
@@ -50,6 +51,51 @@ export const C4_TYPE_WORD = {
50
51
  browser: 'Container',
51
52
  component: 'Component',
52
53
  };
54
+ /**
55
+ * {@link C4_TYPE_WORD}'s own i18n key, one per DISTINCT word (four kinds
56
+ * share `Container`, two share `Person`, two share `Software System`, one
57
+ * word each carries one key).
58
+ *
59
+ * The PO's own glossary (`brief-i18n.md`) names "Software System",
60
+ * "Container" and "Component" franglais — the French proposal IS the English
61
+ * word — and this lot extends the same choice to "Person" and to
62
+ * {@link TYPE_TECHNOLOGY_PLACEHOLDER}, for a reason beyond consistency: this
63
+ * whole file's comparisons (`technologyOfTypeLine`, `C4_TYPE_PLACEHOLDER`,
64
+ * `c4StatedTechnology` in `component.ts`) read the STORED text back against
65
+ * these very words, and `c4StatedTechnology` runs from the `std`-free exporter
66
+ * (`export.ts`, ADR 0012 P3) — it cannot ask a host's catalogue at all. Keeping
67
+ * the shipped French wording IDENTICAL to English is what keeps that
68
+ * comparison correct on a document seeded in French. A host that overrides
69
+ * the catalogue with a genuinely different word regains the risk the
70
+ * `DESCRIPTION_PLACEHOLDER_KEY` comment in `consts.ts` already names for the
71
+ * description tier.
72
+ */
73
+ // Named constants rather than the key literals inline: `manifest.unit.spec.ts`
74
+ // reads two adjacent single-quoted literals in one argument list as a
75
+ // key/fallback PAIR, with no anchor on `translateKey(` — and a `Record`
76
+ // spelling each key out beside the NEXT (quoted, hyphenated) property name
77
+ // below it reads exactly like one. Referencing an identifier instead of
78
+ // repeating the literal sidesteps the false pairing.
79
+ const PERSON_KEY = 'com.labre.c4.type.person';
80
+ const SYSTEM_KEY = 'com.labre.c4.type.system';
81
+ const CONTAINER_KEY = 'com.labre.c4.type.container';
82
+ const COMPONENT_KEY = 'com.labre.c4.type.component';
83
+ export const C4_TYPE_WORD_KEY = {
84
+ person: PERSON_KEY,
85
+ 'person-ext': PERSON_KEY,
86
+ system: SYSTEM_KEY,
87
+ 'system-ext': SYSTEM_KEY,
88
+ container: CONTAINER_KEY,
89
+ database: CONTAINER_KEY,
90
+ mobile: CONTAINER_KEY,
91
+ browser: CONTAINER_KEY,
92
+ component: COMPONENT_KEY,
93
+ };
94
+ /** The word an `std` (when given) resolves {@link kind}'s bracket to. */
95
+ function typeWord(kind, std) {
96
+ const english = C4_TYPE_WORD[kind];
97
+ return std ? translateKey(std, C4_TYPE_WORD_KEY[kind], english) : english;
98
+ }
53
99
  /**
54
100
  * The type line as it is drawn, brackets included.
55
101
  *
@@ -58,11 +104,13 @@ export const C4_TYPE_WORD = {
58
104
  * produce a dangling `[Container: ]`. Whitespace runs collapse for the same
59
105
  * reason they do in the mermaid sanitizer: the line is one line.
60
106
  *
61
- * Pure, total and `std`-free, so the renderer, the exporter and a test can all
62
- * ask the same question and get the same answer.
107
+ * Pure and total; `std` is OPTIONAL and, when given, resolves the bracketed
108
+ * word through the host's catalogue ({@link typeWord}) — the renderer, the
109
+ * exporter and a test can all still ask the same question with no `std` at
110
+ * all and get the same English answer they always have.
63
111
  */
64
- export function c4TypeLine(kind, technology) {
65
- const word = C4_TYPE_WORD[kind];
112
+ export function c4TypeLine(kind, technology, std) {
113
+ const word = typeWord(kind, std);
66
114
  const techn = (technology ?? '').replaceAll(/\s+/g, ' ').trim();
67
115
  return techn ? `[${word}: ${techn}]` : `[${word}]`;
68
116
  }
@@ -82,6 +130,22 @@ export function c4TypeLine(kind, technology) {
82
130
  * instead can only ever strip a word the notation itself writes.
83
131
  */
84
132
  const KNOWN_TYPE_WORDS = new Set(Object.values(C4_TYPE_WORD).map(word => word.toLowerCase()));
133
+ /**
134
+ * {@link KNOWN_TYPE_WORDS}, plus the host-resolved word of every kind when
135
+ * `std` is given — so a line seeded in a translated host (`c4TypeLine(kind,
136
+ * …, std)` at placement, or after a commit the watcher rebuilt) is still
137
+ * recognised as carrying THE NOTATION'S word and not a technology typed on
138
+ * its own. With no `std` this is exactly {@link KNOWN_TYPE_WORDS}.
139
+ */
140
+ function knownTypeWords(std) {
141
+ if (!std)
142
+ return KNOWN_TYPE_WORDS;
143
+ const words = new Set(KNOWN_TYPE_WORDS);
144
+ for (const kind of Object.keys(C4_TYPE_WORD)) {
145
+ words.add(typeWord(kind, std).toLowerCase());
146
+ }
147
+ return words;
148
+ }
85
149
  /**
86
150
  * The technology an author stated in a type line, whatever shape they left it
87
151
  * in — `''` when they stated none.
@@ -99,8 +163,12 @@ const KNOWN_TYPE_WORDS = new Set(Object.values(C4_TYPE_WORD).map(word => word.to
99
163
  * https://x/docs → https://x/docs a colon that is NOT a prefix
100
164
  * ```
101
165
  *
102
- * Pure and `std`-free, so the commit hook, the exporter and a test all read the
103
- * same line the same way.
166
+ * Pure and total; `std` is OPTIONAL, exactly like {@link c4TypeLine} —
167
+ * without it this reads a line the same way it always has, and with it the
168
+ * vocabulary the `<word>:` prefix is matched against ALSO recognises the
169
+ * host's own resolved word ({@link knownTypeWords}), so a line seeded or
170
+ * normalized in a translated host still gives back the right technology
171
+ * rather than the whole line.
104
172
  *
105
173
  * It deliberately does NOT know about the creation placeholder: a node created
106
174
  * and never touched carries `[Container: technology]`, and reading that as "no
@@ -109,18 +177,19 @@ const KNOWN_TYPE_WORDS = new Set(Object.values(C4_TYPE_WORD).map(word => word.to
109
177
  * placeholder is a question for whoever asks what the element STATES, which is
110
178
  * the exporter, and it is answered there.
111
179
  */
112
- export function technologyOfTypeLine(text) {
180
+ export function technologyOfTypeLine(text, std) {
113
181
  const flat = (text ?? '')
114
182
  .replaceAll(/[[\]]/g, ' ')
115
183
  .replaceAll(/\s+/g, ' ')
116
184
  .trim();
117
185
  const colon = flat.indexOf(':');
186
+ const words = knownTypeWords(std);
118
187
  // No colon at all: the line is either the bare notation word — which states no
119
188
  // technology — or it is the technology, typed on its own.
120
189
  if (colon < 0)
121
- return KNOWN_TYPE_WORDS.has(flat.toLowerCase()) ? '' : flat;
190
+ return words.has(flat.toLowerCase()) ? '' : flat;
122
191
  const head = flat.slice(0, colon).trim().toLowerCase();
123
- if (!KNOWN_TYPE_WORDS.has(head))
192
+ if (!words.has(head))
124
193
  return flat;
125
194
  return flat.slice(colon + 1).trim();
126
195
  }
@@ -134,9 +203,15 @@ export function technologyOfTypeLine(text) {
134
203
  *
135
204
  * Idempotent by construction — `normalize(normalize(x)) === normalize(x)` —
136
205
  * which is what lets it run on every commit without a guard.
206
+ *
207
+ * `std` is OPTIONAL and, when given, is threaded to both halves: the
208
+ * technology is read back recognising the host's own word
209
+ * ({@link technologyOfTypeLine}) and the line is rebuilt with it
210
+ * ({@link c4TypeLine}) — see `C4TypeLineWatcher`, the one real caller that
211
+ * has an `std` to give it.
137
212
  */
138
- export function normalizeC4TypeLine(kind, rawText) {
139
- return c4TypeLine(kind, technologyOfTypeLine(rawText));
213
+ export function normalizeC4TypeLine(kind, rawText, std) {
214
+ return c4TypeLine(kind, technologyOfTypeLine(rawText, std), std);
140
215
  }
141
216
  /* ── What a fresh element says before anybody writes on it ─────────────── */
142
217
  /**
@@ -147,6 +222,31 @@ export function normalizeC4TypeLine(kind, rawText) {
147
222
  * {@link C4_TYPE_PLACEHOLDER}.
148
223
  */
149
224
  export const TYPE_TECHNOLOGY_PLACEHOLDER = 'technology';
225
+ /**
226
+ * {@link TYPE_TECHNOLOGY_PLACEHOLDER}'s own key — see the long comment on
227
+ * {@link C4_TYPE_WORD_KEY} for why this lot's shipped French proposal keeps
228
+ * it identical to English.
229
+ */
230
+ export const C4_TECHNOLOGY_PLACEHOLDER_KEY = 'com.labre.c4.type.technology-placeholder';
231
+ /** The word an `std` (when given) resolves the technology prompt to. */
232
+ function technologyPlaceholderWord(std) {
233
+ return std
234
+ ? translateKey(std, C4_TECHNOLOGY_PLACEHOLDER_KEY, TYPE_TECHNOLOGY_PLACEHOLDER)
235
+ : TYPE_TECHNOLOGY_PLACEHOLDER;
236
+ }
237
+ /**
238
+ * Every wording this file writes onto the canvas, for `translations.ts`'s
239
+ * manifest contribution — the four distinct type words plus the technology
240
+ * prompt, all `seed` (written into the document once, at placement or at a
241
+ * commit the watcher normalizes).
242
+ */
243
+ export const C4_TYPE_LINE_WORDINGS = [
244
+ [C4_TYPE_WORD_KEY.person, C4_TYPE_WORD.person],
245
+ [C4_TYPE_WORD_KEY.system, C4_TYPE_WORD.system],
246
+ [C4_TYPE_WORD_KEY.container, C4_TYPE_WORD.container],
247
+ [C4_TYPE_WORD_KEY.component, C4_TYPE_WORD.component],
248
+ [C4_TECHNOLOGY_PLACEHOLDER_KEY, TYPE_TECHNOLOGY_PLACEHOLDER],
249
+ ];
150
250
  /**
151
251
  * Which kinds announce a technology in their type line AT ALL.
152
252
  *
@@ -190,6 +290,17 @@ export const C4_TYPE_PLACEHOLDER = Object.fromEntries(Object.keys(C4_TYPE_WORD).
190
290
  kind,
191
291
  c4TypeLine(kind, C4_TYPE_TAKES_TECHNOLOGY[kind] ? TYPE_TECHNOLOGY_PLACEHOLDER : undefined),
192
292
  ]));
293
+ /**
294
+ * {@link C4_TYPE_PLACEHOLDER}, resolved through `std` when given — the
295
+ * placement site (`createC4Node`, `actions.ts`) seeds a fresh element with
296
+ * this rather than the English-only constant, so a component drawn in a
297
+ * translated host starts in that language, like every other seed
298
+ * (`docs/adr/0016`). With no `std` this returns exactly
299
+ * `C4_TYPE_PLACEHOLDER[kind]`.
300
+ */
301
+ export function c4TypePlaceholder(kind, std) {
302
+ return c4TypeLine(kind, C4_TYPE_TAKES_TECHNOLOGY[kind] ? technologyPlaceholderWord(std) : undefined, std);
303
+ }
193
304
  /* ── What the line becomes when the shape becomes something else ───────── */
194
305
  /**
195
306
  * The type line a component should carry once its shape has morphed from `from`
@@ -232,13 +343,19 @@ export const C4_TYPE_PLACEHOLDER = Object.fromEntries(Object.keys(C4_TYPE_WORD).
232
343
  *
233
344
  * Pure, total and `std`-free, like everything else in this file.
234
345
  */
235
- export function c4MorphedTypeLine(from, to, rawText) {
346
+ export function c4MorphedTypeLine(from, to, rawText, std) {
236
347
  const text = (rawText ?? '').trim();
237
348
  if (!text)
238
349
  return null;
239
- if (text === C4_TYPE_PLACEHOLDER[from])
240
- return C4_TYPE_PLACEHOLDER[to];
241
- if (text !== normalizeC4TypeLine(from, text))
350
+ // The untouched prompt, in EITHER language: the English literal (a document
351
+ // seeded before these keys existed, or with no host) or the host's own
352
+ // resolved wording (`c4TypePlaceholder`, which equals the English constant
353
+ // when `std` is absent) — see the module docstring.
354
+ if (text === C4_TYPE_PLACEHOLDER[from] ||
355
+ text === c4TypePlaceholder(from, std)) {
356
+ return c4TypePlaceholder(to, std);
357
+ }
358
+ if (text !== normalizeC4TypeLine(from, text, std))
242
359
  return null;
243
- return c4TypeLine(to, technologyOfTypeLine(text));
360
+ return c4TypeLine(to, technologyOfTypeLine(text, std), std);
244
361
  }
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.39.3",
4
+ "version": "0.41.0",
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.39.3",
35
- "@formicoidea/labre-ddd-shared": "0.39.3",
34
+ "@formicoidea/labre-core": "0.41.0",
35
+ "@formicoidea/labre-ddd-shared": "0.41.0",
36
36
  "lit": "^3.2.0"
37
37
  }
38
38
  }