@formicoidea/labre-framework-edgy 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.
@@ -1,31 +1,162 @@
1
1
  import { neutralPalettes, paletteColorAction, shapeToolbarConfig, } from '@formicoidea/labre-core/gfx/shape';
2
2
  import { ToolbarModuleExtension, } from '@formicoidea/labre-core/shared/services';
3
3
  import { BlockFlavourIdentifier } from '@formicoidea/labre-core/std';
4
+ /**
5
+ * The twelve EDGY swatches' own names, resolved by `resolvePaletteLabel`
6
+ * (`@labre/affine-components/color-picker`) through each swatch's own
7
+ * {@link NamedPalette.labelWording} — see Wardley's own
8
+ * `WARDLEY_PALETTE_WORDINGS` (`../../wardley/src/toolbar/node-config.ts`)
9
+ * for the same mechanism applied to a sibling framework; the two never
10
+ * import each other.
11
+ *
12
+ * Exported so `../translations.ts` can list them in the manifest under
13
+ * source `chrome`.
14
+ */
15
+ export const EDGY_PALETTE_WORDING_IDENTITY = [
16
+ 'com.labre.edgy.palette.identity',
17
+ 'Identity',
18
+ ];
19
+ export const EDGY_PALETTE_WORDING_ARCHITECTURE = [
20
+ 'com.labre.edgy.palette.architecture',
21
+ 'Architecture',
22
+ ];
23
+ export const EDGY_PALETTE_WORDING_EXPERIENCE = [
24
+ 'com.labre.edgy.palette.experience',
25
+ 'Experience',
26
+ ];
27
+ export const EDGY_PALETTE_WORDING_ORGANISATION = [
28
+ 'com.labre.edgy.palette.organisation',
29
+ 'Organisation',
30
+ ];
31
+ export const EDGY_PALETTE_WORDING_BRAND = [
32
+ 'com.labre.edgy.palette.brand',
33
+ 'Brand',
34
+ ];
35
+ export const EDGY_PALETTE_WORDING_PRODUCT = [
36
+ 'com.labre.edgy.palette.product',
37
+ 'Product',
38
+ ];
39
+ export const EDGY_PALETTE_WORDING_IDENTITY_LIGHT = [
40
+ 'com.labre.edgy.palette.identity-light',
41
+ 'Identity light',
42
+ ];
43
+ export const EDGY_PALETTE_WORDING_ARCHITECTURE_LIGHT = [
44
+ 'com.labre.edgy.palette.architecture-light',
45
+ 'Architecture light',
46
+ ];
47
+ export const EDGY_PALETTE_WORDING_EXPERIENCE_LIGHT = [
48
+ 'com.labre.edgy.palette.experience-light',
49
+ 'Experience light',
50
+ ];
51
+ export const EDGY_PALETTE_WORDING_ORGANISATION_LIGHT = [
52
+ 'com.labre.edgy.palette.organisation-light',
53
+ 'Organisation light',
54
+ ];
55
+ export const EDGY_PALETTE_WORDING_BRAND_LIGHT = [
56
+ 'com.labre.edgy.palette.brand-light',
57
+ 'Brand light',
58
+ ];
59
+ export const EDGY_PALETTE_WORDING_PRODUCT_LIGHT = [
60
+ 'com.labre.edgy.palette.product-light',
61
+ 'Product light',
62
+ ];
63
+ export const EDGY_PALETTE_WORDINGS = [
64
+ EDGY_PALETTE_WORDING_IDENTITY,
65
+ EDGY_PALETTE_WORDING_ARCHITECTURE,
66
+ EDGY_PALETTE_WORDING_EXPERIENCE,
67
+ EDGY_PALETTE_WORDING_ORGANISATION,
68
+ EDGY_PALETTE_WORDING_BRAND,
69
+ EDGY_PALETTE_WORDING_PRODUCT,
70
+ EDGY_PALETTE_WORDING_IDENTITY_LIGHT,
71
+ EDGY_PALETTE_WORDING_ARCHITECTURE_LIGHT,
72
+ EDGY_PALETTE_WORDING_EXPERIENCE_LIGHT,
73
+ EDGY_PALETTE_WORDING_ORGANISATION_LIGHT,
74
+ EDGY_PALETTE_WORDING_BRAND_LIGHT,
75
+ EDGY_PALETTE_WORDING_PRODUCT_LIGHT,
76
+ ];
4
77
  /**
5
78
  * The typical EDGY palette, surfaced as ready-made swatches in the EDGY node
6
79
  * color picker (facet + intersection colours, saturated then pastel), followed
7
80
  * by the default editor palette.
8
81
  */
