executable-stories-react 0.7.0 → 0.8.0

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/ssr.js CHANGED
@@ -375,17 +375,29 @@ function DocHtml({ entry }) {
375
375
  ] });
376
376
  }
377
377
 
378
+ // src/components/doc/DocState.tsx
379
+ import { jsx as jsx13 } from "react/jsx-runtime";
380
+ function DocState({ entry }) {
381
+ let json;
382
+ try {
383
+ json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);
384
+ } catch {
385
+ json = String(entry.value);
386
+ }
387
+ return /* @__PURE__ */ jsx13(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx13("code", { className: "font-mono text-xs language-json", children: json }) });
388
+ }
389
+
378
390
  // src/components/doc/DocCustom.tsx
379
- import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
391
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
380
392
  function DocCustom({ entry }) {
381
393
  const renderers = useCustomRenderers();
382
394
  const renderer = renderers[entry.type];
383
395
  if (renderer) {
384
- return /* @__PURE__ */ jsx13(Fragment4, { children: renderer(entry) });
396
+ return /* @__PURE__ */ jsx14(Fragment4, { children: renderer(entry) });
385
397
  }
386
398
  return /* @__PURE__ */ jsxs9("div", { className: "my-2", "data-type": entry.type, children: [
387
- /* @__PURE__ */ jsx13("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
388
- /* @__PURE__ */ jsx13("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
399
+ /* @__PURE__ */ jsx14("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
400
+ /* @__PURE__ */ jsx14("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
389
401
  ] });
390
402
  }
391
403
  function safeStringify(value) {
@@ -397,45 +409,47 @@ function safeStringify(value) {
397
409
  }
398
410
 
399
411
  // src/components/doc/DocEntry.tsx
400
- import { jsx as jsx14 } from "react/jsx-runtime";
412
+ import { jsx as jsx15 } from "react/jsx-runtime";
401
413
  function DocEntry({ entry }) {
402
414
  switch (entry.kind) {
403
415
  case "note":
404
- return /* @__PURE__ */ jsx14(DocNote, { entry });
416
+ return /* @__PURE__ */ jsx15(DocNote, { entry });
405
417
  case "tag":
406
- return /* @__PURE__ */ jsx14(DocTag, { entry });
418
+ return /* @__PURE__ */ jsx15(DocTag, { entry });
407
419
  case "kv":
408
- return /* @__PURE__ */ jsx14(DocKv, { entry });
420
+ return /* @__PURE__ */ jsx15(DocKv, { entry });
409
421
  case "code":
410
- return /* @__PURE__ */ jsx14(DocCode, { entry });
422
+ return /* @__PURE__ */ jsx15(DocCode, { entry });
411
423
  case "table":
412
- return /* @__PURE__ */ jsx14(DocTable, { entry });
424
+ return /* @__PURE__ */ jsx15(DocTable, { entry });
413
425
  case "link":
414
- return /* @__PURE__ */ jsx14(DocLink, { entry });
426
+ return /* @__PURE__ */ jsx15(DocLink, { entry });
415
427
  case "section":
416
- return /* @__PURE__ */ jsx14(DocSection, { entry });
428
+ return /* @__PURE__ */ jsx15(DocSection, { entry });
417
429
  case "mermaid":
418
- return /* @__PURE__ */ jsx14(DocMermaid, { entry });
430
+ return /* @__PURE__ */ jsx15(DocMermaid, { entry });
419
431
  case "screenshot":
420
- return /* @__PURE__ */ jsx14(DocScreenshot, { entry });
432
+ return /* @__PURE__ */ jsx15(DocScreenshot, { entry });
421
433
  case "video":
422
- return /* @__PURE__ */ jsx14(DocVideo, { entry });
434
+ return /* @__PURE__ */ jsx15(DocVideo, { entry });
423
435
  case "html":
424
- return /* @__PURE__ */ jsx14(DocHtml, { entry });
436
+ return /* @__PURE__ */ jsx15(DocHtml, { entry });
437
+ case "state":
438
+ return /* @__PURE__ */ jsx15(DocState, { entry });
425
439
  case "custom":
426
- return /* @__PURE__ */ jsx14(DocCustom, { entry });
440
+ return /* @__PURE__ */ jsx15(DocCustom, { entry });
427
441
  }
428
442
  }
429
443
 
430
444
  // src/components/ReportDocEntries.tsx
431
- import { Fragment as Fragment5, jsx as jsx15 } from "react/jsx-runtime";
445
+ import { Fragment as Fragment5, jsx as jsx16 } from "react/jsx-runtime";
432
446
  function ReportDocEntries({ entries }) {
433
447
  if (entries.length === 0) return null;
434
- return /* @__PURE__ */ jsx15(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx15(DocEntry, { entry }, i)) });
448
+ return /* @__PURE__ */ jsx16(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx16(DocEntry, { entry }, i)) });
435
449
  }
436
450
 
437
451
  // src/lib/step-params.tsx
438
- import { jsx as jsx16 } from "react/jsx-runtime";
452
+ import { jsx as jsx17 } from "react/jsx-runtime";
439
453
  var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
440
454
  function highlightStepParams(text) {
441
455
  const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
@@ -447,7 +461,7 @@ function highlightStepParams(text) {
447
461
  const end = start + match[0].length;
448
462
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
449
463
  nodes.push(
450
- /* @__PURE__ */ jsx16("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
464
+ /* @__PURE__ */ jsx17("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
451
465
  );
452
466
  lastIndex = end;
453
467
  });
@@ -456,7 +470,7 @@ function highlightStepParams(text) {
456
470
  }
457
471
 
458
472
  // src/components/ReportSteps.tsx
459
- import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
473
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
460
474
  var STEP_GLYPH = {
461
475
  passed: "\u2713",
462
476
  failed: "\u2717",
@@ -471,7 +485,7 @@ var STEP_GLYPH_COLOR = {
471
485
  };
472
486
  function ReportSteps({ scenario }) {
473
487
  if (scenario.steps.length === 0) return null;
474
- return /* @__PURE__ */ jsx17("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx17(ReportStepItem, { step }, step.id)) });
488
+ return /* @__PURE__ */ jsx18("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx18(ReportStepItem, { step }, step.id)) });
475
489
  }
476
490
  function ReportStepItem({ step }) {
477
491
  const kw = step.keyword.toLowerCase();
@@ -484,8 +498,8 @@ function ReportStepItem({ step }) {
484
498
  className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
485
499
  children: [
486
500
  /* @__PURE__ */ jsxs10("div", { className: "flex items-baseline gap-2", children: [
487
- /* @__PURE__ */ jsx17("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
488
- /* @__PURE__ */ jsx17(
501
+ /* @__PURE__ */ jsx18("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
502
+ /* @__PURE__ */ jsx18(
489
503
  "span",
490
504
  {
491
505
  className: cn(
@@ -495,10 +509,10 @@ function ReportStepItem({ step }) {
495
509
  children: step.keyword
496
510
  }
497
511
  ),
498
- /* @__PURE__ */ jsx17("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
499
- step.durationMs > 0 ? /* @__PURE__ */ jsx17("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
512
+ /* @__PURE__ */ jsx18("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
513
+ step.durationMs > 0 ? /* @__PURE__ */ jsx18("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
500
514
  ] }),
501
- step.errorMessage ? /* @__PURE__ */ jsx17(
515
+ step.errorMessage ? /* @__PURE__ */ jsx18(
502
516
  "pre",
503
517
  {
504
518
  role: "alert",
@@ -506,12 +520,72 @@ function ReportStepItem({ step }) {
506
520
  children: step.errorMessage
507
521
  }
508
522
  ) : null,
509
- step.docEntries.length > 0 ? /* @__PURE__ */ jsx17("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx17(ReportDocEntries, { entries: step.docEntries }) }) : null
523
+ step.docEntries.length > 0 ? /* @__PURE__ */ jsx18("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx18(ReportDocEntries, { entries: step.docEntries }) }) : null
510
524
  ]
511
525
  }
512
526
  );
513
527
  }
514
528
 
529
+ // ../executable-stories-core/dist/state-diff.js
530
+ var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
531
+ function deepEqual(a, b) {
532
+ if (Object.is(a, b)) return true;
533
+ if (Array.isArray(a) && Array.isArray(b)) {
534
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
535
+ }
536
+ if (isPlainObject(a) && isPlainObject(b)) {
537
+ const ak = Object.keys(a);
538
+ const bk = Object.keys(b);
539
+ return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
540
+ }
541
+ return false;
542
+ }
543
+ var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
544
+ function walk(path, before, after, out) {
545
+ if (Object.is(before, after)) return;
546
+ if (Array.isArray(before) && Array.isArray(after)) {
547
+ const shared = Math.min(before.length, after.length);
548
+ for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
549
+ for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
550
+ for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
551
+ return;
552
+ }
553
+ if (isPlainObject(before) && isPlainObject(after)) {
554
+ for (const key of Object.keys(after)) {
555
+ const p = joinKey(path, key);
556
+ if (key in before) walk(p, before[key], after[key], out);
557
+ else out.push({ path: p, kind: "added", after: after[key] });
558
+ }
559
+ for (const key of Object.keys(before)) {
560
+ if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
561
+ }
562
+ return;
563
+ }
564
+ if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
565
+ }
566
+ function diffStateValues(before, after) {
567
+ const out = [];
568
+ walk("", before, after, out);
569
+ return out;
570
+ }
571
+ function formatStateValue(value, maxLen = 60) {
572
+ const s = value === void 0 ? "undefined" : JSON.stringify(value);
573
+ return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
574
+ }
575
+ function summarizeStateChanges(changes) {
576
+ return changes.map((c) => {
577
+ const at = c.path === "" ? "(root)" : c.path;
578
+ switch (c.kind) {
579
+ case "added":
580
+ return `+ ${at}: ${formatStateValue(c.after)}`;
581
+ case "removed":
582
+ return `\u2212 ${at}`;
583
+ case "changed":
584
+ return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
585
+ }
586
+ });
587
+ }
588
+
515
589
  // ../executable-stories-core/dist/storyboard.js
516
590
  function findScreenshot(entries) {
517
591
  for (const entry of entries) {
@@ -523,26 +597,55 @@ function findScreenshot(entries) {
523
597
  }
524
598
  return void 0;
525
599
  }
600
+ function findStates(entries, out = []) {
601
+ for (const entry of entries) {
602
+ if (entry.kind === "state") out.push(entry);
603
+ if (entry.children) findStates(entry.children, out);
604
+ }
605
+ return out;
606
+ }
607
+ var laneOf = (label) => label ?? "";
526
608
  function extractStoryboardFrames(scenario) {
527
609
  const frames = [];
610
+ const laneOrder = [];
611
+ const previous = /* @__PURE__ */ new Map();
528
612
  for (const step of scenario.steps) {
529
613
  const shot = findScreenshot(step.docEntries);
530
- if (!shot) continue;
614
+ const stateDocs = findStates(step.docEntries);
615
+ if (!shot && stateDocs.length === 0) continue;
616
+ const byLane = /* @__PURE__ */ new Map();
617
+ for (const doc of stateDocs) {
618
+ const lane = laneOf(doc.label);
619
+ if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
620
+ byLane.set(lane, doc);
621
+ }
622
+ const states = [];
623
+ for (const lane of laneOrder) {
624
+ const doc = byLane.get(lane);
625
+ if (!doc) continue;
626
+ const card = {
627
+ ...doc.label !== void 0 && { label: doc.label },
628
+ value: doc.value
629
+ };
630
+ if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
631
+ previous.set(lane, doc.value);
632
+ states.push(card);
633
+ }
531
634
  frames.push({
532
635
  stepId: step.id,
533
636
  stepIndex: step.index,
534
637
  keyword: step.keyword,
535
638
  text: step.text,
536
639
  status: step.status,
537
- path: shot.path,
538
- ...shot.alt !== void 0 && { alt: shot.alt }
640
+ ...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
641
+ states
539
642
  });
540
643
  }
541
644
  return frames;
542
645
  }
543
646
 
544
647
  // src/components/ReportStoryboard.tsx
545
- import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
648
+ import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
546
649
  var FRAME_GLYPH = {
547
650
  passed: "\u2713",
548
651
  failed: "\u2717",
@@ -559,54 +662,113 @@ function ReportStoryboard({ scenario }) {
559
662
  const frames = extractStoryboardFrames(scenario);
560
663
  if (frames.length < 2) return null;
561
664
  return /* @__PURE__ */ jsxs11("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
562
- /* @__PURE__ */ jsx18("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
563
- /* @__PURE__ */ jsx18("ol", { className: "flex gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx18(StoryboardFrameItem, { frame }, frame.stepId)) })
665
+ /* @__PURE__ */ jsx19("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
666
+ /* @__PURE__ */ jsx19("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx19(StoryboardFrameItem, { frame }, frame.stepId)) })
564
667
  ] });
565
668
  }
566
669
  function StoryboardFrameItem({ frame }) {
567
- const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
568
670
  const label = `${frame.keyword} ${frame.text}`;
569
- return /* @__PURE__ */ jsxs11("li", { className: "w-40 shrink-0", children: [
570
- /* @__PURE__ */ jsx18(
571
- "a",
671
+ const hasStates = frame.states.length > 0;
672
+ const caption = /* @__PURE__ */ jsxs11("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
673
+ /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
674
+ /* @__PURE__ */ jsxs11("span", { className: "min-w-0", children: [
675
+ /* @__PURE__ */ jsx19("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
676
+ " ",
677
+ /* @__PURE__ */ jsx19("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
678
+ ] })
679
+ ] });
680
+ return (
681
+ // State cards need room for diff rows; screenshot-only frames keep the
682
+ // original narrow film-cell width (and DOM) unchanged.
683
+ /* @__PURE__ */ jsxs11("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
684
+ frame.screenshot ? /* @__PURE__ */ jsx19(FrameScreenshot, { frame, label }) : null,
685
+ hasStates ? /* @__PURE__ */ jsx19("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ jsx19(StateCardView, { card }, card.label ?? i)) }) : null,
686
+ frame.screenshot ? caption : (
687
+ // No screenshot means no image anchor, so the caption carries the
688
+ // jump-to-step link instead.
689
+ /* @__PURE__ */ jsx19("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
690
+ )
691
+ ] })
692
+ );
693
+ }
694
+ function FrameScreenshot({ frame, label }) {
695
+ const path = frame.screenshot?.path ?? "";
696
+ const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
697
+ return /* @__PURE__ */ jsx19(
698
+ "a",
699
+ {
700
+ href: `#${frame.stepId}`,
701
+ "aria-label": `Jump to step: ${label}`,
702
+ className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
703
+ children: src ? /* @__PURE__ */ jsx19(
704
+ "img",
705
+ {
706
+ src,
707
+ alt: frame.screenshot?.alt ?? label,
708
+ loading: "lazy",
709
+ className: "h-24 w-full bg-muted object-cover object-top"
710
+ }
711
+ ) : /* @__PURE__ */ jsx19("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
712
+ }
713
+ );
714
+ }
715
+ var CHANGE_TONE = {
716
+ added: "bg-pass-bg text-pass",
717
+ removed: "bg-fail-bg text-fail",
718
+ changed: "bg-skip-bg text-skip"
719
+ };
720
+ function prettyJson(value) {
721
+ try {
722
+ return JSON.stringify(value, null, 2) ?? String(value);
723
+ } catch {
724
+ return String(value);
725
+ }
726
+ }
727
+ function StateCardView({ card }) {
728
+ const json = prettyJson(card.value);
729
+ const firstCapture = card.changes === void 0;
730
+ return /* @__PURE__ */ jsxs11("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
731
+ /* @__PURE__ */ jsxs11("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
732
+ /* @__PURE__ */ jsx19("span", { className: "inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground", children: card.label ?? "State" }),
733
+ firstCapture ? /* @__PURE__ */ jsx19("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
734
+ ] }),
735
+ !firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ jsx19("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ jsx19(
736
+ "li",
572
737
  {
573
- href: `#${frame.stepId}`,
574
- "aria-label": `Jump to step: ${label}`,
575
- className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
576
- children: src ? /* @__PURE__ */ jsx18(
577
- "img",
578
- {
579
- src,
580
- alt: frame.alt ?? label,
581
- loading: "lazy",
582
- className: "h-24 w-full bg-muted object-cover object-top"
583
- }
584
- ) : /* @__PURE__ */ jsx18("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
738
+ className: cn(
739
+ "rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
740
+ CHANGE_TONE[change.kind]
741
+ ),
742
+ children: summarizeStateChanges([change])[0]
743
+ },
744
+ i
745
+ )) }) : /* @__PURE__ */ jsx19("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
746
+ /* @__PURE__ */ jsxs11(
747
+ "details",
748
+ {
749
+ open: firstCapture && json.length <= 240,
750
+ className: cn(firstCapture ? "mt-1.5" : "mt-1"),
751
+ children: [
752
+ /* @__PURE__ */ jsx19("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
753
+ /* @__PURE__ */ jsx19("pre", { tabIndex: 0, className: "mt-1 max-h-48 overflow-auto rounded-sm bg-muted p-1.5 font-mono text-[0.625rem] leading-snug", children: json })
754
+ ]
585
755
  }
586
- ),
587
- /* @__PURE__ */ jsxs11("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
588
- /* @__PURE__ */ jsx18("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
589
- /* @__PURE__ */ jsxs11("span", { className: "min-w-0", children: [
590
- /* @__PURE__ */ jsx18("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
591
- " ",
592
- /* @__PURE__ */ jsx18("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
593
- ] })
594
- ] })
756
+ )
595
757
  ] });
596
758
  }
597
759
 
598
760
  // src/components/ReportAttachments.tsx
599
- import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
761
+ import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
600
762
  function ReportAttachments({ attachments }) {
601
763
  if (attachments.length === 0) return null;
602
764
  return (
603
765
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
604
766
  // blocks don't create duplicate "Attachments" region landmarks.
605
- /* @__PURE__ */ jsx19("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
767
+ /* @__PURE__ */ jsx20("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
606
768
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
607
769
  const isImage = att.mediaType.startsWith("image/");
608
- return /* @__PURE__ */ jsx19("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
609
- /* @__PURE__ */ jsx19(
770
+ return /* @__PURE__ */ jsx20("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
771
+ /* @__PURE__ */ jsx20(
610
772
  "img",
611
773
  {
612
774
  src: dataUri,
@@ -615,7 +777,7 @@ function ReportAttachments({ attachments }) {
615
777
  className: "max-w-full rounded-md border border-border"
616
778
  }
617
779
  ),
618
- /* @__PURE__ */ jsx19("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
780
+ /* @__PURE__ */ jsx20("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
619
781
  ] }) : /* @__PURE__ */ jsxs12(
620
782
  "a",
621
783
  {
@@ -689,15 +851,15 @@ function toTraceRows(spans) {
689
851
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
690
852
  const rows = [];
691
853
  const seen = /* @__PURE__ */ new Set();
692
- const walk = (node, depth) => {
854
+ const walk2 = (node, depth) => {
693
855
  if (seen.has(node.span.spanId)) return;
694
856
  seen.add(node.span.spanId);
695
857
  rows.push({ ...node.span, depth });
696
- for (const child of node.children) walk(child, depth + 1);
858
+ for (const child of node.children) walk2(child, depth + 1);
697
859
  };
698
- for (const root of roots) walk(root, 0);
860
+ for (const root of roots) walk2(root, 0);
699
861
  for (const node of byId.values()) {
700
- if (!seen.has(node.span.spanId)) walk(node, 0);
862
+ if (!seen.has(node.span.spanId)) walk2(node, 0);
701
863
  }
702
864
  return rows;
703
865
  }
@@ -713,7 +875,7 @@ function traceWindow(rows) {
713
875
  }
714
876
 
715
877
  // src/components/ReportTrace.tsx
716
- import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
878
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
717
879
  var BAR_COLOR = {
718
880
  ok: "bg-pass",
719
881
  error: "bg-fail",
@@ -734,11 +896,11 @@ function ReportTrace({ spans }) {
734
896
  formatDuration(totalMs),
735
897
  ")"
736
898
  ] }),
737
- /* @__PURE__ */ jsx20("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
899
+ /* @__PURE__ */ jsx21("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
738
900
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
739
901
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
740
902
  return /* @__PURE__ */ jsxs13("li", { className: "flex items-center gap-2", children: [
741
- /* @__PURE__ */ jsx20(
903
+ /* @__PURE__ */ jsx21(
742
904
  "span",
743
905
  {
744
906
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -747,14 +909,14 @@ function ReportTrace({ spans }) {
747
909
  children: row.name
748
910
  }
749
911
  ),
750
- /* @__PURE__ */ jsx20("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx20(
912
+ /* @__PURE__ */ jsx21("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx21(
751
913
  "span",
752
914
  {
753
915
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
754
916
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
755
917
  }
756
918
  ) }),
757
- /* @__PURE__ */ jsx20("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
919
+ /* @__PURE__ */ jsx21("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
758
920
  ] }, `${row.spanId}-${i}`);
759
921
  }) })
760
922
  ] });
@@ -805,7 +967,7 @@ function flakinessOf(entries) {
805
967
  }
806
968
 
807
969
  // src/components/ScenarioRunHistory.tsx
808
- import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
970
+ import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
809
971
  var MAX_DOTS = 10;
810
972
  var DOT_COLOR = {
811
973
  passed: "bg-pass",
@@ -826,15 +988,15 @@ function ScenarioRunHistory({ scenarioId }) {
826
988
  const flaky = flakinessOf(recent) === "flaky";
827
989
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
828
990
  return /* @__PURE__ */ jsxs14(Fragment7, { children: [
829
- flaky ? /* @__PURE__ */ jsx21(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
830
- /* @__PURE__ */ jsx21(
991
+ flaky ? /* @__PURE__ */ jsx22(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
992
+ /* @__PURE__ */ jsx22(
831
993
  "span",
832
994
  {
833
995
  role: "img",
834
996
  "aria-label": `Run history: ${summary}`,
835
997
  title: summary,
836
998
  className: "flex shrink-0 items-center gap-[3px]",
837
- children: recent.map((e, i) => /* @__PURE__ */ jsx21(
999
+ children: recent.map((e, i) => /* @__PURE__ */ jsx22(
838
1000
  "span",
839
1001
  {
840
1002
  "aria-hidden": true,
@@ -873,9 +1035,9 @@ function useScenarioActions() {
873
1035
 
874
1036
  // src/components/ui/card.tsx
875
1037
  import "react";
876
- import { jsx as jsx22 } from "react/jsx-runtime";
1038
+ import { jsx as jsx23 } from "react/jsx-runtime";
877
1039
  function Card({ className, ...props }) {
878
- return /* @__PURE__ */ jsx22(
1040
+ return /* @__PURE__ */ jsx23(
879
1041
  "div",
880
1042
  {
881
1043
  "data-slot": "card",
@@ -888,7 +1050,7 @@ function Card({ className, ...props }) {
888
1050
  );
889
1051
  }
890
1052
  function CardHeader({ className, ...props }) {
891
- return /* @__PURE__ */ jsx22(
1053
+ return /* @__PURE__ */ jsx23(
892
1054
  "div",
893
1055
  {
894
1056
  "data-slot": "card-header",
@@ -901,7 +1063,7 @@ function CardHeader({ className, ...props }) {
901
1063
  );
902
1064
  }
903
1065
  function CardContent({ className, ...props }) {
904
- return /* @__PURE__ */ jsx22(
1066
+ return /* @__PURE__ */ jsx23(
905
1067
  "div",
906
1068
  {
907
1069
  "data-slot": "card-content",
@@ -915,13 +1077,13 @@ function CardContent({ className, ...props }) {
915
1077
  import "react";
916
1078
  import { Menu as MenuPrimitive } from "@base-ui/react/menu";
917
1079
  import { CheckIcon } from "lucide-react";
918
- import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1080
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
919
1081
  var itemClasses = "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground";
920
1082
  function DropdownMenu(props) {
921
- return /* @__PURE__ */ jsx23(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1083
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
922
1084
  }
923
1085
  function DropdownMenuTrigger(props) {
924
- return /* @__PURE__ */ jsx23(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1086
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
925
1087
  }
926
1088
  function DropdownMenuContent({
927
1089
  className,
@@ -929,14 +1091,14 @@ function DropdownMenuContent({
929
1091
  sideOffset = 4,
930
1092
  ...props
931
1093
  }) {
932
- return /* @__PURE__ */ jsx23(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx23(
1094
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx24(
933
1095
  MenuPrimitive.Positioner,
934
1096
  {
935
1097
  "data-slot": "dropdown-menu-positioner",
936
1098
  className: "z-50",
937
1099
  align,
938
1100
  sideOffset,
939
- children: /* @__PURE__ */ jsx23(
1101
+ children: /* @__PURE__ */ jsx24(
940
1102
  MenuPrimitive.Popup,
941
1103
  {
942
1104
  "data-slot": "dropdown-menu-content",
@@ -954,7 +1116,7 @@ function DropdownMenuItem({
954
1116
  className,
955
1117
  ...props
956
1118
  }) {
957
- return /* @__PURE__ */ jsx23(
1119
+ return /* @__PURE__ */ jsx24(
958
1120
  MenuPrimitive.Item,
959
1121
  {
960
1122
  "data-slot": "dropdown-menu-item",
@@ -966,7 +1128,7 @@ function DropdownMenuItem({
966
1128
 
967
1129
  // src/components/ReportScenario.tsx
968
1130
  import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
969
- import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
1131
+ import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
970
1132
  var STATUS_META = {
971
1133
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
972
1134
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -993,7 +1155,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
993
1155
  /* @__PURE__ */ jsxs16(CardHeader, { className: "px-4 py-3", children: [
994
1156
  /* @__PURE__ */ jsxs16("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
995
1157
  hideTitle ? null : /* @__PURE__ */ jsxs16("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
996
- collapsible ? /* @__PURE__ */ jsx24(
1158
+ collapsible ? /* @__PURE__ */ jsx25(
997
1159
  "button",
998
1160
  {
999
1161
  type: "button",
@@ -1002,36 +1164,36 @@ function ReportScenario({ scenario, hideTitle = false }) {
1002
1164
  "aria-controls": bodyId,
1003
1165
  "aria-label": `Toggle ${scenario.title}`,
1004
1166
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1005
- children: /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1167
+ children: /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1006
1168
  }
1007
1169
  ) : null,
1008
- /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1009
- /* @__PURE__ */ jsx24("span", { children: scenario.title })
1170
+ /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1171
+ /* @__PURE__ */ jsx25("span", { children: scenario.title })
1010
1172
  ] }),
1011
1173
  /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2", children: [
1012
- /* @__PURE__ */ jsx24(ScenarioRunHistory, { scenarioId: scenario.id }),
1013
- scenario.durationMs > 0 ? /* @__PURE__ */ jsx24("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1014
- meta.showPill ? /* @__PURE__ */ jsx24(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx24("span", { className: "sr-only", children: `Status: ${label}` }),
1174
+ /* @__PURE__ */ jsx25(ScenarioRunHistory, { scenarioId: scenario.id }),
1175
+ scenario.durationMs > 0 ? /* @__PURE__ */ jsx25("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1176
+ meta.showPill ? /* @__PURE__ */ jsx25(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx25("span", { className: "sr-only", children: `Status: ${label}` }),
1015
1177
  actions ? /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
1016
- /* @__PURE__ */ jsx24(
1178
+ /* @__PURE__ */ jsx25(
1017
1179
  DropdownMenuTrigger,
1018
1180
  {
1019
1181
  "aria-label": `Actions for ${scenario.title}`,
1020
1182
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1021
- children: /* @__PURE__ */ jsx24(MoreHorizontalIcon, { "aria-hidden": true })
1183
+ children: /* @__PURE__ */ jsx25(MoreHorizontalIcon, { "aria-hidden": true })
1022
1184
  }
1023
1185
  ),
1024
1186
  /* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", children: [
1025
1187
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1026
- /* @__PURE__ */ jsx24(LinkIcon, {}),
1188
+ /* @__PURE__ */ jsx25(LinkIcon, {}),
1027
1189
  " Copy link"
1028
1190
  ] }),
1029
1191
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1030
- /* @__PURE__ */ jsx24(FileTextIcon, {}),
1192
+ /* @__PURE__ */ jsx25(FileTextIcon, {}),
1031
1193
  " Copy as Markdown"
1032
1194
  ] }),
1033
1195
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1034
- /* @__PURE__ */ jsx24(SparklesIcon, {}),
1196
+ /* @__PURE__ */ jsx25(SparklesIcon, {}),
1035
1197
  " Explain with AI"
1036
1198
  ] })
1037
1199
  ] })
@@ -1039,12 +1201,12 @@ function ReportScenario({ scenario, hideTitle = false }) {
1039
1201
  ] })
1040
1202
  ] }),
1041
1203
  scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs16("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1042
- scenario.tags.map((t) => /* @__PURE__ */ jsx24("li", { children: /* @__PURE__ */ jsx24(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1043
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx24("li", { children: ticket.url ? /* @__PURE__ */ jsx24("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx24(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx24(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1204
+ scenario.tags.map((t) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1205
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx25("li", { children: ticket.url ? /* @__PURE__ */ jsx25("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1044
1206
  ] }) : null
1045
1207
  ] }),
1046
1208
  /* @__PURE__ */ jsxs16(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1047
- scenario.errorMessage ? /* @__PURE__ */ jsx24(
1209
+ scenario.errorMessage ? /* @__PURE__ */ jsx25(
1048
1210
  "pre",
1049
1211
  {
1050
1212
  role: "alert",
@@ -1052,11 +1214,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
1052
1214
  children: scenario.errorMessage
1053
1215
  }
1054
1216
  ) : null,
1055
- /* @__PURE__ */ jsx24(ReportStoryboard, { scenario }),
1056
- /* @__PURE__ */ jsx24(ReportSteps, { scenario }),
1057
- scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx24("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx24(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1058
- /* @__PURE__ */ jsx24(ReportAttachments, { attachments: scenario.attachments }),
1059
- /* @__PURE__ */ jsx24(ReportTrace, { spans: scenario.otelSpans })
1217
+ /* @__PURE__ */ jsx25(ReportStoryboard, { scenario }),
1218
+ /* @__PURE__ */ jsx25(ReportSteps, { scenario }),
1219
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx25("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx25(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1220
+ /* @__PURE__ */ jsx25(ReportAttachments, { attachments: scenario.attachments }),
1221
+ /* @__PURE__ */ jsx25(ReportTrace, { spans: scenario.otelSpans })
1060
1222
  ] })
1061
1223
  ]
1062
1224
  }
@@ -1064,13 +1226,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1064
1226
  }
1065
1227
 
1066
1228
  // src/components/ReportScenarioList.tsx
1067
- import { Fragment as Fragment8, jsx as jsx25 } from "react/jsx-runtime";
1229
+ import { Fragment as Fragment8, jsx as jsx26 } from "react/jsx-runtime";
1068
1230
  function ReportScenarioList({ feature }) {
1069
- return /* @__PURE__ */ jsx25(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx25(ReportScenario, { scenario }, scenario.id)) });
1231
+ return /* @__PURE__ */ jsx26(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx26(ReportScenario, { scenario }, scenario.id)) });
1070
1232
  }
1071
1233
 
1072
1234
  // src/components/ReportFeature.tsx
1073
- import { Fragment as Fragment9, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
1235
+ import { Fragment as Fragment9, jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
1074
1236
  function ReportFeature({ feature }) {
1075
1237
  const titleId = `${feature.id}-title`;
1076
1238
  const bodyId = `${feature.id}-body`;
@@ -1091,7 +1253,7 @@ function ReportFeature({ feature }) {
1091
1253
  children: [
1092
1254
  /* @__PURE__ */ jsxs17("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1093
1255
  /* @__PURE__ */ jsxs17("div", { className: "min-w-0", children: [
1094
- /* @__PURE__ */ jsx26("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
1256
+ /* @__PURE__ */ jsx27("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
1095
1257
  "button",
1096
1258
  {
1097
1259
  type: "button",
@@ -1100,12 +1262,12 @@ function ReportFeature({ feature }) {
1100
1262
  "aria-controls": bodyId,
1101
1263
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1102
1264
  children: [
1103
- /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1104
- /* @__PURE__ */ jsx26("span", { className: "truncate", children: feature.title })
1265
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1266
+ /* @__PURE__ */ jsx27("span", { className: "truncate", children: feature.title })
1105
1267
  ]
1106
1268
  }
1107
1269
  ) : feature.title }),
1108
- /* @__PURE__ */ jsx26("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1270
+ /* @__PURE__ */ jsx27("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1109
1271
  ] }),
1110
1272
  /* @__PURE__ */ jsxs17(
1111
1273
  "p",
@@ -1117,13 +1279,13 @@ function ReportFeature({ feature }) {
1117
1279
  s.passed,
1118
1280
  " passed"
1119
1281
  ] }),
1120
- /* @__PURE__ */ jsx26("span", { "aria-hidden": true, children: "\xB7" }),
1282
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1121
1283
  /* @__PURE__ */ jsxs17("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1122
1284
  s.failed,
1123
1285
  " failed"
1124
1286
  ] }),
1125
1287
  skipped > 0 ? /* @__PURE__ */ jsxs17(Fragment9, { children: [
1126
- /* @__PURE__ */ jsx26("span", { "aria-hidden": true, children: "\xB7" }),
1288
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1127
1289
  /* @__PURE__ */ jsxs17("span", { children: [
1128
1290
  skipped,
1129
1291
  " skipped"
@@ -1133,7 +1295,7 @@ function ReportFeature({ feature }) {
1133
1295
  }
1134
1296
  )
1135
1297
  ] }),
1136
- /* @__PURE__ */ jsx26("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx26(ReportScenarioList, { feature }) })
1298
+ /* @__PURE__ */ jsx27("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx27(ReportScenarioList, { feature }) })
1137
1299
  ]
1138
1300
  }
1139
1301
  )
@@ -1141,17 +1303,17 @@ function ReportFeature({ feature }) {
1141
1303
  }
1142
1304
 
1143
1305
  // src/components/ReportFeatureList.tsx
1144
- import { jsx as jsx27 } from "react/jsx-runtime";
1306
+ import { jsx as jsx28 } from "react/jsx-runtime";
1145
1307
  function ReportFeatureList() {
1146
1308
  const report = useReport();
1147
- return /* @__PURE__ */ jsx27("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx27(ReportFeature, { feature }, feature.id)) });
1309
+ return /* @__PURE__ */ jsx28("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx28(ReportFeature, { feature }, feature.id)) });
1148
1310
  }
1149
1311
 
1150
1312
  // src/components/ui/empty.tsx
1151
1313
  import { cva as cva2 } from "class-variance-authority";
1152
- import { jsx as jsx28 } from "react/jsx-runtime";
1314
+ import { jsx as jsx29 } from "react/jsx-runtime";
1153
1315
  function Empty({ className, ...props }) {
1154
- return /* @__PURE__ */ jsx28(
1316
+ return /* @__PURE__ */ jsx29(
1155
1317
  "div",
1156
1318
  {
1157
1319
  "data-slot": "empty",
@@ -1164,7 +1326,7 @@ function Empty({ className, ...props }) {
1164
1326
  );
1165
1327
  }
1166
1328
  function EmptyHeader({ className, ...props }) {
1167
- return /* @__PURE__ */ jsx28(
1329
+ return /* @__PURE__ */ jsx29(
1168
1330
  "div",
1169
1331
  {
1170
1332
  "data-slot": "empty-header",
@@ -1191,7 +1353,7 @@ var emptyMediaVariants = cva2(
1191
1353
  }
1192
1354
  );
1193
1355
  function EmptyTitle({ className, ...props }) {
1194
- return /* @__PURE__ */ jsx28(
1356
+ return /* @__PURE__ */ jsx29(
1195
1357
  "div",
1196
1358
  {
1197
1359
  "data-slot": "empty-title",
@@ -1202,16 +1364,16 @@ function EmptyTitle({ className, ...props }) {
1202
1364
  }
1203
1365
 
1204
1366
  // src/components/ReportEmpty.tsx
1205
- import { jsx as jsx29 } from "react/jsx-runtime";
1367
+ import { jsx as jsx30 } from "react/jsx-runtime";
1206
1368
  function ReportEmpty({ message }) {
1207
- return /* @__PURE__ */ jsx29(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx29(EmptyHeader, { children: /* @__PURE__ */ jsx29(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1369
+ return /* @__PURE__ */ jsx30(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx30(EmptyHeader, { children: /* @__PURE__ */ jsx30(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1208
1370
  }
1209
1371
 
1210
1372
  // src/components/ReportSummary.tsx
1211
- import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
1373
+ import { jsx as jsx31, jsxs as jsxs18 } from "react/jsx-runtime";
1212
1374
  function ReportSummary({ className }) {
1213
1375
  const report = useReport();
1214
- return /* @__PURE__ */ jsx30(
1376
+ return /* @__PURE__ */ jsx31(
1215
1377
  ReportSummaryView,
1216
1378
  {
1217
1379
  summary: report.summary,
@@ -1237,7 +1399,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1237
1399
  if (summary.pending > 0) {
1238
1400
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1239
1401
  }
1240
- return /* @__PURE__ */ jsx30(
1402
+ return /* @__PURE__ */ jsx31(
1241
1403
  "dl",
1242
1404
  {
1243
1405
  className: cn(
@@ -1257,10 +1419,10 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1257
1419
  className: "rounded-lg border bg-card px-4 py-3",
1258
1420
  children: [
1259
1421
  /* @__PURE__ */ jsxs18("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1260
- /* @__PURE__ */ jsx30("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1422
+ /* @__PURE__ */ jsx31("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1261
1423
  c.label
1262
1424
  ] }),
1263
- /* @__PURE__ */ jsx30("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1425
+ /* @__PURE__ */ jsx31("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1264
1426
  ]
1265
1427
  },
1266
1428
  c.status
@@ -1301,7 +1463,7 @@ function prUrl(ci) {
1301
1463
  }
1302
1464
 
1303
1465
  // src/components/ReportMeta.tsx
1304
- import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
1466
+ import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
1305
1467
  function ReportMeta() {
1306
1468
  const report = useReport();
1307
1469
  const items = [];
@@ -1324,7 +1486,7 @@ function ReportMeta() {
1324
1486
  const short = sha.slice(0, 8);
1325
1487
  items.push({
1326
1488
  label: "Commit",
1327
- value: url ? /* @__PURE__ */ jsx31("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1489
+ value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1328
1490
  });
1329
1491
  }
1330
1492
  if (report.ci) {
@@ -1341,7 +1503,7 @@ function ReportMeta() {
1341
1503
  const label = `#${report.ci.prNumber}`;
1342
1504
  items.push({
1343
1505
  label: "PR",
1344
- value: url ? /* @__PURE__ */ jsx31("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1506
+ value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1345
1507
  });
1346
1508
  }
1347
1509
  if (items.length === 0) return null;
@@ -1351,26 +1513,26 @@ function ReportMeta() {
1351
1513
  // so it works with no JS (the SSR/no-hydration report still toggles).
1352
1514
  /* @__PURE__ */ jsxs19("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1353
1515
  /* @__PURE__ */ jsxs19("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1354
- /* @__PURE__ */ jsx31("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1516
+ /* @__PURE__ */ jsx32("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1355
1517
  "Run details"
1356
1518
  ] }),
1357
- /* @__PURE__ */ jsx31("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ jsxs19("div", { className: "flex items-baseline gap-1.5", children: [
1358
- /* @__PURE__ */ jsx31("dt", { className: "font-medium", children: item.label }),
1359
- /* @__PURE__ */ jsx31("dd", { className: "font-mono text-foreground", children: item.value })
1519
+ /* @__PURE__ */ jsx32("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ jsxs19("div", { className: "flex items-baseline gap-1.5", children: [
1520
+ /* @__PURE__ */ jsx32("dt", { className: "font-medium", children: item.label }),
1521
+ /* @__PURE__ */ jsx32("dd", { className: "font-mono text-foreground", children: item.value })
1360
1522
  ] }, item.label)) })
1361
1523
  ] })
1362
1524
  );
1363
1525
  }
1364
1526
 
1365
1527
  // src/components/ReportSchemaError.tsx
1366
- import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
1528
+ import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
1367
1529
  function ReportSchemaError({ error }) {
1368
1530
  return /* @__PURE__ */ jsxs20("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1369
- /* @__PURE__ */ jsx32("p", { children: /* @__PURE__ */ jsx32("strong", { children: "Report could not be displayed." }) }),
1370
- /* @__PURE__ */ jsx32("p", { children: error.message }),
1531
+ /* @__PURE__ */ jsx33("p", { children: /* @__PURE__ */ jsx33("strong", { children: "Report could not be displayed." }) }),
1532
+ /* @__PURE__ */ jsx33("p", { children: error.message }),
1371
1533
  error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs20("p", { children: [
1372
1534
  "The report bundle is newer than this version of ",
1373
- /* @__PURE__ */ jsx32("code", { children: "executable-stories-react" }),
1535
+ /* @__PURE__ */ jsx33("code", { children: "executable-stories-react" }),
1374
1536
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1375
1537
  ] }) : null,
1376
1538
  error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs20("details", { children: [
@@ -1379,18 +1541,18 @@ function ReportSchemaError({ error }) {
1379
1541
  " validation issue",
1380
1542
  error.issues.length === 1 ? "" : "s"
1381
1543
  ] }),
1382
- /* @__PURE__ */ jsx32("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1544
+ /* @__PURE__ */ jsx33("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1383
1545
  ] }) : null
1384
1546
  ] });
1385
1547
  }
1386
1548
 
1387
1549
  // src/components/ReportShell.tsx
1388
- import { Fragment as Fragment10, jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1550
+ import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
1389
1551
  function ReportTitleBlock({ title }) {
1390
1552
  return /* @__PURE__ */ jsxs21(Fragment10, { children: [
1391
- /* @__PURE__ */ jsx33("h1", { children: title ?? "Story Report" }),
1392
- /* @__PURE__ */ jsx33(ReportSummary, {}),
1393
- /* @__PURE__ */ jsx33(ReportMeta, {})
1553
+ /* @__PURE__ */ jsx34("h1", { children: title ?? "Story Report" }),
1554
+ /* @__PURE__ */ jsx34(ReportSummary, {}),
1555
+ /* @__PURE__ */ jsx34(ReportMeta, {})
1394
1556
  ] });
1395
1557
  }
1396
1558
  function ReportErrorShell({
@@ -1399,22 +1561,22 @@ function ReportErrorShell({
1399
1561
  title,
1400
1562
  dataTheme
1401
1563
  }) {
1402
- return /* @__PURE__ */ jsx33("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx33(ReportSchemaError, { error }) });
1564
+ return /* @__PURE__ */ jsx34("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx34(ReportSchemaError, { error }) });
1403
1565
  }
1404
1566
 
1405
1567
  // src/components/Report.tsx
1406
- import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1568
+ import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
1407
1569
  function Report(props) {
1408
1570
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1409
1571
  const result = unwrapReport(report);
1410
1572
  if (!result.ok) {
1411
- return /* @__PURE__ */ jsx34(ReportErrorShell, { error: result.error, className, title, dataTheme });
1573
+ return /* @__PURE__ */ jsx35(ReportErrorShell, { error: result.error, className, title, dataTheme });
1412
1574
  }
1413
1575
  const data = result.data;
1414
1576
  const hasContent = data.features.length > 0;
1415
- return /* @__PURE__ */ jsx34(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs22("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1416
- /* @__PURE__ */ jsx34("header", { className: "es-report-header", children: /* @__PURE__ */ jsx34(ReportTitleBlock, { title }) }),
1417
- hasContent ? /* @__PURE__ */ jsx34(ReportFeatureList, {}) : /* @__PURE__ */ jsx34(ReportEmpty, {})
1577
+ return /* @__PURE__ */ jsx35(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs22("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1578
+ /* @__PURE__ */ jsx35("header", { className: "es-report-header", children: /* @__PURE__ */ jsx35(ReportTitleBlock, { title }) }),
1579
+ hasContent ? /* @__PURE__ */ jsx35(ReportFeatureList, {}) : /* @__PURE__ */ jsx35(ReportEmpty, {})
1418
1580
  ] }) });
1419
1581
  }
1420
1582