@formicoidea/labre-framework-uml 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.
Files changed (114) hide show
  1. package/LICENSE +384 -0
  2. package/dist/actions.d.ts +430 -0
  3. package/dist/actions.js +724 -0
  4. package/dist/background.d.ts +153 -0
  5. package/dist/background.js +557 -0
  6. package/dist/board-hit.d.ts +137 -0
  7. package/dist/board-hit.js +191 -0
  8. package/dist/commands-manifest.d.ts +19 -0
  9. package/dist/commands-manifest.js +571 -0
  10. package/dist/commands.d.ts +4 -0
  11. package/dist/commands.js +983 -0
  12. package/dist/component.d.ts +521 -0
  13. package/dist/component.js +708 -0
  14. package/dist/consts.d.ts +365 -0
  15. package/dist/consts.js +463 -0
  16. package/dist/descriptor.d.ts +12 -0
  17. package/dist/descriptor.js +10 -0
  18. package/dist/drawio-decode.d.ts +32 -0
  19. package/dist/drawio-decode.js +96 -0
  20. package/dist/drawio-import.d.ts +133 -0
  21. package/dist/drawio-import.js +885 -0
  22. package/dist/edge-morph.d.ts +154 -0
  23. package/dist/edge-morph.js +153 -0
  24. package/dist/edge-styles.d.ts +78 -0
  25. package/dist/edge-styles.js +210 -0
  26. package/dist/effects.d.ts +9 -0
  27. package/dist/effects.js +6 -0
  28. package/dist/element-renderer.d.ts +64 -0
  29. package/dist/element-renderer.js +114 -0
  30. package/dist/element-view.d.ts +234 -0
  31. package/dist/element-view.js +430 -0
  32. package/dist/export.d.ts +61 -0
  33. package/dist/export.js +41 -0
  34. package/dist/filename.d.ts +17 -0
  35. package/dist/filename.js +26 -0
  36. package/dist/frame-tag.d.ts +70 -0
  37. package/dist/frame-tag.js +78 -0
  38. package/dist/grammar.d.ts +695 -0
  39. package/dist/grammar.js +1436 -0
  40. package/dist/import.d.ts +306 -0
  41. package/dist/import.js +1270 -0
  42. package/dist/index.d.ts +47 -0
  43. package/dist/index.js +67 -0
  44. package/dist/interchange.d.ts +125 -0
  45. package/dist/interchange.js +372 -0
  46. package/dist/keywords.d.ts +204 -0
  47. package/dist/keywords.js +361 -0
  48. package/dist/kinds.d.ts +73 -0
  49. package/dist/kinds.js +91 -0
  50. package/dist/legend.d.ts +30 -0
  51. package/dist/legend.js +255 -0
  52. package/dist/model.d.ts +862 -0
  53. package/dist/model.js +1316 -0
  54. package/dist/morph.d.ts +178 -0
  55. package/dist/morph.js +496 -0
  56. package/dist/node/act-glyphs.d.ts +30 -0
  57. package/dist/node/act-glyphs.js +142 -0
  58. package/dist/node/compartment-watcher.d.ts +107 -0
  59. package/dist/node/compartment-watcher.js +163 -0
  60. package/dist/node/fit.d.ts +85 -0
  61. package/dist/node/fit.js +129 -0
  62. package/dist/node/node-renderer.d.ts +49 -0
  63. package/dist/node/node-renderer.js +611 -0
  64. package/dist/node/node-view.d.ts +51 -0
  65. package/dist/node/node-view.js +89 -0
  66. package/dist/node/paint.d.ts +84 -0
  67. package/dist/node/paint.js +143 -0
  68. package/dist/node/sd-glyphs.d.ts +36 -0
  69. package/dist/node/sd-glyphs.js +79 -0
  70. package/dist/node/stm-glyphs.d.ts +22 -0
  71. package/dist/node/stm-glyphs.js +111 -0
  72. package/dist/node/tier-metrics.d.ts +38 -0
  73. package/dist/node/tier-metrics.js +45 -0
  74. package/dist/operators.d.ts +45 -0
  75. package/dist/operators.js +75 -0
  76. package/dist/plantuml-import.d.ts +113 -0
  77. package/dist/plantuml-import.js +1723 -0
  78. package/dist/plantuml.d.ts +94 -0
  79. package/dist/plantuml.js +985 -0
  80. package/dist/presets.d.ts +149 -0
  81. package/dist/presets.js +302 -0
  82. package/dist/profiles.d.ts +2 -0
  83. package/dist/profiles.js +358 -0
  84. package/dist/reading.d.ts +160 -0
  85. package/dist/reading.js +648 -0
  86. package/dist/roles.d.ts +257 -0
  87. package/dist/roles.js +997 -0
  88. package/dist/rules.d.ts +267 -0
  89. package/dist/rules.js +3090 -0
  90. package/dist/templates.d.ts +2 -0
  91. package/dist/templates.js +197 -0
  92. package/dist/toolbar/config.d.ts +228 -0
  93. package/dist/toolbar/config.js +833 -0
  94. package/dist/toolbar/icons.d.ts +440 -0
  95. package/dist/toolbar/icons.js +711 -0
  96. package/dist/toolbar/senior-tool.d.ts +11 -0
  97. package/dist/toolbar/senior-tool.js +21 -0
  98. package/dist/toolbar/uml-menu.d.ts +17 -0
  99. package/dist/toolbar/uml-menu.js +20 -0
  100. package/dist/toolbar/uml-senior-button.d.ts +18 -0
  101. package/dist/toolbar/uml-senior-button.js +22 -0
  102. package/dist/translations.d.ts +27 -0
  103. package/dist/translations.js +117 -0
  104. package/dist/view.d.ts +33 -0
  105. package/dist/view.js +236 -0
  106. package/dist/xmi-import.d.ts +174 -0
  107. package/dist/xmi-import.js +2268 -0
  108. package/dist/xmi.d.ts +61 -0
  109. package/dist/xmi.js +1860 -0
  110. package/dist/xml-reader.d.ts +157 -0
  111. package/dist/xml-reader.js +430 -0
  112. package/dist/xml.d.ts +72 -0
  113. package/dist/xml.js +96 -0
  114. package/package.json +38 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * UML's seat on the edgeless senior row.
