waygraph 0.12.38 → 0.12.39

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 CHANGED
@@ -892,9 +892,13 @@ async function installOverlay(page, title) {
892
892
  };
893
893
  window.__wgCameraLock = true;
894
894
  window.__wgSetCamera(pt.x, pt.y, zoom, dur);
895
- setTimeout(() => {
896
- window.__wgCameraLock = false;
897
- }, dur + 40);
895
+ // Unlock for dead-zone follow only when explicitly allowed.
896
+ // zoomOut:false / cart-edge targets stay locked through dwell+click.
897
+ if (followMouse && opts.allowFollow) {
898
+ setTimeout(() => {
899
+ window.__wgCameraLock = false;
900
+ }, dur + 40);
901
+ }
898
902
  }
899
903
  }
900
904
  window.__wgRingRaf = requestAnimationFrame(tick);
@@ -1418,6 +1422,25 @@ async function renderBeforeStep(page, info) {
1418
1422
 
1419
1423
  async function ensureSelectorInView(page, selector) {
1420
1424
  try {
1425
+ // Body-scale camera + scrollIntoView = teleport / "outside viewport" loop.
1426
+ // When zoomed, pan the camera to the target instead of scrolling the document.
1427
+ const zoomed = await page
1428
+ .evaluate(() => !!(window.__wgCamera && window.__wgCamera.scale > 1.001))
1429
+ .catch(() => false);
1430
+ if (zoomed) {
1431
+ await page
1432
+ .evaluate((sel) => {
1433
+ const el = document.querySelector(sel);
1434
+ if (!el || !window.__wgSetCamera || !window.__wgElDocPoint) return;
1435
+ const cam = window.__wgCamera;
1436
+ const pt = window.__wgElDocPoint(el);
1437
+ window.__wgCameraLock = true;
1438
+ window.__wgSetCamera(pt.x, pt.y, cam.scale > 1 ? cam.scale : 1.4, 320);
1439
+ }, selector)
1440
+ .catch(() => {});
1441
+ await new Promise((res) => setTimeout(res, 340));
1442
+ return;
1443
+ }
1421
1444
  const loc = page.locator(selector).first();
1422
1445
  await loc.scrollIntoViewIfNeeded().catch(() => {});
1423
1446
  await page
@@ -1641,7 +1664,7 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
1641
1664
  // body scale (html cursor is outside the transform).
1642
1665
  await page
1643
1666
  .evaluate(
1644
- ({ sel, label, tone, size, weight, focus, color, zoom, followMouse, camMs }) => {
1667
+ ({ sel, label, tone, size, weight, focus, color, zoom, followMouse, camMs, allowFollow }) => {
1645
1668
  if (window.__wgStartHighlightTrack) {
1646
1669
  window.__wgStartHighlightTrack({
1647
1670
  sel,
@@ -1654,6 +1677,7 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
1654
1677
  zoom,
1655
1678
  followMouse,
1656
1679
  camMs,
1680
+ allowFollow,
1657
1681
  });
1658
1682
  }
1659
1683
  },
@@ -1668,6 +1692,9 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
1668
1692
  zoom: z,
1669
1693
  followMouse,
1670
1694
  camMs,
1695
+ // Follow only while zoomed-out-between-rings is OK. zoomOut:false
1696
+ // means hold the frame for the upcoming click - no chase.
1697
+ allowFollow: followMouse && h.zoomOut !== false,
1671
1698
  },
1672
1699
  )
1673
1700
  .catch(() => {});
@@ -2701,12 +2728,28 @@ function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stubBefore
2701
2728
  const zoomedClick = await page
2702
2729
  .evaluate(() => !!(window.__wgCamera && window.__wgCamera.scale > 1.001))
2703
2730
  .catch(() => false);
2704
- const clickOpts =
2705
- zoomedClick || keptCameraLock
2706
- ? { ...(options || {}), force: true }
2707
- : options;
2708
2731
  try {
2709
- const result = await originalClick.call(this, clickOpts);
2732
+ let result;
2733
+ if (zoomedClick || keptCameraLock) {
2734
+ // Playwright scrollIntoView + body-scale camera = "outside viewport"
2735
+ // retry storm. Click the element in-page with no scrolling.
2736
+ const handle = await this.elementHandle().catch(() => null);
2737
+ if (handle) {
2738
+ await handle.evaluate((el) => {
2739
+ if (el && typeof el.click === "function") el.click();
2740
+ });
2741
+ await handle.dispose().catch(() => {});
2742
+ result = undefined;
2743
+ } else {
2744
+ result = await originalClick.call(this, {
2745
+ ...(options || {}),
2746
+ force: true,
2747
+ timeout: (options && options.timeout) || 5000,
2748
+ });
2749
+ }
2750
+ } else {
2751
+ result = await originalClick.call(this, options);
2752
+ }
2710
2753
  await new Promise((res) => setTimeout(res, clickPostPop()));
2711
2754
  await hideRing(page);
2712
2755
  return result;
@@ -30,7 +30,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
30
30
  color: "#c9a6ff",
31
31
  zoom: 1.55,
32
32
  zoomOut: false,
33
- followMouse: true,
33
+ followMouse: false,
34
34
  weight: "bold",
35
35
  },
36
36
  });
@@ -45,7 +45,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
45
45
  focus: true,
46
46
  color: "#86efac",
47
47
  zoom: 1.4,
48
- followMouse: true,
48
+ followMouse: false,
49
49
  duration: true,
50
50
  });
51
51
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waygraph",
3
- "version": "0.12.38",
3
+ "version": "0.12.39",
4
4
  "type": "module",
5
5
  "description": "A typed graph of reusable Blocks for driving a browser through E2E flows.",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
30
30
  color: "#c9a6ff",
31
31
  zoom: 1.55,
32
32
  zoomOut: false,
33
- followMouse: true,
33
+ followMouse: false,
34
34
  weight: "bold",
35
35
  },
36
36
  });
@@ -45,7 +45,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
45
45
  focus: true,
46
46
  color: "#86efac",
47
47
  zoom: 1.4,
48
- followMouse: true,
48
+ followMouse: false,
49
49
  duration: true,
50
50
  });
51
51
  },