9
82
  const EDGY_PALETTES = [
10
- { key: 'Identity', value: '#00ea4e' },
11
- { key: 'Architecture', value: '#034cee' },
12
- { key: 'Experience', value: '#ff0056' },
13
- { key: 'Organisation', value: '#00caf4' },
14
- { key: 'Brand', value: '#ffa500' },
15
- { key: 'Product', value: '#cf00ff' },
16
- { key: 'Identity light', value: '#80ffb7' },
17
- { key: 'Architecture light', value: '#a6c0ff' },
18
- { key: 'Experience light', value: '#ff99bd' },
19
- { key: 'Organisation light', value: '#80eaff' },
20
- { key: 'Brand light', value: '#ffd580' },
21
- { key: 'Product light', value: '#e599ff' },
83
+ {
84
+ key: 'Identity',
85
+ value: '#00ea4e',
86
+ labelWording: EDGY_PALETTE_WORDING_IDENTITY,
87
+ },
88
+ {
89
+ key: 'Architecture',
90
+ value: '#034cee',
91
+ labelWording: EDGY_PALETTE_WORDING_ARCHITECTURE,
92
+ },
93
+ {
94
+ key: 'Experience',
95
+ value: '#ff0056',
96
+ labelWording: EDGY_PALETTE_WORDING_EXPERIENCE,
97
+ },
98
+ {
99
+ key: 'Organisation',
100
+ value: '#00caf4',
101
+ labelWording: EDGY_PALETTE_WORDING_ORGANISATION,
102
+ },
103
+ { key: 'Brand', value: '#ffa500', labelWording: EDGY_PALETTE_WORDING_BRAND },
104
+ {
105
+ key: 'Product',
106
+ value: '#cf00ff',
107
+ labelWording: EDGY_PALETTE_WORDING_PRODUCT,
108
+ },
109
+ {
110
+ key: 'Identity light',
111
+ value: '#80ffb7',
112
+ labelWording: EDGY_PALETTE_WORDING_IDENTITY_LIGHT,
113
+ },
114
+ {
115
+ key: 'Architecture light',
116
+ value: '#a6c0ff',
117
+ labelWording: EDGY_PALETTE_WORDING_ARCHITECTURE_LIGHT,
118
+ },
119
+ {
120
+ key: 'Experience light',
121
+ value: '#ff99bd',
122
+ labelWording: EDGY_PALETTE_WORDING_EXPERIENCE_LIGHT,
123
+ },
124
+ {
125
+ key: 'Organisation light',
126
+ value: '#80eaff',
127
+ labelWording: EDGY_PALETTE_WORDING_ORGANISATION_LIGHT,
128
+ },
129
+ {
130
+ key: 'Brand light',
131
+ value: '#ffd580',
132
+ labelWording: EDGY_PALETTE_WORDING_BRAND_LIGHT,
133
+ },
134
+ {
135
+ key: 'Product light',
136
+ value: '#e599ff',
137
+ labelWording: EDGY_PALETTE_WORDING_PRODUCT_LIGHT,
138
+ },
22
139
  ];
23
140
  /**
24
141
  * From the default editor palette we keep ONLY the neutrals (greys, white,
25
142
  * black, transparent) — the historical colours are dropped in favour of the
26
143
  * EDGY swatches above.
27
144
  */
