@miragon/modeler-shell 0.0.0-stage → 0.2.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 (147) hide show
  1. package/API.md +2869 -0
  2. package/LICENSE +21 -0
  3. package/README.md +566 -2
  4. package/THIRD_PARTY_NOTICES.md +52 -0
  5. package/dist/appearance-BBaM_4bD.d.ts +323 -0
  6. package/dist/appearance-D3FUcbu6.d.cts +53 -0
  7. package/dist/appearance-D3FUcbu6.d.ts +53 -0
  8. package/dist/appearance-XX3JC3pI.d.cts +323 -0
  9. package/dist/chunk-66HCSJNY.js +2792 -0
  10. package/dist/chunk-66HCSJNY.js.map +1 -0
  11. package/dist/chunk-KYDG5DMX.js +136 -0
  12. package/dist/chunk-KYDG5DMX.js.map +1 -0
  13. package/dist/chunk-N4QXFF3A.js +23 -0
  14. package/dist/chunk-N4QXFF3A.js.map +1 -0
  15. package/dist/chunk-OADW3GPA.js +785 -0
  16. package/dist/chunk-OADW3GPA.js.map +1 -0
  17. package/dist/core.cjs +873 -0
  18. package/dist/core.cjs.map +1 -0
  19. package/dist/core.d.cts +246 -0
  20. package/dist/core.d.ts +246 -0
  21. package/dist/core.js +131 -0
  22. package/dist/core.js.map +1 -0
  23. package/dist/diagram-js.cjs +1147 -0
  24. package/dist/diagram-js.cjs.map +1 -0
  25. package/dist/diagram-js.d.cts +170 -0
  26. package/dist/diagram-js.d.ts +170 -0
  27. package/dist/diagram-js.js +879 -0
  28. package/dist/diagram-js.js.map +1 -0
  29. package/dist/index.cjs +3632 -0
  30. package/dist/index.cjs.map +1 -0
  31. package/dist/index.d.cts +29 -0
  32. package/dist/index.d.ts +29 -0
  33. package/dist/index.js +143 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/protocol-DhYBakWL.d.cts +15 -0
  36. package/dist/protocol-IeW8bf4f.d.ts +15 -0
  37. package/dist/shell.css +1603 -0
  38. package/dist/testing-vscode-stub.cjs +332 -0
  39. package/dist/testing-vscode-stub.cjs.map +1 -0
  40. package/dist/testing-vscode-stub.d.cts +65 -0
  41. package/dist/testing-vscode-stub.d.ts +65 -0
  42. package/dist/testing-vscode-stub.js +154 -0
  43. package/dist/testing-vscode-stub.js.map +1 -0
  44. package/dist/testing.cjs +4663 -0
  45. package/dist/testing.cjs.map +1 -0
  46. package/dist/testing.d.cts +231 -0
  47. package/dist/testing.d.ts +231 -0
  48. package/dist/testing.js +4483 -0
  49. package/dist/testing.js.map +1 -0
  50. package/dist/toasts-Bp0REqdq.d.cts +142 -0
  51. package/dist/toasts-Bp0REqdq.d.ts +142 -0
  52. package/dist/types-CnRrINRs.d.cts +445 -0
  53. package/dist/types-PuDZczzy.d.ts +445 -0
  54. package/dist/vscode-extension.cjs +215 -0
  55. package/dist/vscode-extension.cjs.map +1 -0
  56. package/dist/vscode-extension.d.cts +103 -0
  57. package/dist/vscode-extension.d.ts +103 -0
  58. package/dist/vscode-extension.js +24 -0
  59. package/dist/vscode-extension.js.map +1 -0
  60. package/dist/vscode-webview.cjs +3561 -0
  61. package/dist/vscode-webview.cjs.map +1 -0
  62. package/dist/vscode-webview.d.cts +84 -0
  63. package/dist/vscode-webview.d.ts +84 -0
  64. package/dist/vscode-webview.js +259 -0
  65. package/dist/vscode-webview.js.map +1 -0
  66. package/package.json +145 -4
  67. package/src/core/appearance.ts +104 -0
  68. package/src/core/feedback/appearance.ts +141 -0
  69. package/src/core/feedback/problems.ts +23 -0
  70. package/src/core/feedback/toasts.ts +118 -0
  71. package/src/core/fit.ts +220 -0
  72. package/src/core/index.ts +127 -0
  73. package/src/core/keymap.ts +295 -0
  74. package/src/core/layout.ts +69 -0
  75. package/src/core/messages.ts +159 -0
  76. package/src/core/sizes.ts +85 -0
  77. package/src/core/types.ts +106 -0
  78. package/src/core/web-chrome/bottom-row.ts +37 -0
  79. package/src/core/web-chrome/drop.ts +78 -0
  80. package/src/core/web-chrome/top-row.ts +66 -0
  81. package/src/core/zoom.ts +74 -0
  82. package/src/core.ts +2 -0
  83. package/src/diagram-js/connect.ts +75 -0
  84. package/src/diagram-js/index.ts +16 -0
  85. package/src/diagram-js/module.ts +20 -0
  86. package/src/diagram-js/palette-skin.ts +267 -0
  87. package/src/diagram-js/palette.css +269 -0
  88. package/src/diagram-js/service.ts +243 -0
  89. package/src/diagram-js/types.ts +67 -0
  90. package/src/diagram-js/viewport.ts +583 -0
  91. package/src/diagram-js.ts +2 -0
  92. package/src/dom/buttons.css +124 -0
  93. package/src/dom/element.ts +51 -0
  94. package/src/dom/feedback/appearance.ts +184 -0
  95. package/src/dom/feedback/feedback.css +435 -0
  96. package/src/dom/feedback/problems-popover.ts +287 -0
  97. package/src/dom/feedback/toasts.ts +431 -0
  98. package/src/dom/hint.ts +51 -0
  99. package/src/dom/icons.ts +309 -0
  100. package/src/dom/index.ts +42 -0
  101. package/src/dom/inspector.ts +35 -0
  102. package/src/dom/keys.ts +67 -0
  103. package/src/dom/ledger.ts +87 -0
  104. package/src/dom/legend.ts +85 -0
  105. package/src/dom/menu.ts +404 -0
  106. package/src/dom/mount.ts +731 -0
  107. package/src/dom/problems.ts +73 -0
  108. package/src/dom/shell-dom.css +969 -0
  109. package/src/dom/status.ts +72 -0
  110. package/src/dom/tooltip.ts +237 -0
  111. package/src/dom/types.ts +459 -0
  112. package/src/dom/web/drop-zone.ts +181 -0
  113. package/src/dom/web/empty-state.ts +144 -0
  114. package/src/dom/web/legal.ts +75 -0
  115. package/src/dom/web/menu-groups.ts +69 -0
  116. package/src/dom/web/primary.ts +124 -0
  117. package/src/dom/web/web.css +386 -0
  118. package/src/dom/zoom-panel.ts +154 -0
  119. package/src/index.ts +3 -0
  120. package/src/shell.css +9 -0
  121. package/src/testing/case-tools.ts +164 -0
  122. package/src/testing/cases.ts +1077 -0
  123. package/src/testing/checks.ts +868 -0
  124. package/src/testing/facts.ts +641 -0
  125. package/src/testing/geometry.ts +652 -0
  126. package/src/testing/harness.ts +187 -0
  127. package/src/testing/index.ts +19 -0
  128. package/src/testing/page-tools.ts +457 -0
  129. package/src/testing/page.ts +27 -0
  130. package/src/testing/vscode-stub.ts +237 -0
  131. package/src/testing/web-cases.ts +913 -0
  132. package/src/testing/web-checks.ts +1049 -0
  133. package/src/testing/web-facts.ts +713 -0
  134. package/src/testing-vscode-stub.ts +2 -0
  135. package/src/testing.ts +2 -0
  136. package/src/vscode/extension/html.ts +107 -0
  137. package/src/vscode/extension/index.ts +8 -0
  138. package/src/vscode/extension/reveal.ts +9 -0
  139. package/src/vscode/extension/theme-bridge.ts +85 -0
  140. package/src/vscode/extension/types.ts +36 -0
  141. package/src/vscode/protocol.ts +31 -0
  142. package/src/vscode/webview/appearance.ts +141 -0
  143. package/src/vscode/webview/index.ts +8 -0
  144. package/src/vscode/webview/mount.ts +88 -0
  145. package/src/vscode/webview/state.ts +116 -0
  146. package/src/vscode-extension.ts +2 -0
  147. package/src/vscode-webview.ts +2 -0
