@formicoidea/labre-framework-c4 0.40.0 → 0.42.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/LICENSE +384 -0
- package/dist/actions.d.ts +2 -1
- package/dist/actions.js +35 -12
- package/dist/commands.d.ts +3 -0
- package/dist/commands.js +143 -1
- package/dist/consts.d.ts +24 -0
- package/dist/consts.js +24 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +4 -4
- package/dist/morph.js +2 -2
- package/dist/node/type-line-watcher.js +6 -1
- package/dist/templates.js +2 -0
- package/dist/toolbar/c4-senior-button.d.ts +1 -0
- package/dist/toolbar/c4-senior-button.js +1 -0
- package/dist/toolbar/config.d.ts +18 -29
- package/dist/toolbar/config.js +22 -85
- package/dist/toolbar/icons.d.ts +6 -3
- package/dist/toolbar/icons.js +6 -3
- package/dist/toolbar/palette.d.ts +33 -0
- package/dist/toolbar/palette.js +114 -0
- package/dist/translations.js +51 -2
- package/dist/type-line.d.ts +45 -8
- package/dist/type-line.js +133 -16
- package/dist/view.js +7 -0
- package/package.json +3 -3
- package/dist/legend.d.ts +0 -37
- package/dist/legend.js +0 -123
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FrameworkPalette, NamedPalette } from '@formicoidea/labre-core/components/color-picker';
|
|
2
|
+
import type { ChromeWording } from '@formicoidea/labre-core/shared/services';
|
|
3
|
+
/**
|
|
4
|
+
* The C4 swatches' own names, resolved by `resolvePaletteLabel`
|
|
5
|
+
* (`@labre/affine-components/color-picker`) through each swatch's own
|
|
6
|
+
* {@link NamedPalette.labelWording} — the same framework-agnostic mechanism
|
|
7
|
+
* Wardley and EDGY use (`WARDLEY_PALETTE_WORDINGS`), so nothing here touches
|
|
8
|
+
* `packages/affine/model` (RED ZONE) or another framework's package.
|
|
9
|
+
*
|
|
10
|
+
* Exported so `../translations.ts` can list them under source `chrome`: a
|
|
11
|
+
* swatch's name is toolbar chrome, re-rendered on every locale switch, never
|
|
12
|
+
* seeded into a document.
|
|
13
|
+
*/
|
|
14
|
+
export declare const C4_PALETTE_WORDING_PERSON: ChromeWording;
|
|
15
|
+
export declare const C4_PALETTE_WORDING_SYSTEM: ChromeWording;
|
|
16
|
+
export declare const C4_PALETTE_WORDING_CONTAINER: ChromeWording;
|
|
17
|
+
export declare const C4_PALETTE_WORDING_COMPONENT: ChromeWording;
|
|
18
|
+
export declare const C4_PALETTE_WORDING_EXTERNAL: ChromeWording;
|
|
19
|
+
export declare const C4_PALETTE_WORDING_RELATIONSHIP: ChromeWording;
|
|
20
|
+
export declare const C4_PALETTE_WORDINGS: readonly ChromeWording[];
|
|
21
|
+
/**
|
|
22
|
+
* From the default editor palette we keep ONLY the neutrals — the historical
|
|
23
|
+
* colours say nothing in this notation.
|
|
24
|
+
*/
|
|
25
|
+
export declare const C4_PALETTE_LIST: NamedPalette[];
|
|
26
|
+
/**
|
|
27
|
+
* C4's page of the colour pickers' carousel (`docs/adr/0027`). Registered from
|
|
28
|
+
* the FLAG-GATED view extension, because offering hues is TOOLING: a diagram
|
|
29
|
+
* drawn while the flag was on keeps every colour it was painted with when the
|
|
30
|
+
* flag goes off — the shelf that offers more of them is what goes away
|
|
31
|
+
* (`docs/adr/0009`).
|
|
32
|
+
*/
|
|
33
|
+
export declare const C4_FRAMEWORK_PALETTE: FrameworkPalette;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { neutralPalettes } from '@formicoidea/labre-core/gfx/shape';
|
|
2
|
+
import { NODE_PALETTE, RELATIONSHIP_STROKE } from '../consts.js';
|
|
3
|
+
/**
|
|
4
|
+
* The C4 swatches' own names, resolved by `resolvePaletteLabel`
|
|
5
|
+
* (`@labre/affine-components/color-picker`) through each swatch's own
|
|
6
|
+
* {@link NamedPalette.labelWording} — the same framework-agnostic mechanism
|
|
7
|
+
* Wardley and EDGY use (`WARDLEY_PALETTE_WORDINGS`), so nothing here touches
|
|
8
|
+
* `packages/affine/model` (RED ZONE) or another framework's package.
|
|
9
|
+
*
|
|
10
|
+
* Exported so `../translations.ts` can list them under source `chrome`: a
|
|
11
|
+
* swatch's name is toolbar chrome, re-rendered on every locale switch, never
|
|
12
|
+
* seeded into a document.
|
|
13
|
+
*/
|
|
14
|
+
export const C4_PALETTE_WORDING_PERSON = [
|
|
15
|
+
'com.labre.c4.palette.person-blue',
|
|
16
|
+
'Person blue',
|
|
17
|
+
];
|
|
18
|
+
export const C4_PALETTE_WORDING_SYSTEM = [
|
|
19
|
+
'com.labre.c4.palette.system-blue',
|
|
20
|
+
'System blue',
|
|
21
|
+
];
|
|
22
|
+
export const C4_PALETTE_WORDING_CONTAINER = [
|
|
23
|
+
'com.labre.c4.palette.container-blue',
|
|
24
|
+
'Container blue',
|
|
25
|
+
];
|
|
26
|
+
export const C4_PALETTE_WORDING_COMPONENT = [
|
|
27
|
+
'com.labre.c4.palette.component-blue',
|
|
28
|
+
'Component blue',
|
|
29
|
+
];
|
|
30
|
+
export const C4_PALETTE_WORDING_EXTERNAL = [
|
|
31
|
+
'com.labre.c4.palette.external-grey',
|
|
32
|
+
'External grey',
|
|
33
|
+
];
|
|
34
|
+
export const C4_PALETTE_WORDING_RELATIONSHIP = [
|
|
35
|
+
'com.labre.c4.palette.relationship-grey',
|
|
36
|
+
'Relationship grey',
|
|
37
|
+
];
|
|
38
|
+
export const C4_PALETTE_WORDINGS = [
|
|
39
|
+
C4_PALETTE_WORDING_PERSON,
|
|
40
|
+
C4_PALETTE_WORDING_SYSTEM,
|
|
41
|
+
C4_PALETTE_WORDING_CONTAINER,
|
|
42
|
+
C4_PALETTE_WORDING_COMPONENT,
|
|
43
|
+
C4_PALETTE_WORDING_EXTERNAL,
|
|
44
|
+
C4_PALETTE_WORDING_RELATIONSHIP,
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* The C4 **level ladder**, surfaced as ready-made swatches.
|
|
48
|
+
*
|
|
49
|
+
* C4's stencil IS a colour code (see `../consts.ts`): the four levels are four
|
|
50
|
+
* blues running lighter as they go in — person, software system, container,
|
|
51
|
+
* component — anything outside the diagram's scope is one grey, and everything
|
|
52
|
+
* that is not an element (the relationship arrow, the boundary frame) is drawn
|
|
53
|
+
* in a second, darker one.
|
|
54
|
+
*
|
|
55
|
+
* Every value is read off {@link NODE_PALETTE} and {@link RELATIONSHIP_STROKE}
|
|
56
|
+
* rather than restated, so the shelf and the notation cannot drift apart. They
|
|
57
|
+
* are SHORTCUTS, never constraints: no rule of this pack reads a colour.
|
|
58
|
+
*/
|
|
59
|
+
const C4_PALETTES = [
|
|
60
|
+
{
|
|
61
|
+
key: 'Person blue',
|
|
62
|
+
value: NODE_PALETTE.person.fill,
|
|
63
|
+
labelWording: C4_PALETTE_WORDING_PERSON,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
key: 'System blue',
|
|
67
|
+
value: NODE_PALETTE.system.fill,
|
|
68
|
+
labelWording: C4_PALETTE_WORDING_SYSTEM,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: 'Container blue',
|
|
72
|
+
value: NODE_PALETTE.container.fill,
|
|
73
|
+
labelWording: C4_PALETTE_WORDING_CONTAINER,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
key: 'Component blue',
|
|
77
|
+
value: NODE_PALETTE.component.fill,
|
|
78
|
+
labelWording: C4_PALETTE_WORDING_COMPONENT,
|
|
79
|
+
},
|
|
80
|
+
// One grey for both external kinds, because the stencil paints them the same:
|
|
81
|
+
// "outside the scope of this diagram" is one statement.
|
|
82
|
+
{
|
|
83
|
+
key: 'External grey',
|
|
84
|
+
value: NODE_PALETTE['system-ext'].fill,
|
|
85
|
+
labelWording: C4_PALETTE_WORDING_EXTERNAL,
|
|
86
|
+
},
|
|
87
|
+
// The grey of the relationship arrow — and of the boundary frame, which the
|
|
88
|
+
// stencil draws in the very same `#444444`.
|
|
89
|
+
{
|
|
90
|
+
key: 'Relationship grey',
|
|
91
|
+
value: RELATIONSHIP_STROKE,
|
|
92
|
+
labelWording: C4_PALETTE_WORDING_RELATIONSHIP,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
/**
|
|
96
|
+
* From the default editor palette we keep ONLY the neutrals — the historical
|
|
97
|
+
* colours say nothing in this notation.
|
|
98
|
+
*/
|
|
99
|
+
export const C4_PALETTE_LIST = [
|
|
100
|
+
...C4_PALETTES,
|
|
101
|
+
...neutralPalettes(),
|
|
102
|
+
];
|
|
103
|
+
/**
|
|
104
|
+
* C4's page of the colour pickers' carousel (`docs/adr/0027`). Registered from
|
|
105
|
+
* the FLAG-GATED view extension, because offering hues is TOOLING: a diagram
|
|
106
|
+
* drawn while the flag was on keeps every colour it was painted with when the
|
|
107
|
+
* flag goes off — the shelf that offers more of them is what goes away
|
|
108
|
+
* (`docs/adr/0009`).
|
|
109
|
+
*/
|
|
110
|
+
export const C4_FRAMEWORK_PALETTE = {
|
|
111
|
+
framework: 'c4',
|
|
112
|
+
labelWording: ['com.labre.framework.c4', 'C4 model'],
|
|
113
|
+
palettes: C4_PALETTE_LIST,
|
|
114
|
+
};
|
package/dist/translations.js
CHANGED
|
@@ -1,11 +1,60 @@
|
|
|
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
|
-
import { c4Commands } from './commands.js';
|
|
3
|
+
import { c4Commands, C4_LEGEND_SECTION_WORDINGS } from './commands.js';
|
|
4
|
+
import { BOUNDARY_LABEL, boundaryLabelKey, DESCRIPTION_PLACEHOLDER, DESCRIPTION_PLACEHOLDER_KEY, NODE_LABEL, nodeLabelKey, } from './consts.js';
|
|
4
5
|
import { C4_BOARD_LEVEL_MENU } from './levels.js';
|
|
5
6
|
import { C4_PROFILES } from './profiles.js';
|
|
6
7
|
import { C4_READINGS } from './reading.js';
|
|
7
8
|
import { C4_ROLES } from './roles.js';
|
|
8
9
|
import { C4_RULES } from './rules.js';
|
|
10
|
+
import { C4_PALETTE_WORDINGS } from './toolbar/palette.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
|
+
/**
|
|
43
|
+
* The carousel swatches' own names ({@link C4_PALETTE_WORDINGS}) — chrome,
|
|
44
|
+
* re-rendered by the colour picker on every locale switch, never seeded into
|
|
45
|
+
* a document. Same treatment as Wardley's and EDGY's.
|
|
46
|
+
*/
|
|
47
|
+
const paletteEntries = () => C4_PALETTE_WORDINGS.map(([key, fallback]) => ({
|
|
48
|
+
key,
|
|
49
|
+
fallback,
|
|
50
|
+
source: 'chrome',
|
|
51
|
+
}));
|
|
52
|
+
/** The auto-legend's own section titles ({@link C4_LEGEND_SECTION_WORDINGS}). */
|
|
53
|
+
const legendSectionEntries = () => C4_LEGEND_SECTION_WORDINGS.map(([key, fallback]) => ({
|
|
54
|
+
key,
|
|
55
|
+
fallback,
|
|
56
|
+
source: 'chrome',
|
|
57
|
+
}));
|
|
9
58
|
/**
|
|
10
59
|
* THIS framework's contribution to the translation-key manifest — every
|
|
11
60
|
* `com.labre.*` key C4 can hand to `TranslationProvider.t`, derived from the
|
|
@@ -40,7 +89,7 @@ commandCategoryTranslationEntries(c4Commands), collectTranslationKeys('role', C4
|
|
|
40
89
|
// nothing is restated in `affine/all`, so a key added to the picker
|
|
41
90
|
// reaches a host's catalogue by construction.
|
|
42
91
|
C4_BOARD_LEVEL_MENU,
|
|
43
|
-
]),
|
|
92
|
+
]), seedEntries(), legendSectionEntries(), paletteEntries(),
|
|
44
93
|
// AFTER the two above, and the order is load-bearing: a rule carries its
|
|
45
94
|
// framework's `roles` and, for `c4.person-in-boundary`, the boundary's own
|
|
46
95
|
// declaration, so walking the rules reaches keys those two lists already
|
package/dist/type-line.d.ts
CHANGED
|
@@ -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
|
|
53
|
-
*
|
|
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
|
|
74
|
-
*
|
|
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/0023`). 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
|
|
62
|
-
*
|
|
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 =
|
|
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
|
|
103
|
-
*
|
|
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
|
|
190
|
+
return words.has(flat.toLowerCase()) ? '' : flat;
|
|
122
191
|
const head = flat.slice(0, colon).trim().toLowerCase();
|
|
123
|
-
if (!
|
|
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/0023`). 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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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/dist/view.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FrameworkBackgroundInteractionExtension, InterchangeExtension, morphToolbarConfig, ReadingProfileExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { FrameworkPaletteExtension } from '@formicoidea/labre-core/components/color-picker';
|
|
2
3
|
import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
|
|
3
4
|
import { TemplateCategoryExtension } from '@formicoidea/labre-core/gfx/template';
|
|
4
5
|
import { ToolbarModuleExtension, toolbarModuleKey, } from '@formicoidea/labre-core/shared/services';
|
|
@@ -20,6 +21,7 @@ import { C4_ROLES } from './roles.js';
|
|
|
20
21
|
import { C4_RULES } from './rules.js';
|
|
21
22
|
import { c4TemplateCategory } from './templates.js';
|
|
22
23
|
import { c4BoardToolbarExtension, c4BoardToolingToolbarExtension, } from './toolbar/config.js';
|
|
24
|
+
import { C4_FRAMEWORK_PALETTE } from './toolbar/palette.js';
|
|
23
25
|
import { c4SeniorTool } from './toolbar/senior-tool.js';
|
|
24
26
|
/**
|
|
25
27
|
* C4 rendering — ALWAYS registered, independent of any flag. Boards, boundaries
|
|
@@ -112,6 +114,11 @@ export class C4ViewExtension extends ViewExtensionProvider {
|
|
|
112
114
|
context.register(ReadingProfileExtension(reading));
|
|
113
115
|
}
|
|
114
116
|
context.register(c4SeniorTool);
|
|
117
|
+
// C4's page of the colour pickers' carousel (`docs/adr/0027`). Here,
|
|
118
|
+
// beside the senior tool, because offering hues is TOOLING — the colours
|
|
119
|
+
// already painted on a stored diagram are content and do not move
|
|
120
|
+
// (`docs/adr/0009`).
|
|
121
|
+
context.register(FrameworkPaletteExtension(C4_FRAMEWORK_PALETTE));
|
|
115
122
|
// The Templates-panel category — tooling, so it goes with the flag (#244).
|
|
116
123
|
context.register(TemplateCategoryExtension(c4TemplateCategory));
|
|
117
124
|
context.register(CommandExtension(c4Commands, c4CommandIcons));
|
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.
|
|
4
|
+
"version": "0.42.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.
|
|
35
|
-
"@formicoidea/labre-ddd-shared": "0.
|
|
34
|
+
"@formicoidea/labre-core": "0.42.0",
|
|
35
|
+
"@formicoidea/labre-ddd-shared": "0.42.0",
|
|
36
36
|
"lit": "^3.2.0"
|
|
37
37
|
}
|
|
38
38
|
}
|
package/dist/legend.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
*/
|
|
37
|
-
export declare const C4_AUTO_LEGEND: AutoLegendSpec;
|