waygraph 0.15.30 → 0.15.32
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/auto-explore-run.js +9 -6
- package/dist/auto-session/session.js +2 -1
- package/dist/pilot-overlay/action-ring.d.ts +16 -0
- package/dist/pilot-overlay/action-ring.js +67 -0
- package/dist/pilot-overlay/fixtures.js +17 -17
- package/dist/pilot-overlay/panel.js +3 -3
- package/dist/pilot-overlay/shell.js +27 -27
- package/dist/pilot-overlay.d.ts +1 -0
- package/dist/pilot-overlay.js +1 -0
- package/dist/runner/cursor.js +3 -3
- package/dist/runner/inpage/banner.js +2 -2
- package/dist/runner/inpage/core.js +23 -23
- package/dist/runner/inpage/device.js +11 -11
- package/dist/runner/inpage/panel-chrome.js +3 -3
- package/dist/runner/inpage/stamp.js +2 -2
- package/dist/runner/inpage/swipe-zoom.js +10 -10
- package/dist/runner/inpage/todos.js +6 -6
- package/dist/runner/overlay-css.js +21 -18
- package/dist/runner/overlay-install.js +5 -2
- package/dist/runner/rings.js +1 -1
- package/dist/runner/slides.js +11 -11
- package/dist/runner/step-panels.js +18 -18
- package/dist/runner/teardown.js +8 -8
- package/dist/runner/todo-dock.js +1 -1
- package/dist/step-overlay.js +20 -18
- package/dist/ui/components/ring.js +5 -0
- package/dist/ui/shadow.d.ts +15 -0
- package/dist/ui/shadow.js +42 -0
- package/examples/saucedemo/.waygraph-auto/1bd7b7bf.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2a577961.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2c79c73a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2c94a05b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/37b56184.log +0 -0
- package/examples/saucedemo/.waygraph-auto/401177a3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/476cff76.log +0 -0
- package/examples/saucedemo/.waygraph-auto/535e8922.json +8 -0
- package/examples/saucedemo/.waygraph-auto/535e8922.log +0 -0
- package/examples/saucedemo/.waygraph-auto/68fa0682.log +0 -0
- package/examples/saucedemo/.waygraph-auto/73a41843.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8598b4c0.log +0 -0
- package/examples/saucedemo/.waygraph-auto/982138cf.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a8645294.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bf8693e7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f86224c6.log +0 -0
- package/examples/saucedemo/.waygraph-auto/fc917c18.log +0 -0
- package/examples/saucedemo/.waygraph-auto/fe83305d.log +0 -0
- package/package.json +1 -1
package/dist/step-overlay.js
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
|
+
import { ensureShadowRoot } from "./ui/shadow.js";
|
|
1
2
|
import { composeStepOverlay } from "./ui/compose.js";
|
|
2
3
|
const RING_CSS = composeStepOverlay();
|
|
3
4
|
const FAVICON = "data:image/svg+xml," +
|
|
4
5
|
encodeURIComponent("<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><circle cx='16' cy='16' r='14' fill='#7C3AED'/></svg>");
|
|
5
6
|
export async function installDemoChrome(page, title = "waygraph auto", options = {}) {
|
|
6
7
|
const showBanner = options.banner !== false;
|
|
7
|
-
await page
|
|
8
|
+
await ensureShadowRoot(page);
|
|
9
|
+
await page.evaluate(([css, key]) => __wgCss(css, key), [RING_CSS, "wg-overlay-css"]).catch(() => { });
|
|
8
10
|
await page
|
|
9
11
|
.evaluate(({ title, favicon, showBanner }) => {
|
|
10
|
-
if (!
|
|
12
|
+
if (!__wgById("wg-ring")) {
|
|
11
13
|
const ring = document.createElement("div");
|
|
12
14
|
ring.id = "wg-ring";
|
|
13
|
-
|
|
15
|
+
__wgAdd(ring);
|
|
14
16
|
}
|
|
15
|
-
if (!
|
|
17
|
+
if (!__wgById("wg-ring-label")) {
|
|
16
18
|
const ringLabel = document.createElement("div");
|
|
17
19
|
ringLabel.id = "wg-ring-label";
|
|
18
|
-
|
|
20
|
+
__wgAdd(ringLabel);
|
|
19
21
|
}
|
|
20
|
-
if (!
|
|
22
|
+
if (!__wgById("wg-cursor")) {
|
|
21
23
|
const cursor = document.createElement("div");
|
|
22
24
|
cursor.id = "wg-cursor";
|
|
23
25
|
cursor.innerHTML =
|
|
24
26
|
"<svg viewBox='0 0 32 32' width='24' height='24'>" +
|
|
25
27
|
"<path fill='#0C0C1A' stroke='#fff' stroke-width='1.4' stroke-linejoin='round' " +
|
|
26
28
|
"d='M6 3.5l1.4 22.5 5.8-5.4 4.2 9.4 3.6-1.6-4.2-9.2H26z'/></svg>";
|
|
27
|
-
|
|
29
|
+
__wgAdd(cursor);
|
|
28
30
|
}
|
|
29
|
-
if (!
|
|
31
|
+
if (!__wgById("wg-click-pulse")) {
|
|
30
32
|
const pulse = document.createElement("div");
|
|
31
33
|
pulse.id = "wg-click-pulse";
|
|
32
|
-
|
|
34
|
+
__wgAdd(pulse);
|
|
33
35
|
}
|
|
34
36
|
window.__wgMoveCursorTo = (x, y, ms) => {
|
|
35
|
-
const cursor =
|
|
37
|
+
const cursor = __wgById("wg-cursor");
|
|
36
38
|
if (!cursor)
|
|
37
39
|
return;
|
|
38
40
|
cursor.style.setProperty("--wg-cursor-ms", (ms || 600) + "ms");
|
|
@@ -40,7 +42,7 @@ export async function installDemoChrome(page, title = "waygraph auto", options =
|
|
|
40
42
|
cursor.style.opacity = "1";
|
|
41
43
|
};
|
|
42
44
|
window.__wgClickPulse = (x, y, tone) => {
|
|
43
|
-
const pulse =
|
|
45
|
+
const pulse = __wgById("wg-click-pulse");
|
|
44
46
|
if (!pulse)
|
|
45
47
|
return;
|
|
46
48
|
const raw = (tone || "planned") + "";
|
|
@@ -59,8 +61,8 @@ export async function installDemoChrome(page, title = "waygraph auto", options =
|
|
|
59
61
|
pulse.classList.add("wg-pulse");
|
|
60
62
|
};
|
|
61
63
|
window.__wgPositionRing = (box, label, tone, style) => {
|
|
62
|
-
const ring =
|
|
63
|
-
const ringLabel =
|
|
64
|
+
const ring = __wgById("wg-ring");
|
|
65
|
+
const ringLabel = __wgById("wg-ring-label");
|
|
64
66
|
if (!ring || !ringLabel)
|
|
65
67
|
return;
|
|
66
68
|
const raw = (tone || "planned") + "";
|
|
@@ -92,25 +94,25 @@ export async function installDemoChrome(page, title = "waygraph auto", options =
|
|
|
92
94
|
ringLabel.style.opacity = "1";
|
|
93
95
|
};
|
|
94
96
|
window.__wgHideRing = () => {
|
|
95
|
-
const ring =
|
|
96
|
-
const ringLabel =
|
|
97
|
+
const ring = __wgById("wg-ring");
|
|
98
|
+
const ringLabel = __wgById("wg-ring-label");
|
|
97
99
|
if (ring)
|
|
98
100
|
ring.style.opacity = "0";
|
|
99
101
|
if (ringLabel)
|
|
100
102
|
ringLabel.style.opacity = "0";
|
|
101
103
|
};
|
|
102
|
-
if (showBanner && title && !
|
|
104
|
+
if (showBanner && title && !__wgById("wg-banner")) {
|
|
103
105
|
const banner = document.createElement("div");
|
|
104
106
|
banner.id = "wg-banner";
|
|
105
107
|
banner.innerHTML =
|
|
106
108
|
"<span class='wg-banner-tag'>waygraph auto</span><span>" + title + "</span>";
|
|
107
|
-
|
|
109
|
+
__wgAdd(banner);
|
|
108
110
|
banner.setAttribute("data-wg-ui", "1");
|
|
109
111
|
banner.setAttribute("data-wg-modal", "banner");
|
|
110
112
|
banner.setAttribute("data-wg-ready", "1");
|
|
111
113
|
}
|
|
112
114
|
else {
|
|
113
|
-
const existing =
|
|
115
|
+
const existing = __wgById("wg-banner");
|
|
114
116
|
if (existing) {
|
|
115
117
|
existing.setAttribute("data-wg-ui", "1");
|
|
116
118
|
existing.setAttribute("data-wg-modal", "banner");
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { TONES } from "../tokens.js";
|
|
2
|
+
/** Prefix icon for gray (auto) labels. */
|
|
3
|
+
const ROBOT = 'content:"\\1F916\\00a0";';
|
|
2
4
|
const toneNames = Object.keys(TONES);
|
|
3
5
|
/** Tone rules for `sel[data-tone=x]{...}` from the token table. */
|
|
4
6
|
function toneRules(sel, decl, only) {
|
|
@@ -17,6 +19,8 @@ export function ringCss() {
|
|
|
17
19
|
`max-width:min(360px,70vw);white-space:normal;padding:6px 10px;border-radius:7px;background:${p.labelBg};color:${p.labelFg};` +
|
|
18
20
|
"font:600 12px/1.35 system-ui,sans-serif;transition:opacity .3s ease;}" +
|
|
19
21
|
toneRules("#wg-ring-label", (t) => `background:${t.labelBg};color:${t.labelFg};`) +
|
|
22
|
+
// Gray = a real Playwright-driven instruction: mark it with a robot.
|
|
23
|
+
`#wg-ring-label[data-tone=auto]::before{${ROBOT}}` +
|
|
20
24
|
"#wg-ring[data-size=sm]{border-width:1.5px;border-radius:8px;}" +
|
|
21
25
|
"#wg-ring[data-size=lg]{border-width:4px;border-radius:12px;}" +
|
|
22
26
|
"#wg-ring-label[data-size=sm]{font-size:10px;line-height:1.25;padding:4px 7px;border-radius:5px;}" +
|
|
@@ -36,6 +40,7 @@ export function pilotFxRingCss() {
|
|
|
36
40
|
"max-width:min(360px,80vw);box-shadow:0 2px 8px rgba(0,0,0,.25);white-space:nowrap;" +
|
|
37
41
|
"overflow:hidden;text-overflow:ellipsis;transition:opacity .12s ease;}" +
|
|
38
42
|
toneRules(".wg-pilot-fx-label", (t) => `background:${t.labelBg};color:${t.labelFg};`) +
|
|
43
|
+
`.wg-pilot-fx-label[data-tone=auto]::before{${ROBOT}}` +
|
|
39
44
|
".wg-pilot-fx-ring[data-size=sm]{border-width:1.5px;border-radius:8px;}" +
|
|
40
45
|
".wg-pilot-fx-ring[data-size=lg]{border-width:4px;border-radius:12px;}" +
|
|
41
46
|
".wg-pilot-fx-label[data-size=sm]{font-size:10px;padding:4px 7px;}" +
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shadow-DOM mount for every waygraph overlay element. Overlay UI lives in one open shadow root under
|
|
3
|
+
* `<div id="wg-root">`, so the host page's CSS can't restyle it and ours can't leak out.
|
|
4
|
+
*
|
|
5
|
+
* `installShadowRoot` runs INSIDE the page (page.evaluate / addInitScript), so it must stay
|
|
6
|
+
* self-contained. It defines the `__wg*` helpers the overlay code uses in place of `document.*`:
|
|
7
|
+
* lookups check the shadow root first and fall back to the light DOM (the device stage shell and
|
|
8
|
+
* host-page markers such as `[data-wg-zoomed]` intentionally stay in the light DOM).
|
|
9
|
+
*/
|
|
10
|
+
import type { BrowserContext, Page } from "@playwright/test";
|
|
11
|
+
export declare function installShadowRoot(): void;
|
|
12
|
+
/** Idempotent; call before any overlay install on a page. */
|
|
13
|
+
export declare function ensureShadowRoot(page: Page): Promise<void>;
|
|
14
|
+
/** Also define the helpers on every future document (pilot overlay persists across navigations). */
|
|
15
|
+
export declare function installShadowRootEverywhere(context: BrowserContext): Promise<void>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function installShadowRoot() {
|
|
2
|
+
const w = window;
|
|
3
|
+
if (w.__wgById)
|
|
4
|
+
return;
|
|
5
|
+
const root = () => {
|
|
6
|
+
let host = document.getElementById("wg-root");
|
|
7
|
+
if (!host || !host.shadowRoot) {
|
|
8
|
+
host?.remove();
|
|
9
|
+
host = document.createElement("div");
|
|
10
|
+
host.id = "wg-root";
|
|
11
|
+
// No box of its own: children are position:fixed, so the host must never affect page layout.
|
|
12
|
+
host.style.cssText = "display:contents";
|
|
13
|
+
host.attachShadow({ mode: "open" });
|
|
14
|
+
document.documentElement.appendChild(host);
|
|
15
|
+
}
|
|
16
|
+
return host.shadowRoot;
|
|
17
|
+
};
|
|
18
|
+
w.__wgRoot = root;
|
|
19
|
+
w.__wgById = (id) => root().getElementById(id) || document.getElementById(id);
|
|
20
|
+
w.__wgQ = (sel) => root().querySelector(sel) || document.querySelector(sel);
|
|
21
|
+
w.__wgQA = (sel) => Array.from(root().querySelectorAll(sel)).concat(Array.from(document.querySelectorAll(sel)));
|
|
22
|
+
w.__wgAdd = (node) => root().appendChild(node);
|
|
23
|
+
w.__wgCss = (css, key) => {
|
|
24
|
+
const r = root();
|
|
25
|
+
let style = Array.from(r.children).find((c) => c.tagName === "STYLE" && c.getAttribute("data-key") === key);
|
|
26
|
+
if (!style) {
|
|
27
|
+
style = document.createElement("style");
|
|
28
|
+
style.setAttribute("data-key", key);
|
|
29
|
+
r.insertBefore(style, r.firstChild);
|
|
30
|
+
}
|
|
31
|
+
if (style.textContent !== css)
|
|
32
|
+
style.textContent = css;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Idempotent; call before any overlay install on a page. */
|
|
36
|
+
export async function ensureShadowRoot(page) {
|
|
37
|
+
await page.evaluate(installShadowRoot).catch(() => { });
|
|
38
|
+
}
|
|
39
|
+
/** Also define the helpers on every future document (pilot overlay persists across navigations). */
|
|
40
|
+
export async function installShadowRootEverywhere(context) {
|
|
41
|
+
await context.addInitScript(installShadowRoot);
|
|
42
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|