28
- const EDGY_PALETTE_LIST = [...EDGY_PALETTES, ...neutralPalettes()];
145
+ export const EDGY_PALETTE_LIST = [
146
+ ...EDGY_PALETTES,
147
+ ...neutralPalettes(),
148
+ ];
149
+ /**
150
+ * EDGY's page of the colour pickers' carousel (`docs/adr/0027`) — the same
151
+ * list its node picker is seeded with, offered on every other picker too.
152
+ * Registered from the FLAG-GATED view extension: offering hues is tooling
153
+ * (`docs/adr/0009`).
154
+ */
155
+ export const EDGY_FRAMEWORK_PALETTE = {
156
+ framework: 'edgy',
157
+ labelWording: ['com.labre.framework.edgy', 'EDGY'],
158
+ palettes: EDGY_PALETTE_LIST,
159
+ };
29
160
  /**
30
161
  * EDGY fill / stroke colour picker — identical to the shape one but seeded with
31
162
  * the EDGY palette swatches (`.palettes`).
@@ -1,11 +1,83 @@
1
1
  import { collectTranslationKeys, commandCategoryTranslationEntries, commandTranslationEntries, mergeTranslationEntries, } from '@formicoidea/labre-core/std';
2
- import { edgyCommands } from './commands.js';
2
+ import { edgyCommands, EDGY_LEGEND_CHROME_WORDINGS } from './commands.js';
3
+ import { EDGY_DYNAMIC_NODES, EDGY_DYNAMIC_VERBS, EDGY_ZONES, edgyElementLabel, edgyElementLabelKey, edgyVerbSeedKey, } from './metamodel.js';
3
4
  import { NODE_LABEL, nodeLabelKey } from './node/consts.js';
4
5
  import { EDGY_NUDGES } from './nudges.js';
5
6
  import { EDGY_PROFILES } from './profiles.js';
6
7
  import { EDGY_READING } from './reading.js';
7
8
  import { EDGY_ROLES } from './roles.js';
8
9
  import { EDGY_RULES } from './rules.js';
10
+ import { EDGY_TEMPLATE_NAME_CUSTOMER_JOURNEY, EDGY_TEMPLATE_NAME_FACETS_OVERVIEW, EDGY_TEMPLATE_NAME_ORGANISATION_CHART, EDGY_TEMPLATE_NAME_SERVICE_BLUEPRINT, EDGY_TEMPLATE_SEED, } from './templates/index.js';
11
+ import { EDGY_TOOLBAR_WORDINGS } from './toolbar/config.js';
12
+ import { EDGY_PALETTE_WORDINGS } from './toolbar/node-config.js';
13
+ /**
14
+ * The name every one of the 12 official elements and the 6 Venn zones is
15
+ * seeded with — one key per distinct lowercase word (`organisation`, `brand`
16
+ * and `product` name BOTH an element and an intersection zone, so the same
17
+ * key covers both), reused verbatim by `templates/dynamic.ts`,
18
+ * `templates/index.ts` and the facets background's own creation site
19
+ * (`actions.ts`).
20
+ */
21
+ const elementAndZoneSeedEntries = () => {
22
+ const names = new Set([
23
+ ...Object.keys(EDGY_DYNAMIC_NODES),
24
+ ...EDGY_ZONES.map(zone => zone.id),
25
+ ]);
26
+ return [...names].map(name => ({
27
+ key: edgyElementLabelKey(name),
28
+ fallback: edgyElementLabel(name),
29
+ source: 'seed',
30
+ }));
31
+ };
32
+ /** The legend's own section titles (see {@link EDGY_LEGEND_CHROME_WORDINGS}). */
33
+ const legendChromeEntries = () => EDGY_LEGEND_CHROME_WORDINGS.map(([key, fallback]) => ({
34
+ key,
35
+ fallback,
36
+ source: 'chrome',
37
+ }));
38
+ /** The toolbar tooltips this framework used to hard-code as English literals. */
39
+ const toolbarChromeEntries = () => EDGY_TOOLBAR_WORDINGS.map(([key, fallback]) => ({
40
+ key,
41
+ fallback,
42
+ source: 'chrome',
43
+ }));
44
+ /**
45
+ * The twelve node-colour-picker swatches' own names
46
+ * (`EDGY_PALETTE_WORDINGS`, `toolbar/node-config.ts`) — chrome, re-rendered
47
+ * on every locale switch, never seeded into a document.
48
+ */
49
+ const paletteWordingEntries = () => EDGY_PALETTE_WORDINGS.map(([key, fallback]) => ({
50
+ key,
51
+ fallback,
52
+ source: 'chrome',
53
+ }));
54
+ /** The metamodel's 24 canonical verbs, drawn raw as a connector label. */
55
+ const verbSeedEntries = () => EDGY_DYNAMIC_VERBS.map(verb => ({
56
+ key: edgyVerbSeedKey(verb),
57
+ fallback: verb,
58
+ source: 'seed',
59
+ }));
60
+ /**
61
+ * The seeds that belong to the four hand-composed scenes only (a lane title,
62
+ * a case name, a step counter…) — derived from `EDGY_TEMPLATE_SEED`, the very
63
+ * table the scenes read at placement.
64
+ */
65
+ const sceneSeedEntries = () => Object.values(EDGY_TEMPLATE_SEED).map(({ key, fallback }) => ({
66
+ key,
67
+ fallback,
68
+ source: 'seed',
69
+ }));
70
+ /**
71
+ * The four hand-composed scenes' own tile names — chrome, not seeds: a
72
+ * `Template.nameKey`, re-resolved every time the panel opens, never written
73
+ * into a document. None of the four derives from a command.
74
+ */
75
+ const templateNameEntries = () => [
76
+ EDGY_TEMPLATE_NAME_FACETS_OVERVIEW,
77
+ EDGY_TEMPLATE_NAME_CUSTOMER_JOURNEY,
78
+ EDGY_TEMPLATE_NAME_SERVICE_BLUEPRINT,
79
+ EDGY_TEMPLATE_NAME_ORGANISATION_CHART,
80
+ ].map(([key, fallback]) => ({ key, fallback, source: 'chrome' }));
9
81
  /**
10
82
  * THIS framework's contribution to the translation-key manifest — every
11
83
  * `com.labre.*` key EDGY can hand to `TranslationProvider.t`, derived from the
@@ -42,7 +114,7 @@ Object.entries(NODE_LABEL).map(([kind, label]) => ({
42
114
  key: nodeLabelKey(kind),
43
115
  fallback: label,
44
116
  source: 'seed',
45
- })),
117
+ })), elementAndZoneSeedEntries(), verbSeedEntries(), sceneSeedEntries(), templateNameEntries(), legendChromeEntries(), toolbarChromeEntries(), paletteWordingEntries(),
46
118
  // LAST, and the order is load-bearing: a reading profile carries the
47
119
  // framework's own `roles`, so walking it reaches every role key the line
48
120
  // above already named. `mergeTranslationEntries` keeps the FIRST
package/dist/view.js CHANGED
@@ -1,8 +1,8 @@
1
- import { QualityNudgeExtension, ReadingProfileExtension, SpotlightHostExtension, ValidationProfileExtension, ValidationRuleExtension, validationToolbarConfig, } from '@formicoidea/labre-core/blocks/surface';
2
- import { ToolbarModuleExtension } from '@formicoidea/labre-core/shared/services';
1
+ import { QualityNudgeExtension, ReadingProfileExtension, SpotlightHostExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { FrameworkPaletteExtension } from '@formicoidea/labre-core/components/color-picker';
3
3
  import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
4
4
  import { TemplateCategoryExtension } from '@formicoidea/labre-core/gfx/template';
5
- import { BlockFlavourIdentifier, CommandExtension } from '@formicoidea/labre-core/std';
5
+ import { CommandExtension } from '@formicoidea/labre-core/std';
6
6
  import { RoleVocabularyExtension } from '@formicoidea/labre-core/std/gfx';
7
7
  import { edgyCommandIcons, edgyCommands } from './commands.js';
8
8
  import { effects } from './effects.js';
@@ -19,8 +19,8 @@ import { EdgyFacetsRendererExtension } from './element-renderer.js';
19
19
  import { EdgyInteraction, EdgyView } from './element-view.js';
20
20
  import { EdgyNodeRendererExtension } from './node/node-renderer.js';
21
21
  import { EdgyNodeView } from './node/node-view.js';
22
- import { edgyBoardToolbarExtension, edgyToolbarExtension, } from './toolbar/config.js';
23
- import { edgyNodeToolbarExtension } from './toolbar/node-config.js';
22
+ import { edgyBoardToolbarExtension, edgyBoardToolingToolbarExtension, edgyToolbarExtension, edgyToolingToolbarExtension, } from './toolbar/config.js';
23
+ import { EDGY_FRAMEWORK_PALETTE, edgyNodeToolbarExtension, } from './toolbar/node-config.js';
24
24
  import { edgySeniorTool } from './toolbar/senior-tool.js';
25
25
  /**
26
26
  * EDGY rendering — ALWAYS registered, independent of any flag. Disabling `edgy`
@@ -88,22 +88,17 @@ export class EdgyViewExtension extends ViewExtensionProvider {
88
88
  // including the two the PO deliberately kept out of `rules.ts` on
89
89
  // 26/08/2026 (see `./nudges.ts`).
90
90
  context.register(QualityNudgeExtension(EDGY_NUDGES));
91
- // The Validation dropdown on a selected background's contextual toolbar.
92
- // A SECOND module on the same element, through the `custom:` flavour slot
93
- // (the pattern `gfx/wardley` uses on its map): the rendering toolbars are
94
- // registered always-on because a stored board must keep its toggles,
95
- // while choosing how hard to check it is tooling and belongs here. The
96
- // config itself names no framework — it reads roles and profiles — so
97
- // BOTH EDGY frames register the very same object.
98
- for (const flavour of [
99
- 'custom:affine:surface:edgy',
100
- 'custom:affine:surface:edgyBoard',
101
- ]) {
102
- context.register(ToolbarModuleExtension({
103
- id: BlockFlavourIdentifier(flavour),
104
- config: validationToolbarConfig,
105
- }));
106
- }
91
+ // The LEGEND button and the Validation dropdown on a selected
92
+ // background's contextual toolbar. A SECOND module on the same element,
93
+ // through the `custom:` flavour slot (the pattern `gfx/wardley` uses on
94
+ // its map): the rendering toolbars are registered always-on because a
95
+ // stored board must keep its appearance toggles, while asking the
96
+ // framework what its notation means, and choosing how hard to check the
97
+ // board, are both tooling and belong here (`docs/adr/0026`). One module
98
+ // per frame and not one shared object, because the button has to know
99
+ // WHICH background it is documenting.
100
+ context.register(edgyToolingToolbarExtension);
101
+ context.register(edgyBoardToolingToolbarExtension);
107
102
  // The resolver that turns a hand-drawn `edgy:relation` into the verb the
108
103
  // metamodel gives its two ends. It belongs HERE and not in the always-on
109
104
  // extension above, and the test is the one `docs/adr/0009` asks: does it
@@ -122,6 +117,11 @@ export class EdgyViewExtension extends ViewExtensionProvider {
122
117
  // profile, so it goes with the flag without either side naming the other.
123
118
  context.register(ReadingProfileExtension(EDGY_READING));
124
119
  context.register(edgySeniorTool);
120
+ // EDGY's page of the colour pickers' carousel (`docs/adr/0027`). Here,
121
+ // beside the senior tool, because offering hues is TOOLING — the colours
122
+ // already painted on a stored board are content and do not move
123
+ // (`docs/adr/0009`).
124
+ context.register(FrameworkPaletteExtension(EDGY_FRAMEWORK_PALETTE));
125
125
  // The Templates-panel category — tooling, so it goes with the flag (#244).
126
126
  context.register(TemplateCategoryExtension(edgyTemplateCategory));
127
127
  // The eight EDGY commands: the sub-menu renders them, Settings ›
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formicoidea/labre-framework-edgy",
3
3
  "description": "Labre edgy framework for @formicoidea/labre-core.",
4
- "version": "0.40.0",
4
+ "version": "0.42.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",
@@ -31,8 +31,7 @@
31
31
  "dist"
32
32
  ],
33
33
  "dependencies": {
34
- "@formicoidea/labre-core": "0.40.0",
35
- "@formicoidea/labre-ddd-shared": "0.40.0",
34
+ "@formicoidea/labre-core": "0.42.0",
36
35
  "@preact/signals-core": "^1.8.0",
37
36
  "lit": "^3.2.0",
38
37
  "yjs": "^13.6.21"
package/dist/legend.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { type AutoLegendSpec } from '@formicoidea/labre-ddd-shared';
2
- export declare const EDGY_AUTO_LEGEND: AutoLegendSpec;
package/dist/legend.js DELETED
@@ -1,109 +0,0 @@
1
- import { roleLabel, } from '@formicoidea/labre-ddd-shared';
2
- import { EDGY_DYNAMIC_NODES, EDGY_ZONE_FILL, EDGY_ZONES, edgyElementLabel, } from './metamodel.js';
3
- import { NODE_FILL, NODE_STROKE } from './node/consts.js';
4
- import { EDGY_ROLE, EDGY_ROLES } from './roles.js';
5
- /**
6
- * What an EDGY background's automatic legend can say — a TABLE, and nothing
7
- * else: the scan, the placement and the box are `createAutoLegend`'s job, the
8
- * same generic the three DDD backgrounds were given
9
- * (`@labre/affine-gfx-ddd-shared`, `shared/legend-auto.ts`). EDGY takes a
10
- * dependency on that package for the generic and the box prefab alone; moving
11
- * them to a neutral home would be the tidier answer and is not worth the churn
12
- * of this fix.
13
- *
14
- * Every row is DERIVED — from the metamodel (`./metamodel.ts`: which elements
15
- * exist, which zone each belongs to, what colour that zone is drawn in) and
16
- * from the role vocabulary's own labels (`./roles.ts`). Nothing here is
17
- * restated: a thirteenth element added to the metamodel gets its legend row the
18
- * same way it gets its role, with no edit to this file.
19
- *
20
- * ## The order
21
- *
22
- * By ZONE, and the order of the table carries it: the three facets first
23
- * (Identity, Architecture, Experience), then the three intersections in one
24
- * section, then the four base elements, then the relations — which is the
25
- * reading order of {@link EDGY_ZONES} and, before it, of the Venn itself.
26
- */
27
- /** One row per official element of `zone`, in the metamodel's own order. */
28
- function zoneEntries(zone) {
29
- return Object.entries(EDGY_DYNAMIC_NODES)
30
- .filter(([, node]) => node.zone === zone)
31
- .map(([name]) => ({
32
- role: EDGY_ROLE[name],
33
- row: {
34
- swatch: 'square',
35
- // The zone's fill, which IS what the diagram paints the element with.
36
- color: EDGY_ZONE_FILL[zone],
37
- label: roleLabel(EDGY_ROLES, EDGY_ROLE[name]),
38
- },
39
- }));
40
- }
41
- const FACET_SECTIONS = EDGY_ZONES.filter(zone => zone.group === 'facet').map(zone => ({
42
- title: edgyElementLabel(zone.id),
43
- entries: zoneEntries(zone.id),
44
- }));
45
- /**
46
- * The three intersection elements in ONE section: Organisation, Product and
47
- * Brand are not three facets, they are the three lenses between them, and the
48
- * diagram says so by drawing them in the overlaps. Each keeps its own colour.
49
- */
50
- const INTERSECTIONS_SECTION = {
51
- title: 'Intersections',
52
- entries: EDGY_ZONES.filter(zone => zone.group === 'intersection').flatMap(zone => zoneEntries(zone.id)),
53
- };
54
- /**
55
- * The four base elements, listed only when one is on the board BARE — an
56
- * element the user dropped from the toolbox and left as a People, an Outcome,
57
- * an Object or an Activity, without saying which of the twelve it is. White,
58
- * because that is the fill the palette gives them (`node/consts.ts`).
59
- *
60
- * `exact` is what makes "bare" true. Detection is otherwise an ancestor walk,
61
- * and the twelve official elements specialise these four — Content is an
62
- * object, Story an activity — so an "Object" row would appear on a board
63
- * carrying nothing but Contents, keyed to a white swatch that is drawn nowhere
64
- * on it. The relation entry below keeps the walk, because there the parent row
65
- * IS the fair summary: a board carrying `edgy:expresses` carries a relation.
66
- */
67
- const BASE_SECTION = {
68
- title: 'Base elements',
69
- entries: ['people', 'outcome', 'object', 'activity'].map(kind => ({
70
- role: EDGY_ROLE[kind],
71
- exact: true,
72
- row: {
73
- swatch: 'square',
74
- color: NODE_FILL,
75
- label: roleLabel(EDGY_ROLES, EDGY_ROLE[kind]),
76
- },
77
- })),
78
- };
79
- /**
80
- * ONE row for the whole relation family, keyed on the PARENT role: a board
81
- * carrying "content expresses purpose" carries `edgy:expresses`, which is a
82
- * relation, and that is all the legend has to say. Twenty-two rows naming the
83
- * verbs would restate the metamodel rather than document the drawing — and the
84
- * verb travels on the link itself, visible, where it belongs.
85
- */
86
- const RELATIONS_SECTION = {
87
- title: 'Relations',
88
- entries: [
89
- {
90
- role: EDGY_ROLE.relation,
91
- row: {
92
- swatch: 'line',
93
- // The stroke `activateEdgyRelation` arms the connector tool with.
94
- color: NODE_STROKE,
95
- label: roleLabel(EDGY_ROLES, EDGY_ROLE.relation),
96
- },
97
- },
98
- ],
99
- };
100
- export const EDGY_AUTO_LEGEND = {
101
- title: 'Legend',
102
- roles: EDGY_ROLES,
103
- sections: [
104
- ...FACET_SECTIONS,
105
- INTERSECTIONS_SECTION,
106
- BASE_SECTION,
107
- RELATIONS_SECTION,
108
- ],
109
- };