waygraph 0.15.28 → 0.15.29
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/runner/inpage/banner.js +68 -0
- package/dist/runner/inpage/core.js +267 -0
- package/dist/runner/inpage/device.js +211 -0
- package/dist/runner/inpage/panel-chrome.js +152 -0
- package/dist/runner/inpage/stamp.js +46 -0
- package/dist/runner/inpage/swipe-zoom.js +220 -0
- package/dist/runner/inpage/todos.js +332 -0
- package/dist/runner/overlay-install.js +15 -1269
- package/examples/saucedemo/.waygraph-auto/3f088138.log +0 -0
- package/examples/saucedemo/.waygraph-auto/94221b2b.log +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// In-page installer (runs inside the browser via page.evaluate): must stay self-contained - no module-scope closure.
|
|
2
|
+
// Split out of the former single installOverlay evaluate (see src/ARCHITECTURE.md). Shares state only via window.__wg*.
|
|
3
|
+
/* eslint-disable no-unused-vars */
|
|
4
|
+
export function installPanelChrome({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi }) {
|
|
5
|
+
// Hide/Show for #wg-panel - call after every panel.innerHTML refresh.
|
|
6
|
+
// Collapsed = "N / M · block" + Next (when not auto). Never pass
|
|
7
|
+
// forceCollapsed:false - omit so Hide/localStorage wins.
|
|
8
|
+
window.__wgWirePanelChrome = (panel, storageKey, chromeTitle, opts) => {
|
|
9
|
+
if (!panel) return;
|
|
10
|
+
opts = opts || {};
|
|
11
|
+
const ensureChrome = () => {
|
|
12
|
+
let chrome = panel.querySelector(":scope > .wg-chrome");
|
|
13
|
+
if (!chrome) {
|
|
14
|
+
const body = document.createElement("div");
|
|
15
|
+
body.className = "wg-body";
|
|
16
|
+
while (panel.firstChild) body.appendChild(panel.firstChild);
|
|
17
|
+
chrome = document.createElement("div");
|
|
18
|
+
chrome.className = "wg-chrome";
|
|
19
|
+
const titleEl = document.createElement("span");
|
|
20
|
+
titleEl.className = "wg-chrome-title";
|
|
21
|
+
titleEl.textContent = chromeTitle || "waygraph demo";
|
|
22
|
+
const actions = document.createElement("div");
|
|
23
|
+
actions.className = "wg-chrome-actions";
|
|
24
|
+
const nextBtn = document.createElement("button");
|
|
25
|
+
nextBtn.type = "button";
|
|
26
|
+
nextBtn.className = "wg-mini-next";
|
|
27
|
+
nextBtn.setAttribute("data-wg-mini-next", "1");
|
|
28
|
+
nextBtn.textContent = "Next ▶";
|
|
29
|
+
const btn = document.createElement("button");
|
|
30
|
+
btn.type = "button";
|
|
31
|
+
btn.className = "wg-hide-btn";
|
|
32
|
+
btn.setAttribute("data-wg-toggle", "1");
|
|
33
|
+
btn.textContent = "Hide";
|
|
34
|
+
actions.appendChild(nextBtn);
|
|
35
|
+
actions.appendChild(btn);
|
|
36
|
+
chrome.appendChild(titleEl);
|
|
37
|
+
chrome.appendChild(actions);
|
|
38
|
+
panel.appendChild(chrome);
|
|
39
|
+
panel.appendChild(body);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Yap slides ship a bare chrome - ensure actions + mini Next exist.
|
|
43
|
+
let actions = chrome.querySelector(".wg-chrome-actions");
|
|
44
|
+
if (!actions) {
|
|
45
|
+
actions = document.createElement("div");
|
|
46
|
+
actions.className = "wg-chrome-actions";
|
|
47
|
+
const hide = chrome.querySelector("[data-wg-toggle]");
|
|
48
|
+
if (hide) actions.appendChild(hide);
|
|
49
|
+
chrome.appendChild(actions);
|
|
50
|
+
}
|
|
51
|
+
if (!actions.querySelector("[data-wg-mini-next]")) {
|
|
52
|
+
const nextBtn = document.createElement("button");
|
|
53
|
+
nextBtn.type = "button";
|
|
54
|
+
nextBtn.className = "wg-mini-next";
|
|
55
|
+
nextBtn.setAttribute("data-wg-mini-next", "1");
|
|
56
|
+
nextBtn.textContent = "Next ▶";
|
|
57
|
+
actions.insertBefore(nextBtn, actions.firstChild);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
ensureChrome();
|
|
61
|
+
const stepLabel = opts.stepLabel || panel.dataset.wgStepLabel || "";
|
|
62
|
+
if (stepLabel) panel.dataset.wgStepLabel = stepLabel;
|
|
63
|
+
const syncMiniNext = (hidden) => {
|
|
64
|
+
const miniNext = panel.querySelector("[data-wg-mini-next]");
|
|
65
|
+
if (!miniNext) return;
|
|
66
|
+
let auto = false;
|
|
67
|
+
try {
|
|
68
|
+
auto = localStorage.getItem("wg-autoplay") === "1";
|
|
69
|
+
} catch {
|
|
70
|
+
/* ignore */
|
|
71
|
+
}
|
|
72
|
+
const runBtn = document.getElementById("wg-run");
|
|
73
|
+
const show = !!hidden && !auto && !!runBtn;
|
|
74
|
+
miniNext.classList.toggle("wg-mini-next-show", show);
|
|
75
|
+
if (runBtn) {
|
|
76
|
+
miniNext.textContent = runBtn.textContent || "Next ▶";
|
|
77
|
+
miniNext.disabled = !!runBtn.disabled;
|
|
78
|
+
} else {
|
|
79
|
+
miniNext.disabled = true;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const apply = (hidden, persist) => {
|
|
83
|
+
panel.classList.toggle("wg-collapsed", hidden);
|
|
84
|
+
panel.setAttribute("data-wg-collapsed", hidden ? "1" : "0");
|
|
85
|
+
const t = panel.querySelector("[data-wg-toggle]");
|
|
86
|
+
const titleEl = panel.querySelector(".wg-chrome-title");
|
|
87
|
+
const label = panel.dataset.wgStepLabel || stepLabel;
|
|
88
|
+
if (titleEl) {
|
|
89
|
+
titleEl.textContent = hidden
|
|
90
|
+
? (label || chromeTitle || "waygraph demo")
|
|
91
|
+
: (chromeTitle || "waygraph demo");
|
|
92
|
+
}
|
|
93
|
+
if (t) t.textContent = hidden ? "Show" : "Hide";
|
|
94
|
+
syncMiniNext(hidden);
|
|
95
|
+
if (persist !== false) {
|
|
96
|
+
try {
|
|
97
|
+
localStorage.setItem(storageKey, hidden ? "1" : "0");
|
|
98
|
+
} catch {
|
|
99
|
+
/* private mode */
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
let hidden = false;
|
|
104
|
+
if (opts.forceCollapsed === true) {
|
|
105
|
+
hidden = true;
|
|
106
|
+
} else {
|
|
107
|
+
try {
|
|
108
|
+
hidden = localStorage.getItem(storageKey) === "1";
|
|
109
|
+
} catch {
|
|
110
|
+
/* ignore */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// force mini does not overwrite Hide preference in storage.
|
|
114
|
+
apply(hidden, opts.forceCollapsed === true ? false : true);
|
|
115
|
+
const toggle = panel.querySelector("[data-wg-toggle]");
|
|
116
|
+
if (toggle && !toggle.dataset.wgWired) {
|
|
117
|
+
toggle.dataset.wgWired = "1";
|
|
118
|
+
toggle.addEventListener("click", (e) => {
|
|
119
|
+
e.stopPropagation();
|
|
120
|
+
apply(!panel.classList.contains("wg-collapsed"), true);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const miniNext = panel.querySelector("[data-wg-mini-next]");
|
|
124
|
+
if (miniNext && !miniNext.dataset.wgWired) {
|
|
125
|
+
miniNext.dataset.wgWired = "1";
|
|
126
|
+
miniNext.addEventListener("click", (e) => {
|
|
127
|
+
e.stopPropagation();
|
|
128
|
+
const runBtn = document.getElementById("wg-run");
|
|
129
|
+
if (runBtn && !runBtn.disabled) {
|
|
130
|
+
runBtn.click();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (typeof window.__wgNext === "function") window.__wgNext({});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const autoCb = document.getElementById("wg-autoplay-cb");
|
|
137
|
+
if (autoCb && !autoCb.dataset.wgMiniWired) {
|
|
138
|
+
autoCb.dataset.wgMiniWired = "1";
|
|
139
|
+
autoCb.addEventListener("change", () => {
|
|
140
|
+
syncMiniNext(panel.classList.contains("wg-collapsed"));
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const cur = panel.querySelector("#wg-modules .wg-mod-current");
|
|
144
|
+
if (cur && typeof cur.scrollIntoView === "function") {
|
|
145
|
+
try {
|
|
146
|
+
cur.scrollIntoView({ inline: "center", block: "nearest", behavior: "smooth" });
|
|
147
|
+
} catch {
|
|
148
|
+
cur.scrollIntoView(false);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// In-page installer (runs inside the browser via page.evaluate): must stay self-contained - no module-scope closure.
|
|
2
|
+
// Split out of the former single installOverlay evaluate (see src/ARCHITECTURE.md). Shares state only via window.__wg*.
|
|
3
|
+
/* eslint-disable no-unused-vars */
|
|
4
|
+
export function installStamp({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi }) {
|
|
5
|
+
// Blind-agent overlay beacons: every modal root gets data-wg-ui /
|
|
6
|
+
// data-wg-modal / data-wg-ready so tests can fail on a blank panel.
|
|
7
|
+
window.__wgStampModal = (el, kind, meta) => {
|
|
8
|
+
if (!el) return;
|
|
9
|
+
meta = meta || {};
|
|
10
|
+
el.setAttribute("data-wg-ui", "1");
|
|
11
|
+
el.setAttribute("data-wg-modal", kind || "panel");
|
|
12
|
+
if (meta.phase != null) el.setAttribute("data-wg-phase", String(meta.phase));
|
|
13
|
+
if (meta.step != null) el.setAttribute("data-wg-step", String(meta.step));
|
|
14
|
+
if (meta.total != null) el.setAttribute("data-wg-total", String(meta.total));
|
|
15
|
+
if (meta.block != null) el.setAttribute("data-wg-block", String(meta.block));
|
|
16
|
+
el.setAttribute(
|
|
17
|
+
"data-wg-collapsed",
|
|
18
|
+
el.classList.contains("wg-collapsed") ? "1" : "0",
|
|
19
|
+
);
|
|
20
|
+
el.setAttribute("data-wg-ready", meta.ready === false ? "0" : "1");
|
|
21
|
+
};
|
|
22
|
+
window.__wgOverlayBeacon = () => {
|
|
23
|
+
return Array.from(document.querySelectorAll("[data-wg-ui=\"1\"]")).map((el) => {
|
|
24
|
+
const r = el.getBoundingClientRect();
|
|
25
|
+
const st = getComputedStyle(el);
|
|
26
|
+
return {
|
|
27
|
+
id: el.id || null,
|
|
28
|
+
modal: el.getAttribute("data-wg-modal"),
|
|
29
|
+
ready: el.getAttribute("data-wg-ready") === "1",
|
|
30
|
+
phase: el.getAttribute("data-wg-phase"),
|
|
31
|
+
step: el.getAttribute("data-wg-step"),
|
|
32
|
+
block: el.getAttribute("data-wg-block"),
|
|
33
|
+
collapsed:
|
|
34
|
+
el.getAttribute("data-wg-collapsed") === "1" ||
|
|
35
|
+
el.classList.contains("wg-collapsed"),
|
|
36
|
+
opacity: st.opacity,
|
|
37
|
+
textLen: (el.innerText || "").trim().length,
|
|
38
|
+
w: Math.round(r.width),
|
|
39
|
+
h: Math.round(r.height),
|
|
40
|
+
visible: r.width > 0 && r.height > 0 && Number(st.opacity) > 0.05,
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const existingBanner = document.getElementById("wg-banner");
|
|
45
|
+
if (existingBanner) window.__wgStampModal(existingBanner, "banner", { ready: true });
|
|
46
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// In-page installer (runs inside the browser via page.evaluate): must stay self-contained - no module-scope closure.
|
|
2
|
+
// Split out of the former single installOverlay evaluate (see src/ARCHITECTURE.md). Shares state only via window.__wg*.
|
|
3
|
+
/* eslint-disable no-unused-vars */
|
|
4
|
+
export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi }) {
|
|
5
|
+
/**
|
|
6
|
+
* Finger swipe trail for touch theater (orientation rotate / device change).
|
|
7
|
+
* opts: { dir: 'left'|'right'|'up'|'down', label?, ms? }
|
|
8
|
+
* Returns duration waited (ms) via Promise when called from page.evaluate async.
|
|
9
|
+
*/
|
|
10
|
+
window.__wgSwipeTrail = (opts) => {
|
|
11
|
+
const o = opts || {};
|
|
12
|
+
const dir = o.dir === "right" || o.dir === "up" || o.dir === "down" ? o.dir : "left";
|
|
13
|
+
const ms = Math.max(280, Math.min(1400, Number(o.ms) || 720));
|
|
14
|
+
const label =
|
|
15
|
+
o.label ||
|
|
16
|
+
(dir === "left" || dir === "right" ? "swipe" : "swipe") +
|
|
17
|
+
(o.hint ? " \u00b7 " + o.hint : "");
|
|
18
|
+
let layer = document.getElementById("wg-swipe-layer");
|
|
19
|
+
if (layer && layer._wgTimer) {
|
|
20
|
+
clearTimeout(layer._wgTimer);
|
|
21
|
+
layer._wgTimer = null;
|
|
22
|
+
}
|
|
23
|
+
if (layer) layer.remove();
|
|
24
|
+
layer = document.createElement("div");
|
|
25
|
+
layer.id = "wg-swipe-layer";
|
|
26
|
+
layer.setAttribute("data-wg-ui", "1");
|
|
27
|
+
const finger = document.createElement("div");
|
|
28
|
+
finger.className = "wg-swipe-finger";
|
|
29
|
+
const lab = document.createElement("div");
|
|
30
|
+
lab.className = "wg-swipe-label";
|
|
31
|
+
lab.textContent = label;
|
|
32
|
+
layer.appendChild(lab);
|
|
33
|
+
layer.appendChild(finger);
|
|
34
|
+
document.documentElement.appendChild(layer);
|
|
35
|
+
const vw = window.innerWidth || 390;
|
|
36
|
+
const vh = window.innerHeight || 844;
|
|
37
|
+
const pad = Math.min(vw, vh) * 0.18;
|
|
38
|
+
let x0;
|
|
39
|
+
let y0;
|
|
40
|
+
let x1;
|
|
41
|
+
let y1;
|
|
42
|
+
if (dir === "left") {
|
|
43
|
+
x0 = vw - pad;
|
|
44
|
+
x1 = pad;
|
|
45
|
+
y0 = y1 = vh * 0.52;
|
|
46
|
+
} else if (dir === "right") {
|
|
47
|
+
x0 = pad;
|
|
48
|
+
x1 = vw - pad;
|
|
49
|
+
y0 = y1 = vh * 0.52;
|
|
50
|
+
} else if (dir === "up") {
|
|
51
|
+
x0 = x1 = vw * 0.5;
|
|
52
|
+
y0 = vh - pad;
|
|
53
|
+
y1 = pad;
|
|
54
|
+
} else {
|
|
55
|
+
x0 = x1 = vw * 0.5;
|
|
56
|
+
y0 = pad;
|
|
57
|
+
y1 = vh - pad;
|
|
58
|
+
}
|
|
59
|
+
finger.style.left = x0 + "px";
|
|
60
|
+
finger.style.top = y0 + "px";
|
|
61
|
+
finger.style.opacity = "1";
|
|
62
|
+
void layer.offsetWidth;
|
|
63
|
+
layer.classList.add("wg-in");
|
|
64
|
+
const steps = 12;
|
|
65
|
+
const stepMs = Math.floor(ms / steps);
|
|
66
|
+
let i = 0;
|
|
67
|
+
const tick = () => {
|
|
68
|
+
i += 1;
|
|
69
|
+
const t = Math.min(1, i / steps);
|
|
70
|
+
const e = t * t * (3 - 2 * t);
|
|
71
|
+
const x = x0 + (x1 - x0) * e;
|
|
72
|
+
const y = y0 + (y1 - y0) * e;
|
|
73
|
+
finger.style.left = x + "px";
|
|
74
|
+
finger.style.top = y + "px";
|
|
75
|
+
const dot = document.createElement("div");
|
|
76
|
+
dot.className = "wg-swipe-dot";
|
|
77
|
+
dot.style.left = x + "px";
|
|
78
|
+
dot.style.top = y + "px";
|
|
79
|
+
dot.style.opacity = String(0.85 - t * 0.55);
|
|
80
|
+
layer.appendChild(dot);
|
|
81
|
+
requestAnimationFrame(() => {
|
|
82
|
+
dot.style.transition = "opacity .45s ease, transform .45s ease";
|
|
83
|
+
dot.style.opacity = "0";
|
|
84
|
+
dot.style.transform = "scale(1.8)";
|
|
85
|
+
});
|
|
86
|
+
if (i < steps) {
|
|
87
|
+
layer._wgTimer = setTimeout(tick, stepMs);
|
|
88
|
+
} else {
|
|
89
|
+
finger.style.opacity = "0";
|
|
90
|
+
layer.classList.remove("wg-in");
|
|
91
|
+
layer._wgTimer = setTimeout(() => {
|
|
92
|
+
const el = document.getElementById("wg-swipe-layer");
|
|
93
|
+
if (el) el.remove();
|
|
94
|
+
}, 380);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
layer._wgTimer = setTimeout(tick, 40);
|
|
98
|
+
return ms + 120;
|
|
99
|
+
};
|
|
100
|
+
window.__wgClearZoom = () => {
|
|
101
|
+
// Strip leftover element transforms from older zoom path.
|
|
102
|
+
document.querySelectorAll("[data-wg-zoomed=\"1\"]").forEach((el) => {
|
|
103
|
+
el.style.removeProperty("transform");
|
|
104
|
+
el.style.removeProperty("transform-origin");
|
|
105
|
+
el.style.removeProperty("transition");
|
|
106
|
+
el.style.removeProperty("z-index");
|
|
107
|
+
el.style.removeProperty("position");
|
|
108
|
+
delete el.dataset.wgZoomed;
|
|
109
|
+
});
|
|
110
|
+
// Undo any prior shell-camera experiment - restore device fit scale only.
|
|
111
|
+
const shell = document.getElementById("wg-device-shell");
|
|
112
|
+
if (shell && shell.dataset.wgCamBase != null) {
|
|
113
|
+
shell.style.transform = shell.dataset.wgCamBase;
|
|
114
|
+
if (shell.dataset.wgCamOrigin) {
|
|
115
|
+
shell.style.transformOrigin = shell.dataset.wgCamOrigin;
|
|
116
|
+
} else {
|
|
117
|
+
shell.style.transformOrigin = "center center";
|
|
118
|
+
}
|
|
119
|
+
delete shell.dataset.wgCamBase;
|
|
120
|
+
delete shell.dataset.wgCamOrigin;
|
|
121
|
+
delete shell.dataset.wgCamZoom;
|
|
122
|
+
}
|
|
123
|
+
window.__wgZoomLevel = 1;
|
|
124
|
+
window.__wgZoomSel = "";
|
|
125
|
+
if (window.__wgSetZoomBadge) window.__wgSetZoomBadge(1, "");
|
|
126
|
+
};
|
|
127
|
+
const ZOOM_ICO =
|
|
128
|
+
'<svg viewBox="0 0 24 24" fill="none" stroke="#fde68a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
|
|
129
|
+
'<circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>';
|
|
130
|
+
window.__wgSetZoomBadge = (scale, sel) => {
|
|
131
|
+
const n = Number(scale);
|
|
132
|
+
const level = Number.isFinite(n) && n > 0 ? n : 1;
|
|
133
|
+
let badge = document.getElementById("wg-zoom-badge");
|
|
134
|
+
if (!badge) {
|
|
135
|
+
badge = document.createElement("div");
|
|
136
|
+
badge.id = "wg-zoom-badge";
|
|
137
|
+
badge.setAttribute("data-wg-ui", "1");
|
|
138
|
+
document.documentElement.appendChild(badge);
|
|
139
|
+
}
|
|
140
|
+
const zoomed = level > 1.001 || level < 0.999;
|
|
141
|
+
badge.dataset.zoomed = zoomed ? "1" : "0";
|
|
142
|
+
const txt = level.toFixed(2) + "\u00d7";
|
|
143
|
+
badge.innerHTML =
|
|
144
|
+
'<span class="wg-zoom-ico">' +
|
|
145
|
+
ZOOM_ICO +
|
|
146
|
+
'</span><span class="wg-zoom-val">' +
|
|
147
|
+
txt +
|
|
148
|
+
"</span>";
|
|
149
|
+
badge.classList.add("wg-in");
|
|
150
|
+
window.__wgZoomLevel = level;
|
|
151
|
+
window.__wgZoomSel = sel || "";
|
|
152
|
+
};
|
|
153
|
+
window.__wgEnsureZoomBadge = () => {
|
|
154
|
+
if (window.__wgSetZoomBadge) {
|
|
155
|
+
window.__wgSetZoomBadge(window.__wgZoomLevel || 1, window.__wgZoomSel || "");
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
window.__wgSetTypingBadge = (on, label) => {
|
|
159
|
+
let badge = document.getElementById("wg-typing-badge");
|
|
160
|
+
if (!on) {
|
|
161
|
+
if (badge) {
|
|
162
|
+
badge.classList.remove("wg-in");
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
const b = document.getElementById("wg-typing-badge");
|
|
165
|
+
if (b && !b.classList.contains("wg-in")) b.remove();
|
|
166
|
+
}, 220);
|
|
167
|
+
}
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (!badge) {
|
|
171
|
+
badge = document.createElement("div");
|
|
172
|
+
badge.id = "wg-typing-badge";
|
|
173
|
+
badge.setAttribute("data-wg-ui", "1");
|
|
174
|
+
document.documentElement.appendChild(badge);
|
|
175
|
+
}
|
|
176
|
+
const text = label ? String(label).slice(0, 40) : "typing";
|
|
177
|
+
badge.innerHTML =
|
|
178
|
+
'<span class="wg-ty-dots">\u25cf\u25cf\u25cf</span><span>typing \u00b7 ' +
|
|
179
|
+
text.replace(/</g, "<") +
|
|
180
|
+
"</span>";
|
|
181
|
+
void badge.offsetWidth;
|
|
182
|
+
badge.classList.add("wg-in");
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Zoom HUD only - never CSS-scale the target or the device shell.
|
|
186
|
+
* Shell camera zoom fought device-theater fit-scale (broke ring follow
|
|
187
|
+
* + uneven border-radius). Element scale mangled cart rows. Emphasis
|
|
188
|
+
* is ring + focus veil; badge still shows authored zoom level.
|
|
189
|
+
*/
|
|
190
|
+
window.__wgApplyZoom = (sel, scale) => {
|
|
191
|
+
document.querySelectorAll("[data-wg-zoomed=\"1\"]").forEach((el) => {
|
|
192
|
+
el.style.removeProperty("transform");
|
|
193
|
+
el.style.removeProperty("transform-origin");
|
|
194
|
+
el.style.removeProperty("transition");
|
|
195
|
+
el.style.removeProperty("z-index");
|
|
196
|
+
el.style.removeProperty("position");
|
|
197
|
+
delete el.dataset.wgZoomed;
|
|
198
|
+
});
|
|
199
|
+
const shell = document.getElementById("wg-device-shell");
|
|
200
|
+
if (shell && shell.dataset.wgCamBase != null) {
|
|
201
|
+
shell.style.transform = shell.dataset.wgCamBase;
|
|
202
|
+
shell.style.transformOrigin = shell.dataset.wgCamOrigin || "center center";
|
|
203
|
+
delete shell.dataset.wgCamBase;
|
|
204
|
+
delete shell.dataset.wgCamOrigin;
|
|
205
|
+
delete shell.dataset.wgCamZoom;
|
|
206
|
+
}
|
|
207
|
+
const n = Number(scale);
|
|
208
|
+
if (!Number.isFinite(n) || n <= 1.001) {
|
|
209
|
+
window.__wgZoomLevel = 1;
|
|
210
|
+
window.__wgZoomSel = "";
|
|
211
|
+
if (window.__wgSetZoomBadge) window.__wgSetZoomBadge(1, "");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
window.__wgZoomLevel = n;
|
|
215
|
+
window.__wgZoomSel = sel || "";
|
|
216
|
+
if (window.__wgSetZoomBadge) window.__wgSetZoomBadge(n, sel || "");
|
|
217
|
+
};
|
|
218
|
+
// Mount zoom HUD immediately so demos always show 1.00x.
|
|
219
|
+
if (window.__wgEnsureZoomBadge) window.__wgEnsureZoomBadge();
|
|
220
|
+
}
|