@formicoidea/labre-framework-edgy 0.32.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,6 +44,19 @@ export const edgyOutcomeIcon = svg `<svg width="24" height="24" viewBox="0 0 24
44
44
  export const edgyObjectIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
45
45
  <rect x="3.5" y="6.5" width="17" height="11" stroke="currentColor" stroke-width="1.6"/>
46
46
  </svg>`;
47
+ /**
48
+ * Relation — a bare line between two ends, with the label riding on it.
49
+ *
50
+ * No arrowhead, exactly like the 24 relations of the metamodel template: EDGY
51
+ * draws its links as plain lines and lets the verb say which way the sentence
52
+ * runs. The little box in the middle IS the verb the tool writes there.
53
+ */
54
+ export const edgyRelationIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
55
+ <path d="M3.5 12 H20.5" stroke="currentColor" stroke-width="1.6"/>
56
+ <circle cx="3.8" cy="12" r="1.6" fill="currentColor"/>
57
+ <circle cx="20.2" cy="12" r="1.6" fill="currentColor"/>
58
+ <rect x="8" y="8.6" width="8" height="6.8" rx="1.4" fill="var(--affine-background-primary-color, #fff)" stroke="currentColor" stroke-width="1.4"/>
59
+ </svg>`;
47
60
  /** Activity — right-pointing chevron. */
48
61
  export const edgyActivityIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
49
62
  <path d="M3.5 6.5 H15 L20.5 12 L15 17.5 H3.5 Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>
@@ -3,6 +3,7 @@ import { html } from 'lit';
3
3
  export const edgySeniorTool = SeniorToolExtension('edgy', ({ block }) => {
4
4
  return {
5
5
  name: 'EDGY',
6
+ labelKey: 'com.labre.framework.edgy',
6
7
  content: html `<edgeless-edgy-senior-button
7
8
  .edgeless=${block}
