@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.
- package/API.md +2869 -0
- package/LICENSE +21 -0
- package/README.md +566 -2
- package/THIRD_PARTY_NOTICES.md +52 -0
- package/dist/appearance-BBaM_4bD.d.ts +323 -0
- package/dist/appearance-D3FUcbu6.d.cts +53 -0
- package/dist/appearance-D3FUcbu6.d.ts +53 -0
- package/dist/appearance-XX3JC3pI.d.cts +323 -0
- package/dist/chunk-66HCSJNY.js +2792 -0
- package/dist/chunk-66HCSJNY.js.map +1 -0
- package/dist/chunk-KYDG5DMX.js +136 -0
- package/dist/chunk-KYDG5DMX.js.map +1 -0
- package/dist/chunk-N4QXFF3A.js +23 -0
- package/dist/chunk-N4QXFF3A.js.map +1 -0
- package/dist/chunk-OADW3GPA.js +785 -0
- package/dist/chunk-OADW3GPA.js.map +1 -0
- package/dist/core.cjs +873 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +246 -0
- package/dist/core.d.ts +246 -0
- package/dist/core.js +131 -0
- package/dist/core.js.map +1 -0
- package/dist/diagram-js.cjs +1147 -0
- package/dist/diagram-js.cjs.map +1 -0
- package/dist/diagram-js.d.cts +170 -0
- package/dist/diagram-js.d.ts +170 -0
- package/dist/diagram-js.js +879 -0
- package/dist/diagram-js.js.map +1 -0
- package/dist/index.cjs +3632 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol-DhYBakWL.d.cts +15 -0
- package/dist/protocol-IeW8bf4f.d.ts +15 -0
- package/dist/shell.css +1603 -0
- package/dist/testing-vscode-stub.cjs +332 -0
- package/dist/testing-vscode-stub.cjs.map +1 -0
- package/dist/testing-vscode-stub.d.cts +65 -0
- package/dist/testing-vscode-stub.d.ts +65 -0
- package/dist/testing-vscode-stub.js +154 -0
- package/dist/testing-vscode-stub.js.map +1 -0
- package/dist/testing.cjs +4663 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +231 -0
- package/dist/testing.d.ts +231 -0
- package/dist/testing.js +4483 -0
- package/dist/testing.js.map +1 -0
- package/dist/toasts-Bp0REqdq.d.cts +142 -0
- package/dist/toasts-Bp0REqdq.d.ts +142 -0
- package/dist/types-CnRrINRs.d.cts +445 -0
- package/dist/types-PuDZczzy.d.ts +445 -0
- package/dist/vscode-extension.cjs +215 -0
- package/dist/vscode-extension.cjs.map +1 -0
- package/dist/vscode-extension.d.cts +103 -0
- package/dist/vscode-extension.d.ts +103 -0
- package/dist/vscode-extension.js +24 -0
- package/dist/vscode-extension.js.map +1 -0
- package/dist/vscode-webview.cjs +3561 -0
- package/dist/vscode-webview.cjs.map +1 -0
- package/dist/vscode-webview.d.cts +84 -0
- package/dist/vscode-webview.d.ts +84 -0
- package/dist/vscode-webview.js +259 -0
- package/dist/vscode-webview.js.map +1 -0
- package/package.json +145 -4
- package/src/core/appearance.ts +104 -0
- package/src/core/feedback/appearance.ts +141 -0
- package/src/core/feedback/problems.ts +23 -0
- package/src/core/feedback/toasts.ts +118 -0
- package/src/core/fit.ts +220 -0
- package/src/core/index.ts +127 -0
- package/src/core/keymap.ts +295 -0
- package/src/core/layout.ts +69 -0
- package/src/core/messages.ts +159 -0
- package/src/core/sizes.ts +85 -0
- package/src/core/types.ts +106 -0
- package/src/core/web-chrome/bottom-row.ts +37 -0
- package/src/core/web-chrome/drop.ts +78 -0
- package/src/core/web-chrome/top-row.ts +66 -0
- package/src/core/zoom.ts +74 -0
- package/src/core.ts +2 -0
- package/src/diagram-js/connect.ts +75 -0
- package/src/diagram-js/index.ts +16 -0
- package/src/diagram-js/module.ts +20 -0
- package/src/diagram-js/palette-skin.ts +267 -0
- package/src/diagram-js/palette.css +269 -0
- package/src/diagram-js/service.ts +243 -0
- package/src/diagram-js/types.ts +67 -0
- package/src/diagram-js/viewport.ts +583 -0
- package/src/diagram-js.ts +2 -0
- package/src/dom/buttons.css +124 -0
- package/src/dom/element.ts +51 -0
- package/src/dom/feedback/appearance.ts +184 -0
- package/src/dom/feedback/feedback.css +435 -0
- package/src/dom/feedback/problems-popover.ts +287 -0
- package/src/dom/feedback/toasts.ts +431 -0
- package/src/dom/hint.ts +51 -0
- package/src/dom/icons.ts +309 -0
- package/src/dom/index.ts +42 -0
- package/src/dom/inspector.ts +35 -0
- package/src/dom/keys.ts +67 -0
- package/src/dom/ledger.ts +87 -0
- package/src/dom/legend.ts +85 -0
- package/src/dom/menu.ts +404 -0
- package/src/dom/mount.ts +731 -0
- package/src/dom/problems.ts +73 -0
- package/src/dom/shell-dom.css +969 -0
- package/src/dom/status.ts +72 -0
- package/src/dom/tooltip.ts +237 -0
- package/src/dom/types.ts +459 -0
- package/src/dom/web/drop-zone.ts +181 -0
- package/src/dom/web/empty-state.ts +144 -0
- package/src/dom/web/legal.ts +75 -0
- package/src/dom/web/menu-groups.ts +69 -0
- package/src/dom/web/primary.ts +124 -0
- package/src/dom/web/web.css +386 -0
- package/src/dom/zoom-panel.ts +154 -0
- package/src/index.ts +3 -0
- package/src/shell.css +9 -0
- package/src/testing/case-tools.ts +164 -0
- package/src/testing/cases.ts +1077 -0
- package/src/testing/checks.ts +868 -0
- package/src/testing/facts.ts +641 -0
- package/src/testing/geometry.ts +652 -0
- package/src/testing/harness.ts +187 -0
- package/src/testing/index.ts +19 -0
- package/src/testing/page-tools.ts +457 -0
- package/src/testing/page.ts +27 -0
- package/src/testing/vscode-stub.ts +237 -0
- package/src/testing/web-cases.ts +913 -0
- package/src/testing/web-checks.ts +1049 -0
- package/src/testing/web-facts.ts +713 -0
- package/src/testing-vscode-stub.ts +2 -0
- package/src/testing.ts +2 -0
- package/src/vscode/extension/html.ts +107 -0
- package/src/vscode/extension/index.ts +8 -0
- package/src/vscode/extension/reveal.ts +9 -0
- package/src/vscode/extension/theme-bridge.ts +85 -0
- package/src/vscode/extension/types.ts +36 -0
- package/src/vscode/protocol.ts +31 -0
- package/src/vscode/webview/appearance.ts +141 -0
- package/src/vscode/webview/index.ts +8 -0
- package/src/vscode/webview/mount.ts +88 -0
- package/src/vscode/webview/state.ts +116 -0
- package/src/vscode-extension.ts +2 -0
- package/src/vscode-webview.ts +2 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { e as Size, P as PaletteRow, b as ChromeIsland, d as ShellHost, k as ToastStatus } from './toasts-Bp0REqdq.cjs';
|
|
2
|
+
import { A as Appearance, T as Theme, C as ColorThemeSetting } from './appearance-D3FUcbu6.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The part of Playwright's `Page` the kit drives, typed structurally: the kit has no runtime
|
|
6
|
+
* dependency on Playwright, the consumer's e2e suite passes its own `page`.
|
|
7
|
+
*/
|
|
8
|
+
interface PageLike {
|
|
9
|
+
evaluate<R, Arg>(pageFunction: (arg: Arg) => R | Promise<R>, arg: Arg): Promise<R>;
|
|
10
|
+
setViewportSize(size: {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
keyboard: {
|
|
15
|
+
press(key: string): Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
mouse: {
|
|
18
|
+
click(x: number, y: number): Promise<void>;
|
|
19
|
+
dblclick(x: number, y: number): Promise<void>;
|
|
20
|
+
move(x: number, y: number): Promise<void>;
|
|
21
|
+
down(): Promise<void>;
|
|
22
|
+
up(): Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
waitForTimeout(timeout: number): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Playwright's `page.emulateMedia`; the web-host cases need it for the system's mode and contrast
|
|
27
|
+
* (`appearance`) and report a skip with `hook: "open"` without it.
|
|
28
|
+
*/
|
|
29
|
+
emulateMedia?(options: {
|
|
30
|
+
colorScheme?: "light" | "dark" | "no-preference" | null;
|
|
31
|
+
contrast?: "more" | "no-preference" | null;
|
|
32
|
+
reducedMotion?: "reduce" | "no-preference" | null;
|
|
33
|
+
forcedColors?: "active" | "none" | null;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Every island box must match within this many pixels (guide §13.4). */
|
|
38
|
+
declare const GEOMETRY_TOLERANCE_PX = 1;
|
|
39
|
+
/**
|
|
40
|
+
* `getBoundingClientRect()` relative to the shell root's padding box, where its absolutely
|
|
41
|
+
* positioned islands anchor (a border on the root, as in a framed foreign page, does not count).
|
|
42
|
+
*/
|
|
43
|
+
interface IslandBox {
|
|
44
|
+
left: number;
|
|
45
|
+
top: number;
|
|
46
|
+
width: number;
|
|
47
|
+
height: number;
|
|
48
|
+
}
|
|
49
|
+
interface ChromeMeasurement {
|
|
50
|
+
container: Size;
|
|
51
|
+
/** From the root's `data-palette` attribute. */
|
|
52
|
+
paletteRow: PaletteRow;
|
|
53
|
+
/** The visible islands, found by `[data-chrome]`. */
|
|
54
|
+
islands: Partial<Record<ChromeIsland, IslandBox>>;
|
|
55
|
+
/**
|
|
56
|
+
* State attributes of the root: `[data-legend="open"]`, `[data-inspector="open"]`,
|
|
57
|
+
* `[data-problems="shown"]`, and in the web host `[data-empty-state="shown"]`,
|
|
58
|
+
* `[data-primary="collapsed"]` and `[data-zoom-row="raised"]`.
|
|
59
|
+
*/
|
|
60
|
+
open: {
|
|
61
|
+
legend: boolean;
|
|
62
|
+
inspector: boolean;
|
|
63
|
+
problems: boolean;
|
|
64
|
+
emptyState: boolean;
|
|
65
|
+
primaryCollapsed: boolean;
|
|
66
|
+
zoomRaised: boolean;
|
|
67
|
+
};
|
|
68
|
+
/** Width of the widest visible toast card (`[data-status]` in the stack); absent without a toast. */
|
|
69
|
+
toastCardWidth?: number;
|
|
70
|
+
}
|
|
71
|
+
/** Constraints of one island; every given field must hold within `GEOMETRY_TOLERANCE_PX`. */
|
|
72
|
+
interface ExpectedBox {
|
|
73
|
+
left?: number;
|
|
74
|
+
top?: number;
|
|
75
|
+
right?: number;
|
|
76
|
+
bottom?: number;
|
|
77
|
+
width?: number;
|
|
78
|
+
height?: number;
|
|
79
|
+
/** Horizontal centre relative to the root. */
|
|
80
|
+
centerX?: number;
|
|
81
|
+
/** Vertical centre relative to the root (the web app's empty-state card). */
|
|
82
|
+
centerY?: number;
|
|
83
|
+
}
|
|
84
|
+
/** Measures the islands of the shell under `root` (default `.cd-shell`) in the page. */
|
|
85
|
+
declare function measureChrome(page: PageLike, root?: string): Promise<ChromeMeasurement>;
|
|
86
|
+
/** The boxes guide §5.2–§5.12 expects for what was measured (anchors per host and breakpoint). */
|
|
87
|
+
declare function expectedChromeBoxes(measurement: ChromeMeasurement, host: ShellHost): Partial<Record<ChromeIsland, ExpectedBox>>;
|
|
88
|
+
|
|
89
|
+
interface OpenContext {
|
|
90
|
+
/** The page's viewport, which is the modeler's container in an own document. */
|
|
91
|
+
size: Size;
|
|
92
|
+
/**
|
|
93
|
+
* What the host requests before the modeler resolves it: in an IDE host the VS Code color theme
|
|
94
|
+
* (`vsCodeStubSearch` hands it to a page with the VS Code stub). For an embedded host the kit
|
|
95
|
+
* itself puts the foreign page's `<html>` in this mode once `open` resolved. In the web host the
|
|
96
|
+
* system's preference without a stored choice: the kit emulates `prefers-color-scheme` and
|
|
97
|
+
* `prefers-contrast` (`PageLike.emulateMedia`) before `open`, and `open` loads the page with an
|
|
98
|
+
* empty `localStorage` entry `miragon.darstellung`.
|
|
99
|
+
*/
|
|
100
|
+
requested: Appearance;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* How the kit makes the optional islands visible (`geometry`, `aria`) and puts the modeler into its
|
|
104
|
+
* invalid-file state (`readOnly`).
|
|
105
|
+
*/
|
|
106
|
+
interface ShowHooks<P extends PageLike = PageLike> {
|
|
107
|
+
problems?: ((page: P) => Promise<void>) | undefined;
|
|
108
|
+
status?: ((page: P) => Promise<void>) | undefined;
|
|
109
|
+
legend?: ((page: P) => Promise<void>) | undefined;
|
|
110
|
+
inspector?: ((page: P) => Promise<void>) | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Puts the modeler into its invalid-file state the way its host does (an invalid import): a
|
|
113
|
+
* read-only canvas and the status box. The kit waits `INVALID_STATUS_DELAY_MS` afterwards.
|
|
114
|
+
*/
|
|
115
|
+
invalid?: ((page: P) => Promise<void>) | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Web host: puts the page on its start screen, the way a fresh visit without a document shows
|
|
118
|
+
* it (`shell.setEmptyState(true)`); `open` itself loads a document.
|
|
119
|
+
*/
|
|
120
|
+
emptyState?: ((page: P) => Promise<void>) | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Web and embedded hosts: shows `toast` through the modeler's `shell.toast`, with
|
|
123
|
+
* `{ label: toast.actionLabel, onSelect() {} }` as its action when `actionLabel` is given.
|
|
124
|
+
*/
|
|
125
|
+
toast?: ((page: P, toast: ToastFixture) => Promise<void>) | undefined;
|
|
126
|
+
}
|
|
127
|
+
/** A toast the kit asks the `toast` hook to show (cases `toasts`, `geometry`). */
|
|
128
|
+
interface ToastFixture {
|
|
129
|
+
status: ToastStatus;
|
|
130
|
+
text: string;
|
|
131
|
+
actionLabel?: string | undefined;
|
|
132
|
+
}
|
|
133
|
+
/** A file the kit drops on the page (case `dropZone`), built in the page as `new File([text], name, { type })`. */
|
|
134
|
+
interface DropFixture {
|
|
135
|
+
name: string;
|
|
136
|
+
type: string;
|
|
137
|
+
text: string;
|
|
138
|
+
}
|
|
139
|
+
interface DropFixtures {
|
|
140
|
+
/** A file `DropZoneOptions.accept` takes; dropping it on the start screen opens it (the card goes). */
|
|
141
|
+
accepted: DropFixture;
|
|
142
|
+
/** A file outside `accept`; dropping it opens nothing and shows a danger toast (or the modeler's `onReject`). */
|
|
143
|
+
rejected?: DropFixture | undefined;
|
|
144
|
+
/** `DropZoneOptions.multiple` of the modeler; default `false`, so a drag of two files is forbidden. */
|
|
145
|
+
multiple?: boolean | undefined;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* A show hook by name: the islands `legend`, `inspector`, `problems`, `status`, the state
|
|
149
|
+
* `invalid`, and in the web column `emptyState` and `toast`.
|
|
150
|
+
*/
|
|
151
|
+
type ShowHook = keyof ShowHooks;
|
|
152
|
+
/**
|
|
153
|
+
* What a harness can lack: a show hook, the web app's drop zone (`drop`), or problems that point at
|
|
154
|
+
* an element (`problemSelection`: the modeler's diagnostics only name lines, so no row selects).
|
|
155
|
+
*/
|
|
156
|
+
type AbsentFeature = ShowHook | "drop" | "problemSelection";
|
|
157
|
+
interface ShellConformanceHarness<P extends PageLike = PageLike> {
|
|
158
|
+
host: ShellHost;
|
|
159
|
+
/** The modes the modeler declares (static); the appearance case requests dark from `["light"]`. */
|
|
160
|
+
themes: readonly Theme[];
|
|
161
|
+
/** Load the modeler with the shell at `size`, as the host would with `requested`; resolve once the first import is done. */
|
|
162
|
+
open(page: P, context: OpenContext): Promise<void>;
|
|
163
|
+
/** Tear modeler and shell down through the page's own path; `undefined` skips the cleanup case. */
|
|
164
|
+
destroy?: ((page: P) => Promise<void>) | undefined;
|
|
165
|
+
/** CSS selector of the shell root; default `.cd-shell`. */
|
|
166
|
+
root?: string | undefined;
|
|
167
|
+
/** Hooks for the islands and states the modeler has; one that is neither given nor `absent` is reported as skipped. */
|
|
168
|
+
show?: ShowHooks<P> | undefined;
|
|
169
|
+
/** Web host: the files the `dropZone` case drops; without them (and not `absent`) it is skipped with `hook: "drop"`. */
|
|
170
|
+
drop?: DropFixtures | undefined;
|
|
171
|
+
/**
|
|
172
|
+
* The islands and states the modeler does not have. An absent hook is not reported as skipped,
|
|
173
|
+
* and `geometry` and `aria` assert that its island is never visible. Listing a hook that `show`
|
|
174
|
+
* also gives fails every case that uses it.
|
|
175
|
+
*/
|
|
176
|
+
absent?: readonly AbsentFeature[] | undefined;
|
|
177
|
+
/** Container sizes of the geometry case; default wide 1280 × 900, narrow 720 × 700, very narrow 420 × 700. */
|
|
178
|
+
sizes?: readonly Size[] | undefined;
|
|
179
|
+
}
|
|
180
|
+
/** One part of a case the harness could not feed. */
|
|
181
|
+
interface ShellSkip {
|
|
182
|
+
/**
|
|
183
|
+
* The harness field that would feed it: a show hook, `destroy`, or `open` when the document it
|
|
184
|
+
* opens lacks what the case needs (a shape on the canvas).
|
|
185
|
+
*/
|
|
186
|
+
hook: ShowHook | "drop" | "destroy" | "open";
|
|
187
|
+
reason: string;
|
|
188
|
+
}
|
|
189
|
+
interface ShellCaseOutcome {
|
|
190
|
+
/** What the case could not (fully) run, one entry per missing harness field. */
|
|
191
|
+
skipped?: readonly ShellSkip[];
|
|
192
|
+
}
|
|
193
|
+
interface ShellConformanceCase {
|
|
194
|
+
name: string;
|
|
195
|
+
run<P extends PageLike>(page: P, harness: ShellConformanceHarness<P>): Promise<ShellCaseOutcome | void>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The cases: `geometry` (every `data-chrome` island ±1px, per host and breakpoint), `aria`
|
|
199
|
+
* (roles, names, `aria-expanded`/`-controls`/`-keyshortcuts`/`-disabled`, DOM order, no positive
|
|
200
|
+
* tabindex), `keys` (each chrome key acts exactly once; in the IDE host a `keydown` listener on
|
|
201
|
+
* `window` never fires for a handled key; unmodified `+`/`-` never zoom; select all acts on the
|
|
202
|
+
* canvas only), `create` (Enter on the first creating palette entry places one selected element in
|
|
203
|
+
* the free rectangle and focuses the canvas), `readOnly` (the invalid-file lock of guide §13.5),
|
|
204
|
+
* `appearance` (dark requested from a light-only modeler: nothing turns dark, `color-scheme` light
|
|
205
|
+
* everywhere, the canvas surround and the palette's tool colours from the roles; the web app's mode
|
|
206
|
+
* and its Appearance group) and `cleanup` (after `destroy` no shell element, class, attribute or
|
|
207
|
+
* key handling remains); then the web column's `webChrome`, `emptyState`, `toasts`,
|
|
208
|
+
* `problemsList` and `dropZone`, which assert in the other hosts that nothing of them shows.
|
|
209
|
+
*/
|
|
210
|
+
declare function shellConformanceCases(): ShellConformanceCase[];
|
|
211
|
+
/** Playwright's `test` (or any runner whose body receives `{ page }`). */
|
|
212
|
+
type ShellConformanceTest<P extends PageLike = PageLike> = (name: string, body: (fixtures: {
|
|
213
|
+
page: P;
|
|
214
|
+
}) => Promise<void>) => unknown;
|
|
215
|
+
interface RegisterShellConformanceOptions {
|
|
216
|
+
/** Default: `console.warn`, one line per case with its skips joined by "; ". */
|
|
217
|
+
onSkip?: ((caseName: string, skips: readonly ShellSkip[]) => void) | undefined;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The query string for a test page that installs the VS Code stub of
|
|
221
|
+
* `@miragon/modeler-shell/testing/vscode-stub` with `stubOptionsFromSearch(location.search)`:
|
|
222
|
+
* `theme=dark&kontrast=hoch`, plus the `colorTheme` setting and VS Code's reduce motion.
|
|
223
|
+
*/
|
|
224
|
+
declare function vsCodeStubSearch(requested: Appearance, extra?: {
|
|
225
|
+
colorTheme?: ColorThemeSetting | undefined;
|
|
226
|
+
reduceMotion?: boolean | undefined;
|
|
227
|
+
}): string;
|
|
228
|
+
/** Registers every case as `shell conformance: <name>`. */
|
|
229
|
+
declare function registerShellConformance<P extends PageLike>(harness: ShellConformanceHarness<P>, test: ShellConformanceTest<P>, options?: RegisterShellConformanceOptions): void;
|
|
230
|
+
|
|
231
|
+
export { type AbsentFeature, type ChromeMeasurement, type DropFixture, type DropFixtures, type ExpectedBox, GEOMETRY_TOLERANCE_PX, type IslandBox, type OpenContext, type PageLike, type RegisterShellConformanceOptions, type ShellCaseOutcome, type ShellConformanceCase, type ShellConformanceHarness, type ShellConformanceTest, type ShellSkip, type ShowHook, type ShowHooks, type ToastFixture, expectedChromeBoxes, measureChrome, registerShellConformance, shellConformanceCases, vsCodeStubSearch };
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { e as Size, P as PaletteRow, b as ChromeIsland, d as ShellHost, k as ToastStatus } from './toasts-Bp0REqdq.js';
|
|
2
|
+
import { A as Appearance, T as Theme, C as ColorThemeSetting } from './appearance-D3FUcbu6.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The part of Playwright's `Page` the kit drives, typed structurally: the kit has no runtime
|
|
6
|
+
* dependency on Playwright, the consumer's e2e suite passes its own `page`.
|
|
7
|
+
*/
|
|
8
|
+
interface PageLike {
|
|
9
|
+
evaluate<R, Arg>(pageFunction: (arg: Arg) => R | Promise<R>, arg: Arg): Promise<R>;
|
|
10
|
+
setViewportSize(size: {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
keyboard: {
|
|
15
|
+
press(key: string): Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
mouse: {
|
|
18
|
+
click(x: number, y: number): Promise<void>;
|
|
19
|
+
dblclick(x: number, y: number): Promise<void>;
|
|
20
|
+
move(x: number, y: number): Promise<void>;
|
|
21
|
+
down(): Promise<void>;
|
|
22
|
+
up(): Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
waitForTimeout(timeout: number): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Playwright's `page.emulateMedia`; the web-host cases need it for the system's mode and contrast
|
|
27
|
+
* (`appearance`) and report a skip with `hook: "open"` without it.
|
|
28
|
+
*/
|
|
29
|
+
emulateMedia?(options: {
|
|
30
|
+
colorScheme?: "light" | "dark" | "no-preference" | null;
|
|
31
|
+
contrast?: "more" | "no-preference" | null;
|
|
32
|
+
reducedMotion?: "reduce" | "no-preference" | null;
|
|
33
|
+
forcedColors?: "active" | "none" | null;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Every island box must match within this many pixels (guide §13.4). */
|
|
38
|
+
declare const GEOMETRY_TOLERANCE_PX = 1;
|
|
39
|
+
/**
|
|
40
|
+
* `getBoundingClientRect()` relative to the shell root's padding box, where its absolutely
|
|
41
|
+
* positioned islands anchor (a border on the root, as in a framed foreign page, does not count).
|
|
42
|
+
*/
|
|
43
|
+
interface IslandBox {
|
|
44
|
+
left: number;
|
|
45
|
+
top: number;
|
|
46
|
+
width: number;
|
|
47
|
+
height: number;
|
|
48
|
+
}
|
|
49
|
+
interface ChromeMeasurement {
|
|
50
|
+
container: Size;
|
|
51
|
+
/** From the root's `data-palette` attribute. */
|
|
52
|
+
paletteRow: PaletteRow;
|
|
53
|
+
/** The visible islands, found by `[data-chrome]`. */
|
|
54
|
+
islands: Partial<Record<ChromeIsland, IslandBox>>;
|
|
55
|
+
/**
|
|
56
|
+
* State attributes of the root: `[data-legend="open"]`, `[data-inspector="open"]`,
|
|
57
|
+
* `[data-problems="shown"]`, and in the web host `[data-empty-state="shown"]`,
|
|
58
|
+
* `[data-primary="collapsed"]` and `[data-zoom-row="raised"]`.
|
|
59
|
+
*/
|
|
60
|
+
open: {
|
|
61
|
+
legend: boolean;
|
|
62
|
+
inspector: boolean;
|
|
63
|
+
problems: boolean;
|
|
64
|
+
emptyState: boolean;
|
|
65
|
+
primaryCollapsed: boolean;
|
|
66
|
+
zoomRaised: boolean;
|
|
67
|
+
};
|
|
68
|
+
/** Width of the widest visible toast card (`[data-status]` in the stack); absent without a toast. */
|
|
69
|
+
toastCardWidth?: number;
|
|
70
|
+
}
|
|
71
|
+
/** Constraints of one island; every given field must hold within `GEOMETRY_TOLERANCE_PX`. */
|
|
72
|
+
interface ExpectedBox {
|
|
73
|
+
left?: number;
|
|
74
|
+
top?: number;
|
|
75
|
+
right?: number;
|
|
76
|
+
bottom?: number;
|
|
77
|
+
width?: number;
|
|
78
|
+
height?: number;
|
|
79
|
+
/** Horizontal centre relative to the root. */
|
|
80
|
+
centerX?: number;
|
|
81
|
+
/** Vertical centre relative to the root (the web app's empty-state card). */
|
|
82
|
+
centerY?: number;
|
|
83
|
+
}
|
|
84
|
+
/** Measures the islands of the shell under `root` (default `.cd-shell`) in the page. */
|
|
85
|
+
declare function measureChrome(page: PageLike, root?: string): Promise<ChromeMeasurement>;
|
|
86
|
+
/** The boxes guide §5.2–§5.12 expects for what was measured (anchors per host and breakpoint). */
|
|
87
|
+
declare function expectedChromeBoxes(measurement: ChromeMeasurement, host: ShellHost): Partial<Record<ChromeIsland, ExpectedBox>>;
|
|
88
|
+
|
|
89
|
+
interface OpenContext {
|
|
90
|
+
/** The page's viewport, which is the modeler's container in an own document. */
|
|
91
|
+
size: Size;
|
|
92
|
+
/**
|
|
93
|
+
* What the host requests before the modeler resolves it: in an IDE host the VS Code color theme
|
|
94
|
+
* (`vsCodeStubSearch` hands it to a page with the VS Code stub). For an embedded host the kit
|
|
95
|
+
* itself puts the foreign page's `<html>` in this mode once `open` resolved. In the web host the
|
|
96
|
+
* system's preference without a stored choice: the kit emulates `prefers-color-scheme` and
|
|
97
|
+
* `prefers-contrast` (`PageLike.emulateMedia`) before `open`, and `open` loads the page with an
|
|
98
|
+
* empty `localStorage` entry `miragon.darstellung`.
|
|
99
|
+
*/
|
|
100
|
+
requested: Appearance;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* How the kit makes the optional islands visible (`geometry`, `aria`) and puts the modeler into its
|
|
104
|
+
* invalid-file state (`readOnly`).
|
|
105
|
+
*/
|
|
106
|
+
interface ShowHooks<P extends PageLike = PageLike> {
|
|
107
|
+
problems?: ((page: P) => Promise<void>) | undefined;
|
|
108
|
+
status?: ((page: P) => Promise<void>) | undefined;
|
|
109
|
+
legend?: ((page: P) => Promise<void>) | undefined;
|
|
110
|
+
inspector?: ((page: P) => Promise<void>) | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Puts the modeler into its invalid-file state the way its host does (an invalid import): a
|
|
113
|
+
* read-only canvas and the status box. The kit waits `INVALID_STATUS_DELAY_MS` afterwards.
|
|
114
|
+
*/
|
|
115
|
+
invalid?: ((page: P) => Promise<void>) | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Web host: puts the page on its start screen, the way a fresh visit without a document shows
|
|
118
|
+
* it (`shell.setEmptyState(true)`); `open` itself loads a document.
|
|
119
|
+
*/
|
|
120
|
+
emptyState?: ((page: P) => Promise<void>) | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Web and embedded hosts: shows `toast` through the modeler's `shell.toast`, with
|
|
123
|
+
* `{ label: toast.actionLabel, onSelect() {} }` as its action when `actionLabel` is given.
|
|
124
|
+
*/
|
|
125
|
+
toast?: ((page: P, toast: ToastFixture) => Promise<void>) | undefined;
|
|
126
|
+
}
|
|
127
|
+
/** A toast the kit asks the `toast` hook to show (cases `toasts`, `geometry`). */
|
|
128
|
+
interface ToastFixture {
|
|
129
|
+
status: ToastStatus;
|
|
130
|
+
text: string;
|
|
131
|
+
actionLabel?: string | undefined;
|
|
132
|
+
}
|
|
133
|
+
/** A file the kit drops on the page (case `dropZone`), built in the page as `new File([text], name, { type })`. */
|
|
134
|
+
interface DropFixture {
|
|
135
|
+
name: string;
|
|
136
|
+
type: string;
|
|
137
|
+
text: string;
|
|
138
|
+
}
|
|
139
|
+
interface DropFixtures {
|
|
140
|
+
/** A file `DropZoneOptions.accept` takes; dropping it on the start screen opens it (the card goes). */
|
|
141
|
+
accepted: DropFixture;
|
|
142
|
+
/** A file outside `accept`; dropping it opens nothing and shows a danger toast (or the modeler's `onReject`). */
|
|
143
|
+
rejected?: DropFixture | undefined;
|
|
144
|
+
/** `DropZoneOptions.multiple` of the modeler; default `false`, so a drag of two files is forbidden. */
|
|
145
|
+
multiple?: boolean | undefined;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* A show hook by name: the islands `legend`, `inspector`, `problems`, `status`, the state
|
|
149
|
+
* `invalid`, and in the web column `emptyState` and `toast`.
|
|
150
|
+
*/
|
|
151
|
+
type ShowHook = keyof ShowHooks;
|
|
152
|
+
/**
|
|
153
|
+
* What a harness can lack: a show hook, the web app's drop zone (`drop`), or problems that point at
|
|
154
|
+
* an element (`problemSelection`: the modeler's diagnostics only name lines, so no row selects).
|
|
155
|
+
*/
|
|
156
|
+
type AbsentFeature = ShowHook | "drop" | "problemSelection";
|
|
157
|
+
interface ShellConformanceHarness<P extends PageLike = PageLike> {
|
|
158
|
+
host: ShellHost;
|
|
159
|
+
/** The modes the modeler declares (static); the appearance case requests dark from `["light"]`. */
|
|
160
|
+
themes: readonly Theme[];
|
|
161
|
+
/** Load the modeler with the shell at `size`, as the host would with `requested`; resolve once the first import is done. */
|
|
162
|
+
open(page: P, context: OpenContext): Promise<void>;
|
|
163
|
+
/** Tear modeler and shell down through the page's own path; `undefined` skips the cleanup case. */
|
|
164
|
+
destroy?: ((page: P) => Promise<void>) | undefined;
|
|
165
|
+
/** CSS selector of the shell root; default `.cd-shell`. */
|
|
166
|
+
root?: string | undefined;
|
|
167
|
+
/** Hooks for the islands and states the modeler has; one that is neither given nor `absent` is reported as skipped. */
|
|
168
|
+
show?: ShowHooks<P> | undefined;
|
|
169
|
+
/** Web host: the files the `dropZone` case drops; without them (and not `absent`) it is skipped with `hook: "drop"`. */
|
|
170
|
+
drop?: DropFixtures | undefined;
|
|
171
|
+
/**
|
|
172
|
+
* The islands and states the modeler does not have. An absent hook is not reported as skipped,
|
|
173
|
+
* and `geometry` and `aria` assert that its island is never visible. Listing a hook that `show`
|
|
174
|
+
* also gives fails every case that uses it.
|
|
175
|
+
*/
|
|
176
|
+
absent?: readonly AbsentFeature[] | undefined;
|
|
177
|
+
/** Container sizes of the geometry case; default wide 1280 × 900, narrow 720 × 700, very narrow 420 × 700. */
|
|
178
|
+
sizes?: readonly Size[] | undefined;
|
|
179
|
+
}
|
|
180
|
+
/** One part of a case the harness could not feed. */
|
|
181
|
+
interface ShellSkip {
|
|
182
|
+
/**
|
|
183
|
+
* The harness field that would feed it: a show hook, `destroy`, or `open` when the document it
|
|
184
|
+
* opens lacks what the case needs (a shape on the canvas).
|
|
185
|
+
*/
|
|
186
|
+
hook: ShowHook | "drop" | "destroy" | "open";
|
|
187
|
+
reason: string;
|
|
188
|
+
}
|
|
189
|
+
interface ShellCaseOutcome {
|
|
190
|
+
/** What the case could not (fully) run, one entry per missing harness field. */
|
|
191
|
+
skipped?: readonly ShellSkip[];
|
|
192
|
+
}
|
|
193
|
+
interface ShellConformanceCase {
|
|
194
|
+
name: string;
|
|
195
|
+
run<P extends PageLike>(page: P, harness: ShellConformanceHarness<P>): Promise<ShellCaseOutcome | void>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The cases: `geometry` (every `data-chrome` island ±1px, per host and breakpoint), `aria`
|
|
199
|
+
* (roles, names, `aria-expanded`/`-controls`/`-keyshortcuts`/`-disabled`, DOM order, no positive
|
|
200
|
+
* tabindex), `keys` (each chrome key acts exactly once; in the IDE host a `keydown` listener on
|
|
201
|
+
* `window` never fires for a handled key; unmodified `+`/`-` never zoom; select all acts on the
|
|
202
|
+
* canvas only), `create` (Enter on the first creating palette entry places one selected element in
|
|
203
|
+
* the free rectangle and focuses the canvas), `readOnly` (the invalid-file lock of guide §13.5),
|
|
204
|
+
* `appearance` (dark requested from a light-only modeler: nothing turns dark, `color-scheme` light
|
|
205
|
+
* everywhere, the canvas surround and the palette's tool colours from the roles; the web app's mode
|
|
206
|
+
* and its Appearance group) and `cleanup` (after `destroy` no shell element, class, attribute or
|
|
207
|
+
* key handling remains); then the web column's `webChrome`, `emptyState`, `toasts`,
|
|
208
|
+
* `problemsList` and `dropZone`, which assert in the other hosts that nothing of them shows.
|
|
209
|
+
*/
|
|
210
|
+
declare function shellConformanceCases(): ShellConformanceCase[];
|
|
211
|
+
/** Playwright's `test` (or any runner whose body receives `{ page }`). */
|
|
212
|
+
type ShellConformanceTest<P extends PageLike = PageLike> = (name: string, body: (fixtures: {
|
|
213
|
+
page: P;
|
|
214
|
+
}) => Promise<void>) => unknown;
|
|
215
|
+
interface RegisterShellConformanceOptions {
|
|
216
|
+
/** Default: `console.warn`, one line per case with its skips joined by "; ". */
|
|
217
|
+
onSkip?: ((caseName: string, skips: readonly ShellSkip[]) => void) | undefined;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The query string for a test page that installs the VS Code stub of
|
|
221
|
+
* `@miragon/modeler-shell/testing/vscode-stub` with `stubOptionsFromSearch(location.search)`:
|
|
222
|
+
* `theme=dark&kontrast=hoch`, plus the `colorTheme` setting and VS Code's reduce motion.
|
|
223
|
+
*/
|
|
224
|
+
declare function vsCodeStubSearch(requested: Appearance, extra?: {
|
|
225
|
+
colorTheme?: ColorThemeSetting | undefined;
|
|
226
|
+
reduceMotion?: boolean | undefined;
|
|
227
|
+
}): string;
|
|
228
|
+
/** Registers every case as `shell conformance: <name>`. */
|
|
229
|
+
declare function registerShellConformance<P extends PageLike>(harness: ShellConformanceHarness<P>, test: ShellConformanceTest<P>, options?: RegisterShellConformanceOptions): void;
|
|
230
|
+
|
|
231
|
+
export { type AbsentFeature, type ChromeMeasurement, type DropFixture, type DropFixtures, type ExpectedBox, GEOMETRY_TOLERANCE_PX, type IslandBox, type OpenContext, type PageLike, type RegisterShellConformanceOptions, type ShellCaseOutcome, type ShellConformanceCase, type ShellConformanceHarness, type ShellConformanceTest, type ShellSkip, type ShowHook, type ShowHooks, type ToastFixture, expectedChromeBoxes, measureChrome, registerShellConformance, shellConformanceCases, vsCodeStubSearch };
|