From d1cbdc1c96cfdb6b887fa852229cb10cd8c28e30 Mon Sep 17 00:00:00 2001 From: dominikhorn Date: Mon, 19 Oct 2026 14:02:01 +0200 Subject: [PATCH 01/15] feat(shell): scaffold the web-app chrome for 0.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit API.md gains the web host (guide §5.2, web column): primary action with label collapse, legal line, File and Appearance groups, problems popover, toasts, empty-state card, drop zone and the web app's mode (head script and runtime choice). Exact signatures land as stubs in exclusive directories for three implementers: src/dom/web and src/core/web-chrome (web-chrome), src/dom/feedback and src/core/feedback (feedback), src/testing/web-cases.ts plus demo/web.* (kit-demo). mountShell wires every stub (web host only; toasts and the popover also embedded), the menu renders File, Model, Export, Appearance, Help, the fit keeps 92px for a raised zoom row, and Viewport.newDocument() lets every new web document open like the first. The IDE host is unchanged: VsCodeShellOptions does not accept the web options, and the 0.1 kit and e2e suite pass as before. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/shell/implementation-notes.md | 5 +- packages/shell/API.md | 941 ++++++++++++++++-- packages/shell/README.md | 26 +- packages/shell/demo/web.html | 12 + packages/shell/demo/web.ts | 107 ++ packages/shell/fixtures/brand/README.md | 8 + .../fixtures/brand/miragon-komet-blau.svg | 6 + packages/shell/package.json | 2 +- .../shell/src/core/feedback/appearance.ts | 83 ++ packages/shell/src/core/feedback/problems.ts | 23 + packages/shell/src/core/feedback/toasts.ts | 95 ++ packages/shell/src/core/fit.test.ts | 6 + packages/shell/src/core/fit.ts | 14 +- packages/shell/src/core/index.ts | 42 + packages/shell/src/core/messages.test.ts | 41 + packages/shell/src/core/messages.ts | 61 ++ packages/shell/src/core/types.ts | 26 +- .../shell/src/core/web-chrome/bottom-row.ts | 21 + packages/shell/src/core/web-chrome/drop.ts | 50 + packages/shell/src/core/web-chrome/top-row.ts | 53 + .../shell/src/diagram-js/viewport.test.ts | 36 + packages/shell/src/diagram-js/viewport.ts | 19 + packages/shell/src/dom/buttons.css | 112 +++ packages/shell/src/dom/feedback/appearance.ts | 38 + packages/shell/src/dom/feedback/feedback.css | 10 + .../src/dom/feedback/problems-popover.ts | 69 ++ packages/shell/src/dom/feedback/toasts.ts | 59 ++ packages/shell/src/dom/index.ts | 13 + packages/shell/src/dom/keys.ts | 5 + packages/shell/src/dom/menu-order.test.ts | 79 ++ packages/shell/src/dom/menu.ts | 30 +- packages/shell/src/dom/mount.ts | 238 ++++- packages/shell/src/dom/problems.ts | 9 +- packages/shell/src/dom/types.ts | 190 +++- packages/shell/src/dom/web-wiring.test.ts | 115 +++ packages/shell/src/dom/web/drop-zone.ts | 60 ++ packages/shell/src/dom/web/empty-state.ts | 52 + packages/shell/src/dom/web/legal.ts | 44 + packages/shell/src/dom/web/menu-groups.ts | 32 + packages/shell/src/dom/web/primary.ts | 63 ++ packages/shell/src/dom/web/web.css | 12 + packages/shell/src/shell.css | 3 + packages/shell/src/testing/checks.ts | 6 +- packages/shell/src/testing/geometry.test.ts | 10 +- packages/shell/src/testing/geometry.ts | 21 +- packages/shell/src/testing/harness.ts | 52 +- packages/shell/src/testing/index.ts | 4 + packages/shell/src/testing/page.test.ts | 9 +- packages/shell/src/testing/page.ts | 10 + packages/shell/src/testing/web-cases.ts | 37 + .../shell/src/vscode/webview/mount.test.ts | 5 + packages/shell/src/vscode/webview/mount.ts | 14 +- .../shell/test/package-boundaries.test.ts | 17 +- 53 files changed, 2971 insertions(+), 124 deletions(-) create mode 100644 packages/shell/demo/web.html create mode 100644 packages/shell/demo/web.ts create mode 100644 packages/shell/fixtures/brand/README.md create mode 100644 packages/shell/fixtures/brand/miragon-komet-blau.svg create mode 100644 packages/shell/src/core/feedback/appearance.ts create mode 100644 packages/shell/src/core/feedback/problems.ts create mode 100644 packages/shell/src/core/feedback/toasts.ts create mode 100644 packages/shell/src/core/web-chrome/bottom-row.ts create mode 100644 packages/shell/src/core/web-chrome/drop.ts create mode 100644 packages/shell/src/core/web-chrome/top-row.ts create mode 100644 packages/shell/src/dom/buttons.css create mode 100644 packages/shell/src/dom/feedback/appearance.ts create mode 100644 packages/shell/src/dom/feedback/feedback.css create mode 100644 packages/shell/src/dom/feedback/problems-popover.ts create mode 100644 packages/shell/src/dom/feedback/toasts.ts create mode 100644 packages/shell/src/dom/menu-order.test.ts create mode 100644 packages/shell/src/dom/web-wiring.test.ts create mode 100644 packages/shell/src/dom/web/drop-zone.ts create mode 100644 packages/shell/src/dom/web/empty-state.ts create mode 100644 packages/shell/src/dom/web/legal.ts create mode 100644 packages/shell/src/dom/web/menu-groups.ts create mode 100644 packages/shell/src/dom/web/primary.ts create mode 100644 packages/shell/src/dom/web/web.css create mode 100644 packages/shell/src/testing/web-cases.ts diff --git a/docs/shell/implementation-notes.md b/docs/shell/implementation-notes.md index 8b480dac..1e902b99 100644 --- a/docs/shell/implementation-notes.md +++ b/docs/shell/implementation-notes.md @@ -1219,8 +1219,9 @@ These topics stay in the design guide because they are not part of the shell: Phase 7 of [#4](https://github.com/Miragon/modeler-api/issues/4) own them); - light-only export (guide §10.7); - the token files and the token module (guide §13.1, §13.2); -- the mode recipes for IntelliJ, Electron, Tauri and Theia and the web-app bootstrap script with its - `localStorage` key (guide §13.3); +- the mode recipes for IntelliJ, Electron, Tauri and Theia (guide §13.3); the web app's head script + and its `localStorage` key are the shell's since 0.2 (`webModeScript`, `webHeadMarkup` and + `shell.appearance`, see `packages/shell/API.md`, "Web host (0.2)"); - the IntelliJ white-flash fix (guide §13.5). ## Open verification points diff --git a/packages/shell/API.md b/packages/shell/API.md index 96c31814..d7fc7602 100644 --- a/packages/shell/API.md +++ b/packages/shell/API.md @@ -1,14 +1,17 @@ -# @miragon/modeler-shell 0.1 — public API +# @miragon/modeler-shell 0.2 — public API The shared, framework-free implementation of everything around a Miragon diagram-js modeler: menu button with dropdown, horizontal palette skin, chrome tooltip, zoom panel, zoom and fit keys, fit, -problems pill, status box, empty-file hint, legend and inspector slots, and the plumbing to a VS Code -webview. Planned in [Miragon/modeler-api#4](https://github.com/Miragon/modeler-api/issues/4) -(Phase 4); the first consumer is the Event Storming modeler. +problems pill, status box, empty-file hint, legend and inspector slots, the plumbing to a VS Code +webview, and (0.2) the web-app chrome: primary action, legal line, File and Appearance groups, +problems popover, toasts, empty-state card, drop zone and the web app's mode. Planned in +[Miragon/modeler-api#4](https://github.com/Miragon/modeler-api/issues/4) (Phase 4); the first +consumer is the Event Storming modeler, in VS Code (0.1) and in its web app (0.2, see +[Usage: Event Storming in the web app](#usage-event-storming-in-the-web-app)). - **Look and behaviour** come from the Miragon design system, guide `modeler-design-system.md` - (skill `miragon-brand:modeler-tool-design`), §5.1 to §5.15, §6, §8, §9, §11, §12 and §13.3 to - §13.5. Section numbers below (§x.y) refer to it. + (skill `miragon-brand:modeler-tool-design`, design system 1.13.0), §2, §5.1 to §5.15, §6, §7, §8, + §9, §11, §12 and §13.3 to §13.5. Section numbers below (§x.y) refer to it. - **Mechanics** (diagram-js services, VS Code quirks) are in [`docs/shell/implementation-notes.md`](../../docs/shell/implementation-notes.md). - **Zero runtime dependencies.** The shell never imports `diagram-js`, `didi`, `vscode`, Lucide or @@ -17,22 +20,27 @@ webview. Planned in [Miragon/modeler-api#4](https://github.com/Miragon/modeler-a - **Tokens are the consumer's.** The modeler vendors `cd-tokens.generated.css` unchanged; the shell CSS reads only `var(--cd-ui-*)` roles, `var(--cd-shell-*)` sizes and the mode-independent non-colour tokens `--cd-radius-*`, `--cd-shadow-*`, `--cd-motion-*`, `--cd-ease`, `--cd-ease-out`. - It contains no colour literal and never a fixed palette token (`--cd-blau`, `--cd-schwarz`, …). + It contains no colour literal and no fixed palette token (`--cd-blau`, `--cd-schwarz`, …), with + one exception the guide itself makes: the primary button's fill is `--cd-blau` with `--cd-weiss` + text in both modes, hover `--cd-blau-link` (§8: "Feste Werte nimmst du nur für die Fläche von + Primär- und Destruktiv-Button"). Those three tokens appear in `src/dom/buttons.css` only, and the + stylesheet test allows them nowhere else (see [Buttons](#buttons)). Values the shell needs in + script (the two `theme-color`s) come from the modeler's vendored JSON as well. - **English by default.** Every text comes from one messages table (`ShellMessages`), every number goes through `Intl` in the UI language. ## Entry points -| Entry | For | Needs a DOM | -| -------------------------------------------- | ----------------------------------------------------------- | ------------------------------ | -| `@miragon/modeler-shell` | the chrome (`mountShell`), icons, plus all of `./core` | yes (at call time) | -| `@miragon/modeler-shell/core` | fit math, keymap, zoom readout, appearance, sizes, messages | no | -| `@miragon/modeler-shell/diagram-js` | `shellModule`, viewport, `connectDiagramJs` | yes | -| `@miragon/modeler-shell/vscode/extension` | webview HTML, nonce, theme bridge (extension host) | no | -| `@miragon/modeler-shell/vscode/webview` | `mountVsCodeShell`, appearance handler, webview state | yes | -| `@miragon/modeler-shell/testing` | Playwright-driven shell conformance kit | runs in Node, drives a browser | -| `@miragon/modeler-shell/testing/vscode-stub` | a stand-in for VS Code around a webview test page | yes (in the test page) | -| `@miragon/modeler-shell/shell.css` | every style of the shell | — | +| Entry | For | Needs a DOM | +| -------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------ | +| `@miragon/modeler-shell` | the chrome (`mountShell`, web chrome included), icons, plus all of `./core` | yes (at call time) | +| `@miragon/modeler-shell/core` | fit math, keymap, zoom readout, appearance, sizes, messages, the web host's decisions and head script | no | +| `@miragon/modeler-shell/diagram-js` | `shellModule`, viewport, `connectDiagramJs` | yes | +| `@miragon/modeler-shell/vscode/extension` | webview HTML, nonce, theme bridge (extension host) | no | +| `@miragon/modeler-shell/vscode/webview` | `mountVsCodeShell`, appearance handler, webview state | yes | +| `@miragon/modeler-shell/testing` | Playwright-driven shell conformance kit | runs in Node, drives a browser | +| `@miragon/modeler-shell/testing/vscode-stub` | a stand-in for VS Code around a webview test page | yes (in the test page) | +| `@miragon/modeler-shell/shell.css` | every style of the shell | — | All JavaScript entries ship as ESM and CJS with types (`typesVersions` covers `moduleResolution: node10`); importing any of them has no side effects. The package also ships `src/` without its tests, @@ -91,8 +99,22 @@ interface Insets { } type ShellHost = "ide" | "web" | "embedded"; -type ChromeIsland = "menu" | "palette" | "primary" | "zoom" | "problems" | "legend" | "inspector" | "status"; -const CHROME_ISLANDS: readonly ChromeIsland[]; +type ChromeIsland = + | "menu" + | "palette" + | "primary" + | "zoom" + | "problems" + | "legend" + | "inspector" + | "status" + // 0.2, web column (toasts and problems-popover also embedded) + | "legal" + | "toasts" + | "empty-state" + | "drop-zone" + | "problems-popover"; +const CHROME_ISLANDS: readonly ChromeIsland[]; // in this order type PaletteRow = "top" | "second-row"; interface ZoomTarget { @@ -182,6 +204,7 @@ interface FitLayout { host: ShellHost; paletteRow: PaletteRow; problemsVisible: boolean; + zoomRaised?: boolean; // web: the zoom panel stands above the legal line (zoomRowRaised) legendWidth?: number; // open legend's rendered width, undefined when closed/absent inspector?: { sheetTop?: number }; // present = open; sheetTop measured when it is a bottom sheet } @@ -204,7 +227,7 @@ function easeStandard(progress: number): number; // cubic-bezier(0.4, 0, 0.2, 1) the other dimension. An axis whose insets leave no room (a container lower or narrower than its chrome) centres in the whole container. - `fitInsets` (§5.9): top 88, 140 in the second row; left and right 24; bottom 64, in the `web` host - with a visible pill 92; right 324 (12 + 288 + 24) with an open side inspector (container wider + with a visible pill or with the zoom panel raised above the legal line (`zoomRaised`) 92; right 324 (12 + 288 + 24) with an open side inspector (container wider than 760); left 12 + legend width + 24 with an open legend in containers wider than 440 (`legendWidth <= 0` counts as closed); bottom `container.height − sheetTop + 12` with an open bottom sheet (up to 760). The sheet hides zoom panel, pill and legend (§5.11), so while it is open @@ -386,6 +409,26 @@ interface ShellMessages { invalidFile(diagram: string): string; // "This file isn't a valid right now. The diagram shows the last valid version and is read-only until you fix the text." keyNames: { ctrl: string; shift: string; plus: string; minus: string }; // Ctrl, Shift, Plus, Minus + // 0.2, web host (guide §2 shared terms) + share: string; // "Share": default label of the primary action + legal: string; // "Legal": aria-label of the legal line's