waygraph 0.12.34 → 0.12.36
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 +25 -7
- package/dist/highlights.d.ts +15 -3
- package/dist/highlights.js +12 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +6 -1
- package/package.json +1 -1
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -1
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +6 -1
package/dist/cli.js
CHANGED
|
@@ -829,11 +829,15 @@ async function installOverlay(page, title) {
|
|
|
829
829
|
const el0 = document.querySelector(sel);
|
|
830
830
|
if (el0) {
|
|
831
831
|
const r0 = el0.getBoundingClientRect();
|
|
832
|
+
const already =
|
|
833
|
+
window.__wgCamera && window.__wgCamera.scale > 1.001;
|
|
834
|
+
// Already zoomed (zoomOut:false chain): short pan, not full zoom-in.
|
|
835
|
+
const dur = already ? Math.min(camMs, 420) : camMs;
|
|
832
836
|
window.__wgSetCamera(
|
|
833
837
|
r0.left + r0.width / 2,
|
|
834
838
|
r0.top + r0.height / 2,
|
|
835
839
|
zoom,
|
|
836
|
-
|
|
840
|
+
dur,
|
|
837
841
|
);
|
|
838
842
|
}
|
|
839
843
|
}
|
|
@@ -885,7 +889,8 @@ async function installOverlay(page, title) {
|
|
|
885
889
|
if (ring) ring.style.opacity = "0";
|
|
886
890
|
if (ringLabel) ringLabel.style.opacity = "0";
|
|
887
891
|
if (window.__wgHideFocusVeil) window.__wgHideFocusVeil();
|
|
888
|
-
|
|
892
|
+
// Do NOT clear camera zoom here - zoomOut:false keeps scale between
|
|
893
|
+
// rings; only resetCameraZoom / teardown call __wgClearZoom.
|
|
889
894
|
};
|
|
890
895
|
// Screen Studio-style camera: scale <body>, keep overlays on <html> fixed.
|
|
891
896
|
window.__wgCamera = { scale: 1, cx: 0, cy: 0 };
|
|
@@ -1590,7 +1595,11 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1590
1595
|
},
|
|
1591
1596
|
)
|
|
1592
1597
|
.catch(() => {});
|
|
1593
|
-
|
|
1598
|
+
const alreadyZoomed = await page
|
|
1599
|
+
.evaluate(() => !!(window.__wgCamera && window.__wgCamera.scale > 1.001))
|
|
1600
|
+
.catch(() => false);
|
|
1601
|
+
const waitMs = alreadyZoomed ? Math.min(camMs, 420) : camMs;
|
|
1602
|
+
await new Promise((res) => setTimeout(res, waitMs));
|
|
1594
1603
|
|
|
1595
1604
|
// Appear settle
|
|
1596
1605
|
await new Promise((res) => setTimeout(res, fadeMs));
|
|
@@ -1599,17 +1608,22 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1599
1608
|
const holdMs =
|
|
1600
1609
|
authored != null ? authored : defaultHoldMs != null ? defaultHoldMs : legacyMs;
|
|
1601
1610
|
await new Promise((res) => setTimeout(res, holdMs));
|
|
1602
|
-
// Disappear before next
|
|
1611
|
+
// Disappear before next. zoomOut:false keeps camera for the next ring.
|
|
1603
1612
|
await stopLiveFollow();
|
|
1604
1613
|
await hideRing(page);
|
|
1605
|
-
|
|
1606
|
-
|
|
1614
|
+
const doZoomOut = h.zoomOut !== false;
|
|
1615
|
+
if (doZoomOut) await resetCameraZoom(page);
|
|
1616
|
+
await new Promise((res) => setTimeout(res, doZoomOut ? fadeMs : 120));
|
|
1607
1617
|
} catch {
|
|
1608
1618
|
/* best-effort */
|
|
1609
1619
|
}
|
|
1610
1620
|
}
|
|
1611
1621
|
await stopLiveFollow();
|
|
1612
|
-
|
|
1622
|
+
// Keep camera if the last ring (or phase default) asked zoomOut:false.
|
|
1623
|
+
const last = list.length > 0 ? list[list.length - 1] : null;
|
|
1624
|
+
if (!last || last.zoomOut !== false) {
|
|
1625
|
+
await resetCameraZoom(page);
|
|
1626
|
+
}
|
|
1613
1627
|
if (list.length === 0) {
|
|
1614
1628
|
await hideRing(page);
|
|
1615
1629
|
}
|
|
@@ -2336,6 +2350,7 @@ async function teardownOverlay(page) {
|
|
|
2336
2350
|
window.__wgRingTrack = null;
|
|
2337
2351
|
}
|
|
2338
2352
|
window.__wgNarrateOwnsRing = false;
|
|
2353
|
+
if (window.__wgClearZoom) window.__wgClearZoom();
|
|
2339
2354
|
for (const id of ["wg-panel", "wg-ring", "wg-ring-label", "wg-cursor", "wg-click-pulse", "wg-banner", "wg-todo-modal", "wg-focus-veil"]) {
|
|
2340
2355
|
const el = document.getElementById(id);
|
|
2341
2356
|
if (el) el.remove();
|
|
@@ -2939,6 +2954,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2939
2954
|
focus: styled.focus,
|
|
2940
2955
|
color: styled.color,
|
|
2941
2956
|
cursor: styled.cursor,
|
|
2957
|
+
zoomOut: styled.zoomOut,
|
|
2942
2958
|
};
|
|
2943
2959
|
});
|
|
2944
2960
|
await cycleHighlightRings(page, beforeRings, !!pacing.gatesFast, {
|
|
@@ -3019,6 +3035,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
3019
3035
|
focus: styled.focus,
|
|
3020
3036
|
color: styled.color,
|
|
3021
3037
|
cursor: styled.cursor,
|
|
3038
|
+
zoomOut: styled.zoomOut,
|
|
3022
3039
|
};
|
|
3023
3040
|
});
|
|
3024
3041
|
await cycleHighlightRings(page, errHighlights, !!pacing.gatesFast, {
|
|
@@ -3113,6 +3130,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
3113
3130
|
focus: styled.focus,
|
|
3114
3131
|
color: styled.color,
|
|
3115
3132
|
cursor: styled.cursor,
|
|
3133
|
+
zoomOut: styled.zoomOut,
|
|
3116
3134
|
};
|
|
3117
3135
|
});
|
|
3118
3136
|
} else {
|
package/dist/highlights.d.ts
CHANGED
|
@@ -50,6 +50,8 @@ export type StubPhaseFixtures = {
|
|
|
50
50
|
* cursor. Not element CSS zoom. Typical `1.25` .. `2`.
|
|
51
51
|
*/
|
|
52
52
|
zoom?: number;
|
|
53
|
+
/** Default zoomOut for rings (false = keep camera between rings). */
|
|
54
|
+
zoomOut?: boolean;
|
|
53
55
|
/** Top demo banner title (the purple "waygraph demo" card). */
|
|
54
56
|
title?: string;
|
|
55
57
|
};
|
|
@@ -81,10 +83,15 @@ export interface WaygraphHighlightStub extends FixtureDurationFields {
|
|
|
81
83
|
weight?: HighlightWeight;
|
|
82
84
|
/**
|
|
83
85
|
* Camera zoom while this ring is up (Screen Studio style - page scales toward
|
|
84
|
-
* the target / cursor). Typical `1.25` .. `2`. Cleared when the ring hides
|
|
85
|
-
* Episode default: {@link StubCtx.zoom}.
|
|
86
|
+
* the target / cursor). Typical `1.25` .. `2`. Cleared when the ring hides
|
|
87
|
+
* unless `zoomOut: false`. Episode default: {@link StubCtx.zoom}.
|
|
86
88
|
*/
|
|
87
89
|
zoom?: number;
|
|
90
|
+
/**
|
|
91
|
+
* When false, keep the camera zoomed after this ring (pan to the next target
|
|
92
|
+
* instead of zooming out). Default true. Phase default: {@link StubCtx.zoomOut}.
|
|
93
|
+
*/
|
|
94
|
+
zoomOut?: boolean;
|
|
88
95
|
/**
|
|
89
96
|
* Spotlight: dim the rest of the page, keep this target as the focal point.
|
|
90
97
|
*/
|
|
@@ -109,7 +116,7 @@ export interface WaygraphHighlightStub extends FixtureDurationFields {
|
|
|
109
116
|
cursor?: boolean;
|
|
110
117
|
}
|
|
111
118
|
/** Flow fixture patch: label required; selector optional (inherits from stub). */
|
|
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;
|
|
119
|
+
export type WaygraphHighlightFixture = Partial<Pick<WaygraphHighlightStub, "selector">> & Required<Pick<WaygraphHighlightStub, "label">> & Pick<WaygraphHighlightStub, "detail" | "tag" | "tone" | "size" | "weight" | "zoom" | "zoomOut" | "focus" | "followMouse" | "follow" | "color" | "cursor"> & FixtureDurationFields;
|
|
113
120
|
export type HighlightStubPhase = Record<string, WaygraphHighlightStub>;
|
|
114
121
|
/**
|
|
115
122
|
* Open stub lifecycle context. Authors set rings + episode fixtures freely —
|
|
@@ -147,6 +154,10 @@ export type StubCtx<Out extends Checkpoint<string> = Checkpoint<string>> = {
|
|
|
147
154
|
todoIndex(n: number): void;
|
|
148
155
|
/** Default camera zoom for rings without their own zoom. */
|
|
149
156
|
zoom(n: number): void;
|
|
157
|
+
/**
|
|
158
|
+
* Default zoomOut for rings in this phase. `false` = keep camera between rings.
|
|
159
|
+
*/
|
|
160
|
+
zoomOut(keep: boolean): void;
|
|
150
161
|
/** Top banner title (waygraph demo card). */
|
|
151
162
|
title(text: string): void;
|
|
152
163
|
/** Alias for {@link StubCtx.title}. */
|
|
@@ -170,6 +181,7 @@ export type StubPhaseResult = {
|
|
|
170
181
|
todos: WaygraphTodoItem[];
|
|
171
182
|
todoIndex?: number;
|
|
172
183
|
zoom?: number;
|
|
184
|
+
zoomOut?: boolean;
|
|
173
185
|
title?: string;
|
|
174
186
|
};
|
|
175
187
|
/**
|
package/dist/highlights.js
CHANGED
|
@@ -403,6 +403,9 @@ function createStubCtx(bag, opts) {
|
|
|
403
403
|
if (Number.isFinite(n) && n > 0)
|
|
404
404
|
bag.zoom = n;
|
|
405
405
|
},
|
|
406
|
+
zoomOut(keep) {
|
|
407
|
+
bag.zoomOut = !!keep;
|
|
408
|
+
},
|
|
406
409
|
title(text) {
|
|
407
410
|
bag.title = String(text ?? "");
|
|
408
411
|
},
|
|
@@ -419,6 +422,8 @@ function createStubCtx(bag, opts) {
|
|
|
419
422
|
if (partial.zoom !== undefined && Number.isFinite(partial.zoom) && partial.zoom > 0) {
|
|
420
423
|
bag.zoom = partial.zoom;
|
|
421
424
|
}
|
|
425
|
+
if (partial.zoomOut !== undefined)
|
|
426
|
+
bag.zoomOut = !!partial.zoomOut;
|
|
422
427
|
if (partial.title !== undefined)
|
|
423
428
|
bag.title = String(partial.title ?? "");
|
|
424
429
|
},
|
|
@@ -443,6 +448,11 @@ function applyDefaultZoom(slots, defaultZoom) {
|
|
|
443
448
|
return slots;
|
|
444
449
|
return slots.map((h) => (h.zoom !== undefined && h.zoom > 0 ? h : { ...h, zoom: defaultZoom }));
|
|
445
450
|
}
|
|
451
|
+
function applyDefaultZoomOut(slots, defaultZoomOut) {
|
|
452
|
+
if (defaultZoomOut === undefined)
|
|
453
|
+
return slots;
|
|
454
|
+
return slots.map((h) => h.zoomOut !== undefined ? h : { ...h, zoomOut: defaultZoomOut });
|
|
455
|
+
}
|
|
446
456
|
function mergePhaseMaps(phaseMap, fixturePhase) {
|
|
447
457
|
const slotIds = new Set([...Object.keys(phaseMap), ...Object.keys(fixturePhase || {})]);
|
|
448
458
|
const ordered = [...slotIds].sort((a, b) => {
|
|
@@ -546,12 +556,14 @@ export async function runStubPhase(block, phase, opts) {
|
|
|
546
556
|
const fixturePhase = opts?.fixtures?.[block.name]?.[phase];
|
|
547
557
|
let highlights = mergePhaseMaps(bag.highlights, fixturePhase);
|
|
548
558
|
highlights = applyDefaultZoom(highlights, bag.zoom);
|
|
559
|
+
highlights = applyDefaultZoomOut(highlights, bag.zoomOut);
|
|
549
560
|
const todos = normalizeTodos(bag.todos, bag.todoIndex);
|
|
550
561
|
return {
|
|
551
562
|
highlights,
|
|
552
563
|
todos,
|
|
553
564
|
...(bag.todoIndex !== undefined ? { todoIndex: bag.todoIndex } : {}),
|
|
554
565
|
...(bag.zoom !== undefined ? { zoom: bag.zoom } : {}),
|
|
566
|
+
...(bag.zoomOut !== undefined ? { zoomOut: bag.zoomOut } : {}),
|
|
555
567
|
...(bag.title !== undefined && bag.title !== "" ? { title: bag.title } : {}),
|
|
556
568
|
};
|
|
557
569
|
}
|
|
@@ -15,12 +15,12 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
15
15
|
checkpoint: "CartPage",
|
|
16
16
|
click: ".shopping_cart_link",
|
|
17
17
|
verify: [Trait.url({ pathname: "/cart.html" })],
|
|
18
|
-
// Demo: zoom cart chrome, then the cart line items after landing.
|
|
19
18
|
stubBefore: (ctx) => {
|
|
20
19
|
ctx.title("Open cart");
|
|
21
20
|
ctx.todos(["Find the product", "Add to cart", "Open cart"]);
|
|
22
21
|
ctx.todoIndex(2);
|
|
23
22
|
ctx.zoom(1.4);
|
|
23
|
+
ctx.zoomOut(false);
|
|
24
24
|
ctx.highlights({
|
|
25
25
|
cart: {
|
|
26
26
|
selector: ".shopping_cart_link",
|
|
@@ -29,6 +29,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
29
29
|
focus: true,
|
|
30
30
|
color: "#c9a6ff",
|
|
31
31
|
zoom: 1.55,
|
|
32
|
+
zoomOut: false,
|
|
32
33
|
followMouse: true,
|
|
33
34
|
weight: "bold",
|
|
34
35
|
},
|
|
@@ -36,6 +37,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
36
37
|
},
|
|
37
38
|
stubAfter: (ctx) => {
|
|
38
39
|
ctx.banner("Your cart");
|
|
40
|
+
ctx.zoomOut(false);
|
|
39
41
|
ctx.ring("items", {
|
|
40
42
|
selector: InventorySel.cartItem,
|
|
41
43
|
label: "Cart items",
|
package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts
CHANGED
|
@@ -33,12 +33,13 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
33
33
|
},
|
|
34
34
|
},
|
|
35
35
|
],
|
|
36
|
-
// Demo
|
|
36
|
+
// Demo: zoom product -> add (stay zoomed), then badge after act.
|
|
37
37
|
stubBefore: (ctx) => {
|
|
38
38
|
ctx.title("Pick a product");
|
|
39
39
|
ctx.todos(["Find the product", "Add to cart", "Open cart"]);
|
|
40
40
|
ctx.todoIndex(0);
|
|
41
41
|
ctx.zoom(1.35);
|
|
42
|
+
ctx.zoomOut(false);
|
|
42
43
|
ctx.highlights({
|
|
43
44
|
product: {
|
|
44
45
|
selector: InventorySel.title(DEMO_PRODUCT_ID),
|
|
@@ -47,6 +48,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
47
48
|
focus: true,
|
|
48
49
|
color: "#c9a6ff",
|
|
49
50
|
zoom: 1.45,
|
|
51
|
+
zoomOut: false,
|
|
50
52
|
followMouse: true,
|
|
51
53
|
},
|
|
52
54
|
add: {
|
|
@@ -55,6 +57,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
55
57
|
focus: true,
|
|
56
58
|
color: "#86efac",
|
|
57
59
|
zoom: 1.5,
|
|
60
|
+
zoomOut: false,
|
|
58
61
|
weight: "bold",
|
|
59
62
|
},
|
|
60
63
|
});
|
|
@@ -63,6 +66,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
63
66
|
ctx.banner("In the cart");
|
|
64
67
|
ctx.todos(["Find the product", "Add to cart", "Open cart"]);
|
|
65
68
|
ctx.todoIndex(1);
|
|
69
|
+
ctx.zoomOut(false);
|
|
66
70
|
ctx.ring("badge", {
|
|
67
71
|
selector: InventorySel.cartBadge,
|
|
68
72
|
label: "Cart badge",
|
|
@@ -70,6 +74,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
70
74
|
focus: true,
|
|
71
75
|
color: "#86efac",
|
|
72
76
|
zoom: 1.6,
|
|
77
|
+
zoomOut: false,
|
|
73
78
|
followMouse: true,
|
|
74
79
|
duration: true,
|
|
75
80
|
});
|
package/package.json
CHANGED
|
@@ -15,12 +15,12 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
15
15
|
checkpoint: "CartPage",
|
|
16
16
|
click: ".shopping_cart_link",
|
|
17
17
|
verify: [Trait.url({ pathname: "/cart.html" })],
|
|
18
|
-
// Demo: zoom cart chrome, then the cart line items after landing.
|
|
19
18
|
stubBefore: (ctx) => {
|
|
20
19
|
ctx.title("Open cart");
|
|
21
20
|
ctx.todos(["Find the product", "Add to cart", "Open cart"]);
|
|
22
21
|
ctx.todoIndex(2);
|
|
23
22
|
ctx.zoom(1.4);
|
|
23
|
+
ctx.zoomOut(false);
|
|
24
24
|
ctx.highlights({
|
|
25
25
|
cart: {
|
|
26
26
|
selector: ".shopping_cart_link",
|
|
@@ -29,6 +29,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
29
29
|
focus: true,
|
|
30
30
|
color: "#c9a6ff",
|
|
31
31
|
zoom: 1.55,
|
|
32
|
+
zoomOut: false,
|
|
32
33
|
followMouse: true,
|
|
33
34
|
weight: "bold",
|
|
34
35
|
},
|
|
@@ -36,6 +37,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
36
37
|
},
|
|
37
38
|
stubAfter: (ctx) => {
|
|
38
39
|
ctx.banner("Your cart");
|
|
40
|
+
ctx.zoomOut(false);
|
|
39
41
|
ctx.ring("items", {
|
|
40
42
|
selector: InventorySel.cartItem,
|
|
41
43
|
label: "Cart items",
|
package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts
CHANGED
|
@@ -33,12 +33,13 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
33
33
|
},
|
|
34
34
|
},
|
|
35
35
|
],
|
|
36
|
-
// Demo
|
|
36
|
+
// Demo: zoom product -> add (stay zoomed), then badge after act.
|
|
37
37
|
stubBefore: (ctx) => {
|
|
38
38
|
ctx.title("Pick a product");
|
|
39
39
|
ctx.todos(["Find the product", "Add to cart", "Open cart"]);
|
|
40
40
|
ctx.todoIndex(0);
|
|
41
41
|
ctx.zoom(1.35);
|
|
42
|
+
ctx.zoomOut(false);
|
|
42
43
|
ctx.highlights({
|
|
43
44
|
product: {
|
|
44
45
|
selector: InventorySel.title(DEMO_PRODUCT_ID),
|
|
@@ -47,6 +48,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
47
48
|
focus: true,
|
|
48
49
|
color: "#c9a6ff",
|
|
49
50
|
zoom: 1.45,
|
|
51
|
+
zoomOut: false,
|
|
50
52
|
followMouse: true,
|
|
51
53
|
},
|
|
52
54
|
add: {
|
|
@@ -55,6 +57,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
55
57
|
focus: true,
|
|
56
58
|
color: "#86efac",
|
|
57
59
|
zoom: 1.5,
|
|
60
|
+
zoomOut: false,
|
|
58
61
|
weight: "bold",
|
|
59
62
|
},
|
|
60
63
|
});
|
|
@@ -63,6 +66,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
63
66
|
ctx.banner("In the cart");
|
|
64
67
|
ctx.todos(["Find the product", "Add to cart", "Open cart"]);
|
|
65
68
|
ctx.todoIndex(1);
|
|
69
|
+
ctx.zoomOut(false);
|
|
66
70
|
ctx.ring("badge", {
|
|
67
71
|
selector: InventorySel.cartBadge,
|
|
68
72
|
label: "Cart badge",
|
|
@@ -70,6 +74,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
70
74
|
focus: true,
|
|
71
75
|
color: "#86efac",
|
|
72
76
|
zoom: 1.6,
|
|
77
|
+
zoomOut: false,
|
|
73
78
|
followMouse: true,
|
|
74
79
|
duration: true,
|
|
75
80
|
});
|