waygraph 0.15.32 → 0.15.33
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/dist/highlights/run-phase.js +2 -0
- package/dist/highlights/stub-ctx.js +36 -2
- package/dist/highlights/types.d.ts +35 -3
- package/dist/index.d.ts +1 -1
- package/dist/pilot-overlay/fixtures.d.ts +9 -1
- package/dist/pilot-overlay/fixtures.js +38 -1
- package/dist/pilot-overlay/overlay-fixtures.d.ts +9 -0
- package/dist/pilot-overlay/overlay-fixtures.js +45 -0
- package/dist/pilot-overlay/shell.js +4 -23
- package/dist/pilot-overlay.d.ts +1 -0
- package/dist/pilot-overlay.js +1 -0
- package/dist/runner/banner-log.js +62 -0
- package/dist/runner/demo-log.js +9 -1
- package/dist/runner/inpage/banner.js +56 -1
- package/dist/runner/inpage/core.js +2 -0
- package/dist/runner/overlay-css.js +6 -27
- package/dist/runner/overlay-install.js +7 -4
- package/dist/runner/overlay-present.d.ts +8 -0
- package/dist/runner/overlay-present.js +57 -0
- package/dist/runner/overlay-stage.js +105 -0
- package/dist/runner/step-mode.js +35 -126
- package/dist/runner/step-panels.js +3 -3
- package/dist/step-overlay.js +1 -3
- package/dist/ui/overlay.css +209 -0
- package/dist/ui/shadow.d.ts +7 -2
- package/dist/ui/shadow.js +12 -4
- package/dist/ui/stylesheet.d.ts +7 -0
- package/dist/ui/stylesheet.js +18 -0
- package/dist/verbose-log.d.ts +1 -0
- package/dist/verbose-log.js +16 -0
- package/examples/saucedemo/.waygraph-auto/03df352d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/0a8c3719.log +0 -0
- package/examples/saucedemo/.waygraph-auto/232a1d81.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2553d107.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2f4f531e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/3bdb2f5a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5b838485.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5d13bdde.log +0 -0
- package/examples/saucedemo/.waygraph-auto/63b0f4cd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/6f05bdc1.log +0 -0
- package/examples/saucedemo/.waygraph-auto/70279fc3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/731a14bd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/76128a2d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/796ab578.log +0 -0
- package/examples/saucedemo/.waygraph-auto/859a261d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a1ab5d29.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a94738b7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b3d172f3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b57921c5.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b9ab0983.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d37719a6.log +0 -0
- package/examples/saucedemo/.waygraph-auto/da0a06bf.log +0 -0
- package/examples/saucedemo/.waygraph-auto/dc58eb72.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ff616932.log +0 -0
- package/package.json +3 -2
- package/examples/saucedemo/.waygraph-auto/535e8922.json +0 -8
|
@@ -107,6 +107,8 @@ export async function runStubPhase(block, phase, opts) {
|
|
|
107
107
|
...(bag.zoom !== undefined ? { zoom: bag.zoom } : {}),
|
|
108
108
|
...(bag.zoomOut !== undefined ? { zoomOut: bag.zoomOut } : {}),
|
|
109
109
|
...(bag.title !== undefined && bag.title !== "" ? { title: bag.title } : {}),
|
|
110
|
+
...(bag.titlePos !== undefined ? { titlePos: bag.titlePos } : {}),
|
|
111
|
+
...(bag.bannerUi !== undefined ? { bannerUi: bag.bannerUi } : {}),
|
|
110
112
|
...(bag.todoPos !== undefined ? { todoPos: bag.todoPos } : {}),
|
|
111
113
|
...(bag.todoDockUi !== undefined ? { todoDockUi: bag.todoDockUi } : {}),
|
|
112
114
|
...(bag.todoParallel === true ? { todoParallel: true } : {}),
|
|
@@ -162,11 +162,35 @@ export function createStubCtx(bag, opts) {
|
|
|
162
162
|
zoomOut(keep) {
|
|
163
163
|
bag.zoomOut = !!keep;
|
|
164
164
|
},
|
|
165
|
-
title(text) {
|
|
165
|
+
title(text, opts) {
|
|
166
166
|
bag.title = String(text ?? "");
|
|
167
|
+
const p = normalizeBannerPos(opts?.pos);
|
|
168
|
+
if (p)
|
|
169
|
+
bag.titlePos = p;
|
|
167
170
|
},
|
|
168
|
-
banner(text) {
|
|
171
|
+
banner(text, opts) {
|
|
169
172
|
bag.title = String(text ?? "");
|
|
173
|
+
const p = normalizeBannerPos(opts?.pos);
|
|
174
|
+
if (p)
|
|
175
|
+
bag.titlePos = p;
|
|
176
|
+
},
|
|
177
|
+
titlePos(side) {
|
|
178
|
+
const p = normalizeBannerPos(side);
|
|
179
|
+
if (p)
|
|
180
|
+
bag.titlePos = p;
|
|
181
|
+
},
|
|
182
|
+
bannerPos(side) {
|
|
183
|
+
const p = normalizeBannerPos(side);
|
|
184
|
+
if (p)
|
|
185
|
+
bag.titlePos = p;
|
|
186
|
+
},
|
|
187
|
+
bannerUi(opts) {
|
|
188
|
+
if (!opts || typeof opts !== "object")
|
|
189
|
+
return;
|
|
190
|
+
bag.bannerUi = { ...(bag.bannerUi || {}), ...opts };
|
|
191
|
+
},
|
|
192
|
+
hideBanner() {
|
|
193
|
+
bag.bannerUi = { ...(bag.bannerUi || {}), hidden: true };
|
|
170
194
|
},
|
|
171
195
|
todoPos(side) {
|
|
172
196
|
const p = normalizeTodoPos(side);
|
|
@@ -256,6 +280,12 @@ export function createStubCtx(bag, opts) {
|
|
|
256
280
|
bag.zoomOut = !!partial.zoomOut;
|
|
257
281
|
if (partial.title !== undefined)
|
|
258
282
|
bag.title = String(partial.title ?? "");
|
|
283
|
+
const bp = normalizeBannerPos(partial.titlePos);
|
|
284
|
+
if (bp)
|
|
285
|
+
bag.titlePos = bp;
|
|
286
|
+
if (partial.bannerUi && typeof partial.bannerUi === "object") {
|
|
287
|
+
bag.bannerUi = { ...(bag.bannerUi || {}), ...partial.bannerUi };
|
|
288
|
+
}
|
|
259
289
|
const tp = normalizeTodoPos(partial.todoPos);
|
|
260
290
|
if (tp)
|
|
261
291
|
bag.todoPos = tp;
|
|
@@ -279,3 +309,7 @@ export function liftLegacySlotTodos(bag) {
|
|
|
279
309
|
}
|
|
280
310
|
}
|
|
281
311
|
}
|
|
312
|
+
function normalizeBannerPos(raw) {
|
|
313
|
+
const v = String(raw ?? "").toLowerCase();
|
|
314
|
+
return v === "left" || v === "center" || v === "right" ? v : undefined;
|
|
315
|
+
}
|
|
@@ -41,6 +41,15 @@ export type WaygraphTodoInput = string | WaygraphTodoItem;
|
|
|
41
41
|
* - `bullets` - flat bullet list (no arrow/checkbox; open notes / trimmed dock)
|
|
42
42
|
*/
|
|
43
43
|
export type TodoListStyle = "sequential" | "checklist" | "bullets";
|
|
44
|
+
/** Where the top banner sits. */
|
|
45
|
+
export type BannerPos = "left" | "center" | "right";
|
|
46
|
+
/** Banner UX, mirrors {@link TodoDockUiOpts}: pass `false` fields to opt out for this phase. */
|
|
47
|
+
export interface BannerUiOpts {
|
|
48
|
+
/** Move to a free spot while a highlight ring would overlap it (default true). */
|
|
49
|
+
collision?: boolean;
|
|
50
|
+
/** Hide the banner entirely for this phase. */
|
|
51
|
+
hidden?: boolean;
|
|
52
|
+
}
|
|
44
53
|
/** One titled group in the floating todo dock (FR / Scenarios / ACs, etc.). */
|
|
45
54
|
export type WaygraphTodoGroupInput = {
|
|
46
55
|
/** Stable group id -> `data-wg-todo-group`. */
|
|
@@ -146,6 +155,10 @@ export type StubPhaseFixtures = {
|
|
|
146
155
|
zoomOut?: boolean;
|
|
147
156
|
/** Top demo banner title (the purple "waygraph demo" card). */
|
|
148
157
|
title?: string;
|
|
158
|
+
/** Banner side/position (`left` | `center` | `right`). Authored control, like {@link todoPos}. */
|
|
159
|
+
titlePos?: BannerPos;
|
|
160
|
+
/** Banner UX: collision (move away from a ring it overlaps), hidden. See {@link BannerUiOpts}. */
|
|
161
|
+
bannerUi?: BannerUiOpts;
|
|
149
162
|
/**
|
|
150
163
|
* Floating checklist dock side. `left` | `right`.
|
|
151
164
|
* Authored control (also click / WAYGRAPH_TODO_POS / --todo-left|right).
|
|
@@ -373,10 +386,25 @@ export type StubCtx<Out extends Checkpoint<string> = Checkpoint<string>> = {
|
|
|
373
386
|
* Default zoomOut for rings in this phase. `false` = keep camera between rings.
|
|
374
387
|
*/
|
|
375
388
|
zoomOut(keep: boolean): void;
|
|
376
|
-
/** Top banner title (waygraph demo card). */
|
|
377
|
-
title(text: string
|
|
389
|
+
/** Top banner title (waygraph demo card). `opts.pos` also places it (left | center | right). */
|
|
390
|
+
title(text: string, opts?: {
|
|
391
|
+
pos?: BannerPos;
|
|
392
|
+
}): void;
|
|
378
393
|
/** Alias for {@link StubCtx.title}. */
|
|
379
|
-
banner(text: string
|
|
394
|
+
banner(text: string, opts?: {
|
|
395
|
+
pos?: BannerPos;
|
|
396
|
+
}): void;
|
|
397
|
+
/** Place the banner: `left` | `center` | `right` (authored; click / env are fallbacks). */
|
|
398
|
+
titlePos(side: BannerPos): void;
|
|
399
|
+
/** Alias for {@link StubCtx.titlePos}. */
|
|
400
|
+
bannerPos(side: BannerPos): void;
|
|
401
|
+
/**
|
|
402
|
+
* Banner UX: `{ collision: false }` keeps it put even over a ring; `{ hidden: true }` hides it.
|
|
403
|
+
* @example ctx.bannerUi({ collision: false });
|
|
404
|
+
*/
|
|
405
|
+
bannerUi(opts: BannerUiOpts): void;
|
|
406
|
+
/** Shorthand for `bannerUi({ hidden: true })`. */
|
|
407
|
+
hideBanner(): void;
|
|
380
408
|
/**
|
|
381
409
|
* Floating checklist dock side (`left` | `right`). Authors control this in
|
|
382
410
|
* code; click / env / --todo-left|right are fallbacks.
|
|
@@ -433,6 +461,8 @@ export type StubPhaseResult = {
|
|
|
433
461
|
zoom?: number;
|
|
434
462
|
zoomOut?: boolean;
|
|
435
463
|
title?: string;
|
|
464
|
+
titlePos?: BannerPos;
|
|
465
|
+
bannerUi?: BannerUiOpts;
|
|
436
466
|
todoPos?: "left" | "right";
|
|
437
467
|
/** When true, keep other docks (multi-todo). Default false = replace. */
|
|
438
468
|
todoParallel?: boolean;
|
|
@@ -528,6 +558,8 @@ export type StubBagState = {
|
|
|
528
558
|
zoom?: number | undefined;
|
|
529
559
|
zoomOut?: boolean | undefined;
|
|
530
560
|
title?: string | undefined;
|
|
561
|
+
titlePos?: BannerPos | undefined;
|
|
562
|
+
bannerUi?: BannerUiOpts | undefined;
|
|
531
563
|
todoPos?: "left" | "right" | undefined;
|
|
532
564
|
/** Author patched todo-dock UX this phase. */
|
|
533
565
|
todoDockUi?: TodoDockUiOpts | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { registerMemStub, seedMemStub, getMemStub } from "./mem-stub.js";
|
|
|
5
5
|
export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible, frameTextEquals, frameContainsText, } from "./trait.js";
|
|
6
6
|
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withMemStub, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, withStubBefore, withStubAfter, withStubOnError, chainFlow, defineLayout, map, MapBuilder, } from "./engine.js";
|
|
7
7
|
export { resolveHighlightSlots, resolveSlides, runStubPhase, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, normalizeTodoPos, normalizeTodoStyle, buildTodoDock, applyTodoPhase, advanceTodoDock, completeSequentialTodoDock, applyDevicePhase, resolveDeviceState, normalizeDevicePreset, normalizeDeviceOrientation, applyOrientation, orientationFromViewport, DEVICE_PRESETS, resolveTodoDockUi, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, WAYGRAPH_RING_CSS, } from "./highlights.js";
|
|
8
|
-
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, WaygraphTodoGroup, WaygraphTodoGroupInput, WaygraphTodosOpts, TodoDockUiOpts, TodoDockUiResolved, TodoDockState, TodoListStyle, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, DemoPaceName, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, DevicePreset, DeviceViewport, DeviceState, DeviceOrientation, } from "./highlights.js";
|
|
8
|
+
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, WaygraphTodoGroup, WaygraphTodoGroupInput, WaygraphTodosOpts, TodoDockUiOpts, BannerPos, BannerUiOpts, TodoDockUiResolved, TodoDockState, TodoListStyle, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, DemoPaceName, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, DevicePreset, DeviceViewport, DeviceState, DeviceOrientation, } from "./highlights.js";
|
|
9
9
|
export type { Flow, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, AssertBlock, AssertBlockOptions, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, Layout, LayoutOptions, MapBuilderOptions, } from "./engine.js";
|
|
10
10
|
export type { ActionPage } from "./types.js";
|
|
11
11
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DevicePreset, DeviceState, HighlightTone, TodoDockUiOpts } from "../highlights.js";
|
|
1
|
+
import type { BannerPos, BannerUiOpts, DevicePreset, DeviceState, HighlightTone, TodoDockUiOpts } from "../highlights.js";
|
|
2
2
|
import type { Page } from "@playwright/test";
|
|
3
3
|
/** One ring the Pilot agent wants painted (same fields as demo stub rings). */
|
|
4
4
|
export type PilotFixtureRing = {
|
|
@@ -68,6 +68,14 @@ export type PilotHighlightFixtures = {
|
|
|
68
68
|
device?: DevicePreset | DeviceState;
|
|
69
69
|
/** Drop every agent fixture ring/todo/focus/zoom immediately. */
|
|
70
70
|
clear?: boolean;
|
|
71
|
+
/** Top banner title card (same as `ctx.title`). */
|
|
72
|
+
title?: string;
|
|
73
|
+
/** Banner position (same as `ctx.titlePos`). */
|
|
74
|
+
titlePos?: BannerPos;
|
|
75
|
+
/** Banner UX: collision / hidden (same as `ctx.bannerUi`). */
|
|
76
|
+
bannerUi?: BannerUiOpts;
|
|
77
|
+
/** Alias of {@link todoUi} - the name `ctx.todoDockUi` uses. */
|
|
78
|
+
todoDockUi?: TodoDockUiOpts;
|
|
71
79
|
};
|
|
72
80
|
/**
|
|
73
81
|
* Paint (or clear) agent-authored highlight fixtures on the live page.
|
|
@@ -92,8 +92,41 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
92
92
|
: typeof fixtures.device === "string"
|
|
93
93
|
? fixtures.device
|
|
94
94
|
: fixtures.device.preset || "device";
|
|
95
|
+
const bannerTitle = fixtures.clear ? undefined : fixtures.title;
|
|
96
|
+
const bannerPos = fixtures.clear ? undefined : fixtures.titlePos;
|
|
97
|
+
const bannerHidden = !!fixtures.clear || !!fixtures.bannerUi?.hidden;
|
|
98
|
+
const bannerCollision = fixtures.bannerUi?.collision !== false;
|
|
95
99
|
return page
|
|
96
|
-
.evaluate(({ rings, todos, todoIndex, todoTitle, todoPos, holdMs, zoom, zoomSelector, zoomOut, clearAll, deviceLabel, todoUi, }) => {
|
|
100
|
+
.evaluate(({ rings, todos, todoIndex, todoTitle, todoPos, holdMs, zoom, zoomSelector, zoomOut, clearAll, deviceLabel, todoUi, bannerTitle, bannerPos, bannerHidden, bannerCollision, }) => {
|
|
101
|
+
// Same #wg-banner element/CSS the demo runner paints (ui/css/banner.css, already in the
|
|
102
|
+
// shared bundle) - so ctx.title / ctx.titlePos / ctx.bannerUi behave identically on a Pilot
|
|
103
|
+
// session, not a separate re-implementation.
|
|
104
|
+
if (bannerHidden) {
|
|
105
|
+
const b = __wgById("wg-banner");
|
|
106
|
+
if (b)
|
|
107
|
+
b.style.display = "none";
|
|
108
|
+
}
|
|
109
|
+
else if (bannerTitle) {
|
|
110
|
+
let banner = __wgById("wg-banner");
|
|
111
|
+
if (!banner) {
|
|
112
|
+
banner = document.createElement("div");
|
|
113
|
+
banner.id = "wg-banner";
|
|
114
|
+
const tag = document.createElement("span");
|
|
115
|
+
tag.className = "wg-banner-tag";
|
|
116
|
+
tag.textContent = "waygraph pilot";
|
|
117
|
+
const text = document.createElement("span");
|
|
118
|
+
text.className = "wg-banner-text";
|
|
119
|
+
banner.appendChild(tag);
|
|
120
|
+
banner.appendChild(text);
|
|
121
|
+
__wgAdd(banner);
|
|
122
|
+
}
|
|
123
|
+
banner.style.display = "";
|
|
124
|
+
banner.dataset.pos = bannerPos || banner.dataset.pos || "left";
|
|
125
|
+
banner.dataset.collision = bannerCollision ? "1" : "0";
|
|
126
|
+
const textEl = banner.querySelector(".wg-banner-text");
|
|
127
|
+
if (textEl)
|
|
128
|
+
textEl.textContent = bannerTitle;
|
|
129
|
+
}
|
|
97
130
|
const w = window;
|
|
98
131
|
if (w.__wgPilotFxHideTimer)
|
|
99
132
|
clearTimeout(w.__wgPilotFxHideTimer);
|
|
@@ -329,6 +362,10 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
329
362
|
clearAll: fixtures.clear === true,
|
|
330
363
|
deviceLabel,
|
|
331
364
|
todoUi,
|
|
365
|
+
bannerTitle,
|
|
366
|
+
bannerPos,
|
|
367
|
+
bannerHidden,
|
|
368
|
+
bannerCollision,
|
|
332
369
|
})
|
|
333
370
|
.catch(() => ({ painted: 0, missing: rings.map((r) => r.selector) }));
|
|
334
371
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { StubPhaseResult } from "../highlights.js";
|
|
2
|
+
import type { PilotHighlightFixtures } from "./fixtures.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve agent-sent "waygraph overlay fixtures" (`auto highlight` JSON / shorthand) through the SAME
|
|
5
|
+
* stub-ctx path a Block's `stubBefore(ctx)` uses, so ctx.todos / ctx.device / ctx.title / ctx.bannerUi semantics
|
|
6
|
+
* (keep vs set vs clear, defaults, normalisation) cannot diverge between `waygraph demo` and pilot/auto/browser.
|
|
7
|
+
* Not Playwright test fixtures - these describe what the waygraph overlay paints on the page under test.
|
|
8
|
+
*/
|
|
9
|
+
export declare function overlayFixturesToPhase(f: PilotHighlightFixtures): Promise<StubPhaseResult>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { runStubPhase } from "../highlights.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve agent-sent "waygraph overlay fixtures" (`auto highlight` JSON / shorthand) through the SAME
|
|
4
|
+
* stub-ctx path a Block's `stubBefore(ctx)` uses, so ctx.todos / ctx.device / ctx.title / ctx.bannerUi semantics
|
|
5
|
+
* (keep vs set vs clear, defaults, normalisation) cannot diverge between `waygraph demo` and pilot/auto/browser.
|
|
6
|
+
* Not Playwright test fixtures - these describe what the waygraph overlay paints on the page under test.
|
|
7
|
+
*/
|
|
8
|
+
export async function overlayFixturesToPhase(f) {
|
|
9
|
+
const lifecycle = (ctx) => {
|
|
10
|
+
if (f.clear) {
|
|
11
|
+
ctx.hideTodos();
|
|
12
|
+
ctx.hideDevice();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (f.title !== undefined)
|
|
16
|
+
ctx.title(f.title, f.titlePos ? { pos: f.titlePos } : undefined);
|
|
17
|
+
else if (f.titlePos)
|
|
18
|
+
ctx.titlePos(f.titlePos);
|
|
19
|
+
if (f.bannerUi)
|
|
20
|
+
ctx.bannerUi(f.bannerUi);
|
|
21
|
+
if (f.todos !== undefined) {
|
|
22
|
+
ctx.todos("pilot", f.todos, {
|
|
23
|
+
title: f.todoTitle ?? "Plan",
|
|
24
|
+
index: f.todoIndex ?? 0,
|
|
25
|
+
pos: f.todoPos === "left" ? "left" : "right",
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const ui = f.todoDockUi ?? f.todoUi;
|
|
29
|
+
if (ui)
|
|
30
|
+
ctx.todoDockUi(ui);
|
|
31
|
+
if (f.device)
|
|
32
|
+
ctx.device(f.device);
|
|
33
|
+
if (typeof f.zoom === "number" && Number.isFinite(f.zoom) && f.zoom > 0)
|
|
34
|
+
ctx.zoom(f.zoom);
|
|
35
|
+
if (f.zoomOut !== undefined)
|
|
36
|
+
ctx.zoomOut(f.zoomOut);
|
|
37
|
+
if (f.rings?.length) {
|
|
38
|
+
f.rings.forEach((r, i) => {
|
|
39
|
+
const { selector, label, ...rest } = r;
|
|
40
|
+
ctx.ring(`ring${i + 1}`, { selector, label, ...rest });
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return runStubPhase({ name: "overlay-fixtures", stubBefore: lifecycle }, "stubBefore");
|
|
45
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Split out of the former 950-line pilot-overlay.ts (see src/ARCHITECTURE.md). Behavior unchanged.
|
|
2
2
|
import { SURFACE } from "../ui/tokens.js";
|
|
3
3
|
import { ensureShadowRoot, installShadowRoot } from "../ui/shadow.js";
|
|
4
|
-
import { pilotFxRingCss } from "../ui/components/ring.js";
|
|
5
|
-
import { WAYGRAPH_RING_CSS } from "../highlights.js";
|
|
6
4
|
// Real, direct user request: this overlay's own colors were an improvised
|
|
7
5
|
// purple/white scheme (#a78bfa / #1a1033) that didn't match anything else -
|
|
8
6
|
// "our design here seems like barely shares with the ui on the stepper
|
|
@@ -64,26 +62,9 @@ const OVERLAY_CSS = `
|
|
|
64
62
|
opacity: 0; transform: translateY(4px); transition: opacity 0.15s, transform 0.15s;
|
|
65
63
|
}
|
|
66
64
|
#wg-pilot-activity.wg-pilot-toast-show { opacity: 1; transform: translateY(0); }
|
|
67
|
-
/* Agent
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
position:fixed;z-index:2147483645;top:72px;max-width:280px;max-height:calc(100vh - 100px);overflow:auto;
|
|
71
|
-
font:12px/1.4 ui-sans-serif,system-ui,sans-serif;color:#fff;
|
|
72
|
-
background:${SURFACE};border-radius:10px;padding:10px 12px;
|
|
73
|
-
box-shadow:0 2px 10px rgba(0,0,0,.3);pointer-events:auto;
|
|
74
|
-
transition:opacity .25s ease;
|
|
75
|
-
}
|
|
76
|
-
#wg-pilot-fx-todos.wg-todo-behind{z-index:2147483643;opacity:.42;pointer-events:none;}
|
|
77
|
-
#wg-pilot-fx-todos[data-pos=left]{left:14px;right:auto;}
|
|
78
|
-
#wg-pilot-fx-todos[data-pos=right]{right:14px;left:auto;}
|
|
79
|
-
#wg-pilot-fx-todos .wg-pilot-fx-todo-title{font-weight:700;color:#c9a6ff;margin-bottom:6px;}
|
|
80
|
-
#wg-pilot-fx-todos ol{margin:0;padding-left:18px;}
|
|
81
|
-
#wg-pilot-fx-todos li{margin:3px 0;color:#ddd;}
|
|
82
|
-
#wg-pilot-fx-todos li.wg-pilot-fx-todo-done{color:#888;text-decoration:line-through;}
|
|
83
|
-
#wg-pilot-fx-todos li.wg-pilot-fx-todo-now{color:#fff;font-weight:700;}
|
|
84
|
-
#wg-pilot-fx-todos[data-compact="1"]:not(:hover) li.wg-todo-fold{display:none;}
|
|
85
|
-
#wg-pilot-fx-todos .wg-todo-more{margin-top:6px;padding:4px 8px;border-radius:8px;
|
|
86
|
-
background:rgba(124,58,237,.22);font:700 11px/1.2 system-ui,sans-serif;color:#e8dcff;}
|
|
65
|
+
/* Agent fixture rings (.wg-pilot-fx-ring/label), #wg-pilot-fx-todos, #wg-ring/#wg-ring-label and
|
|
66
|
+
#wg-banner all come from the ONE shared bundle ensureShadowRoot installs (ui/css/*.css) - not
|
|
67
|
+
redefined here. */
|
|
87
68
|
/* Spotlight (demo focus:true) - dim page, cutout around target. */
|
|
88
69
|
#wg-pilot-fx-focus{position:fixed;z-index:2147483644;pointer-events:none;
|
|
89
70
|
border-radius:12px;box-shadow:0 0 0 9999px rgba(8,4,20,.62);
|
|
@@ -107,7 +88,7 @@ ${pilotFxRingCss()}
|
|
|
107
88
|
#wg-pilot-fx-device[data-preset=mobile]{border-color:#3B82F6;}
|
|
108
89
|
#wg-pilot-fx-device[data-preset=tablet]{border-color:#22C55E;}
|
|
109
90
|
#wg-pilot-fx-device[data-preset=desktop]{border-color:#9CA3AF;}
|
|
110
|
-
|
|
91
|
+
`;
|
|
111
92
|
/** Browser-side shell install — runs on every document via context.addInitScript. */
|
|
112
93
|
function installPilotOverlayShell(css) {
|
|
113
94
|
if (__wgById("wg-pilot-overlay"))
|
package/dist/pilot-overlay.d.ts
CHANGED
package/dist/pilot-overlay.js
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Banner (title card) authoring + verbose log helpers. Mirrors the todo dock's probe/log path
|
|
2
|
+
// so an agent without eyes can read banner state from the demo log.
|
|
3
|
+
import { demoLog } from "./demo-log.js";
|
|
4
|
+
|
|
5
|
+
/** Authored banner UX from a stub phase -> the { pos, collision, hidden } shape installOverlay takes. */
|
|
6
|
+
export function bannerUiFromPhase(phase) {
|
|
7
|
+
const ui = {};
|
|
8
|
+
if (phase && phase.titlePos) ui.pos = phase.titlePos;
|
|
9
|
+
if (phase && phase.bannerUi) {
|
|
10
|
+
if (phase.bannerUi.collision !== undefined) ui.collision = !!phase.bannerUi.collision;
|
|
11
|
+
if (phase.bannerUi.hidden !== undefined) ui.hidden = !!phase.bannerUi.hidden;
|
|
12
|
+
}
|
|
13
|
+
return ui;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Read the live banner: text, position, whether it was moved by ring collision; drains the move log. */
|
|
17
|
+
export async function probeBanner(page) {
|
|
18
|
+
return page
|
|
19
|
+
.evaluate(() => {
|
|
20
|
+
const b = __wgById("wg-banner");
|
|
21
|
+
const log = window.__wgBannerLog || [];
|
|
22
|
+
window.__wgBannerLog = [];
|
|
23
|
+
if (!b) return { present: false, log };
|
|
24
|
+
const r = b.getBoundingClientRect();
|
|
25
|
+
const text = b.querySelector(".wg-banner-text");
|
|
26
|
+
return {
|
|
27
|
+
present: true,
|
|
28
|
+
text: text ? text.textContent : "",
|
|
29
|
+
pos: b.dataset.pos || null,
|
|
30
|
+
home: b.dataset.home || null,
|
|
31
|
+
moved: b.dataset.moved || null,
|
|
32
|
+
collision: b.dataset.collision !== "0",
|
|
33
|
+
hidden: b.style.display === "none",
|
|
34
|
+
authored: b.dataset.authored === "1",
|
|
35
|
+
left: Math.round(r.left),
|
|
36
|
+
top: Math.round(r.top),
|
|
37
|
+
w: Math.round(r.width),
|
|
38
|
+
h: Math.round(r.height),
|
|
39
|
+
log,
|
|
40
|
+
};
|
|
41
|
+
})
|
|
42
|
+
.catch(() => ({ present: false, log: [] }));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function logBannerDom(tag, p) {
|
|
46
|
+
if (!p) return;
|
|
47
|
+
if (!p.present) {
|
|
48
|
+
demoLog(" " + tag + " banner-dom absent");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
demoLog(
|
|
52
|
+
" " + tag + " banner-dom " +
|
|
53
|
+
JSON.stringify(String(p.text || "").slice(0, 60)) +
|
|
54
|
+
"@" + p.pos +
|
|
55
|
+
(p.home && p.home !== p.pos ? " (home=" + p.home + ")" : "") +
|
|
56
|
+
" " + p.left + "," + p.top + " " + p.w + "x" + p.h +
|
|
57
|
+
" collision=" + (p.collision ? "on" : "off") +
|
|
58
|
+
(p.hidden ? " HIDDEN" : "") +
|
|
59
|
+
(p.authored ? " authored" : ""),
|
|
60
|
+
);
|
|
61
|
+
for (const line of p.log || []) demoLog(" " + tag + " banner " + line);
|
|
62
|
+
}
|
package/dist/runner/demo-log.js
CHANGED
|
@@ -109,8 +109,14 @@ function demoTs() {
|
|
|
109
109
|
);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
let logSurface = "demo";
|
|
113
|
+
/** Which surface is talking (demo | auto | browser | pilot) - same log format everywhere, only the tag differs. */
|
|
114
|
+
export function setDemoLogSurface(name) {
|
|
115
|
+
logSurface = String(name || "demo");
|
|
116
|
+
}
|
|
117
|
+
|
|
112
118
|
function demoPrefix() {
|
|
113
|
-
return ansiPaint(ANSI.dim, "[" + demoTs() + "]") + " waygraph
|
|
119
|
+
return ansiPaint(ANSI.dim, "[" + demoTs() + "]") + " waygraph " + logSurface + ": ";
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
export function demoLog(msg) {
|
|
@@ -170,6 +176,8 @@ export function logStubPhaseFixtures(phaseName, phase) {
|
|
|
170
176
|
const tag = "stub." + phaseName;
|
|
171
177
|
if (phase.title) demoFixture(tag, "ctx.title(...)", JSON.stringify(phase.title));
|
|
172
178
|
if (phase.banner) demoFixture(tag, "ctx.banner(...)", JSON.stringify(phase.banner));
|
|
179
|
+
if (phase.titlePos) demoFixture(tag, "ctx.titlePos(...)", JSON.stringify(phase.titlePos));
|
|
180
|
+
if (phase.bannerUi) demoFixture(tag, "ctx.bannerUi(...)", JSON.stringify(phase.bannerUi));
|
|
173
181
|
if (phase.deviceSync && phase.deviceSync !== "keep") {
|
|
174
182
|
demoFixture(
|
|
175
183
|
tag,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// In-page installer (runs inside the browser via page.evaluate): must stay self-contained - no module-scope closure.
|
|
2
2
|
// Split out of the former single installOverlay evaluate (see src/ARCHITECTURE.md). Shares state only via window.__wg*.
|
|
3
3
|
/* eslint-disable no-unused-vars */
|
|
4
|
-
export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi }) {
|
|
4
|
+
export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi, bannerUi }) {
|
|
5
5
|
const POSITIONS = ["left", "center", "right"];
|
|
6
6
|
const applyPos = (el, pos) => {
|
|
7
7
|
el.dataset.pos = pos;
|
|
8
|
+
el.dataset.home = pos;
|
|
8
9
|
try {
|
|
9
10
|
localStorage.setItem("wg-banner-pos", pos);
|
|
10
11
|
} catch {
|
|
@@ -52,6 +53,60 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
52
53
|
text.textContent = title;
|
|
53
54
|
}
|
|
54
55
|
}
|
|
56
|
+
// Authored banner UX (StubCtx.titlePos / bannerUi): applied every step, wins over click/env.
|
|
57
|
+
if (bannerUi) {
|
|
58
|
+
const cur = window.__wgBannerUi || {};
|
|
59
|
+
window.__wgBannerUi = { ...cur, ...bannerUi };
|
|
60
|
+
}
|
|
61
|
+
const bui = window.__wgBannerUi || {};
|
|
62
|
+
const bannerEl = __wgById("wg-banner");
|
|
63
|
+
if (bannerEl) {
|
|
64
|
+
if (bui.pos && POSITIONS.includes(bui.pos) && bannerEl.dataset.home !== bui.pos) {
|
|
65
|
+
bannerEl.dataset.pos = bui.pos;
|
|
66
|
+
bannerEl.dataset.home = bui.pos;
|
|
67
|
+
bannerEl.dataset.authored = "1";
|
|
68
|
+
}
|
|
69
|
+
bannerEl.dataset.collision = bui.collision === false ? "0" : "1";
|
|
70
|
+
bannerEl.style.display = bui.hidden ? "none" : "";
|
|
71
|
+
}
|
|
72
|
+
// Move the banner out of the way of a highlight ring (mirrors the todo dock's collision flip).
|
|
73
|
+
window.__wgBannerAvoidRing = (box) => {
|
|
74
|
+
const b = __wgById("wg-banner");
|
|
75
|
+
if (!b || !box || b.dataset.collision === "0" || b.style.display === "none") return;
|
|
76
|
+
const pad = 10;
|
|
77
|
+
const hits = () => {
|
|
78
|
+
const r = b.getBoundingClientRect();
|
|
79
|
+
return !(
|
|
80
|
+
r.right < box.x - pad ||
|
|
81
|
+
r.left > box.x + box.width + pad ||
|
|
82
|
+
r.bottom < box.y - pad ||
|
|
83
|
+
r.top > box.y + box.height + pad
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
const home = b.dataset.home || b.dataset.pos || "left";
|
|
87
|
+
b.dataset.pos = home;
|
|
88
|
+
if (!hits()) {
|
|
89
|
+
delete b.dataset.moved;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
for (const cand of POSITIONS.filter((p) => p !== home)) {
|
|
93
|
+
b.dataset.pos = cand;
|
|
94
|
+
if (!hits()) {
|
|
95
|
+
b.dataset.moved = home + ">" + cand;
|
|
96
|
+
(window.__wgBannerLog = window.__wgBannerLog || []).push("moved " + home + " -> " + cand + " (ring overlap)");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
b.dataset.pos = home;
|
|
101
|
+
b.dataset.moved = "none-free";
|
|
102
|
+
(window.__wgBannerLog = window.__wgBannerLog || []).push("overlap at every position (kept " + home + ")");
|
|
103
|
+
};
|
|
104
|
+
window.__wgBannerRestore = () => {
|
|
105
|
+
const b = __wgById("wg-banner");
|
|
106
|
+
if (!b) return;
|
|
107
|
+
if (b.dataset.home) b.dataset.pos = b.dataset.home;
|
|
108
|
+
delete b.dataset.moved;
|
|
109
|
+
};
|
|
55
110
|
// Tab title/favicon: a real navigation resets document.title and any
|
|
56
111
|
// <link rel="icon"> the new document brings, so re-check (not
|
|
57
112
|
// re-append) on every call instead of a one-time flag.
|
|
@@ -114,6 +114,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
114
114
|
ringLabel.style.top = labelTop + "px";
|
|
115
115
|
if (window.__wgTodosSetBehind) window.__wgTodosSetBehind(true);
|
|
116
116
|
if (window.__wgTodosAvoidRingCollision) window.__wgTodosAvoidRingCollision(box);
|
|
117
|
+
if (window.__wgBannerAvoidRing) window.__wgBannerAvoidRing(box);
|
|
117
118
|
};
|
|
118
119
|
/** Dim/lower floating todo docks while a ring caption is the focus. */
|
|
119
120
|
window.__wgTodosSetBehind = (on) => {
|
|
@@ -220,6 +221,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
220
221
|
if (ringLabel) ringLabel.style.opacity = "0";
|
|
221
222
|
if (window.__wgClearFocus) window.__wgClearFocus();
|
|
222
223
|
if (window.__wgTodosSetBehind) window.__wgTodosSetBehind(false);
|
|
224
|
+
if (window.__wgBannerRestore) window.__wgBannerRestore();
|
|
223
225
|
window.__wgTodoCollisionLocked = false;
|
|
224
226
|
__wgQA(".wg-todo-dock[data-tucked], #wg-todo-dock[data-tucked]").forEach((el) => {
|
|
225
227
|
delete el.dataset.tucked;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
|
|
2
2
|
// Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
|
|
3
|
-
import { WAYGRAPH_RING_CSS } from "../highlights.js";
|
|
4
|
-
import { cursorCss } from "../ui/components/cursor.js";
|
|
5
3
|
import { SURFACE } from "../ui/tokens.js";
|
|
6
4
|
|
|
7
5
|
// ---------------------------------------------------------------------------
|
|
@@ -13,22 +11,11 @@ import { SURFACE } from "../ui/tokens.js";
|
|
|
13
11
|
// label-under-box language, minus everything camera/narration-specific).
|
|
14
12
|
// Purely CLI-level orchestration - no engine changes, no change to the
|
|
15
13
|
// non-STEP path above.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// Mouse cursor icon that travels to a target before it's acted on, plus a
|
|
22
|
-
// quick expanding ripple at the moment of a click - same idea as
|
|
23
|
-
// help-center-clip-engine's #clip-cursor/#clip-ring (video-pipeline). The
|
|
24
|
-
// shape itself is an inline SVG set as innerHTML in installOverlay below
|
|
25
|
-
// (dark fill + white stroke, same as the clip-engine's own cursor) - a
|
|
26
|
-
// plain solid-white CSS clip-path (the first attempt here) had no outline
|
|
27
|
-
// at all and all but disappeared against this app's light background.
|
|
28
|
-
// Travel duration is JS-driven per call via --wg-cursor-ms, same reason
|
|
29
|
-
// the clip engine's own comment gives: a hardcoded CSS duration would
|
|
30
|
-
// make the speed param a no-op.
|
|
31
|
-
cursorCss() +
|
|
14
|
+
// Runner-only chrome (step panel, todo-dock legacy variant, zoom/typing/device chips) - NOT
|
|
15
|
+
// ring/cursor/banner, which come from the one shared bundle every surface installs
|
|
16
|
+
// (ui/css/*.css, see ensureShadowRoot in overlay-install.js). Injected under its own key so it
|
|
17
|
+
// never collides with that bundle.
|
|
18
|
+
export const RUNNER_EXTRA_CSS =
|
|
32
19
|
// Spotlight: dim everything except the highlight target (focus: true).
|
|
33
20
|
"#wg-focus-veil{position:fixed;z-index:2147483644;pointer-events:none;" +
|
|
34
21
|
"border-radius:12px;box-shadow:0 0 0 9999px rgba(8,4,20,.62);" +
|
|
@@ -225,15 +212,7 @@ export const RING_CSS =
|
|
|
225
212
|
"#wg-modules .wg-mod-done{background:#2a1650;color:#9a7ad1;}" +
|
|
226
213
|
"#wg-modules .wg-mod-current{background:#7C3AED;color:#fff;}" +
|
|
227
214
|
"#wg-modules .wg-mod-upcoming{background:transparent;color:#5a4a80;border:1px solid #3a2a60;}" +
|
|
228
|
-
|
|
229
|
-
"background:" + SURFACE + ";color:#fff;border-radius:12px;padding:10px 16px;" +
|
|
230
|
-
"font:14px/1.4 system-ui,sans-serif;box-shadow:0 8px 20px rgba(0,0,0,.3);" +
|
|
231
|
-
"border:1px solid rgba(124,58,237,.4);cursor:pointer;user-select:none;}" +
|
|
232
|
-
"#wg-banner[data-pos=left]{left:14px;right:auto;transform:none;}" +
|
|
233
|
-
"#wg-banner[data-pos=center]{left:50%;right:auto;transform:translateX(-50%);}" +
|
|
234
|
-
"#wg-banner[data-pos=right]{right:14px;left:auto;transform:none;}" +
|
|
235
|
-
"#wg-banner .wg-banner-tag{display:block;font-size:10px;font-weight:700;color:#c9a6ff;" +
|
|
236
|
-
"letter-spacing:.05em;text-transform:uppercase;margin-bottom:2px;}" +
|
|
215
|
+
// #wg-banner: comes from the shared bundle (ui/css/banner.css) now - not redefined here.
|
|
237
216
|
"#wg-panel .wg-key{margin:8px 0;}" +
|
|
238
217
|
// A live, human-readable preview of what's about to be written for this
|
|
239
218
|
// MemKey - Dan: "i want pretty to exist in memkeys too... it shows what
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
|
|
2
2
|
// Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
|
|
3
|
-
import { HOST_CSS,
|
|
3
|
+
import { HOST_CSS, RUNNER_EXTRA_CSS, WAYGRAPH_FAVICON } from "./overlay-css.js";
|
|
4
4
|
import { ensureShadowRoot } from "../ui/shadow.js";
|
|
5
5
|
import { resolveTodoDockUi } from "../highlights.js";
|
|
6
6
|
import { installCore } from "./inpage/core.js";
|
|
@@ -12,9 +12,12 @@ import { installTodos } from "./inpage/todos.js";
|
|
|
12
12
|
import { installDevice } from "./inpage/device.js";
|
|
13
13
|
import { applyVideoDeviceStage } from "./device-stage.js";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/** `ui` = authored banner UX from the stub phase: { pos, collision, hidden } (all optional). */
|
|
16
|
+
export async function installOverlay(page, title, ui) {
|
|
17
|
+
// ring/cursor/banner/dock come from the ONE shared bundle every surface installs (ui/css/*.css).
|
|
16
18
|
await ensureShadowRoot(page);
|
|
17
|
-
|
|
19
|
+
// Runner-only chrome (step panel, zoom/typing/device chips) - separate key, no collision.
|
|
20
|
+
await page.evaluate(([css, key]) => __wgCss(css, key), [RUNNER_EXTRA_CSS, "wg-runner-css"]).catch(() => {});
|
|
18
21
|
await page.addStyleTag({ content: HOST_CSS }).catch(() => {});
|
|
19
22
|
// Default top-left; override with WAYGRAPH_TITLE_POS=left|center|right.
|
|
20
23
|
// Click cycles left -> center -> right (persisted in localStorage so a
|
|
@@ -25,7 +28,7 @@ export async function installOverlay(page, title) {
|
|
|
25
28
|
const todoPos = envTodoPos === "right" ? "right" : "left";
|
|
26
29
|
const envAutoplay = process.env.WAYGRAPH_AUTOPLAY === "1";
|
|
27
30
|
const todoDockUi = resolveTodoDockUi();
|
|
28
|
-
const args = { title, favicon: WAYGRAPH_FAVICON, bannerPos, todoPos, envAutoplay, todoDockUi };
|
|
31
|
+
const args = { title, favicon: WAYGRAPH_FAVICON, bannerPos, todoPos, envAutoplay, todoDockUi, bannerUi: ui || null };
|
|
29
32
|
await page.evaluate(installCore, args).catch(() => {});
|
|
30
33
|
await page.evaluate(installSwipeZoom, args).catch(() => {});
|
|
31
34
|
await page.evaluate(installBanner, args).catch(() => {});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Page } from "@playwright/test";
|
|
2
|
+
import type { StubPhaseResult } from "../highlights/types.js";
|
|
3
|
+
|
|
4
|
+
export interface SessionOverlay {
|
|
5
|
+
present(tag: string, phase: Partial<StubPhaseResult>): Promise<void>;
|
|
6
|
+
restore(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export function createSessionOverlay(page: Page, surface: string): SessionOverlay;
|