@@ -0,0 +1,237 @@
1
+ import type { Appearance, ColorThemeSetting, Theme } from "../core/index.js";
2
+ import {
3
+ connectThemeBridge,
4
+ currentAppearance,
5
+ renderWebviewHtml,
6
+ type ColorThemeLike,
7
+ type DisposableLike,
8
+ type VsCodeLike,
9
+ type WebviewPanelLike,
10
+ } from "../vscode/extension/index.js";
11
+
12
+ /*
13
+ * Runs in the page, in front of a modeler's webview bundle: a stand-in for the VS Code around it,
14
+ * so a modeler's e2e suite runs the conformance kit for the `ide` host without VS Code.
15
+ */
16
+
17
+ /** `vscode.ColorThemeKind`: 1 Light, 2 Dark, 3 High Contrast, 4 High Contrast Light. */
18
+ export type ColorThemeKind = 1 | 2 | 3 | 4;
19
+
20
+ /** The body classes VS Code's webview host page sets per color theme (High Contrast Light keeps both). */
21
+ const BODY_CLASSES: Readonly<Record<ColorThemeKind, readonly string[]>> = {
22
+ 1: ["vscode-light"],
23
+ 2: ["vscode-dark"],
24
+ 3: ["vscode-high-contrast"],
25
+ 4: ["vscode-high-contrast-light", "vscode-high-contrast"],
26
+ };
27
+ const ALL_BODY_CLASSES = Object.values(BODY_CLASSES).flat();
28
+ const REDUCE_MOTION_BODY_CLASS = "vscode-reduce-motion";
29
+
30
+ /**
31
+ * The rules of VS Code's default webview stylesheet the shell's own-document reset must beat
32
+ * (implementation notes, "VS Code: host hygiene"), with deliberately foreign values so a leak shows.
33
+ */
34
+ const VSCODE_DEFAULT_STYLES = `@layer vscode-default {
35
+ body { margin: 0; padding: 0 20px; color: currentColor; font-family: serif; font-size: 17px; }
36
+ kbd { box-shadow: inset 0 -1px 0 currentColor; vertical-align: middle; padding: 1px 3px; border-radius: 3px; font-family: serif; }
37
+ code { font-family: serif; padding: 1px 3px; border-radius: 4px; }
38
+ a:focus, input:focus, select:focus, textarea:focus { outline: 1px solid -webkit-focus-ring-color; outline-offset: -1px; }
39
+ }`;
40
+
41
+ /** The default setting key the stub answers when `colorTheme` is given without one. */
42
+ export const STUB_SETTING_KEY = "miragon.modeler.colorTheme";
43
+
44
+ /** The VS Code color theme that requests `appearance` (guide §13.3). */
45
+ export function colorThemeKindOf(appearance: Appearance): ColorThemeKind {
46
+ if (appearance.kontrast) return appearance.theme === "dark" ? 3 : 4;
47
+ return appearance.theme === "dark" ? 2 : 1;
48
+ }
49
+
50
+ export interface VsCodeWebviewStubOptions {
51
+ /** What VS Code requests: its color theme, as the appearance the kit asks for. */
52
+ requested: Appearance;
53
+ /** The modes the modeler declares (what its extension passes to the theme bridge). */
54
+ themes: readonly Theme[];
55
+ /** `<html lang>`; default `"en"`. */
56
+ lang?: string | undefined;
57
+ /** The value of the modeler's `colorTheme` setting (from its dark-mode release on). */
58
+ colorTheme?: ColorThemeSetting | undefined;
59
+ /** The full setting key the stub answers and the bridge listens to; default `STUB_SETTING_KEY`. */
60
+ settingKey?: string | undefined;
61
+ /** VS Code's `workbench.reduceMotion` (the body class `vscode-reduce-motion`). */
62
+ reduceMotion?: boolean | undefined;
63
+ /** What `getState()` of the stubbed `acquireVsCodeApi()` returns at first. */
64
+ state?: unknown;
65
+ }
66
+
67
+ /** The stubbed `acquireVsCodeApi()`. */
68
+ export interface StubbedVsCodeApi {
69
+ getState(): unknown;
70
+ setState(state: unknown): void;
71
+ postMessage(message: unknown): void;
72
+ }
73
+
74
+ export interface VsCodeWebviewStub {
75
+ readonly kind: ColorThemeKind;
76
+ /** What VS Code does on a color theme change: body classes first, then the extension's bridge posts. */
77
+ setColorThemeKind(kind: ColorThemeKind): void;
78
+ /** Changes the `colorTheme` setting, as the user does in the settings editor. */
79
+ setColorTheme(setting: ColorThemeSetting | undefined): void;
80
+ setReduceMotion(reduceMotion: boolean): void;
81
+ /** Messages the bridge posted that have not reached the window yet. */
82
+ pendingMessages(): number;
83
+ /** What the webview posted with `acquireVsCodeApi().postMessage`. */
84
+ readonly posted: readonly unknown[];
85
+ /** The webview state as the last `setState` left it. */
86
+ state(): unknown;
87
+ }
88
+
89
+ /** The page globals the stub sets. */
90
+ export type StubWindow = Window & {
91
+ /** The stub of `installVsCodeWebviewStub`, for a Playwright suite to drive. */
92
+ __modelerShellVsCodeStub?: VsCodeWebviewStub;
93
+ acquireVsCodeApi?: () => StubbedVsCodeApi;
94
+ };
95
+
96
+ /**
97
+ * The stub's options from a query string (`theme`, `kontrast=hoch`, `colorTheme`, `reduceMotion`),
98
+ * the counterpart of `vsCodeStubSearch` of `@miragon/modeler-shell/testing`.
99
+ */
100
+ export function stubOptionsFromSearch(
101
+ search: string,
102
+ ): Pick<VsCodeWebviewStubOptions, "requested" | "colorTheme" | "reduceMotion"> {
103
+ const params = new URLSearchParams(search);
104
+ const theme: Theme = params.get("theme") === "dark" ? "dark" : "light";
105
+ const setting = params.get("colorTheme");
106
+ return {
107
+ requested: params.get("kontrast") === "hoch" ? { theme, kontrast: "hoch" } : { theme },
108
+ colorTheme: setting === "automatic" || setting === "light" || setting === "dark" ? setting : undefined,
109
+ reduceMotion: params.has("reduceMotion"),
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Stands in for VS Code around the page: its default stylesheet in `@layer vscode-default`, `<html>`
115
+ * with the attributes `renderWebviewHtml` writes before the first paint, `<body>` with the host
116
+ * page's theme (and reduce-motion) classes, `acquireVsCodeApi()`, and the real `connectThemeBridge`
117
+ * running against a fake `vscode` namespace whose panel posts to this window. Call it before the
118
+ * modeler's webview code runs; also exposed as `window.__modelerShellVsCodeStub`.
119
+ */
120
+ export function installVsCodeWebviewStub(options: VsCodeWebviewStubOptions): VsCodeWebviewStub {
121
+ const settingKey = options.settingKey ?? STUB_SETTING_KEY;
122
+ const scope = window as StubWindow;
123
+ let kind = colorThemeKindOf(options.requested);
124
+ let setting = options.colorTheme;
125
+ const themeListeners = new Set<(theme: ColorThemeLike) => unknown>();
126
+ const configurationListeners = new Set<
127
+ (event: { affectsConfiguration(section: string): boolean }) => unknown
128
+ >();
129
+ const vscode: VsCodeLike = {
130
+ window: {
131
+ get activeColorTheme() {
132
+ return { kind };
133
+ },
134
+ onDidChangeActiveColorTheme(listener) {
135
+ themeListeners.add(listener);
136
+ return { dispose: () => themeListeners.delete(listener) };
137
+ },
138
+ },
139
+ workspace: {
140
+ getConfiguration: (section?: string) => ({
141
+ get: <T>(key: string): T | undefined =>
142
+ (section ? `${section}.${key}` : key) === settingKey ? (setting as T | undefined) : undefined,
143
+ }),
144
+ onDidChangeConfiguration(listener) {
145
+ configurationListeners.add(listener);
146
+ return { dispose: () => configurationListeners.delete(listener) };
147
+ },
148
+ },
149
+ };
150
+ const none: DisposableLike = { dispose: () => undefined };
151
+ let posted = 0;
152
+ let delivered = 0;
153
+ // Registered before the modeler's listeners, so it counts a message before the shell applies it.
154
+ window.addEventListener("message", () => delivered++);
155
+ const panel: WebviewPanelLike = {
156
+ webview: {
157
+ postMessage(message) {
158
+ posted++;
159
+ window.postMessage(message, "*");
160
+ },
161
+ },
162
+ visible: true,
163
+ onDidChangeViewState: () => none,
164
+ onDidDispose: () => none,
165
+ };
166
+ const bridgeOptions = { themes: options.themes, settingKey };
167
+
168
+ const defaults = document.createElement("style");
169
+ defaults.id = "_defaultStyles";
170
+ defaults.textContent = VSCODE_DEFAULT_STYLES;
171
+ document.head.prepend(defaults);
172
+
173
+ const html = new DOMParser().parseFromString(
174
+ renderWebviewHtml({
175
+ cspSource: window.location.origin,
176
+ scriptUri: "webview.js",
177
+ title: document.title,
178
+ lang: options.lang ?? "en",
179
+ appearance: currentAppearance(vscode, bridgeOptions),
180
+ }),
181
+ "text/html",
182
+ ).documentElement;
183
+ for (const name of html.getAttributeNames()) {
184
+ if (name === "class") document.documentElement.classList.add(...html.classList);
185
+ else document.documentElement.setAttribute(name, html.getAttribute(name) ?? "");
186
+ }
187
+
188
+ const setBodyClasses = (next: ColorThemeKind): void => {
189
+ document.body.classList.remove(...ALL_BODY_CLASSES);
190
+ document.body.classList.add(...BODY_CLASSES[next]);
191
+ };
192
+ setBodyClasses(kind);
193
+ document.body.classList.toggle(REDUCE_MOTION_BODY_CLASS, options.reduceMotion === true);
194
+ connectThemeBridge(vscode, panel, bridgeOptions);
195
+
196
+ let state = options.state;
197
+ const sent: unknown[] = [];
198
+ let acquired = false;
199
+ scope.acquireVsCodeApi = () => {
200
+ if (acquired) throw new Error("An instance of the VS Code API has already been acquired");
201
+ acquired = true;
202
+ return {
203
+ getState: () => state,
204
+ setState(next) {
205
+ state = next;
206
+ },
207
+ postMessage(message) {
208
+ sent.push(message);
209
+ },
210
+ };
211
+ };
212
+
213
+ const stub: VsCodeWebviewStub = {
214
+ get kind() {
215
+ return kind;
216
+ },
217
+ setColorThemeKind(next) {
218
+ kind = next;
219
+ setBodyClasses(next);
220
+ for (const listener of [...themeListeners]) listener({ kind: next });
221
+ },
222
+ setColorTheme(next) {
223
+ setting = next;
224
+ for (const listener of [...configurationListeners]) {
225
+ listener({ affectsConfiguration: (section) => settingKey.startsWith(section) });
226
+ }
227
+ },
228
+ setReduceMotion(reduceMotion) {
229
+ document.body.classList.toggle(REDUCE_MOTION_BODY_CLASS, reduceMotion);
230
+ },
231
+ pendingMessages: () => posted - delivered,
232
+ posted: sent,
233
+ state: () => state,
234
+ };
235
+ scope.__modelerShellVsCodeStub = stub;
236
+ return stub;
237
+ }