waygraph 0.12.31 → 0.12.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/cli.js +241 -148
- package/dist/highlights.d.ts +9 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -274,12 +274,12 @@ async function findBlock(projectDir, ref) {
|
|
|
274
274
|
if (byRuntimeName.length === 1) return byRuntimeName[0];
|
|
275
275
|
if (byRuntimeName.length > 1) {
|
|
276
276
|
throw new Error(
|
|
277
|
-
"waygraph chain:
|
|
277
|
+
"waygraph chain: \\\"" + ref + "\\\" matches " + byRuntimeName.length + " Blocks by name - " +
|
|
278
278
|
byRuntimeName.map((b) => b.exportName + " (" + b.file + ")").join(", ") +
|
|
279
279
|
". Use the export name to disambiguate.",
|
|
280
280
|
);
|
|
281
281
|
}
|
|
282
|
-
throw new Error("waygraph chain: no Block named
|
|
282
|
+
throw new Error("waygraph chain: no Block named \\\"" + ref + "\\\" found under " + projectDir);
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
/**
|
|
@@ -316,7 +316,7 @@ function parseChainSpec(spec) {
|
|
|
316
316
|
const m = /^([A-Za-z_$][\\w-]*)\\s*(?:\\(([\\s\\S]*)\\))?$/.exec(s);
|
|
317
317
|
if (!m) {
|
|
318
318
|
throw new Error(
|
|
319
|
-
"waygraph chain: could not parse segment
|
|
319
|
+
"waygraph chain: could not parse segment \\\"" + s + "\\\" - expected \\\"blockName\\\" or \\\"blockName({...json...})\\\"",
|
|
320
320
|
);
|
|
321
321
|
}
|
|
322
322
|
const ref = m[1];
|
|
@@ -329,7 +329,7 @@ function seedMemFromRequires(mem, requires, json, label) {
|
|
|
329
329
|
if (requires.length === 0) {
|
|
330
330
|
if (json !== undefined) {
|
|
331
331
|
throw new Error(
|
|
332
|
-
"waygraph chain:
|
|
332
|
+
"waygraph chain: \\\"" + label + "\\\" takes no input (empty requires) but got a payload: " + json,
|
|
333
333
|
);
|
|
334
334
|
}
|
|
335
335
|
return;
|
|
@@ -341,7 +341,7 @@ function seedMemFromRequires(mem, requires, json, label) {
|
|
|
341
341
|
json = fromEnv;
|
|
342
342
|
} else {
|
|
343
343
|
throw new Error(
|
|
344
|
-
"waygraph chain:
|
|
344
|
+
"waygraph chain: \\\"" + label + "\\\" requires " + requires.map((k) => k.name).join(", ") +
|
|
345
345
|
" - give a JSON payload (inline blockName({...}) or --data '{...}')",
|
|
346
346
|
);
|
|
347
347
|
}
|
|
@@ -350,7 +350,7 @@ function seedMemFromRequires(mem, requires, json, label) {
|
|
|
350
350
|
try {
|
|
351
351
|
parsed = JSON.parse(json);
|
|
352
352
|
} catch (err) {
|
|
353
|
-
throw new Error("waygraph chain:
|
|
353
|
+
throw new Error("waygraph chain: \\\"" + label + "\\\" payload is not valid JSON - " + String(err));
|
|
354
354
|
}
|
|
355
355
|
// Keyed-by-name when every require name is a top-level key (preferred for
|
|
356
356
|
// --data and for {"saucedemo.credentials":{...}} even with one require).
|
|
@@ -367,13 +367,13 @@ function seedMemFromRequires(mem, requires, json, label) {
|
|
|
367
367
|
}
|
|
368
368
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
369
369
|
throw new Error(
|
|
370
|
-
"waygraph chain:
|
|
370
|
+
"waygraph chain: \\\"" + label + "\\\" requires " + requires.length + " keys (" +
|
|
371
371
|
requires.map((k) => k.name).join(", ") + ") - payload must be an object keyed by each key's name",
|
|
372
372
|
);
|
|
373
373
|
}
|
|
374
374
|
for (const k of requires) {
|
|
375
375
|
if (!(k.name in parsed)) {
|
|
376
|
-
throw new Error("waygraph chain:
|
|
376
|
+
throw new Error("waygraph chain: \\\"" + label + "\\\" payload is missing required key \\\"" + k.name + "\\\"");
|
|
377
377
|
}
|
|
378
378
|
mem.set(k, parsed[k.name]);
|
|
379
379
|
}
|
|
@@ -413,19 +413,11 @@ const RING_CSS =
|
|
|
413
413
|
"#wg-ring{position:fixed;z-index:2147483646;pointer-events:none;opacity:0;" +
|
|
414
414
|
"border:2.5px solid #7C3AED;border-radius:10px;" +
|
|
415
415
|
"box-shadow:0 0 0 4px rgba(124,58,237,.16);" +
|
|
416
|
-
"transition:opacity .32s ease,
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
"#wg-
|
|
421
|
-
"#wg-ring[data-tone=auto][data-focus=1]{box-shadow:0 0 0 4px rgba(156,163,175,.28),0 0 0 9999px rgba(15,6,32,.55);}" +
|
|
422
|
-
"#wg-ring[data-tone=info][data-focus=1]{box-shadow:0 0 0 4px rgba(59,130,246,.22),0 0 0 9999px rgba(15,6,32,.55);}" +
|
|
423
|
-
"#wg-ring[data-tone=warning][data-focus=1]{box-shadow:0 0 0 4px rgba(234,179,8,.22),0 0 0 9999px rgba(15,6,32,.55);}" +
|
|
424
|
-
"#wg-ring[data-tone=danger][data-focus=1]{box-shadow:0 0 0 4px rgba(239,68,68,.22),0 0 0 9999px rgba(15,6,32,.55);}" +
|
|
425
|
-
"#wg-ring[data-tone=success][data-focus=1]{box-shadow:0 0 0 4px rgba(34,197,94,.22),0 0 0 9999px rgba(15,6,32,.55);}" +
|
|
426
|
-
// Planned (stubs / fixtures / YAP / instruction.highlights) = purple.
|
|
427
|
-
// Automation (verify fallback, unmatched fill/click) = gray - operators
|
|
428
|
-
// can ignore engine checks and watch purple + semantic tones.
|
|
416
|
+
"transition:opacity .32s ease,border-color .15s;}" +
|
|
417
|
+
"#wg-focus-veil{position:fixed;z-index:2147483645;pointer-events:none;opacity:0;" +
|
|
418
|
+
"border-radius:10px;box-shadow:0 0 0 9999px rgba(12,6,28,.62);" +
|
|
419
|
+
"transition:opacity .28s ease;}" +
|
|
420
|
+
"#wg-focus-veil.wg-focus-on{opacity:1;}" +
|
|
429
421
|
"#wg-ring[data-tone=auto]{border-color:#9CA3AF;box-shadow:0 0 0 4px rgba(156,163,175,.28);}" +
|
|
430
422
|
"#wg-ring[data-tone=info]{border-color:#3B82F6;box-shadow:0 0 0 4px rgba(59,130,246,.22);}" +
|
|
431
423
|
"#wg-ring[data-tone=warning]{border-color:#EAB308;box-shadow:0 0 0 4px rgba(234,179,8,.22);}" +
|
|
@@ -441,7 +433,7 @@ const RING_CSS =
|
|
|
441
433
|
// window.__wgPositionRing in installOverlay.
|
|
442
434
|
"#wg-ring-label{position:fixed;z-index:2147483646;pointer-events:none;opacity:0;" +
|
|
443
435
|
"max-width:min(360px,70vw);white-space:normal;padding:6px 10px;border-radius:7px;background:#7C3AED;color:#fff;" +
|
|
444
|
-
"font:600 12px/1.35 system-ui,sans-serif;transition:opacity .32s ease,
|
|
436
|
+
"font:600 12px/1.35 system-ui,sans-serif;transition:opacity .32s ease,background .15s,color .15s;}" +
|
|
445
437
|
"#wg-ring-label[data-tone=auto]{background:#6B7280;color:#fff;}" +
|
|
446
438
|
"#wg-ring-label[data-tone=info]{background:#2563EB;color:#fff;}" +
|
|
447
439
|
"#wg-ring-label[data-tone=warning]{background:#EAB308;color:#1c1917;}" +
|
|
@@ -683,6 +675,11 @@ async function installOverlay(page, title) {
|
|
|
683
675
|
} catch {
|
|
684
676
|
/* private mode / blocked storage - falls back to manual gating */
|
|
685
677
|
}
|
|
678
|
+
if (!document.getElementById("wg-focus-veil")) {
|
|
679
|
+
const veil = document.createElement("div");
|
|
680
|
+
veil.id = "wg-focus-veil";
|
|
681
|
+
document.documentElement.appendChild(veil);
|
|
682
|
+
}
|
|
686
683
|
if (!document.getElementById("wg-ring")) {
|
|
687
684
|
const ring = document.createElement("div");
|
|
688
685
|
ring.id = "wg-ring";
|
|
@@ -733,6 +730,7 @@ async function installOverlay(page, title) {
|
|
|
733
730
|
window.__wgPositionRing = (box, label, tone, style) => {
|
|
734
731
|
const ring = document.getElementById("wg-ring");
|
|
735
732
|
const ringLabel = document.getElementById("wg-ring-label");
|
|
733
|
+
const veil = document.getElementById("wg-focus-veil");
|
|
736
734
|
if (!ring || !ringLabel) return;
|
|
737
735
|
const raw = (tone || "planned") + "";
|
|
738
736
|
const t =
|
|
@@ -757,8 +755,8 @@ async function installOverlay(page, title) {
|
|
|
757
755
|
const vh = window.innerHeight;
|
|
758
756
|
let left = box.x - pad;
|
|
759
757
|
let top = box.y - pad;
|
|
760
|
-
const width = box.width + pad * 2;
|
|
761
|
-
const height = box.height + pad * 2;
|
|
758
|
+
const width = Math.max(0, box.width + pad * 2);
|
|
759
|
+
const height = Math.max(0, box.height + pad * 2);
|
|
762
760
|
if (left < margin) left = margin;
|
|
763
761
|
if (top < margin) top = margin;
|
|
764
762
|
if (left + width > vw - margin) left = Math.max(margin, vw - margin - width);
|
|
@@ -768,24 +766,100 @@ async function installOverlay(page, title) {
|
|
|
768
766
|
ring.style.width = width + "px";
|
|
769
767
|
ring.style.height = height + "px";
|
|
770
768
|
ring.style.opacity = "1";
|
|
769
|
+
if (veil) {
|
|
770
|
+
veil.style.left = left + "px";
|
|
771
|
+
veil.style.top = top + "px";
|
|
772
|
+
veil.style.width = width + "px";
|
|
773
|
+
veil.style.height = height + "px";
|
|
774
|
+
const br = size === "sm" ? "8px" : size === "lg" ? "12px" : "10px";
|
|
775
|
+
veil.style.borderRadius = br;
|
|
776
|
+
if (st.focus) veil.classList.add("wg-focus-on");
|
|
777
|
+
else veil.classList.remove("wg-focus-on");
|
|
778
|
+
}
|
|
771
779
|
ringLabel.textContent = label;
|
|
772
780
|
ringLabel.style.opacity = "1";
|
|
773
781
|
const capColor = st.color || st.labelColor || st.textColor;
|
|
774
782
|
if (capColor) ringLabel.style.color = String(capColor);
|
|
775
783
|
else ringLabel.style.removeProperty("color");
|
|
776
|
-
// Measure the label's own natural width/height (its real
|
|
777
|
-
// rendered size, unchanged) before deciding where it fits.
|
|
778
784
|
const lw = ringLabel.offsetWidth;
|
|
779
785
|
const lh = ringLabel.offsetHeight;
|
|
780
786
|
let labelLeft = left;
|
|
781
787
|
let labelTop = top + height + 8;
|
|
782
|
-
if (labelTop + lh > vh - margin) labelTop = top - lh - 8;
|
|
788
|
+
if (labelTop + lh > vh - margin) labelTop = top - lh - 8;
|
|
783
789
|
if (labelTop < margin) labelTop = margin;
|
|
784
790
|
if (labelLeft + lw > vw - margin) labelLeft = Math.max(margin, vw - margin - lw);
|
|
785
791
|
if (labelLeft < margin) labelLeft = margin;
|
|
786
792
|
ringLabel.style.left = labelLeft + "px";
|
|
787
793
|
ringLabel.style.top = labelTop + "px";
|
|
788
794
|
};
|
|
795
|
+
window.__wgHideFocusVeil = () => {
|
|
796
|
+
const veil = document.getElementById("wg-focus-veil");
|
|
797
|
+
if (veil) veil.classList.remove("wg-focus-on");
|
|
798
|
+
};
|
|
799
|
+
window.__wgStartHighlightTrack = (opts) => {
|
|
800
|
+
if (window.__wgStopHighlightTrack) window.__wgStopHighlightTrack();
|
|
801
|
+
const sel = opts.sel;
|
|
802
|
+
const label = opts.label;
|
|
803
|
+
const tone = opts.tone || "planned";
|
|
804
|
+
const size = opts.size || "md";
|
|
805
|
+
const weight = opts.weight || "normal";
|
|
806
|
+
const focus = !!opts.focus;
|
|
807
|
+
const color = opts.color || "";
|
|
808
|
+
const zoom = opts.zoom != null && opts.zoom > 1 ? opts.zoom : 1;
|
|
809
|
+
const followMouse = opts.followMouse !== false && zoom > 1;
|
|
810
|
+
const camMs = opts.camMs != null ? opts.camMs : 700;
|
|
811
|
+
let settled = zoom <= 1;
|
|
812
|
+
const settleAt = Date.now() + camMs;
|
|
813
|
+
const style = { size, weight, focus, color };
|
|
814
|
+
const tick = () => {
|
|
815
|
+
const el = document.querySelector(sel);
|
|
816
|
+
if (el && window.__wgPositionRing) {
|
|
817
|
+
const r = el.getBoundingClientRect();
|
|
818
|
+
window.__wgPositionRing(
|
|
819
|
+
{ x: r.left, y: r.top, width: r.width, height: r.height },
|
|
820
|
+
label,
|
|
821
|
+
tone,
|
|
822
|
+
style,
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
if (!settled && Date.now() >= settleAt) settled = true;
|
|
826
|
+
window.__wgRingRaf = requestAnimationFrame(tick);
|
|
827
|
+
};
|
|
828
|
+
if (zoom > 1 && window.__wgSetCamera) {
|
|
829
|
+
const el0 = document.querySelector(sel);
|
|
830
|
+
if (el0) {
|
|
831
|
+
const r0 = el0.getBoundingClientRect();
|
|
832
|
+
window.__wgSetCamera(
|
|
833
|
+
r0.left + r0.width / 2,
|
|
834
|
+
r0.top + r0.height / 2,
|
|
835
|
+
zoom,
|
|
836
|
+
camMs,
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
window.__wgRingRaf = requestAnimationFrame(tick);
|
|
841
|
+
const onMove = (ev) => {
|
|
842
|
+
if (!followMouse || !settled) return;
|
|
843
|
+
if (!window.__wgSetCamera) return;
|
|
844
|
+
const cam = window.__wgCamera;
|
|
845
|
+
const scale = (cam && cam.scale > 1 ? cam.scale : zoom) || zoom;
|
|
846
|
+
if (!(scale > 1)) return;
|
|
847
|
+
window.__wgSetCamera(ev.clientX, ev.clientY, scale, 140);
|
|
848
|
+
};
|
|
849
|
+
window.addEventListener("mousemove", onMove, { passive: true });
|
|
850
|
+
window.__wgRingTrack = onMove;
|
|
851
|
+
window.__wgStopHighlightTrack = () => {
|
|
852
|
+
if (window.__wgRingRaf) {
|
|
853
|
+
cancelAnimationFrame(window.__wgRingRaf);
|
|
854
|
+
window.__wgRingRaf = null;
|
|
855
|
+
}
|
|
856
|
+
if (window.__wgRingTrack) {
|
|
857
|
+
window.removeEventListener("mousemove", window.__wgRingTrack);
|
|
858
|
+
window.__wgRingTrack = null;
|
|
859
|
+
}
|
|
860
|
+
window.__wgStopHighlightTrack = null;
|
|
861
|
+
};
|
|
862
|
+
};
|
|
789
863
|
window.__wgClickPulse = (x, y, tone) => {
|
|
790
864
|
const pulse = document.getElementById("wg-click-pulse");
|
|
791
865
|
if (!pulse) return;
|
|
@@ -810,6 +884,7 @@ async function installOverlay(page, title) {
|
|
|
810
884
|
const ringLabel = document.getElementById("wg-ring-label");
|
|
811
885
|
if (ring) ring.style.opacity = "0";
|
|
812
886
|
if (ringLabel) ringLabel.style.opacity = "0";
|
|
887
|
+
if (window.__wgHideFocusVeil) window.__wgHideFocusVeil();
|
|
813
888
|
if (window.__wgClearZoom) window.__wgClearZoom();
|
|
814
889
|
};
|
|
815
890
|
// Screen Studio-style camera: scale <body>, keep overlays on <html> fixed.
|
|
@@ -861,23 +936,27 @@ async function installOverlay(page, title) {
|
|
|
861
936
|
: t.done
|
|
862
937
|
? "wg-todo-done"
|
|
863
938
|
: "wg-todo-pending";
|
|
864
|
-
const mark = t.done
|
|
939
|
+
const mark = t.done
|
|
940
|
+
? String.fromCharCode(0x2713)
|
|
941
|
+
: t.current
|
|
942
|
+
? String.fromCharCode(0x2192)
|
|
943
|
+
: String.fromCharCode(0x25cb);
|
|
865
944
|
return (
|
|
866
|
-
|
|
945
|
+
'<li class="' +
|
|
867
946
|
cls +
|
|
868
|
-
"
|
|
947
|
+
'"><span class="wg-todo-mark">' +
|
|
869
948
|
mark +
|
|
870
|
-
|
|
949
|
+
'</span><span>' +
|
|
871
950
|
esc(t.text || "") +
|
|
872
|
-
|
|
951
|
+
'</span></li>'
|
|
873
952
|
);
|
|
874
953
|
})
|
|
875
954
|
.join("");
|
|
876
955
|
modal.innerHTML =
|
|
877
|
-
|
|
956
|
+
'<div class="wg-todo-head">Checklist</div><ul>' + rows + '</ul>';
|
|
878
957
|
modal.classList.add("wg-todo-on");
|
|
879
958
|
};
|
|
880
|
-
|
|
959
|
+
window.__wgResetCamera = () => {
|
|
881
960
|
window.__wgSetCamera(window.innerWidth / 2, window.innerHeight / 2, 1);
|
|
882
961
|
};
|
|
883
962
|
window.__wgClearZoom = () => {
|
|
@@ -1066,7 +1145,7 @@ async function renderBeforeStep(page, info) {
|
|
|
1066
1145
|
// active, the episode 2 tab is inactive"). Absent entirely for an ad
|
|
1067
1146
|
// hoc block chain with no named Flows.
|
|
1068
1147
|
const episodesHtml = info.allEpisodes && info.allEpisodes.length > 0
|
|
1069
|
-
? "<div id
|
|
1148
|
+
? "<div id=\\\"wg-episodes\\\">" +
|
|
1070
1149
|
info.allEpisodes
|
|
1071
1150
|
.map((e) => {
|
|
1072
1151
|
const cls = e.episodeNumber < info.episodeNumber ? "wg-ep-done"
|
|
@@ -1077,7 +1156,7 @@ async function renderBeforeStep(page, info) {
|
|
|
1077
1156
|
const enteredCls = info.justEnteredEpisode && e.episodeNumber === info.episodeNumber
|
|
1078
1157
|
? " wg-ep-entered"
|
|
1079
1158
|
: "";
|
|
1080
|
-
return "<span class
|
|
1159
|
+
return "<span class=\\\"wg-ep-tab " + cls + enteredCls + "\\\">Episode " + e.episodeNumber + ": " +
|
|
1081
1160
|
esc(e.episodeTitle || "") + "</span>";
|
|
1082
1161
|
})
|
|
1083
1162
|
.join("") +
|
|
@@ -1093,62 +1172,66 @@ async function renderBeforeStep(page, info) {
|
|
|
1093
1172
|
.map((name, idx) => {
|
|
1094
1173
|
const cls = idx < info.moduleIndex ? "wg-mod-done" : idx === info.moduleIndex ? "wg-mod-current" : "wg-mod-upcoming";
|
|
1095
1174
|
const desc = info.allDescriptions && info.allDescriptions[idx];
|
|
1096
|
-
const titleAttr = desc ? " title
|
|
1097
|
-
return "<span class
|
|
1175
|
+
const titleAttr = desc ? " title=\\\"" + esc(desc) + "\\\"" : "";
|
|
1176
|
+
return "<span class=\\\"wg-mod " + cls + "\\\"" + titleAttr + ">" + name + "</span>";
|
|
1098
1177
|
})
|
|
1099
1178
|
.join("");
|
|
1100
1179
|
const narrationHtml = info.description
|
|
1101
|
-
? "<div class
|
|
1180
|
+
? "<div class=\\\"wg-narration\\\">" + esc(info.description) + "</div>"
|
|
1102
1181
|
: "";
|
|
1103
1182
|
const paceHtml =
|
|
1104
1183
|
info.paceBadge || info.paceLabel
|
|
1105
|
-
? "<div class
|
|
1184
|
+
? "<div class=\\\"wg-pace\\\" data-pace-kind=\\\"" +
|
|
1106
1185
|
esc(info.paceKind || "normal") +
|
|
1107
|
-
"
|
|
1186
|
+
"\\\"><span class=\\\"wg-pace-badge\\\">" +
|
|
1108
1187
|
esc(info.paceBadge || "1x") +
|
|
1109
1188
|
"</span><span>" +
|
|
1110
1189
|
esc(info.paceLabel || "") +
|
|
1111
1190
|
"</span></div>"
|
|
1112
1191
|
: "";
|
|
1113
1192
|
let html =
|
|
1114
|
-
"<div id
|
|
1193
|
+
"<div id=\\\"wg-progress\\\"><div id=\\\"wg-progress-bar\\\" style=\\\"width:" + pct + "%\\\"></div></div>" +
|
|
1115
1194
|
episodesHtml +
|
|
1116
1195
|
paceHtml +
|
|
1117
|
-
"<div id
|
|
1196
|
+
"<div id=\\\"wg-modules\\\" class=\\\"" + modulesClass + "\\\">" + modulesHtml + "</div>" +
|
|
1118
1197
|
"<h3>Step " + (info.index + 1) + " / " + info.total + " - " + info.blockName + "</h3>" +
|
|
1119
1198
|
narrationHtml +
|
|
1120
1199
|
((() => {
|
|
1121
1200
|
const list = info.todos || [];
|
|
1122
1201
|
if (!list.length) return "";
|
|
1123
1202
|
return (
|
|
1124
|
-
|
|
1203
|
+
'<ul id="wg-todos">' +
|
|
1125
1204
|
list
|
|
1126
1205
|
.map((t) => {
|
|
1127
1206
|
const cls = t.current ? "wg-todo-current" : t.done ? "wg-todo-done" : "wg-todo-pending";
|
|
1128
|
-
const mark = t.done
|
|
1207
|
+
const mark = t.done
|
|
1208
|
+
? String.fromCharCode(0x2713)
|
|
1209
|
+
: t.current
|
|
1210
|
+
? String.fromCharCode(0x2192)
|
|
1211
|
+
: String.fromCharCode(0x25cb);
|
|
1129
1212
|
return (
|
|
1130
|
-
|
|
1213
|
+
'<li class="' +
|
|
1131
1214
|
cls +
|
|
1132
|
-
"
|
|
1215
|
+
'"><span class="wg-todo-mark">' +
|
|
1133
1216
|
mark +
|
|
1134
|
-
|
|
1217
|
+
'</span><span>' +
|
|
1135
1218
|
esc(t.text || "") +
|
|
1136
|
-
|
|
1219
|
+
'</span></li>'
|
|
1137
1220
|
);
|
|
1138
1221
|
})
|
|
1139
1222
|
.join("") +
|
|
1140
|
-
|
|
1223
|
+
'</ul>'
|
|
1141
1224
|
);
|
|
1142
1225
|
})());
|
|
1143
1226
|
if (info.keys.length === 0) {
|
|
1144
|
-
html += "<div class
|
|
1227
|
+
html += "<div class=\\\"wg-key\\\">(no MemKeys required)</div>";
|
|
1145
1228
|
}
|
|
1146
1229
|
for (const k of info.keys) {
|
|
1147
1230
|
html +=
|
|
1148
|
-
"<div class
|
|
1149
|
-
"<textarea data-key
|
|
1231
|
+
"<div class=\\\"wg-key\\\"><label>" + k.name + "</label>" +
|
|
1232
|
+
"<textarea data-key=\\\"" + k.name + "\\\" rows=\\\"2\\\">" +
|
|
1150
1233
|
k.value.replace(/</g, "<") + "</textarea>" +
|
|
1151
|
-
"<div class
|
|
1234
|
+
"<div class=\\\"wg-key-pretty\\\" data-pretty-for=\\\"" + esc(k.name) + "\\\"></div>" +
|
|
1152
1235
|
"</div>";
|
|
1153
1236
|
}
|
|
1154
1237
|
let autoNow = false;
|
|
@@ -1158,12 +1241,12 @@ async function renderBeforeStep(page, info) {
|
|
|
1158
1241
|
/* private mode / blocked storage - defaults to manual */
|
|
1159
1242
|
}
|
|
1160
1243
|
html +=
|
|
1161
|
-
"<div class
|
|
1244
|
+
"<div class=\\\"wg-autoplay-row\\\"><label><input type=\\\"checkbox\\\" id=\\\"wg-autoplay-cb\\\"" +
|
|
1162
1245
|
(autoNow ? " checked" : "") +
|
|
1163
1246
|
"> Auto-advance</label></div>" +
|
|
1164
|
-
"<div id
|
|
1165
|
-
"><button id
|
|
1166
|
-
"<div id
|
|
1247
|
+
"<div id=\\\"wg-gate-manual\\\"" + (autoNow ? " style=\\\"display:none\\\"" : "") +
|
|
1248
|
+
"><button id=\\\"wg-run\\\">Run this step \\u25B6</button></div>" +
|
|
1249
|
+
"<div id=\\\"wg-gate-auto\\\" class=\\\"wg-auto\\\"" + (autoNow ? "" : " style=\\\"display:none\\\"") +
|
|
1167
1250
|
">Auto-advancing...</div>";
|
|
1168
1251
|
panel.innerHTML = html;
|
|
1169
1252
|
if (isNewPanel) {
|
|
@@ -1196,7 +1279,7 @@ async function renderBeforeStep(page, info) {
|
|
|
1196
1279
|
return Object.entries(parsed)
|
|
1197
1280
|
.map(([field, value]) => {
|
|
1198
1281
|
const label = field.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
|
|
1199
|
-
return "<div class
|
|
1282
|
+
return "<div class=\\\"wg-key-pretty-row\\\"><span class=\\\"wg-key-pretty-label\\\">" +
|
|
1200
1283
|
esc(label) + ":</span> " + esc(String(value)) + "</div>";
|
|
1201
1284
|
})
|
|
1202
1285
|
.join("");
|
|
@@ -1205,7 +1288,7 @@ async function renderBeforeStep(page, info) {
|
|
|
1205
1288
|
const prettyOn = window.__wgPretty !== false;
|
|
1206
1289
|
panel.querySelectorAll("textarea[data-key]").forEach((ta) => {
|
|
1207
1290
|
const key = ta.getAttribute("data-key");
|
|
1208
|
-
const previewEl = panel.querySelector(".wg-key-pretty[data-pretty-for
|
|
1291
|
+
const previewEl = panel.querySelector(".wg-key-pretty[data-pretty-for=\\\"" + key + "\\\"]");
|
|
1209
1292
|
if (!previewEl) return;
|
|
1210
1293
|
previewEl.style.display = prettyOn ? "" : "none";
|
|
1211
1294
|
if (prettyOn) previewEl.innerHTML = prettyMemValue(ta.value);
|
|
@@ -1423,15 +1506,18 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1423
1506
|
const stopLiveFollow = async () => {
|
|
1424
1507
|
await page
|
|
1425
1508
|
.evaluate(() => {
|
|
1509
|
+
if (window.__wgStopHighlightTrack) window.__wgStopHighlightTrack();
|
|
1426
1510
|
if (window.__wgRingRaf) {
|
|
1427
1511
|
cancelAnimationFrame(window.__wgRingRaf);
|
|
1428
1512
|
window.__wgRingRaf = null;
|
|
1429
1513
|
}
|
|
1430
1514
|
if (window.__wgRingTrack) {
|
|
1515
|
+
window.removeEventListener("mousemove", window.__wgRingTrack);
|
|
1431
1516
|
window.removeEventListener("resize", window.__wgRingTrack);
|
|
1432
1517
|
window.removeEventListener("scroll", window.__wgRingTrack, true);
|
|
1433
1518
|
window.__wgRingTrack = null;
|
|
1434
1519
|
}
|
|
1520
|
+
if (window.__wgHideFocusVeil) window.__wgHideFocusVeil();
|
|
1435
1521
|
})
|
|
1436
1522
|
.catch(() => {});
|
|
1437
1523
|
};
|
|
@@ -1454,12 +1540,16 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1454
1540
|
} else if (h.todos && h.todos.length) {
|
|
1455
1541
|
await setDemoTodos(page, normalizeTodos(h.todos, h.todoIndex));
|
|
1456
1542
|
}
|
|
1457
|
-
const cx = box.x + box.width / 2;
|
|
1458
|
-
const cy = box.y + box.height / 2;
|
|
1459
1543
|
const z = h.zoom != null && Number(h.zoom) > 1 ? Number(h.zoom) : 1;
|
|
1460
1544
|
const camMs = 700;
|
|
1461
|
-
|
|
1462
|
-
|
|
1545
|
+
const followMouse =
|
|
1546
|
+
h.followMouse !== undefined
|
|
1547
|
+
? !!h.followMouse
|
|
1548
|
+
: h.follow !== undefined
|
|
1549
|
+
? !!h.follow
|
|
1550
|
+
: z > 1;
|
|
1551
|
+
const cx = box.x + box.width / 2;
|
|
1552
|
+
const cy = box.y + box.height / 2;
|
|
1463
1553
|
if (h.cursor !== false) {
|
|
1464
1554
|
await page
|
|
1465
1555
|
.evaluate(({ cx, cy, camMs }) => {
|
|
@@ -1467,41 +1557,40 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1467
1557
|
}, { cx, cy, camMs })
|
|
1468
1558
|
.catch(() => {});
|
|
1469
1559
|
}
|
|
1470
|
-
|
|
1471
|
-
size: h.size,
|
|
1472
|
-
weight: h.weight,
|
|
1473
|
-
focus: !!h.focus,
|
|
1474
|
-
color: h.color || h.labelColor || h.textColor,
|
|
1475
|
-
});
|
|
1476
|
-
await new Promise((res) => setTimeout(res, camMs));
|
|
1477
|
-
// Live ring track only - camera stays locked (no per-frame re-pan).
|
|
1560
|
+
// Track first: ring rides visual rect through the zoom (no re-adjust).
|
|
1478
1561
|
await page
|
|
1479
|
-
.evaluate(
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1562
|
+
.evaluate(
|
|
1563
|
+
({ sel, label, tone, size, weight, focus, color, zoom, followMouse, camMs }) => {
|
|
1564
|
+
if (window.__wgStartHighlightTrack) {
|
|
1565
|
+
window.__wgStartHighlightTrack({
|
|
1566
|
+
sel,
|
|
1567
|
+
label,
|
|
1568
|
+
tone,
|
|
1569
|
+
size,
|
|
1570
|
+
weight,
|
|
1571
|
+
focus,
|
|
1572
|
+
color,
|
|
1573
|
+
zoom,
|
|
1574
|
+
followMouse,
|
|
1575
|
+
camMs,
|
|
1576
|
+
});
|
|
1485
1577
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
weight: h.weight || "normal",
|
|
1501
|
-
focus: !!h.focus,
|
|
1502
|
-
color: h.color || h.labelColor || h.textColor || "",
|
|
1503
|
-
})
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
sel: h.selector,
|
|
1581
|
+
label: h.label,
|
|
1582
|
+
tone: h.tone || "planned",
|
|
1583
|
+
size: h.size || "md",
|
|
1584
|
+
weight: h.weight || "normal",
|
|
1585
|
+
focus: !!h.focus,
|
|
1586
|
+
color: h.color || h.labelColor || h.textColor || "",
|
|
1587
|
+
zoom: z,
|
|
1588
|
+
followMouse,
|
|
1589
|
+
camMs,
|
|
1590
|
+
},
|
|
1591
|
+
)
|
|
1504
1592
|
.catch(() => {});
|
|
1593
|
+
await new Promise((res) => setTimeout(res, camMs));
|
|
1505
1594
|
|
|
1506
1595
|
// Appear settle
|
|
1507
1596
|
await new Promise((res) => setTimeout(res, fadeMs));
|
|
@@ -1570,8 +1659,8 @@ async function renderAfterStep(page, info) {
|
|
|
1570
1659
|
.map((name, idx) => {
|
|
1571
1660
|
const cls = idx <= info.moduleIndex ? "wg-mod-done" : "wg-mod-upcoming";
|
|
1572
1661
|
const desc = info.allDescriptions && info.allDescriptions[idx];
|
|
1573
|
-
const titleAttr = desc ? " title
|
|
1574
|
-
return "<span class
|
|
1662
|
+
const titleAttr = desc ? " title=\\\"" + escA(desc) + "\\\"" : "";
|
|
1663
|
+
return "<span class=\\\"wg-mod " + cls + "\\\"" + titleAttr + ">" + name + "</span>";
|
|
1575
1664
|
})
|
|
1576
1665
|
.join("");
|
|
1577
1666
|
// QA-friendly by default ("LoginSuccess" -> "Login Success") - raw
|
|
@@ -1582,13 +1671,13 @@ async function renderAfterStep(page, info) {
|
|
|
1582
1671
|
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2") || info.resultTag;
|
|
1583
1672
|
const pretty = window.__wgPretty !== false;
|
|
1584
1673
|
const resultHtml =
|
|
1585
|
-
"<div class
|
|
1586
|
-
"<button class
|
|
1587
|
-
"<button class
|
|
1674
|
+
"<div class=\\\"wg-toggle\\\">" +
|
|
1675
|
+
"<button class=\\\"wg-toggle-btn" + (pretty ? " wg-active" : "") + "\\\" data-mode=\\\"pretty\\\">Pretty</button>" +
|
|
1676
|
+
"<button class=\\\"wg-toggle-btn" + (pretty ? "" : " wg-active") + "\\\" data-mode=\\\"json\\\">JSON</button>" +
|
|
1588
1677
|
"</div>" +
|
|
1589
|
-
"<div class
|
|
1678
|
+
"<div class=\\\"wg-result wg-result-pretty\\\" style=\\\"display:" + (pretty ? "block" : "none") + "\\\">" +
|
|
1590
1679
|
prettyText + "</div>" +
|
|
1591
|
-
"<div class
|
|
1680
|
+
"<div class=\\\"wg-result wg-result-json\\\" style=\\\"display:" + (pretty ? "none" : "block") + "\\\">" +
|
|
1592
1681
|
info.resultTag + "</div>";
|
|
1593
1682
|
let autoNow = false;
|
|
1594
1683
|
try {
|
|
@@ -1597,21 +1686,21 @@ async function renderAfterStep(page, info) {
|
|
|
1597
1686
|
/* private mode / blocked storage - defaults to manual */
|
|
1598
1687
|
}
|
|
1599
1688
|
const gateHtml =
|
|
1600
|
-
"<div class
|
|
1689
|
+
"<div class=\\\"wg-autoplay-row\\\"><label><input type=\\\"checkbox\\\" id=\\\"wg-autoplay-cb\\\"" +
|
|
1601
1690
|
(autoNow ? " checked" : "") +
|
|
1602
1691
|
"> Auto-advance</label></div>" +
|
|
1603
|
-
"<div id
|
|
1604
|
-
"><button id
|
|
1605
|
-
"<div id
|
|
1692
|
+
"<div id=\\\"wg-gate-manual\\\"" + (autoNow ? " style=\\\"display:none\\\"" : "") +
|
|
1693
|
+
"><button id=\\\"wg-run\\\">" + buttonLabel + "</button></div>" +
|
|
1694
|
+
"<div id=\\\"wg-gate-auto\\\" class=\\\"wg-auto\\\"" + (autoNow ? "" : " style=\\\"display:none\\\"") +
|
|
1606
1695
|
">Auto-advancing...</div>";
|
|
1607
1696
|
const episodesHtml = info.allEpisodes && info.allEpisodes.length > 0
|
|
1608
|
-
? "<div id
|
|
1697
|
+
? "<div id=\\\"wg-episodes\\\">" +
|
|
1609
1698
|
info.allEpisodes
|
|
1610
1699
|
.map((e) => {
|
|
1611
1700
|
const cls = e.episodeNumber < info.episodeNumber ? "wg-ep-done"
|
|
1612
1701
|
: e.episodeNumber === info.episodeNumber ? "wg-ep-current"
|
|
1613
1702
|
: "wg-ep-upcoming";
|
|
1614
|
-
return "<span class
|
|
1703
|
+
return "<span class=\\\"wg-ep-tab " + cls + "\\\">Episode " + e.episodeNumber + ": " +
|
|
1615
1704
|
escA(e.episodeTitle || "") + "</span>";
|
|
1616
1705
|
})
|
|
1617
1706
|
.join("") +
|
|
@@ -1619,41 +1708,45 @@ async function renderAfterStep(page, info) {
|
|
|
1619
1708
|
: "";
|
|
1620
1709
|
const paceHtml =
|
|
1621
1710
|
info.paceBadge || info.paceLabel
|
|
1622
|
-
? "<div class
|
|
1711
|
+
? "<div class=\\\"wg-pace\\\" data-pace-kind=\\\"" +
|
|
1623
1712
|
escA(info.paceKind || "normal") +
|
|
1624
|
-
"
|
|
1713
|
+
"\\\"><span class=\\\"wg-pace-badge\\\">" +
|
|
1625
1714
|
escA(info.paceBadge || "1x") +
|
|
1626
1715
|
"</span><span>" +
|
|
1627
1716
|
escA(info.paceLabel || "") +
|
|
1628
1717
|
"</span></div>"
|
|
1629
1718
|
: "";
|
|
1630
1719
|
panel.innerHTML =
|
|
1631
|
-
"<div id
|
|
1720
|
+
"<div id=\\\"wg-progress\\\"><div id=\\\"wg-progress-bar\\\" style=\\\"width:" + pct + "%\\\"></div></div>" +
|
|
1632
1721
|
episodesHtml +
|
|
1633
1722
|
paceHtml +
|
|
1634
|
-
"<div id
|
|
1723
|
+
"<div id=\\\"wg-modules\\\" class=\\\"" + modulesClass + "\\\">" + modulesHtml + "</div>" +
|
|
1635
1724
|
"<h3>" + heading + "</h3>" +
|
|
1636
1725
|
((() => {
|
|
1637
1726
|
const list = info.todos || [];
|
|
1638
1727
|
if (!list.length) return "";
|
|
1639
1728
|
return (
|
|
1640
|
-
|
|
1729
|
+
'<ul id="wg-todos">' +
|
|
1641
1730
|
list
|
|
1642
1731
|
.map((t) => {
|
|
1643
1732
|
const cls = t.current ? "wg-todo-current" : t.done ? "wg-todo-done" : "wg-todo-pending";
|
|
1644
|
-
const mark = t.done
|
|
1733
|
+
const mark = t.done
|
|
1734
|
+
? String.fromCharCode(0x2713)
|
|
1735
|
+
: t.current
|
|
1736
|
+
? String.fromCharCode(0x2192)
|
|
1737
|
+
: String.fromCharCode(0x25cb);
|
|
1645
1738
|
return (
|
|
1646
|
-
|
|
1739
|
+
'<li class="' +
|
|
1647
1740
|
cls +
|
|
1648
|
-
"
|
|
1741
|
+
'"><span class="wg-todo-mark">' +
|
|
1649
1742
|
mark +
|
|
1650
|
-
|
|
1743
|
+
'</span><span>' +
|
|
1651
1744
|
escA(t.text || "") +
|
|
1652
|
-
|
|
1745
|
+
'</span></li>'
|
|
1653
1746
|
);
|
|
1654
1747
|
})
|
|
1655
1748
|
.join("") +
|
|
1656
|
-
|
|
1749
|
+
'</ul>'
|
|
1657
1750
|
);
|
|
1658
1751
|
})()) +
|
|
1659
1752
|
resultHtml +
|
|
@@ -1722,13 +1815,13 @@ async function renderStepError(page, info) {
|
|
|
1722
1815
|
if (!isNewPanel) panel.classList.add("wg-in");
|
|
1723
1816
|
const esc = (s) => String(s).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
1724
1817
|
const episodesHtml = info.allEpisodes && info.allEpisodes.length > 0
|
|
1725
|
-
? "<div id
|
|
1818
|
+
? "<div id=\\\"wg-episodes\\\">" +
|
|
1726
1819
|
info.allEpisodes
|
|
1727
1820
|
.map((e) => {
|
|
1728
1821
|
const cls = e.episodeNumber < info.episodeNumber ? "wg-ep-done"
|
|
1729
1822
|
: e.episodeNumber === info.episodeNumber ? "wg-ep-current"
|
|
1730
1823
|
: "wg-ep-upcoming";
|
|
1731
|
-
return "<span class
|
|
1824
|
+
return "<span class=\\\"wg-ep-tab " + cls + "\\\">Episode " + e.episodeNumber + ": " +
|
|
1732
1825
|
esc(e.episodeTitle || "") + "</span>";
|
|
1733
1826
|
})
|
|
1734
1827
|
.join("") +
|
|
@@ -1739,8 +1832,8 @@ async function renderStepError(page, info) {
|
|
|
1739
1832
|
.map((name, idx) => {
|
|
1740
1833
|
const cls = idx === info.moduleIndex ? "wg-mod-current" : idx < info.moduleIndex ? "wg-mod-done" : "wg-mod-upcoming";
|
|
1741
1834
|
const desc = info.allDescriptions && info.allDescriptions[idx];
|
|
1742
|
-
const titleAttr = desc ? " title
|
|
1743
|
-
return "<span class
|
|
1835
|
+
const titleAttr = desc ? " title=\\\"" + esc(desc) + "\\\"" : "";
|
|
1836
|
+
return "<span class=\\\"wg-mod " + cls + "\\\"" + titleAttr + ">" + name + "</span>";
|
|
1744
1837
|
})
|
|
1745
1838
|
.join("");
|
|
1746
1839
|
const retryLabel = info.episodeNumber !== undefined ? "Retry Episode " + info.episodeNumber : "Retry";
|
|
@@ -1748,17 +1841,17 @@ async function renderStepError(page, info) {
|
|
|
1748
1841
|
? "Expected outcome - Step " + (info.index + 1) + " / " + info.total + " - " + info.blockName + " failed as intended"
|
|
1749
1842
|
: "Step " + (info.index + 1) + " / " + info.total + " - " + info.blockName + " threw";
|
|
1750
1843
|
const reasonHtml = isExpected
|
|
1751
|
-
? "<div class
|
|
1844
|
+
? "<div class=\\\"wg-expected-reason\\\">" + esc(info.expectedFailureReason) + "</div>"
|
|
1752
1845
|
: "";
|
|
1753
1846
|
panel.innerHTML =
|
|
1754
1847
|
episodesHtml +
|
|
1755
|
-
"<div id
|
|
1756
|
-
"<h3 class
|
|
1848
|
+
"<div id=\\\"wg-modules\\\" class=\\\"" + modulesClass + "\\\">" + modulesHtml + "</div>" +
|
|
1849
|
+
"<h3 class=\\\"" + (isExpected ? "wg-expected-heading" : "wg-error-heading") + "\\\">" + headingText + "</h3>" +
|
|
1757
1850
|
reasonHtml +
|
|
1758
|
-
"<div class
|
|
1759
|
-
"<div class
|
|
1760
|
-
"<button id
|
|
1761
|
-
"<button id
|
|
1851
|
+
"<div class=\\\"wg-error-msg\\\">" + esc(info.message) + "</div>" +
|
|
1852
|
+
"<div class=\\\"wg-error-actions\\\">" +
|
|
1853
|
+
"<button id=\\\"wg-error-retry\\\" class=\\\"wg-error-retry\\\">" + esc(retryLabel) + "</button>" +
|
|
1854
|
+
"<button id=\\\"wg-run\\\" class=\\\"wg-error-stop\\\">Stop</button>" +
|
|
1762
1855
|
"</div>";
|
|
1763
1856
|
if (isNewPanel) {
|
|
1764
1857
|
document.documentElement.appendChild(panel);
|
|
@@ -2022,25 +2115,25 @@ async function presentSlides(page, slides, _gate, opts) {
|
|
|
2022
2115
|
String(t).replace(/&/g, "&").replace(/</g, "<").replace(/"/g, """);
|
|
2023
2116
|
const episodeLine =
|
|
2024
2117
|
info.episodeNumber !== undefined && info.episodeNumber !== null
|
|
2025
|
-
? "<div class
|
|
2118
|
+
? "<div class=\\\"wg-episode\\\">Episode " +
|
|
2026
2119
|
info.episodeNumber +
|
|
2027
2120
|
(info.episodeTitle ? ": " + esc(info.episodeTitle) : "") +
|
|
2028
2121
|
" · yap slides</div>"
|
|
2029
2122
|
: "";
|
|
2030
2123
|
const paceHtml =
|
|
2031
2124
|
info.paceBadge || info.paceLabel
|
|
2032
|
-
? "<div class
|
|
2125
|
+
? "<div class=\\\"wg-pace\\\" data-pace-kind=\\\"" +
|
|
2033
2126
|
esc(info.paceKind || "normal") +
|
|
2034
|
-
"
|
|
2127
|
+
"\\\"><span class=\\\"wg-pace-badge\\\">" +
|
|
2035
2128
|
esc(info.paceBadge || "1x") +
|
|
2036
2129
|
"</span><span>" +
|
|
2037
2130
|
esc(info.paceLabel || "") +
|
|
2038
2131
|
"</span></div>"
|
|
2039
2132
|
: "";
|
|
2040
2133
|
panel.innerHTML =
|
|
2041
|
-
"<div class
|
|
2042
|
-
"<button type
|
|
2043
|
-
"<div class
|
|
2134
|
+
"<div class=\\\"wg-chrome\\\"><span class=\\\"wg-chrome-title\\\">waygraph demo</span>" +
|
|
2135
|
+
"<button type=\\\"button\\\" class=\\\"wg-hide-btn\\\" data-wg-toggle=\\\"1\\\">Hide</button></div>" +
|
|
2136
|
+
"<div class=\\\"wg-body\\\">" +
|
|
2044
2137
|
episodeLine +
|
|
2045
2138
|
paceHtml +
|
|
2046
2139
|
"<h3>Slide " +
|
|
@@ -2050,35 +2143,35 @@ async function presentSlides(page, slides, _gate, opts) {
|
|
|
2050
2143
|
(info.blockName ? " · " + esc(info.blockName) : "") +
|
|
2051
2144
|
"</h3>" +
|
|
2052
2145
|
(info.tag
|
|
2053
|
-
? "<div style
|
|
2146
|
+
? "<div style=\\\"border:none;padding:0;margin:0 0 6px;font-size:11px;color:#c9a6ff\\\">" +
|
|
2054
2147
|
esc(info.tag) +
|
|
2055
2148
|
"</div>"
|
|
2056
2149
|
: "") +
|
|
2057
|
-
"<div class
|
|
2150
|
+
"<div class=\\\"wg-narration\\\">" +
|
|
2058
2151
|
esc(info.caption) +
|
|
2059
2152
|
"</div>" +
|
|
2060
2153
|
(info.detail
|
|
2061
|
-
? "<div class
|
|
2154
|
+
? "<div class=\\\"wg-result-pretty\\\" style=\\\"margin:0 0 12px;color:#f0e8ff\\\">" +
|
|
2062
2155
|
esc(info.detail) +
|
|
2063
2156
|
"</div>"
|
|
2064
2157
|
: "") +
|
|
2065
2158
|
(info.dwellMs != null
|
|
2066
|
-
? "<div class
|
|
2159
|
+
? "<div class=\\\"wg-auto\\\" id=\\\"wg-dwell-hint\\\" style=\\\"margin:0 0 8px\\\">Hold " +
|
|
2067
2160
|
(info.dwellMs / 1000).toFixed(1) +
|
|
2068
2161
|
"s before next...</div>"
|
|
2069
2162
|
: "") +
|
|
2070
|
-
"<div class
|
|
2163
|
+
"<div class=\\\"wg-autoplay-row\\\"><label><input type=\\\"checkbox\\\" id=\\\"wg-autoplay-cb\\\"" +
|
|
2071
2164
|
(info.autoNow ? " checked" : "") +
|
|
2072
2165
|
"> Auto-advance</label></div>" +
|
|
2073
|
-
"<div id
|
|
2074
|
-
(info.autoNow ? " style
|
|
2075
|
-
"><button type
|
|
2166
|
+
"<div id=\\\"wg-gate-manual\\\"" +
|
|
2167
|
+
(info.autoNow ? " style=\\\"display:none\\\"" : "") +
|
|
2168
|
+
"><button type=\\\"button\\\" id=\\\"wg-run\\\"" +
|
|
2076
2169
|
(info.dwellMs != null ? " disabled" : "") +
|
|
2077
2170
|
">" +
|
|
2078
2171
|
(info.isLast ? "Continue \\u25B6" : "Next slide \\u25B6") +
|
|
2079
2172
|
"</button></div>" +
|
|
2080
|
-
"<div id
|
|
2081
|
-
(info.autoNow ? "" : " style
|
|
2173
|
+
"<div id=\\\"wg-gate-auto\\\" class=\\\"wg-auto\\\"" +
|
|
2174
|
+
(info.autoNow ? "" : " style=\\\"display:none\\\"") +
|
|
2082
2175
|
">Auto-advancing...</div>" +
|
|
2083
2176
|
"</div>";
|
|
2084
2177
|
if (isNew) {
|
|
@@ -2243,7 +2336,7 @@ async function teardownOverlay(page) {
|
|
|
2243
2336
|
window.__wgRingTrack = null;
|
|
2244
2337
|
}
|
|
2245
2338
|
window.__wgNarrateOwnsRing = false;
|
|
2246
|
-
for (const id of ["wg-panel", "wg-ring", "wg-ring-label", "wg-cursor", "wg-click-pulse", "wg-banner", "wg-todo-modal"]) {
|
|
2339
|
+
for (const id of ["wg-panel", "wg-ring", "wg-ring-label", "wg-cursor", "wg-click-pulse", "wg-banner", "wg-todo-modal", "wg-focus-veil"]) {
|
|
2247
2340
|
const el = document.getElementById(id);
|
|
2248
2341
|
if (el) el.remove();
|
|
2249
2342
|
}
|
package/dist/highlights.d.ts
CHANGED
|
@@ -89,6 +89,14 @@ export interface WaygraphHighlightStub extends FixtureDurationFields {
|
|
|
89
89
|
* Spotlight: dim the rest of the page, keep this target as the focal point.
|
|
90
90
|
*/
|
|
91
91
|
focus?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* After camera zoom settles, pan with the real mouse pointer (Screen Studio).
|
|
94
|
+
* Default: on when `zoom` > 1. Set false to lock the camera on the target.
|
|
95
|
+
* Alias: `follow`.
|
|
96
|
+
*/
|
|
97
|
+
followMouse?: boolean;
|
|
98
|
+
/** Alias for {@link WaygraphHighlightStub.followMouse}. */
|
|
99
|
+
follow?: boolean;
|
|
92
100
|
/**
|
|
93
101
|
* Caption text color (CSS color). Overrides tone label color when set.
|
|
94
102
|
* Aliases accepted at runtime: `color`, `labelColor`, `textColor`.
|
|
@@ -101,7 +109,7 @@ export interface WaygraphHighlightStub extends FixtureDurationFields {
|
|
|
101
109
|
cursor?: boolean;
|
|
102
110
|
}
|
|
103
111
|
/** Flow fixture patch: label required; selector optional (inherits from stub). */
|
|
104
|
-
export type WaygraphHighlightFixture = Partial<Pick<WaygraphHighlightStub, "selector">> & Required<Pick<WaygraphHighlightStub, "label">> & Pick<WaygraphHighlightStub, "detail" | "tag" | "tone" | "size" | "weight" | "zoom" | "focus" | "color" | "cursor"> & FixtureDurationFields;
|
|
112
|
+
export type WaygraphHighlightFixture = Partial<Pick<WaygraphHighlightStub, "selector">> & Required<Pick<WaygraphHighlightStub, "label">> & Pick<WaygraphHighlightStub, "detail" | "tag" | "tone" | "size" | "weight" | "zoom" | "focus" | "followMouse" | "follow" | "color" | "cursor"> & FixtureDurationFields;
|
|
105
113
|
export type HighlightStubPhase = Record<string, WaygraphHighlightStub>;
|
|
106
114
|
/**
|
|
107
115
|
* Open stub lifecycle context. Authors set rings + episode fixtures freely —
|