waygraph 0.12.15 → 0.12.17
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/README.md +3 -1
- package/dist/cli.js +95 -32
- package/dist/engine.d.ts +14 -2
- package/dist/engine.js +19 -0
- package/dist/highlights.d.ts +37 -1
- package/dist/highlights.js +63 -8
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/step-overlay.js +19 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -235,7 +235,9 @@ snapshot, partitions edges by hash, and claims via in-process edge leases (audit
|
|
|
235
235
|
`docs/proposals/traverse-ffcompose-rfc.md`.
|
|
236
236
|
|
|
237
237
|
**Richer demo narration:** automation rings are **gray**; authored stubs/slides can use
|
|
238
|
-
`tone: "info" | "warning" | "danger" | "success"` (iconified captions)
|
|
238
|
+
`tone: "info" | "warning" | "danger" | "success"` (iconified captions), plus
|
|
239
|
+
`size: "sm" | "md" | "lg"` and `weight: "normal" | "bold"`. Flow episode defaults:
|
|
240
|
+
`withHighlightStyle(flow, { size, weight, tone? })` (slot/fixture wins). Episode pacing:
|
|
239
241
|
`withDemoPace(flow, "fast" | "slow" | "normal" | "blitz")` or `withBlockPace(block, ...)`
|
|
240
242
|
(FFCompose stays blitz). Living objectives: `docs/proposals/OBJECTIVES.md`.
|
|
241
243
|
`spawnTab(entry, page, mem)` drives a genuinely separate second tab through its own
|
package/dist/cli.js
CHANGED
|
@@ -213,6 +213,9 @@ import {
|
|
|
213
213
|
hasAuthoredStubOnError,
|
|
214
214
|
normalizeHighlightTone,
|
|
215
215
|
normalizeDemoPace,
|
|
216
|
+
normalizeHighlightSize,
|
|
217
|
+
normalizeHighlightWeight,
|
|
218
|
+
applyHighlightStyleDefaults,
|
|
216
219
|
resolveStepDemoPace,
|
|
217
220
|
} from "waygraph";
|
|
218
221
|
|
|
@@ -425,6 +428,13 @@ const RING_CSS =
|
|
|
425
428
|
"#wg-ring-label[data-tone=warning]{background:#EAB308;color:#1c1917;}" +
|
|
426
429
|
"#wg-ring-label[data-tone=danger]{background:#DC2626;color:#fff;}" +
|
|
427
430
|
"#wg-ring-label[data-tone=success]{background:#16A34A;color:#fff;}" +
|
|
431
|
+
// size: ring pad + label font; weight: label boldness
|
|
432
|
+
"#wg-ring[data-size=sm]{border-width:1.5px;border-radius:8px;}" +
|
|
433
|
+
"#wg-ring[data-size=lg]{border-width:4px;border-radius:12px;}" +
|
|
434
|
+
"#wg-ring-label[data-size=sm]{font-size:10px;line-height:1.25;padding:4px 7px;border-radius:5px;}" +
|
|
435
|
+
"#wg-ring-label[data-size=lg]{font-size:16px;line-height:1.35;padding:8px 14px;border-radius:9px;max-width:min(480px,85vw);}" +
|
|
436
|
+
"#wg-ring-label[data-weight=bold]{font-weight:800;}" +
|
|
437
|
+
"#wg-ring-label[data-weight=normal]{font-weight:600;}" +
|
|
428
438
|
// Mouse cursor icon that travels to a target before it's acted on, plus a
|
|
429
439
|
// quick expanding ripple at the moment of a click - same idea as
|
|
430
440
|
// help-center-clip-engine's #clip-cursor/#clip-ring (video-pipeline). The
|
|
@@ -662,7 +672,7 @@ async function installOverlay(page, title) {
|
|
|
662
672
|
const cursor = document.getElementById("wg-cursor");
|
|
663
673
|
if (cursor) cursor.style.opacity = "0";
|
|
664
674
|
};
|
|
665
|
-
window.__wgPositionRing = (box, label, tone) => {
|
|
675
|
+
window.__wgPositionRing = (box, label, tone, style) => {
|
|
666
676
|
const ring = document.getElementById("wg-ring");
|
|
667
677
|
const ringLabel = document.getElementById("wg-ring-label");
|
|
668
678
|
if (!ring || !ringLabel) return;
|
|
@@ -671,15 +681,25 @@ async function installOverlay(page, title) {
|
|
|
671
681
|
raw === "auto" || raw === "info" || raw === "warning" || raw === "danger" || raw === "success"
|
|
672
682
|
? raw
|
|
673
683
|
: "planned";
|
|
684
|
+
const st = style && typeof style === "object" ? style : {};
|
|
685
|
+
const sizeRaw = (st.size || "md") + "";
|
|
686
|
+
const size =
|
|
687
|
+
sizeRaw === "sm" || sizeRaw === "lg" ? sizeRaw : "md";
|
|
688
|
+
const weightRaw = (st.weight || "normal") + "";
|
|
689
|
+
const weight = weightRaw === "bold" ? "bold" : "normal";
|
|
674
690
|
ring.dataset.tone = t;
|
|
675
691
|
ringLabel.dataset.tone = t;
|
|
692
|
+
ring.dataset.size = size;
|
|
693
|
+
ringLabel.dataset.size = size;
|
|
694
|
+
ringLabel.dataset.weight = weight;
|
|
695
|
+
const pad = size === "sm" ? 3 : size === "lg" ? 10 : 6;
|
|
676
696
|
const margin = 6;
|
|
677
697
|
const vw = window.innerWidth;
|
|
678
698
|
const vh = window.innerHeight;
|
|
679
|
-
let left = box.x -
|
|
680
|
-
let top = box.y -
|
|
681
|
-
const width = box.width +
|
|
682
|
-
const height = box.height +
|
|
699
|
+
let left = box.x - pad;
|
|
700
|
+
let top = box.y - pad;
|
|
701
|
+
const width = box.width + pad * 2;
|
|
702
|
+
const height = box.height + pad * 2;
|
|
683
703
|
if (left < margin) left = margin;
|
|
684
704
|
if (top < margin) top = margin;
|
|
685
705
|
if (left + width > vw - margin) left = Math.max(margin, vw - margin - width);
|
|
@@ -1058,7 +1078,10 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1058
1078
|
try {
|
|
1059
1079
|
const box = await page.locator(h.selector).first().boundingBox();
|
|
1060
1080
|
if (box) {
|
|
1061
|
-
await showRing(page, box, h.label, h.tone || "planned"
|
|
1081
|
+
await showRing(page, box, h.label, h.tone || "planned", {
|
|
1082
|
+
size: h.size,
|
|
1083
|
+
weight: h.weight,
|
|
1084
|
+
});
|
|
1062
1085
|
const authored = resolveFixtureDwellMs(h, { gatesFast });
|
|
1063
1086
|
const legacyMs = i === list.length - 1 ? 200 : 900;
|
|
1064
1087
|
const holdMs =
|
|
@@ -1080,7 +1103,10 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1080
1103
|
if (window.__wgHideRing) window.__wgHideRing();
|
|
1081
1104
|
return;
|
|
1082
1105
|
}
|
|
1083
|
-
window.__wgPositionRing(el.getBoundingClientRect(), h.label, h.tone || "planned"
|
|
1106
|
+
window.__wgPositionRing(el.getBoundingClientRect(), h.label, h.tone || "planned", {
|
|
1107
|
+
size: h.size || "md",
|
|
1108
|
+
weight: h.weight || "normal",
|
|
1109
|
+
});
|
|
1084
1110
|
};
|
|
1085
1111
|
reposition();
|
|
1086
1112
|
window.__wgRingTrack = reposition;
|
|
@@ -1425,13 +1451,17 @@ async function markStepRunning(page, _opts) {
|
|
|
1425
1451
|
.catch(() => {});
|
|
1426
1452
|
}
|
|
1427
1453
|
|
|
1428
|
-
async function showRing(page, box, label, tone) {
|
|
1454
|
+
async function showRing(page, box, label, tone, style) {
|
|
1455
|
+
const size = normalizeHighlightSize(style && style.size);
|
|
1456
|
+
const weight = normalizeHighlightWeight(style && style.weight);
|
|
1429
1457
|
await page
|
|
1430
1458
|
.evaluate(
|
|
1431
|
-
({ box, label, tone }) => {
|
|
1432
|
-
if (window.__wgPositionRing)
|
|
1459
|
+
({ box, label, tone, size, weight }) => {
|
|
1460
|
+
if (window.__wgPositionRing) {
|
|
1461
|
+
window.__wgPositionRing(box, label, tone || "planned", { size, weight });
|
|
1462
|
+
}
|
|
1433
1463
|
},
|
|
1434
|
-
{ box, label, tone: tone || "planned" },
|
|
1464
|
+
{ box, label, tone: tone || "planned", size, weight },
|
|
1435
1465
|
)
|
|
1436
1466
|
.catch(() => {});
|
|
1437
1467
|
}
|
|
@@ -1465,9 +1495,11 @@ async function captionForLocator(page, locator, stubs, fallback) {
|
|
|
1465
1495
|
return {
|
|
1466
1496
|
label: formatHighlightCaption(matched),
|
|
1467
1497
|
tone: normalizeHighlightTone(matched.tone),
|
|
1498
|
+
size: normalizeHighlightSize(matched.size),
|
|
1499
|
+
weight: normalizeHighlightWeight(matched.weight),
|
|
1468
1500
|
};
|
|
1469
1501
|
}
|
|
1470
|
-
return { label: fallback, tone: "auto" };
|
|
1502
|
+
return { label: fallback, tone: "auto", size: "md", weight: "normal" };
|
|
1471
1503
|
}
|
|
1472
1504
|
|
|
1473
1505
|
async function dwellMatchedStub(page, locator, stubs, pacing) {
|
|
@@ -1510,13 +1542,17 @@ async function presentSlides(page, slides, _gate, opts) {
|
|
|
1510
1542
|
const s = slides[i];
|
|
1511
1543
|
const caption = formatHighlightCaption(s);
|
|
1512
1544
|
const slideTone = normalizeHighlightTone(s.tone);
|
|
1545
|
+
const slideStyle = {
|
|
1546
|
+
size: normalizeHighlightSize(s.size),
|
|
1547
|
+
weight: normalizeHighlightWeight(s.weight),
|
|
1548
|
+
};
|
|
1513
1549
|
const isLast = i === slides.length - 1;
|
|
1514
1550
|
const dwellMs = resolveFixtureDwellMs(s, { gatesFast, pace: demoPace });
|
|
1515
1551
|
await installOverlay(page, title);
|
|
1516
1552
|
if (s.selector) {
|
|
1517
1553
|
try {
|
|
1518
1554
|
const box = await page.locator(s.selector).first().boundingBox();
|
|
1519
|
-
if (box) await showRing(page, box, caption, slideTone);
|
|
1555
|
+
if (box) await showRing(page, box, caption, slideTone, slideStyle);
|
|
1520
1556
|
} catch {
|
|
1521
1557
|
await hideRing(page);
|
|
1522
1558
|
}
|
|
@@ -1828,7 +1864,10 @@ function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stubBefore
|
|
|
1828
1864
|
const stubs = (stubBeforeRef && stubBeforeRef.current) || [];
|
|
1829
1865
|
const cap = await captionForLocator(page, this, stubs, fallback);
|
|
1830
1866
|
await moveCursorTo(page, box, cursorMs(500));
|
|
1831
|
-
await showRing(page, box, cap.label, cap.tone
|
|
1867
|
+
await showRing(page, box, cap.label, cap.tone, {
|
|
1868
|
+
size: cap.size,
|
|
1869
|
+
weight: cap.weight,
|
|
1870
|
+
});
|
|
1832
1871
|
await dwellMatchedStub(page, this, stubs, pacing);
|
|
1833
1872
|
await new Promise((res) => setTimeout(res, skipTheater() ? 0 : 200));
|
|
1834
1873
|
} else if (box) {
|
|
@@ -1900,7 +1939,10 @@ function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stubBefore
|
|
|
1900
1939
|
const cap = await captionForLocator(page, this, stubs, fallback);
|
|
1901
1940
|
clickTone = cap.tone;
|
|
1902
1941
|
clickPoint = await moveCursorTo(page, box, cursorMs(600));
|
|
1903
|
-
await showRing(page, box, cap.label, cap.tone
|
|
1942
|
+
await showRing(page, box, cap.label, cap.tone, {
|
|
1943
|
+
size: cap.size,
|
|
1944
|
+
weight: cap.weight,
|
|
1945
|
+
});
|
|
1904
1946
|
await dwellMatchedStub(page, this, stubs, pacing);
|
|
1905
1947
|
// "pop for a few seconds" - Dan's own phrase, matching the
|
|
1906
1948
|
// zsign demo-engine's ring-before-click pattern in
|
|
@@ -2236,7 +2278,10 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2236
2278
|
!!r.block.fastForward ||
|
|
2237
2279
|
!!r.wasFastForward;
|
|
2238
2280
|
const fixtures = r.highlightFixtures;
|
|
2239
|
-
|
|
2281
|
+
const flowStyle = r.highlightStyle;
|
|
2282
|
+
stubBeforeRef.current = resolveHighlightSlots(r.block, "stubBefore", { fixtures }).map((h) =>
|
|
2283
|
+
applyHighlightStyleDefaults(h, flowStyle),
|
|
2284
|
+
);
|
|
2240
2285
|
const isNavBlock = r.block.__waygraphKind === "nav";
|
|
2241
2286
|
const autoNow = await currentAutoplay();
|
|
2242
2287
|
// Auto-next: tuck stepper on NavBlocks so the page transition fills the frame.
|
|
@@ -2328,13 +2373,18 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2328
2373
|
.catch(() => {});
|
|
2329
2374
|
const errHighlights = resolveHighlightSlots(r.block, "stubOnError", {
|
|
2330
2375
|
fixtures: fixturesOnError,
|
|
2331
|
-
}).map((h) =>
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2376
|
+
}).map((h) => {
|
|
2377
|
+
const styled = applyHighlightStyleDefaults(h, r.highlightStyle);
|
|
2378
|
+
return {
|
|
2379
|
+
selector: styled.selector,
|
|
2380
|
+
label: formatHighlightCaption(styled),
|
|
2381
|
+
duration: styled.duration,
|
|
2382
|
+
fastMode: styled.fastMode,
|
|
2383
|
+
tone: styled.tone,
|
|
2384
|
+
size: styled.size,
|
|
2385
|
+
weight: styled.weight,
|
|
2386
|
+
};
|
|
2387
|
+
});
|
|
2338
2388
|
await cycleHighlightRings(page, errHighlights, !!pacing.gatesFast, {
|
|
2339
2389
|
defaultHoldMs: 2000,
|
|
2340
2390
|
});
|
|
@@ -2387,7 +2437,9 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2387
2437
|
.catch(() => {});
|
|
2388
2438
|
result = stepOutcome.result;
|
|
2389
2439
|
const fixturesAfter = r.highlightFixtures;
|
|
2390
|
-
const slides = resolveSlides(r.block, { out: result, fixtures: fixturesAfter })
|
|
2440
|
+
const slides = resolveSlides(r.block, { out: result, fixtures: fixturesAfter }).map((s) =>
|
|
2441
|
+
applyHighlightStyleDefaults(s, r.highlightStyle),
|
|
2442
|
+
);
|
|
2391
2443
|
if (slides.length > 0) {
|
|
2392
2444
|
await presentSlides(page, slides, gate, {
|
|
2393
2445
|
title,
|
|
@@ -2402,16 +2454,23 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2402
2454
|
let highlights;
|
|
2403
2455
|
if (hasAuthoredStubAfter(r.block, result, fixturesAfter)) {
|
|
2404
2456
|
highlights = resolveHighlightSlots(r.block, "stubAfter", { out: result, fixtures: fixturesAfter }).map(
|
|
2405
|
-
(h) =>
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2457
|
+
(h) => {
|
|
2458
|
+
const styled = applyHighlightStyleDefaults(h, r.highlightStyle);
|
|
2459
|
+
return {
|
|
2460
|
+
selector: styled.selector,
|
|
2461
|
+
label: formatHighlightCaption(styled),
|
|
2462
|
+
duration: styled.duration,
|
|
2463
|
+
fastMode: styled.fastMode,
|
|
2464
|
+
tone: styled.tone,
|
|
2465
|
+
size: styled.size,
|
|
2466
|
+
weight: styled.weight,
|
|
2467
|
+
};
|
|
2468
|
+
},
|
|
2412
2469
|
);
|
|
2413
2470
|
} else {
|
|
2414
|
-
highlights = extractVerifyHighlights(r.block, result.__state)
|
|
2471
|
+
highlights = extractVerifyHighlights(r.block, result.__state).map((h) =>
|
|
2472
|
+
applyHighlightStyleDefaults(h, r.highlightStyle),
|
|
2473
|
+
);
|
|
2415
2474
|
}
|
|
2416
2475
|
await renderAfterStep(page, {
|
|
2417
2476
|
index: i,
|
|
@@ -2593,6 +2652,7 @@ async function main() {
|
|
|
2593
2652
|
seedMem: idx === 0 ? seedMem : undefined,
|
|
2594
2653
|
highlightFixtures: flow.highlightFixtures,
|
|
2595
2654
|
demoPace: flow.demoPace,
|
|
2655
|
+
highlightStyle: flow.highlightStyle,
|
|
2596
2656
|
expectedFailureReason:
|
|
2597
2657
|
flow.expectedFailureReason && idx === blockInfos.length - 1
|
|
2598
2658
|
? flow.expectedFailureReason
|
|
@@ -2662,6 +2722,7 @@ async function main() {
|
|
|
2662
2722
|
expectedFailureReason: flow.expectedFailureReason,
|
|
2663
2723
|
highlightFixtures: flow.highlightFixtures,
|
|
2664
2724
|
demoPace: flow.demoPace,
|
|
2725
|
+
highlightStyle: flow.highlightStyle,
|
|
2665
2726
|
seedMem: () => seedMemForFlow(mem, flow.blocks(), seg.json, seg.ref),
|
|
2666
2727
|
});
|
|
2667
2728
|
} else {
|
|
@@ -2672,6 +2733,7 @@ async function main() {
|
|
|
2672
2733
|
episodeTitle: undefined,
|
|
2673
2734
|
highlightFixtures: undefined,
|
|
2674
2735
|
demoPace: undefined,
|
|
2736
|
+
highlightStyle: undefined,
|
|
2675
2737
|
seedMem: () => seedMemForBlock(mem, r, seg.json),
|
|
2676
2738
|
});
|
|
2677
2739
|
}
|
|
@@ -2697,6 +2759,7 @@ async function main() {
|
|
|
2697
2759
|
episodeTitle: meta.episodeTitle,
|
|
2698
2760
|
highlightFixtures: meta.highlightFixtures,
|
|
2699
2761
|
demoPace: meta.demoPace,
|
|
2762
|
+
highlightStyle: meta.highlightStyle,
|
|
2700
2763
|
expectedFailureReason:
|
|
2701
2764
|
meta.expectedFailureReason && remainingInFlow === 1 ? meta.expectedFailureReason : undefined,
|
|
2702
2765
|
seedMem: isFirstOfSegment ? meta.seedMem : undefined,
|
package/dist/engine.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Block, Checkpoint, Instruction, DefinedBlock, ActionPage, Waygraph
|
|
|
3
3
|
import { MemPage } from "./mem-page.js";
|
|
4
4
|
import type { MemKey } from "./mem-page.js";
|
|
5
5
|
import type { Trait } from "./trait.js";
|
|
6
|
+
import { type HighlightStyleDefaults, type DemoPace } from "./highlights.js";
|
|
6
7
|
/**
|
|
7
8
|
* Checks `block.requires` against `mem` and throws, naming every missing key at
|
|
8
9
|
* once, if any are unset. `connect()` unions each Block's `requires` into the
|
|
@@ -191,6 +192,11 @@ export interface Flow<Out extends Checkpoint<string>> {
|
|
|
191
192
|
* `run()` ignores; step/demo applies per Block in the episode.
|
|
192
193
|
*/
|
|
193
194
|
readonly demoPace?: import("./highlights.js").DemoPace;
|
|
195
|
+
/**
|
|
196
|
+
* Default highlight size/weight/tone for this Flow's episode (`withHighlightStyle`).
|
|
197
|
+
* Per-slot stub/fixture values win. `run()` ignores.
|
|
198
|
+
*/
|
|
199
|
+
readonly highlightStyle?: import("./highlights.js").HighlightStyleDefaults;
|
|
194
200
|
/**
|
|
195
201
|
* This Flow's constituent Blocks, in order between `start`/`end`, as plain
|
|
196
202
|
* data - for introspection/visualization tools, without running anything.
|
|
@@ -264,12 +270,18 @@ export declare function withTitle<Out extends Checkpoint<string>>(flow: Flow<Out
|
|
|
264
270
|
* use this when an entire episode should be fast or slow.
|
|
265
271
|
* @example withDemoPace(withTitle(gapFlow, "Episode 2 - gaps"), "slow")
|
|
266
272
|
*/
|
|
267
|
-
export declare function withDemoPace<Out extends Checkpoint<string>>(flow: Flow<Out>, pace:
|
|
273
|
+
export declare function withDemoPace<Out extends Checkpoint<string>>(flow: Flow<Out>, pace: DemoPace): Flow<Out>;
|
|
274
|
+
/**
|
|
275
|
+
* Default highlight look for a Flow episode (size / weight / optional tone).
|
|
276
|
+
* Per-slot stub or {@link withHighlightFixtures} values win when set.
|
|
277
|
+
* @example withHighlightStyle(withDemoPace(gapFlow, "slow"), { size: "lg", weight: "bold" })
|
|
278
|
+
*/
|
|
279
|
+
export declare function withHighlightStyle<Out extends Checkpoint<string>>(flow: Flow<Out>, style: HighlightStyleDefaults): Flow<Out>;
|
|
268
280
|
/**
|
|
269
281
|
* Demo pacing for one Block or compose unit (not FF - use fastForwardComposeBlock for blitz).
|
|
270
282
|
* @example withBlockPace(composeBlock("gap-review", [...]), "slow")
|
|
271
283
|
*/
|
|
272
|
-
export declare function withBlockPace<In extends Checkpoint<string>, Out extends Checkpoint<string>>(block: Block<In, Out>, pace:
|
|
284
|
+
export declare function withBlockPace<In extends Checkpoint<string>, Out extends Checkpoint<string>>(block: Block<In, Out>, pace: DemoPace): Block<In, Out>;
|
|
273
285
|
/**
|
|
274
286
|
* Marks a Flow as one that's SUPPOSED to throw - e.g. a locked-out user's
|
|
275
287
|
* login attempt genuinely failing, demonstrating the app's own real
|
package/dist/engine.js
CHANGED
|
@@ -2,6 +2,7 @@ import { chromium, firefox, webkit } from "@playwright/test";
|
|
|
2
2
|
import { connect, checkpoint } from "./types.js";
|
|
3
3
|
import { MemPage } from "./mem-page.js";
|
|
4
4
|
import { runVerify, runPrecondition } from "./trait.js";
|
|
5
|
+
import { normalizeHighlightTone, normalizeHighlightSize, normalizeHighlightWeight, } from "./highlights.js";
|
|
5
6
|
const LAUNCHERS = { chromium, firefox, webkit };
|
|
6
7
|
/**
|
|
7
8
|
* Resolves which `BrowserType` actually launches for a `mem`-only run (no
|
|
@@ -366,6 +367,24 @@ export function withDemoPace(flow, pace) {
|
|
|
366
367
|
modBlockVerify: (block, nameOrIndex, newCheck) => withDemoPace(flow.modBlockVerify(block, nameOrIndex, newCheck), demoPace),
|
|
367
368
|
};
|
|
368
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Default highlight look for a Flow episode (size / weight / optional tone).
|
|
372
|
+
* Per-slot stub or {@link withHighlightFixtures} values win when set.
|
|
373
|
+
* @example withHighlightStyle(withDemoPace(gapFlow, "slow"), { size: "lg", weight: "bold" })
|
|
374
|
+
*/
|
|
375
|
+
export function withHighlightStyle(flow, style) {
|
|
376
|
+
const highlightStyle = {
|
|
377
|
+
...(style.tone !== undefined ? { tone: normalizeHighlightTone(style.tone) } : {}),
|
|
378
|
+
...(style.size !== undefined ? { size: normalizeHighlightSize(style.size) } : {}),
|
|
379
|
+
...(style.weight !== undefined ? { weight: normalizeHighlightWeight(style.weight) } : {}),
|
|
380
|
+
};
|
|
381
|
+
return {
|
|
382
|
+
...flow,
|
|
383
|
+
highlightStyle,
|
|
384
|
+
withBlockVerify: (block, verify) => withHighlightStyle(flow.withBlockVerify(block, verify), highlightStyle),
|
|
385
|
+
modBlockVerify: (block, nameOrIndex, newCheck) => withHighlightStyle(flow.modBlockVerify(block, nameOrIndex, newCheck), highlightStyle),
|
|
386
|
+
};
|
|
387
|
+
}
|
|
369
388
|
/**
|
|
370
389
|
* Demo pacing for one Block or compose unit (not FF - use fastForwardComposeBlock for blitz).
|
|
371
390
|
* @example withBlockPace(composeBlock("gap-review", [...]), "slow")
|
package/dist/highlights.d.ts
CHANGED
|
@@ -40,9 +40,19 @@ export interface WaygraphHighlightStub extends FixtureDurationFields {
|
|
|
40
40
|
* - `info` blue · `warning` yellow · `danger` red · `success` green
|
|
41
41
|
*/
|
|
42
42
|
tone?: HighlightTone;
|
|
43
|
+
/**
|
|
44
|
+
* Ring padding + label font scale: `sm` | `md` (default) | `lg`.
|
|
45
|
+
* Aliases: small/medium/large, s/m/l.
|
|
46
|
+
*/
|
|
47
|
+
size?: HighlightSize;
|
|
48
|
+
/**
|
|
49
|
+
* Label font weight: `normal` (default) | `bold`.
|
|
50
|
+
* Aliases: regular, strong.
|
|
51
|
+
*/
|
|
52
|
+
weight?: HighlightWeight;
|
|
43
53
|
}
|
|
44
54
|
/** Flow fixture patch: label required; selector optional (inherits from stub). */
|
|
45
|
-
export type WaygraphHighlightFixture = Partial<Pick<WaygraphHighlightStub, "selector">> & Required<Pick<WaygraphHighlightStub, "label">> & Pick<WaygraphHighlightStub, "detail" | "tag" | "tone"> & FixtureDurationFields;
|
|
55
|
+
export type WaygraphHighlightFixture = Partial<Pick<WaygraphHighlightStub, "selector">> & Required<Pick<WaygraphHighlightStub, "label">> & Pick<WaygraphHighlightStub, "detail" | "tag" | "tone" | "size" | "weight"> & FixtureDurationFields;
|
|
46
56
|
export type HighlightStubPhase = Record<string, WaygraphHighlightStub>;
|
|
47
57
|
export type HighlightStubPhaseOrFn<Out extends Checkpoint<string>> = HighlightStubPhase | ((out: Out) => HighlightStubPhase);
|
|
48
58
|
/**
|
|
@@ -57,14 +67,40 @@ export interface WaygraphSlide extends FixtureDurationFields {
|
|
|
57
67
|
/** Optional ring while this slide is showing. */
|
|
58
68
|
selector?: string;
|
|
59
69
|
tone?: HighlightTone;
|
|
70
|
+
size?: HighlightSize;
|
|
71
|
+
weight?: HighlightWeight;
|
|
60
72
|
}
|
|
61
73
|
/**
|
|
62
74
|
* Demo ring tones (iconified).
|
|
63
75
|
* Automation (`auto`) is gray so authored planned/info/warning/danger/success stand out.
|
|
64
76
|
*/
|
|
65
77
|
export type HighlightTone = "planned" | "auto" | "info" | "warning" | "danger" | "success";
|
|
78
|
+
/** Ring + label scale. */
|
|
79
|
+
export type HighlightSize = "sm" | "md" | "lg";
|
|
80
|
+
/** Label font weight. */
|
|
81
|
+
export type HighlightWeight = "normal" | "bold";
|
|
82
|
+
/** Optional Flow-level defaults for demo rings (episode-wide). Stub/fixture wins. */
|
|
83
|
+
export type HighlightStyleDefaults = {
|
|
84
|
+
tone?: HighlightTone;
|
|
85
|
+
size?: HighlightSize;
|
|
86
|
+
weight?: HighlightWeight;
|
|
87
|
+
};
|
|
88
|
+
/** Apply Flow defaults under per-slot authored values (slot wins when set). */
|
|
89
|
+
export declare function applyHighlightStyleDefaults<T extends {
|
|
90
|
+
tone?: HighlightTone | string;
|
|
91
|
+
size?: HighlightSize | string;
|
|
92
|
+
weight?: HighlightWeight | string;
|
|
93
|
+
}>(slot: T, defaults?: HighlightStyleDefaults | null): T & {
|
|
94
|
+
tone: HighlightTone;
|
|
95
|
+
size: HighlightSize;
|
|
96
|
+
weight: HighlightWeight;
|
|
97
|
+
};
|
|
66
98
|
/** Map author aliases (`error` -> danger) to a canonical tone. */
|
|
67
99
|
export declare function normalizeHighlightTone(raw: unknown): HighlightTone;
|
|
100
|
+
/** Map size aliases to sm/md/lg. */
|
|
101
|
+
export declare function normalizeHighlightSize(raw: unknown): HighlightSize;
|
|
102
|
+
/** Map weight aliases to normal/bold. */
|
|
103
|
+
export declare function normalizeHighlightWeight(raw: unknown): HighlightWeight;
|
|
68
104
|
/** Prefix label with a short ASCII icon for semantic tones. */
|
|
69
105
|
export declare function toneIconPrefix(tone: HighlightTone): string;
|
|
70
106
|
/**
|
package/dist/highlights.js
CHANGED
|
@@ -8,6 +8,25 @@
|
|
|
8
8
|
* All fixture shapes share optional {@link FixtureDurationFields} so demo dwell
|
|
9
9
|
* before advancing is authored the same way on stubs, flow fixtures, and slides.
|
|
10
10
|
*/
|
|
11
|
+
/** Apply Flow defaults under per-slot authored values (slot wins when set). */
|
|
12
|
+
export function applyHighlightStyleDefaults(slot, defaults) {
|
|
13
|
+
const tone = slot.tone !== undefined && slot.tone !== ""
|
|
14
|
+
? normalizeHighlightTone(slot.tone)
|
|
15
|
+
: defaults?.tone !== undefined
|
|
16
|
+
? normalizeHighlightTone(defaults.tone)
|
|
17
|
+
: "planned";
|
|
18
|
+
const size = slot.size !== undefined && slot.size !== ""
|
|
19
|
+
? normalizeHighlightSize(slot.size)
|
|
20
|
+
: defaults?.size !== undefined
|
|
21
|
+
? normalizeHighlightSize(defaults.size)
|
|
22
|
+
: "md";
|
|
23
|
+
const weight = slot.weight !== undefined && slot.weight !== ""
|
|
24
|
+
? normalizeHighlightWeight(slot.weight)
|
|
25
|
+
: defaults?.weight !== undefined
|
|
26
|
+
? normalizeHighlightWeight(defaults.weight)
|
|
27
|
+
: "normal";
|
|
28
|
+
return { ...slot, tone, size, weight };
|
|
29
|
+
}
|
|
11
30
|
const TONE_ICONS = {
|
|
12
31
|
planned: "",
|
|
13
32
|
auto: "",
|
|
@@ -35,6 +54,26 @@ export function normalizeHighlightTone(raw) {
|
|
|
35
54
|
return "planned";
|
|
36
55
|
return "planned";
|
|
37
56
|
}
|
|
57
|
+
/** Map size aliases to sm/md/lg. */
|
|
58
|
+
export function normalizeHighlightSize(raw) {
|
|
59
|
+
if (typeof raw !== "string")
|
|
60
|
+
return "md";
|
|
61
|
+
const t = raw.trim().toLowerCase();
|
|
62
|
+
if (t === "sm" || t === "s" || t === "small" || t === "tiny")
|
|
63
|
+
return "sm";
|
|
64
|
+
if (t === "lg" || t === "l" || t === "large" || t === "big" || t === "xl")
|
|
65
|
+
return "lg";
|
|
66
|
+
return "md";
|
|
67
|
+
}
|
|
68
|
+
/** Map weight aliases to normal/bold. */
|
|
69
|
+
export function normalizeHighlightWeight(raw) {
|
|
70
|
+
if (typeof raw !== "string")
|
|
71
|
+
return "normal";
|
|
72
|
+
const t = raw.trim().toLowerCase();
|
|
73
|
+
if (t === "bold" || t === "strong" || t === "heavy" || t === "b")
|
|
74
|
+
return "bold";
|
|
75
|
+
return "normal";
|
|
76
|
+
}
|
|
38
77
|
/** Prefix label with a short ASCII icon for semantic tones. */
|
|
39
78
|
export function toneIconPrefix(tone) {
|
|
40
79
|
const icon = TONE_ICONS[tone];
|
|
@@ -116,10 +155,24 @@ function pickDurationFields(base, patch) {
|
|
|
116
155
|
out.fastMode = fastMode;
|
|
117
156
|
return out;
|
|
118
157
|
}
|
|
158
|
+
function pickStyleFields(base, patch) {
|
|
159
|
+
const out = {};
|
|
160
|
+
const tone = patch?.tone !== undefined ? patch.tone : base?.tone;
|
|
161
|
+
const size = patch?.size !== undefined ? patch.size : base?.size;
|
|
162
|
+
const weight = patch?.weight !== undefined ? patch.weight : base?.weight;
|
|
163
|
+
if (tone !== undefined)
|
|
164
|
+
out.tone = normalizeHighlightTone(tone);
|
|
165
|
+
if (size !== undefined)
|
|
166
|
+
out.size = normalizeHighlightSize(size);
|
|
167
|
+
if (weight !== undefined)
|
|
168
|
+
out.weight = normalizeHighlightWeight(weight);
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
119
171
|
function mergeSlot(base, patch) {
|
|
120
172
|
if (!base && !patch)
|
|
121
173
|
return null;
|
|
122
174
|
const dwell = pickDurationFields(base, patch);
|
|
175
|
+
const style = pickStyleFields(base, patch);
|
|
123
176
|
if (!base && patch) {
|
|
124
177
|
if (!patch.selector)
|
|
125
178
|
return null;
|
|
@@ -128,12 +181,18 @@ function mergeSlot(base, patch) {
|
|
|
128
181
|
label: patch.label,
|
|
129
182
|
...(patch.detail ? { detail: patch.detail } : {}),
|
|
130
183
|
...(patch.tag ? { tag: patch.tag } : {}),
|
|
131
|
-
...
|
|
184
|
+
...style,
|
|
132
185
|
...dwell,
|
|
133
186
|
};
|
|
134
187
|
}
|
|
135
|
-
if (base && !patch)
|
|
136
|
-
return {
|
|
188
|
+
if (base && !patch) {
|
|
189
|
+
return {
|
|
190
|
+
...base,
|
|
191
|
+
...(base.tone ? { tone: normalizeHighlightTone(base.tone) } : {}),
|
|
192
|
+
...(base.size ? { size: normalizeHighlightSize(base.size) } : {}),
|
|
193
|
+
...(base.weight ? { weight: normalizeHighlightWeight(base.weight) } : {}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
137
196
|
return {
|
|
138
197
|
selector: patch.selector ?? base.selector,
|
|
139
198
|
label: patch.label,
|
|
@@ -143,11 +202,7 @@ function mergeSlot(base, patch) {
|
|
|
143
202
|
? { detail: base.detail }
|
|
144
203
|
: {}),
|
|
145
204
|
...(patch.tag !== undefined ? { tag: patch.tag } : base.tag ? { tag: base.tag } : {}),
|
|
146
|
-
...
|
|
147
|
-
? { tone: normalizeHighlightTone(patch.tone) }
|
|
148
|
-
: base.tone
|
|
149
|
-
? { tone: normalizeHighlightTone(base.tone) }
|
|
150
|
-
: {}),
|
|
205
|
+
...style,
|
|
151
206
|
...dwell,
|
|
152
207
|
};
|
|
153
208
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ export type { Checkpoint, Instruction, Block, DefinedBlock, Start, WaygraphInsta
|
|
|
2
2
|
export { connect, checkpoint } from "./types.js";
|
|
3
3
|
export { MemKey, MemPage, key, keyGroup } from "./mem-page.js";
|
|
4
4
|
export { Trait, urlMatches, textEquals, visible } from "./trait.js";
|
|
5
|
-
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withExpectedFailure, withHighlightFixtures, chainFlow, } from "./engine.js";
|
|
6
|
-
export { resolveHighlightSlots, resolveSlides, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, toneIconPrefix, resolveStepDemoPace, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
7
|
-
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, DemoPace, } from "./highlights.js";
|
|
5
|
+
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, chainFlow, } from "./engine.js";
|
|
6
|
+
export { resolveHighlightSlots, resolveSlides, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
7
|
+
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, } from "./highlights.js";
|
|
8
8
|
export type { Flow, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, } from "./engine.js";
|
|
9
9
|
export type { ActionPage } from "./types.js";
|
|
10
10
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { connect, checkpoint } from "./types.js";
|
|
2
2
|
export { MemKey, MemPage, key, keyGroup } from "./mem-page.js";
|
|
3
3
|
export { Trait, urlMatches, textEquals, visible } from "./trait.js";
|
|
4
|
-
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withExpectedFailure, withHighlightFixtures, chainFlow, } from "./engine.js";
|
|
5
|
-
export { resolveHighlightSlots, resolveSlides, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, toneIconPrefix, resolveStepDemoPace, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
4
|
+
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, chainFlow, } from "./engine.js";
|
|
5
|
+
export { resolveHighlightSlots, resolveSlides, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
6
6
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
7
7
|
export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp, } from "./blocks-select.js";
|
|
8
8
|
export { EdgeLeaseCoordinator } from "./traverse-lease.js";
|
package/dist/step-overlay.js
CHANGED
|
@@ -15,6 +15,12 @@ const RING_CSS = "#wg-ring{position:fixed;z-index:2147483646;pointer-events:none
|
|
|
15
15
|
"#wg-ring-label[data-tone=warning]{background:#EAB308;color:#1c1917;}" +
|
|
16
16
|
"#wg-ring-label[data-tone=danger]{background:#DC2626;color:#fff;}" +
|
|
17
17
|
"#wg-ring-label[data-tone=success]{background:#16A34A;color:#fff;}" +
|
|
18
|
+
"#wg-ring[data-size=sm]{border-width:1.5px;border-radius:8px;}" +
|
|
19
|
+
"#wg-ring[data-size=lg]{border-width:4px;border-radius:12px;}" +
|
|
20
|
+
"#wg-ring-label[data-size=sm]{font-size:10px;line-height:1.25;padding:4px 7px;border-radius:5px;}" +
|
|
21
|
+
"#wg-ring-label[data-size=lg]{font-size:16px;line-height:1.35;padding:8px 14px;border-radius:9px;}" +
|
|
22
|
+
"#wg-ring-label[data-weight=bold]{font-weight:800;}" +
|
|
23
|
+
"#wg-ring-label[data-weight=normal]{font-weight:600;}" +
|
|
18
24
|
"#wg-cursor{position:fixed;z-index:2147483647;width:24px;height:24px;pointer-events:none;" +
|
|
19
25
|
"left:0;top:0;opacity:0;margin:0;" +
|
|
20
26
|
"transition:transform var(--wg-cursor-ms,600ms) cubic-bezier(.22,1,.36,1),opacity .2s ease;" +
|
|
@@ -93,7 +99,7 @@ export async function installDemoChrome(page, title = "waygraph auto", options =
|
|
|
93
99
|
void pulse.offsetWidth;
|
|
94
100
|
pulse.classList.add("wg-pulse");
|
|
95
101
|
};
|
|
96
|
-
window.__wgPositionRing = (box, label, tone) => {
|
|
102
|
+
window.__wgPositionRing = (box, label, tone, style) => {
|
|
97
103
|
const ring = document.getElementById("wg-ring");
|
|
98
104
|
const ringLabel = document.getElementById("wg-ring-label");
|
|
99
105
|
if (!ring || !ringLabel)
|
|
@@ -106,12 +112,20 @@ export async function installDemoChrome(page, title = "waygraph auto", options =
|
|
|
106
112
|
raw === "success"
|
|
107
113
|
? raw
|
|
108
114
|
: "planned";
|
|
115
|
+
const sizeRaw = ((style && style.size) || "md") + "";
|
|
116
|
+
const size = sizeRaw === "sm" || sizeRaw === "lg" ? sizeRaw : "md";
|
|
117
|
+
const weightRaw = ((style && style.weight) || "normal") + "";
|
|
118
|
+
const weight = weightRaw === "bold" ? "bold" : "normal";
|
|
109
119
|
ring.dataset.tone = t;
|
|
110
120
|
ringLabel.dataset.tone = t;
|
|
111
|
-
ring.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
121
|
+
ring.dataset.size = size;
|
|
122
|
+
ringLabel.dataset.size = size;
|
|
123
|
+
ringLabel.dataset.weight = weight;
|
|
124
|
+
const pad = size === "sm" ? 3 : size === "lg" ? 10 : 6;
|
|
125
|
+
ring.style.left = box.x - pad + "px";
|
|
126
|
+
ring.style.top = box.y - pad + "px";
|
|
127
|
+
ring.style.width = box.width + pad * 2 + "px";
|
|
128
|
+
ring.style.height = box.height + pad * 2 + "px";
|
|
115
129
|
ring.style.opacity = "1";
|
|
116
130
|
ringLabel.textContent = label;
|
|
117
131
|
ringLabel.style.left = box.x + "px";
|