3
+ *
4
+ * No `order:` — like every other framework. The row IS the registration order
5
+ * of the flag-gated view extensions in `packages/affine/all/src/extensions/
6
+ * view.ts`, which follows `FRAMEWORK_DESCRIPTORS`; declaring an order here
7
+ * would make the stable sort start mattering and break that premise. Pinned by
8
+ * `all/src/__tests__/toolbar/senior-row-order.unit.spec.ts`, which reads this
9
+ * very file.
10
+ */
11
+ export declare const umlSeniorTool: import("@formicoidea/labre-core/store").ExtensionType;
@@ -0,0 +1,21 @@
1
+ import { SeniorToolExtension } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
2
+ import { html } from 'lit';
3
+ /**
4
+ * UML's seat on the edgeless senior row.
5
+ *
6
+ * No `order:` — like every other framework. The row IS the registration order
7
+ * of the flag-gated view extensions in `packages/affine/all/src/extensions/
8
+ * view.ts`, which follows `FRAMEWORK_DESCRIPTORS`; declaring an order here
9
+ * would make the stable sort start mattering and break that premise. Pinned by
10
+ * `all/src/__tests__/toolbar/senior-row-order.unit.spec.ts`, which reads this
11
+ * very file.
12
+ */
13
+ export const umlSeniorTool = SeniorToolExtension('uml', ({ block }) => {
14
+ return {
15
+ name: 'UML',
16
+ labelKey: 'com.labre.framework.uml',
17
+ content: html `<edgeless-uml-senior-button
18
+ .edgeless=${block}
19
+ ></edgeless-uml-senior-button>`,
20
+ };
21
+ });
@@ -0,0 +1,17 @@
1
+ import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
2
+ import { EdgelessCommandMenu } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
3
+ /**
4
+ * The popover above the toolbar for the UML toolbox. It declares nothing:
5
+ * {@link EdgelessCommandMenu} renders `umlCommands` for the `senior-menu`
6
+ * surface (`docs/adr/0008`).
7
+ *
8
+ * UML is past the fourteen-slot cap — twenty-one catalogue entries — so what
9
+ * this popover actually renders is the arbitrated thirteen plus the permanent
10
+ * "More artefacts…" button. That is the menu's own business, not this class's:
11
+ * `selectSeniorMenuCommands` does the ranking, and `commands.ts` documents the
12
+ * order it ranks from.
13
+ */
14
+ export declare class EdgelessUmlMenu extends EdgelessCommandMenu {
15
+ protected owner: "uml";
16
+ type: typeof EmptyTool;
17
+ }
@@ -0,0 +1,20 @@
1
+ import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
2
+ import { EdgelessCommandMenu } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
3
+ /**
4
+ * The popover above the toolbar for the UML toolbox. It declares nothing:
5
+ * {@link EdgelessCommandMenu} renders `umlCommands` for the `senior-menu`
6
+ * surface (`docs/adr/0008`).
7
+ *
8
+ * UML is past the fourteen-slot cap — twenty-one catalogue entries — so what
9
+ * this popover actually renders is the arbitrated thirteen plus the permanent
10
+ * "More artefacts…" button. That is the menu's own business, not this class's:
11
+ * `selectSeniorMenuCommands` does the ranking, and `commands.ts` documents the
12
+ * order it ranks from.
13
+ */
14
+ export class EdgelessUmlMenu extends EdgelessCommandMenu {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.owner = 'uml';
18
+ this.type = EmptyTool;
19
+ }
20
+ }
@@ -0,0 +1,18 @@
1
+ import { DddSeniorButtonBase } from '@formicoidea/labre-ddd-shared';
2
+ /**
3
+ * Main toolbar button (the class-box-and-ellipse tile) that opens the UML
4
+ * toolbox sub-menu above the toolbar.
5
+ *
6
+ * It reuses the shared senior-button base rather than restating the
7
+ * toggle/popper wiring a seventh time. The base lives in `ddd-shared` because
8
+ * the three DDD buttons were the first to need it and it was lifted out of them
9
+ * — the class itself knows nothing about DDD: it is a glyph, a tooltip key and
10
+ * a menu tag, which is the entirety of what a senior button is.
11
+ */
12
+ export declare class EdgelessUmlSeniorButton extends DddSeniorButtonBase {
13
+ protected menuTag: "edgeless-uml-menu";
14
+ protected owner: "uml";
15
+ protected label: string;
16
+ protected labelKey: string;
17
+ protected icon: import("lit-html").TemplateResult<2>;
18
+ }
@@ -0,0 +1,22 @@
1
+ import { DddSeniorButtonBase } from '@formicoidea/labre-ddd-shared';
2
+ import { umlToolbarIcon } from './icons.js';
3
+ /**
4
+ * Main toolbar button (the class-box-and-ellipse tile) that opens the UML
5
+ * toolbox sub-menu above the toolbar.
6
+ *
7
+ * It reuses the shared senior-button base rather than restating the
8
+ * toggle/popper wiring a seventh time. The base lives in `ddd-shared` because
9
+ * the three DDD buttons were the first to need it and it was lifted out of them
10
+ * — the class itself knows nothing about DDD: it is a glyph, a tooltip key and
11
+ * a menu tag, which is the entirety of what a senior button is.
12
+ */
13
+ export class EdgelessUmlSeniorButton extends DddSeniorButtonBase {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.menuTag = 'edgeless-uml-menu';
17
+ this.owner = 'uml';
18
+ this.label = 'UML';
19
+ this.labelKey = 'com.labre.framework.uml';
20
+ this.icon = umlToolbarIcon;
21
+ }
22
+ }
@@ -0,0 +1,27 @@
1
+ import { type TranslationKeyManifestEntry } from '@formicoidea/labre-core/std';
2
+ /**
3
+ * THIS framework's contribution to the translation-key manifest — every
4
+ * `com.labre.*` key UML can hand to `TranslationProvider.t`, derived from the
5
+ * very declarations the editor registers (never restated).
6
+ *
7
+ * The contribution ships WITH the framework, exactly as C4's and BPMN's do: in
8
+ * the bundled distribution `@formicoidea/labre-framework-uml` carries it, and a
9
+ * host composes it into its catalogue the same way it already composes
10
+ * `umlCommands` into the command registry. See
11
+ * `packages/affine/all/src/translations.ts`.
12
+ *
13
+ * The two BACKGROUND declarations are walked even though neither carries a
14
+ * `labelKey` today: both frames write the user's own words (a diagram's
15
+ * heading, a subject's name) and have no vocabulary to fall back to. Walking
16
+ * them costs nothing and means the day one of them gains a declared label the
17
+ * manifest already names it — which is the whole reason these lists are derived
18
+ * rather than written.
19
+ *
20
+ * The RULES and the two PROFILES are walked after the roles and the backgrounds,
21
+ * and the order is load-bearing: a rule carries its framework's `roles` and, for
22
+ * `uml.actor-inside-subject`, the subject's own declaration, so walking the pack
23
+ * reaches keys those lists already named. `mergeTranslationEntries` keeps the
24
+ * FIRST occurrence, which is what makes each key report the source it actually
25
+ * comes from.
26
+ */
27
+ export declare const umlTranslationEntries: TranslationKeyManifestEntry[];
@@ -0,0 +1,117 @@
1
+ import { collectTranslationKeys, commandCategoryTranslationEntries, commandTranslationEntries, mergeTranslationEntries, } from '@formicoidea/labre-core/std';
2
+ import { UML_DIAGRAM_FRAME, UML_SUBJECT_FRAME } from './background.js';
3
+ import { umlCommands } from './commands.js';
4
+ import { UML_DRAWIO_REMARKS } from './drawio-import.js';
5
+ import { UML_LAYOUT_REMARKS } from './import.js';
6
+ import { UML_ATTRIBUTES_SEED, UML_ATTRIBUTES_SEED_KEY, UML_NAME_SEED, UML_OPERATIONS_SEED, UML_OPERATIONS_SEED_KEY, UML_SLOTS_SEED, UML_SLOTS_SEED_KEY, umlSeedKey, } from './keywords.js';
7
+ import { UML_DIAGRAM_KIND_MENU } from './kinds.js';
8
+ import { UML_LEGEND_SECTION_WORDINGS } from './legend.js';
9
+ import { UML_FRAGMENT_OPERATOR_MENU } from './operators.js';
10
+ import { UML_PLANTUML_REMARKS } from './plantuml-import.js';
11
+ import { UML_PROFILES } from './profiles.js';
12
+ import { UML_READINGS } from './reading.js';
13
+ import { UML_ROLES } from './roles.js';
14
+ import { UML_RULES } from './rules.js';
15
+ import { UML_XMI_REMARKS } from './xmi-import.js';
16
+ /**
17
+ * The words a placed artefact is SEEDED with — its name compartment, and the
18
+ * three compartment lines a fresh classifier carries.
19
+ *
20
+ * Derived from {@link UML_NAME_SEED} itself, never restated: the fallback IS
21
+ * the very string the creation site used to write raw, mirroring BPMN's
22
+ * `seedEntries` exactly. The kinds the notation draws with no words
23
+ * (`UML_UNLABELLED_KINDS`, an empty seed) contribute no key — there is nothing
24
+ * to translate, and BPMN's own filter says the same thing one package over.
25
+ *
26
+ * `seed`, not `chrome`: unlike the section titles below, this text is WRITTEN
27
+ * INTO THE DOCUMENT and is the author's content from that moment on, so it is
28
+ * resolved once at placement (`actions.ts`) and never re-resolved.
29
+ */
30
+ const seedEntries = () => [
31
+ ...Object.entries(UML_NAME_SEED)
32
+ .filter(([, seed]) => seed !== '')
33
+ .map(([kind, seed]) => ({
34
+ key: umlSeedKey(kind),
35
+ fallback: seed,
36
+ source: 'seed',
37
+ })),
38
+ ...[
39
+ [UML_ATTRIBUTES_SEED_KEY, UML_ATTRIBUTES_SEED],
40
+ [UML_OPERATIONS_SEED_KEY, UML_OPERATIONS_SEED],
41
+ [UML_SLOTS_SEED_KEY, UML_SLOTS_SEED],
42
+ ].map(([key, fallback]) => ({ key, fallback, source: 'seed' })),
43
+ ];
44
+ /**
45
+ * The auto-legend's own section titles ({@link UML_LEGEND_SECTION_WORDINGS})
46
+ * and the fixed-wording remarks the three readers and the materializer
47
+ * produce — chrome, not seeds: both are re-rendered every time the box is
48
+ * built or the report is drawn, never written into a document.
49
+ *
50
+ * Derived from the very tables the code reads (the fallback IS
51
+ * `UML_PLANTUML_REMARKS[…][1]`, never restated), so the wording a host is
52
+ * offered and the wording the library shows cannot drift. Mirrors BPMN's
53
+ * `importRemarkEntries` exactly, one table per reader instead of one.
54
+ */
55
+ const chromeEntries = () => [
56
+ ...UML_LEGEND_SECTION_WORDINGS,
57
+ ...Object.values(UML_PLANTUML_REMARKS),
58
+ ...Object.values(UML_XMI_REMARKS),
59
+ ...Object.values(UML_DRAWIO_REMARKS),
60
+ ...Object.values(UML_LAYOUT_REMARKS),
61
+ ].map(([key, fallback]) => ({ key, fallback, source: 'chrome' }));
62
+ /**
63
+ * THIS framework's contribution to the translation-key manifest — every
64
+ * `com.labre.*` key UML can hand to `TranslationProvider.t`, derived from the
65
+ * very declarations the editor registers (never restated).
66
+ *
67
+ * The contribution ships WITH the framework, exactly as C4's and BPMN's do: in
68
+ * the bundled distribution `@formicoidea/labre-framework-uml` carries it, and a
69
+ * host composes it into its catalogue the same way it already composes
70
+ * `umlCommands` into the command registry. See
71
+ * `packages/affine/all/src/translations.ts`.
72
+ *
73
+ * The two BACKGROUND declarations are walked even though neither carries a
74
+ * `labelKey` today: both frames write the user's own words (a diagram's
75
+ * heading, a subject's name) and have no vocabulary to fall back to. Walking
76
+ * them costs nothing and means the day one of them gains a declared label the
77
+ * manifest already names it — which is the whole reason these lists are derived
78
+ * rather than written.
79
+ *
80
+ * The RULES and the two PROFILES are walked after the roles and the backgrounds,
81
+ * and the order is load-bearing: a rule carries its framework's `roles` and, for
82
+ * `uml.actor-inside-subject`, the subject's own declaration, so walking the pack
83
+ * reaches keys those lists already named. `mergeTranslationEntries` keeps the
84
+ * FIRST occurrence, which is what makes each key report the source it actually
85
+ * comes from.
86
+ */
87
+ export const umlTranslationEntries = mergeTranslationEntries(commandTranslationEntries(umlCommands),
88
+ // The catalogue's own group headers, derived from the very categories these
89
+ // commands declare. They ship WITH the framework because core's registry
90
+ // names no framework category in the bundled distribution, so a host that
91
+ // composed core's manifest alone drew translated entries under English
92
+ // headers (#183).
93
+ commandCategoryTranslationEntries(umlCommands), collectTranslationKeys('role', UML_ROLES), collectTranslationKeys('background', [
94
+ UML_DIAGRAM_FRAME,
95
+ UML_SUBJECT_FRAME,
96
+ // Which of the four diagrams a frame declares it draws, and the words the
97
+ // picker offers them under. Filed under `background` with the two
98
+ // declarations above, and it is the honest bucket rather than a
99
+ // convenient one: `kind` is a prop of the diagram frame, these are the
100
+ // names of the values it can take, and the table is walked exactly as the
101
+ // two declarations beside it are.
102
+ UML_DIAGRAM_KIND_MENU,
103
+ // …and, since phase 3, which kind of COMBINED FRAGMENT a box declares it
104
+ // is (§17.6.4). Filed here with the diagram's own table and for the same
105
+ // reason: `operator` is a prop of a background element, these are the
106
+ // names of the values it can take, and the table is walked exactly as the
107
+ // three declarations beside it are.
108
+ UML_FRAGMENT_OPERATOR_MENU,
109
+ ]), seedEntries(), chromeEntries(),
110
+ // AFTER the two groups above — see the header on why the order decides
111
+ // which source each key is reported under.
112
+ collectTranslationKeys('rule', UML_RULES), collectTranslationKeys('profile', UML_PROFILES),
113
+ // LAST, and the order is load-bearing: a reading profile carries the
114
+ // framework's own `roles`, so walking it reaches keys the list above
115
+ // already named. `mergeTranslationEntries` keeps the FIRST occurrence,
116
+ // which is what makes each key report the source it actually comes from.
117
+ collectTranslationKeys('reading', UML_READINGS));
package/dist/view.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { type ViewExtensionContext, ViewExtensionProvider } from '@formicoidea/labre-core/ext-loader';
2
+ /**
3
+ * UML rendering — ALWAYS registered, independent of any flag. Diagram frames,
4
+ * subjects and nodes already drawn must paint, stay selectable, stay editable
5
+ * and keep their resize gating whatever the tooling flag says. See
6
+ * `docs/adr/0009`.
7
+ *
8
+ * This is the RENDER half. The creation tooling — the senior button, its menu
9
+ * and its twenty-one commands — is {@link UmlViewExtension} below, exactly as
10
+ * `C4ViewExtension` is separate from `C4RenderViewExtension`. Nothing in this
11
+ * class may become flag-gated: a stored document needs every one of these
12
+ * registrations to load and paint.
13
+ */
14
+ export declare class UmlRenderViewExtension extends ViewExtensionProvider {
15
+ name: string;
16
+ setup(context: ViewExtensionContext): void;
17
+ }
18
+ /**
19
+ * UML creation tooling — flag-gated (`uml`): the senior toolbar button, its
20
+ * sub-menu, the twenty-one commands behind them, its templates category, the
21
+ * frame's legend button and kind picker, the reading profiles and the two
22
+ * interchange capabilities.
23
+ *
24
+ * All of it is tooling in the sense `docs/adr/0009` means: a diagram drawn
25
+ * while the flag was on keeps painting, stays selectable and keeps its
26
+ * contextual toolbar when it goes off — only the ways to add new elements go
27
+ * away, the legend included since generating one CREATES elements.
28
+ */
29
+ export declare class UmlViewExtension extends ViewExtensionProvider {
30
+ name: string;
31
+ effect(): void;
32
+ setup(context: ViewExtensionContext): void;
33
+ }
package/dist/view.js ADDED
@@ -0,0 +1,236 @@
1
+ import { FrameworkBackgroundInteractionExtension, InterchangeExtension, morphToolbarConfig, ReadingProfileExtension, ValidationProfileExtension, ValidationRuleExtension, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
3
+ import { TemplateCategoryExtension } from '@formicoidea/labre-core/gfx/template';
4
+ import { ToolbarModuleExtension, toolbarModuleKey, } from '@formicoidea/labre-core/shared/services';
5
+ import { BlockFlavourIdentifier, CommandExtension } from '@formicoidea/labre-core/std';
6
+ import { RoleVocabularyExtension } from '@formicoidea/labre-core/std/gfx';
7
+ import { UML_DIAGRAM_FRAME, UML_FRAGMENT_FRAME, UML_PARTITION_FRAME_V, UML_REGION_FRAME, UML_SUBJECT_FRAME, } from './background.js';
8
+ import { umlCommandIcons, umlCommands } from './commands.js';
9
+ import { UML_EDGE_MORPH_SPEC } from './edge-morph.js';
10
+ import { effects } from './effects.js';
11
+ import { UmlDiagramRendererExtension, UmlFragmentRendererExtension, UmlPartitionRendererExtension, UmlRegionRendererExtension, UmlSubjectRendererExtension, } from './element-renderer.js';
12
+ import { UmlDiagramView, UmlFragmentView, UmlPartitionView, UmlRegionView, UmlSubjectView, } from './element-view.js';
13
+ import { UML_INTERCHANGE } from './interchange.js';
14
+ import { UML_BARE_MORPH_SPEC, UML_MORPH_SPEC } from './morph.js';
15
+ import { UmlCompartmentWatcher } from './node/compartment-watcher.js';
16
+ import { UmlNodeRendererExtension } from './node/node-renderer.js';
17
+ import { UmlNodeView } from './node/node-view.js';
18
+ import { UML_PROFILES } from './profiles.js';
19
+ import { UML_READINGS } from './reading.js';
20
+ import { UML_ROLES } from './roles.js';
21
+ import { UML_RULES } from './rules.js';
22
+ import { umlTemplateCategory } from './templates.js';
23
+ import { umlDiagramToolbarExtension, umlDiagramToolingToolbarExtension, umlFragmentToolbarExtension, umlFragmentToolingToolbarExtension, umlPartitionToolbarExtension, umlRegionToolbarExtension, } from './toolbar/config.js';
24
+ import { umlSeniorTool } from './toolbar/senior-tool.js';
25
+ /**
26
+ * UML rendering — ALWAYS registered, independent of any flag. Diagram frames,
27
+ * subjects and nodes already drawn must paint, stay selectable, stay editable
28
+ * and keep their resize gating whatever the tooling flag says. See
29
+ * `docs/adr/0009`.
30
+ *
31
+ * This is the RENDER half. The creation tooling — the senior button, its menu
32
+ * and its twenty-one commands — is {@link UmlViewExtension} below, exactly as
33
+ * `C4ViewExtension` is separate from `C4RenderViewExtension`. Nothing in this
34
+ * class may become flag-gated: a stored document needs every one of these
35
+ * registrations to load and paint.
36
+ */
37
+ export class UmlRenderViewExtension extends ViewExtensionProvider {
38
+ constructor() {
39
+ super(...arguments);
40
+ this.name = 'affine-uml-render-gfx';
41
+ }
42
+ setup(context) {
43
+ super.setup(context);
44
+ context.register(UmlDiagramView);
45
+ context.register(UmlDiagramRendererExtension);
46
+ context.register(UmlSubjectView);
47
+ context.register(UmlSubjectRendererExtension);
48
+ // The two BANDED frames of the behaviour diagrams (phase 2): the activity
49
+ // partition (§15.6.4) and the composite state's region (§14.2.4). Content
50
+ // to the letter — a swimlane holds its actions by GEOMETRY, so a document
51
+ // that loses the frame loses which partition every action was in.
52
+ context.register(UmlPartitionView);
53
+ context.register(UmlPartitionRendererExtension);
54
+ context.register(UmlRegionView);
55
+ context.register(UmlRegionRendererExtension);
56
+ // The COMBINED FRAGMENT of §17.6.4 (phase 3) — content to the letter, like
57
+ // the two frames above it: an `alt` holds its messages by GEOMETRY, so a
58
+ // document that loses the frame loses which branch every exchange was in.
59
+ context.register(UmlFragmentView);
60
+ context.register(UmlFragmentRendererExtension);
61
+ context.register(UmlNodeView);
62
+ context.register(UmlNodeRendererExtension);
63
+ // The role VOCABULARY, always on. A role is written in the document, not in
64
+ // the tooling: the direction reveal of a typed edge, the inversion command
65
+ // and the toolbar entry that must not lie about a generalization all read
66
+ // this, and they have to keep working on a diagram drawn while the flag was
67
+ // on and opened while it is off (`docs/adr/0009`, `docs/adr/0010`).
68
+ context.register(RoleVocabularyExtension(UML_ROLES));
69
+ if (this.isEdgeless(context.scope)) {
70
+ // Resize gating, driven by the declarations like every other framework
71
+ // background: the handles follow `resizeEnabled`, which both declarations
72
+ // seed to `true` — a diagram and a subject are both stretched to fit.
73
+ context.register(FrameworkBackgroundInteractionExtension(UML_DIAGRAM_FRAME));
74
+ context.register(FrameworkBackgroundInteractionExtension(UML_SUBJECT_FRAME));
75
+ // ONE registration for the partition, even though `background.ts`
76
+ // declares TWO of them — the column and the row (`UML_PARTITION_FRAME_V`
77
+ // / `_H`, picked per element by `umlPartitionFrame`). This extension is
78
+ // keyed on `def.type` alone, so registering the second would not gate the
79
+ // horizontal lane: it would refuse to mount, on every document, with
80
+ // `DuplicateServiceDefinitionError`.
81
+ //
82
+ // Passing the vertical one is not an arbitrary pick either. What the
83
+ // extension reads off a declaration is `geometry.resizable`, the FALLBACK
84
+ // for an element carrying no `resizeEnabled` — and the two declarations
85
+ // are one factory called twice, so they agree on it by construction. The
86
+ // orientation changes where the band is, never whether the handles are
87
+ // offered.
88
+ context.register(FrameworkBackgroundInteractionExtension(UML_PARTITION_FRAME_V));
89
+ context.register(FrameworkBackgroundInteractionExtension(UML_REGION_FRAME));
90
+ context.register(FrameworkBackgroundInteractionExtension(UML_FRAGMENT_FRAME));
91
+ // The selected frame's own row — the resize toggle and the two exports in
92
+ // its "⋮". Always-on for the reason `docs/adr/0009` gives: a stored
93
+ // diagram must keep its handles usable with the UML button switched off,
94
+ // and each "⋮" entry hides itself when its command is absent from the
95
+ // registry, so nothing on the row can be clicked into a no-op.
96
+ context.register(umlDiagramToolbarExtension);
97
+ // …and the two phase-2 frames' own rows, always-on for the same reason
98
+ // and with the same contents: the gestures you make on a frame that is
99
+ // ALREADY THERE. The partition's row carries one more — the orientation
100
+ // flip — and `toolbar/config.ts` argues at length why a toggle that
101
+ // writes a stored field still belongs on this side of `docs/adr/0009`:
102
+ // the flag takes away the ways to CREATE, not the ways to work with what
103
+ // a document already holds.
104
+ context.register(umlPartitionToolbarExtension);
105
+ context.register(umlRegionToolbarExtension);
106
+ // …and phase 3's, on the same terms: a stored combined fragment keeps its
107
+ // handles with the UML button off. The two gestures that CREATE — adding
108
+ // an operand, declaring which kind of fragment this is — are in the
109
+ // flag-gated module below.
110
+ context.register(umlFragmentToolbarExtension);
111
+ // Keeps a classifier's box big enough for the words an author types into
112
+ // it: when an edit into a compartment commits, the stack is re-measured,
113
+ // the node grows if it no longer fits and the tiers move to the boxes the
114
+ // new box yields. Always-on for the reason `docs/adr/0009` gives — it
115
+ // creates nothing and adds no field, it keeps words ALREADY in the
116
+ // document from being drawn over their own separator, and a diagram drawn
117
+ // while the UML button was on must stay editable when it goes off. The
118
+ // same place `C4TypeLineWatcher` is registered, for the same reason.
119
+ context.register(UmlCompartmentWatcher);
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * UML creation tooling — flag-gated (`uml`): the senior toolbar button, its
125
+ * sub-menu, the twenty-one commands behind them, its templates category, the
126
+ * frame's legend button and kind picker, the reading profiles and the two
127
+ * interchange capabilities.
128
+ *
129
+ * All of it is tooling in the sense `docs/adr/0009` means: a diagram drawn
130
+ * while the flag was on keeps painting, stays selectable and keeps its
131
+ * contextual toolbar when it goes off — only the ways to add new elements go
132
+ * away, the legend included since generating one CREATES elements.
133
+ */
134
+ export class UmlViewExtension extends ViewExtensionProvider {
135
+ constructor() {
136
+ super(...arguments);
137
+ this.name = 'affine-uml-gfx';
138
+ }
139
+ effect() {
140
+ super.effect();
141
+ // Defines the senior button and its menu — tooling-only custom elements.
142
+ effects();
143
+ }
144
+ setup(context) {
145
+ super.setup(context);
146
+ if (this.isEdgeless(context.scope)) {
147
+ // Writing PlantUML and XMI files, declared rather than assumed
148
+ // (`docs/adr/0012`). Tooling like the rest of this class: with the flag
149
+ // off there is nothing to export WITH, while a stored diagram keeps
150
+ // painting (`docs/adr/0009`).
151
+ context.register(InterchangeExtension(UML_INTERCHANGE));
152
+ // The reversed reading (MF3): what the diagram says about an element, on
153
+ // demand. One profile per node role, because a class, an actor and a use
154
+ // case are read as three different things. The CLICK that triggers it is
155
+ // registered once by the surface and gated by the presence of a profile.
156
+ for (const reading of UML_READINGS) {
157
+ context.register(ReadingProfileExtension(reading));
158
+ }
159
+ // The review checklist and its two levels of requirement — DATA, like the
160
+ // roles and the readings above (`rules.ts`, `profiles.ts`). Tooling in the
161
+ // sense `docs/adr/0009` means: with the flag off a stored diagram keeps
162
+ // painting and simply stops being checked, and a frame already set to the
163
+ // strict level keeps that id written, untouched.
164
+ context.register(ValidationRuleExtension(UML_RULES));
165
+ context.register(ValidationProfileExtension(UML_PROFILES));
166
+ context.register(umlSeniorTool);
167
+ // The Templates-panel category — tooling, so it goes with the flag (#244).
168
+ context.register(TemplateCategoryExtension(umlTemplateCategory));
169
+ context.register(CommandExtension(umlCommands, umlCommandIcons));
170
+ // The flag-gated half of the selected FRAME's row, through the `custom:`
171
+ // flavour slot — the shape wardley, bpmn and C4 all use to hang
172
+ // flag-gated entries off a row whose base is always-on. One module,
173
+ // carrying the legend button AND the diagram-kind picker, because both
174
+ // are gated by this one flag and there is no reason to spend a second
175
+ // registration on them.
176
+ context.register(umlDiagramToolingToolbarExtension);
177
+ // The COMBINED FRAGMENT's flag-gated row, through the same `custom:`
178
+ // slot: the add-operand button and the operator picker. Both create —
179
+ // one puts a band on the canvas, the other declares how the box is to be
180
+ // read — which is the line `docs/adr/0009` draws (`toolbar/config.ts`).
181
+ context.register(umlFragmentToolingToolbarExtension);
182
+ // The "Change type" dropdown on a selected CLASSIFIER's contextual
183
+ // toolbar — the generic module, parameterized by UML's own families.
184
+ //
185
+ // ## Why the key carries an owner
186
+ //
187
+ // A UML artefact is a native `group`, so the row the toolbar draws for it
188
+ // is the GROUP's row, merged from `affine:surface:group`,
189
+ // `custom:affine:surface:group` and the two surface wildcards. Both group
190
+ // keys were claimed long ago — the first by the native group operations
191
+ // (rename, ungroup), the second by Wardley's qualification dropdown — and
192
+ // C4's morph is already hanging off a third. `toolbarModuleKey` is what
193
+ // lifts the ceiling of two contributors per element: the module is
194
+ // registered under the distinct variant
195
+ // `custom:affine:surface:group#uml-morph` and the registry hands it to the
196
+ // same row (`toolbar-service/registry.ts`).
197
+ //
198
+ // ## Why here
199
+ //
200
+ // In the flag-gated half, because a morph is TOOLING: a classifier drawn
201
+ // while the flag was on keeps its kind, its role, its colours, its words
202
+ // and its place in every rule when the flag goes off — it just stops being
203
+ // something the toolbar offers to say differently (`docs/adr/0009`).
204
+ context.register(ToolbarModuleExtension({
205
+ id: BlockFlavourIdentifier(toolbarModuleKey('custom:affine:surface:group', 'uml-morph')),
206
+ config: morphToolbarConfig(UML_MORPH_SPEC),
207
+ }));
208
+ // The same dropdown on a BARE UML shape — the routing marks phase 2 added.
209
+ //
210
+ // §15.3.4 and §14.2.4 name none of them, so a bullseye, a bar, a diamond
211
+ // and a crossed circle are created as the shape alone (`actions.ts`) and
212
+ // a click selects a `umlNode` rather than a group. The widget derives a
213
+ // surface element's flavour from `model.type`, so their row is
214
+ // `affine:surface:umlNode`'s and not the group's — which is why this is a
215
+ // second registration under a second key rather than a widened
216
+ // `modelType` on the one above. The families, the props and the wording
217
+ // are shared by reference (`morph.ts`), so the two rows can never offer
218
+ // different menus.
219
+ context.register(ToolbarModuleExtension({
220
+ id: BlockFlavourIdentifier(toolbarModuleKey('custom:affine:surface:umlNode', 'uml-morph')),
221
+ config: morphToolbarConfig(UML_BARE_MORPH_SPEC),
222
+ }));
223
+ // The same dropdown on a selected RELATIONSHIP. A second registration
224
+ // rather than a second family inside the first, because the two speak
225
+ // about different element types: a classifier is a group, a relationship
226
+ // is a connector, and `modelType` is what each spec filters the selection
227
+ // with. The connector's own row is always-on (stroke, ends, routing) and
228
+ // this is an addition to it, so it takes the `custom:` twin under the same
229
+ // owner suffix.
230
+ context.register(ToolbarModuleExtension({
231
+ id: BlockFlavourIdentifier(toolbarModuleKey('custom:affine:surface:connector', 'uml-morph')),
232
+ config: morphToolbarConfig(UML_EDGE_MORPH_SPEC),
233
+ }));
234
+ }
235
+ }
236
+ }