8
9
  ></edgeless-edgy-senior-button>`,
@@ -1,14 +1,24 @@
1
1
  import { type TranslationKeyManifestEntry } from '@formicoidea/labre-core/std';
2
2
  /**
3
- * THIS framework's contribution to the translation-key manifest.
3
+ * THIS framework's contribution to the translation-key manifest — every
4
+ * `com.labre.*` key EDGY can hand to `TranslationProvider.t`, derived from the
5
+ * very declarations the editor registers.
4
6
  *
5
7
  * Its command labels and descriptions are built from a TEMPLATE, so the
6
- * concrete keys exist nowhere but in the declarations themselves and the
7
- * core manifest could not restate them even if it wanted to. The
8
- * contribution therefore ships WITH the framework: in the bundled
8
+ * concrete keys exist nowhere but in the declarations themselves and the core
9
+ * manifest could not restate them even if it wanted to. The same now holds for
10
+ * the roles: one key per canonical verb, derived from the metamodel, so a
11
+ * relation added there contributes its keys without anybody editing this file.
12
+ *
13
+ * That derivation is why the hand-drawn relation tool needed no line here: its
14
+ * `com.labre.commands.edgy.addRelation` and the `.description` key that carries
15
+ * its gesture sentence — the first DESCRIPTION any EDGY command has declared —
16
+ * are collected off `edgyCommands` with their English fallbacks, like every
17
+ * label before them.
18
+ *
19
+ * The contribution therefore ships WITH the framework: in the bundled
9
20
  * distribution `@formicoidea/labre-framework-edgy` carries it, and a host
10
- * composes it into its catalogue exactly as it already composes
11
- * `edgyCommands` into the command registry. See
12
- * `packages/affine/all/src/translations.ts`.
21
+ * composes it into its catalogue exactly as it already composes `edgyCommands`
22
+ * into the command registry. See `packages/affine/all/src/translations.ts`.
13
23
  */
14
24
  export declare const edgyTranslationEntries: TranslationKeyManifestEntry[];
@@ -1,15 +1,44 @@
1
- import { commandTranslationEntries, } from '@formicoidea/labre-core/std';
1
+ import { collectTranslationKeys, commandCategoryTranslationEntries, commandTranslationEntries, mergeTranslationEntries, } from '@formicoidea/labre-core/std';
2
2
  import { edgyCommands } from './commands.js';
3
+ import { NODE_LABEL, nodeLabelKey } from './node/consts.js';
4
+ import { EDGY_NUDGES } from './nudges.js';
5
+ import { EDGY_PROFILES } from './profiles.js';
6
+ import { EDGY_ROLES } from './roles.js';
7
+ import { EDGY_RULES } from './rules.js';
3
8
  /**
4
- * THIS framework's contribution to the translation-key manifest.
9
+ * THIS framework's contribution to the translation-key manifest — every
10
+ * `com.labre.*` key EDGY can hand to `TranslationProvider.t`, derived from the
11
+ * very declarations the editor registers.
5
12
  *
6
13
  * Its command labels and descriptions are built from a TEMPLATE, so the
7
- * concrete keys exist nowhere but in the declarations themselves and the
8
- * core manifest could not restate them even if it wanted to. The
9
- * contribution therefore ships WITH the framework: in the bundled
14
+ * concrete keys exist nowhere but in the declarations themselves and the core
15
+ * manifest could not restate them even if it wanted to. The same now holds for
16
+ * the roles: one key per canonical verb, derived from the metamodel, so a
17
+ * relation added there contributes its keys without anybody editing this file.
18
+ *
19
+ * That derivation is why the hand-drawn relation tool needed no line here: its
20
+ * `com.labre.commands.edgy.addRelation` and the `.description` key that carries
21
+ * its gesture sentence — the first DESCRIPTION any EDGY command has declared —
22
+ * are collected off `edgyCommands` with their English fallbacks, like every
23
+ * label before them.
24
+ *
25
+ * The contribution therefore ships WITH the framework: in the bundled
10
26
  * distribution `@formicoidea/labre-framework-edgy` carries it, and a host
11
- * composes it into its catalogue exactly as it already composes
12
- * `edgyCommands` into the command registry. See
13
- * `packages/affine/all/src/translations.ts`.
27
+ * composes it into its catalogue exactly as it already composes `edgyCommands`
28
+ * into the command registry. See `packages/affine/all/src/translations.ts`.
14
29
  */
15
- export const edgyTranslationEntries = commandTranslationEntries(edgyCommands);
30
+ export const edgyTranslationEntries = mergeTranslationEntries(commandTranslationEntries(edgyCommands),
31
+ // The catalogue's own group headers, derived from the very categories
32
+ // these commands declare. They ship WITH the framework because core's
33
+ // registry names no framework category in the bundled distribution, so a
34
+ // host that composed core's manifest alone drew translated entries under
35
+ // English headers (#183).
36
+ commandCategoryTranslationEntries(edgyCommands), collectTranslationKeys('role', EDGY_ROLES), collectTranslationKeys('rule', EDGY_RULES), collectTranslationKeys('nudge', EDGY_NUDGES), collectTranslationKeys('profile', EDGY_PROFILES),
37
+ // The captions a placed base element is seeded with. Derived from
38
+ // `NODE_LABEL`, the very table the gesture writes from, so the wording a
39
+ // host is offered is the wording the canvas would have carried.
40
+ Object.entries(NODE_LABEL).map(([kind, label]) => ({
41
+ key: nodeLabelKey(kind),
42
+ fallback: label,
43
+ source: 'seed',
44
+ })));
package/dist/view.d.ts CHANGED
@@ -2,17 +2,20 @@ import { type ViewExtensionContext, ViewExtensionProvider } from '@formicoidea/l
2
2
  /**
3
3
  * EDGY rendering — ALWAYS registered, independent of any flag. Disabling `edgy`
4
4
  * hides only the creation tooling (see {@link EdgyViewExtension}); boards and
5
- * facets already drawn must still paint, stay selectable, stay editable, keep
6
- * their contextual toolbar and keep the dependency spotlight. See
7
- * `docs/adr/0009`.
5
+ * facets already drawn must still paint, stay selectable, stay editable and
6
+ * keep their contextual toolbar and a board must keep the dependency
7
+ * spotlight it hosts. See `docs/adr/0009`.
8
8
  */
9
9
  export declare class EdgyRenderViewExtension extends ViewExtensionProvider {
10
10
  name: string;
11
11
  setup(context: ViewExtensionContext): void;
12
12
  }
13
13
  /**
14
- * EDGY creation tooling — flag-gated (`edgy`): the senior toolbar button and
15
- * its templates category.
14
+ * EDGY creation tooling — flag-gated (`edgy`): the senior toolbar button, its
15
+ * templates category, and the validation rules, profiles and quality checklist.
16
+ * All of it is tooling: a board drawn while the flag was on keeps rendering when
17
+ * it goes off, it just stops being checked — and the profile it was put on stays
18
+ * written, unread, until the flag comes back (`docs/adr/0009`).
16
19
  */
17
20
  export declare class EdgyViewExtension extends ViewExtensionProvider {
18
21
  name: string;
package/dist/view.js CHANGED
@@ -1,9 +1,16 @@
1
- import { SpotlightHostExtension } from '@formicoidea/labre-core/blocks/surface';
1
+ import { QualityNudgeExtension, SpotlightHostExtension, ValidationProfileExtension, ValidationRuleExtension, validationToolbarConfig, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { ToolbarModuleExtension } from '@formicoidea/labre-core/shared/services';
2
3
  import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
3
4
  import { extendTemplateCategory } from '@formicoidea/labre-core/gfx/template';
4
- import { CommandExtension } from '@formicoidea/labre-core/std';
5
+ import { BlockFlavourIdentifier, CommandExtension } from '@formicoidea/labre-core/std';
6
+ import { RoleVocabularyExtension } from '@formicoidea/labre-core/std/gfx';
5
7
  import { edgyCommandIcons, edgyCommands } from './commands.js';
6
8
  import { effects } from './effects.js';
9
+ import { EDGY_NUDGES } from './nudges.js';
10
+ import { EDGY_PROFILES } from './profiles.js';
11
+ import { EdgyRelationResolver } from './relation-resolver.js';
12
+ import { EDGY_ROLES } from './roles.js';
13
+ import { EDGY_RULES } from './rules.js';
7
14
  import { edgyTemplateCategory } from './templates/index.js';
8
15
  import { EdgyBoardRendererExtension } from './board-renderer.js';
9
16
  import { EdgyBoardInteraction, EdgyBoardView } from './board-view.js';
@@ -17,9 +24,9 @@ import { edgySeniorTool } from './toolbar/senior-tool.js';
17
24
  /**
18
25
  * EDGY rendering — ALWAYS registered, independent of any flag. Disabling `edgy`
19
26
  * hides only the creation tooling (see {@link EdgyViewExtension}); boards and
20
- * facets already drawn must still paint, stay selectable, stay editable, keep
21
- * their contextual toolbar and keep the dependency spotlight. See
22
- * `docs/adr/0009`.
27
+ * facets already drawn must still paint, stay selectable, stay editable and
28
+ * keep their contextual toolbar and a board must keep the dependency
29
+ * spotlight it hosts. See `docs/adr/0009`.
23
30
  */
24
31
  export class EdgyRenderViewExtension extends ViewExtensionProvider {
25
32
  constructor() {
@@ -34,21 +41,32 @@ export class EdgyRenderViewExtension extends ViewExtensionProvider {
34
41
  context.register(EdgyBoardRendererExtension);
35
42
  context.register(EdgyNodeView);
36
43
  context.register(EdgyNodeRendererExtension);
44
+ // The role VOCABULARY, always on. A role is written in the document, not in
45
+ // the tooling: the direction reveal of a typed relation, the inversion
46
+ // command and the toolbar entry that must not lie about one all read this,
47
+ // and they have to keep working on a board drawn while the flag was on and
48
+ // opened while it is off (`docs/adr/0009`, `docs/adr/0010`). The rules that
49
+ // JUDGE those roles stay in the flag-gated extension below.
50
+ context.register(RoleVocabularyExtension(EDGY_ROLES));
37
51
  if (this.isEdgeless(context.scope)) {
38
52
  context.register(EdgyInteraction);
39
53
  context.register(EdgyBoardInteraction);
40
54
  context.register(edgyToolbarExtension);
41
55
  context.register(edgyBoardToolbarExtension);
42
56
  context.register(edgyNodeToolbarExtension);
43
- // Both EDGY backgrounds grant the dependency spotlight on hover.
44
- context.register(SpotlightHostExtension('edgy'));
57
+ // The dependency spotlight on hover is BOARD logic: only the EDGY board
58
+ // grants it. The facets Venn is a drawing — it keeps its appearance
59
+ // toggles (labels, pictos, crop, resize) and nothing else (#195).
45
60
  context.register(SpotlightHostExtension('edgyBoard'));
46
61
  }
47
62
  }
48
63
  }
49
64
  /**
50
- * EDGY creation tooling — flag-gated (`edgy`): the senior toolbar button and
51
- * its templates category.
65
+ * EDGY creation tooling — flag-gated (`edgy`): the senior toolbar button, its
66
+ * templates category, and the validation rules, profiles and quality checklist.
67
+ * All of it is tooling: a board drawn while the flag was on keeps rendering when
68
+ * it goes off, it just stops being checked — and the profile it was put on stays
69
+ * written, unread, until the flag comes back (`docs/adr/0009`).
52
70
  */
53
71
  export class EdgyViewExtension extends ViewExtensionProvider {
54
72
  constructor() {
@@ -64,8 +82,40 @@ export class EdgyViewExtension extends ViewExtensionProvider {
64
82
  setup(context) {
65
83
  super.setup(context);
66
84
  if (this.isEdgeless(context.scope)) {
85
+ context.register(ValidationRuleExtension(EDGY_RULES));
86
+ context.register(ValidationProfileExtension(EDGY_PROFILES));
87
+ // Work quality (WS1): the four expectations no algorithm can decide —
88
+ // including the two the PO deliberately kept out of `rules.ts` on
89
+ // 26/08/2026 (see `./nudges.ts`).
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
+ }
107
+ // The resolver that turns a hand-drawn `edgy:relation` into the verb the
108
+ // metamodel gives its two ends. It belongs HERE and not in the always-on
109
+ // extension above, and the test is the one `docs/adr/0009` asks: does it
110
+ // paint stored content, or does it author new content? It authors — it
111
+ // writes a role and a label into the document — and the only edges it
112
+ // ever sees are the ones the flag-gated tool below stamps. A board drawn
113
+ // while the flag was on keeps every verb it was given (the vocabulary and
114
+ // the renderers are always on); with the flag off nothing new is named
115
+ // because nothing new is being armed. See `./relation-resolver.ts`.
116
+ context.register(EdgyRelationResolver);
67
117
  context.register(edgySeniorTool);
68
- // The seven EDGY commands: the sub-menu renders them, Settings ›
118
+ // The eight EDGY commands: the sub-menu renders them, Settings ›
69
119
  // Shortcuts finally lists them, and a host override on an id binds.
70
120
  context.register(CommandExtension(edgyCommands, edgyCommandIcons));
71
121
  }
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.32.0",
4
+ "version": "0.34.1",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",
@@ -21,13 +21,20 @@
21
21
  "./descriptor": {
22
22
  "types": "./dist/descriptor.d.ts",
23
23
  "import": "./dist/descriptor.js"
24
+ },
25
+ "./commands-manifest": {
26
+ "types": "./dist/commands-manifest.d.ts",
27
+ "import": "./dist/commands-manifest.js"
24
28
  }
25
29
  },
26
30
  "files": [
27
31
  "dist"
28
32
  ],
29
33
  "dependencies": {
30
- "@formicoidea/labre-core": "0.32.0",
31
- "lit": "^3.2.0"
34
+ "@formicoidea/labre-core": "0.34.1",
35
+ "@formicoidea/labre-ddd-shared": "0.34.1",
36
+ "@preact/signals-core": "^1.8.0",
37
+ "lit": "^3.2.0",
38
+ "yjs": "^13.6.21"
32
39
  }
33
40
  }