executable-stories-react 0.10.0 → 0.11.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.cjs CHANGED
@@ -311,23 +311,11 @@ function useReport() {
311
311
  return ctx.report;
312
312
  }
313
313
 
314
- // ../executable-stories-core/dist/utils/duration.js
315
- function formatDuration(ms) {
316
- if (ms < 1e3) {
317
- return `${Math.round(ms)} ms`;
318
- }
319
- if (ms < 6e4) {
320
- return `${(ms / 1e3).toFixed(2)} s`;
321
- }
322
- const minutes = Math.floor(ms / 6e4);
323
- const seconds = Math.floor(ms % 6e4 / 1e3);
324
- if (minutes < 60) {
325
- return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
326
- }
327
- const hours = Math.floor(minutes / 60);
328
- const remainingMinutes = minutes % 60;
329
- return `${hours}h ${remainingMinutes}m`;
330
- }
314
+ // src/components/ReportScenario.tsx
315
+ var import_duration3 = require("executable-stories-core/utils/duration");
316
+
317
+ // src/components/ReportSteps.tsx
318
+ var import_duration = require("executable-stories-core/utils/duration");
331
319
 
332
320
  // src/components/doc/DocNote.tsx
333
321
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -416,36 +404,29 @@ function DocLink({ entry }) {
416
404
  );
417
405
  }
418
406
 
419
- // src/components/doc/DocSection.tsx
407
+ // src/lib/markdown.ts
420
408
  var import_marked = require("marked");
421
409
 
422
- // ../executable-stories-core/dist/utils/url.js
423
- function safeUrl(value) {
424
- if (!value) return void 0;
425
- const trimmed = value.trim();
426
- const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
427
- if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
428
- return trimmed;
429
- }
430
- function safeImageUrl(value) {
431
- if (!value) return void 0;
432
- const trimmed = value.trim();
433
- if (/^data:image\//i.test(trimmed)) return trimmed;
434
- return safeUrl(trimmed);
435
- }
436
- function isLocalFsPath(value) {
437
- return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
438
- }
410
+ // src/lib/url.ts
411
+ var import_url = require("executable-stories-core/utils/url");
439
412
 
440
- // src/components/doc/DocSection.tsx
441
- var import_jsx_runtime9 = require("react/jsx-runtime");
442
- function neutralizeUrl(value) {
443
- return safeUrl(value) ?? "#";
444
- }
413
+ // src/lib/markdown.ts
445
414
  function safeMarkdownHtml(markdown) {
446
415
  const raw = import_marked.marked.parse(markdown, { async: false });
447
416
  return raw.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<\/?(?:iframe|object|embed|form|base)\b[^>]*>/gi, "").replace(/\son[a-z]+\s*=\s*"[^"]*"/gi, "").replace(/\son[a-z]+\s*=\s*'[^']*'/gi, "").replace(/\son[a-z]+\s*=\s*[^\s>]+/gi, "").replace(/(href|src)\s*=\s*"([^"]*)"/gi, (_m, attr, val) => `${attr}="${neutralizeUrl(val)}"`).replace(/(href|src)\s*=\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);
448
417
  }
418
+ function dedent(text) {
419
+ const lines = text.replace(/\t/g, " ").split("\n");
420
+ const indents = lines.filter((line) => line.trim().length > 0).map((line) => line.length - line.trimStart().length);
421
+ const shortest = indents.length > 0 ? Math.min(...indents) : 0;
422
+ return lines.map((line) => line.slice(shortest)).join("\n").trim();
423
+ }
424
+ function neutralizeUrl(value) {
425
+ return (0, import_url.safeUrl)(value) ?? "#";
426
+ }
427
+
428
+ // src/components/doc/DocSection.tsx
429
+ var import_jsx_runtime9 = require("react/jsx-runtime");
449
430
  function DocSection({ entry }) {
450
431
  const renderers = useBuiltinRenderers();
451
432
  if (renderers.section) {
@@ -491,7 +472,7 @@ function DocMermaid({ entry }) {
491
472
  // src/components/doc/DocScreenshot.tsx
492
473
  var import_jsx_runtime11 = require("react/jsx-runtime");
493
474
  function DocScreenshot({ entry }) {
494
- const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
475
+ const src = (0, import_url.isLocalFsPath)(entry.path) ? void 0 : (0, import_url.safeImageUrl)(entry.path);
495
476
  if (!src) {
496
477
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
497
478
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
@@ -516,15 +497,15 @@ function DocScreenshot({ entry }) {
516
497
  // src/components/doc/DocVideo.tsx
517
498
  var import_jsx_runtime12 = require("react/jsx-runtime");
518
499
  function DocVideo({ entry }) {
519
- if (isLocalFsPath(entry.path)) {
500
+ if ((0, import_url.isLocalFsPath)(entry.path)) {
520
501
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
521
502
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
522
503
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
523
504
  entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
524
505
  ] });
525
506
  }
526
- const src = safeUrl(entry.path);
527
- const poster = safeUrl(entry.poster);
507
+ const src = (0, import_url.safeUrl)(entry.path);
508
+ const poster = (0, import_url.safeUrl)(entry.poster);
528
509
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3", children: [
529
510
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
530
511
  "video",
@@ -545,7 +526,7 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
545
526
  function DocHtml({ entry }) {
546
527
  const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
547
528
  const title = entry.title ?? "Embedded HTML";
548
- const safeHref = safeUrl(entry.url ?? entry.path);
529
+ const safeHref = (0, import_url.safeUrl)(entry.url ?? entry.path);
549
530
  const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
550
531
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
551
532
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figcaption", { className: "flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground", children: [
@@ -712,7 +693,7 @@ function ReportStepItem({ step }) {
712
693
  }
713
694
  ),
714
695
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
715
- step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
696
+ step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration.formatDuration)(step.durationMs) }) : null
716
697
  ] }),
717
698
  step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
718
699
  "pre",
@@ -728,125 +709,10 @@ function ReportStepItem({ step }) {
728
709
  );
729
710
  }
730
711
 
731
- // ../executable-stories-core/dist/state-diff.js
732
- var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
733
- function deepEqual(a, b) {
734
- if (Object.is(a, b)) return true;
735
- if (Array.isArray(a) && Array.isArray(b)) {
736
- return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
737
- }
738
- if (isPlainObject(a) && isPlainObject(b)) {
739
- const ak = Object.keys(a);
740
- const bk = Object.keys(b);
741
- return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
742
- }
743
- return false;
744
- }
745
- var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
746
- function walk(path, before, after, out) {
747
- if (Object.is(before, after)) return;
748
- if (Array.isArray(before) && Array.isArray(after)) {
749
- const shared = Math.min(before.length, after.length);
750
- for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
751
- for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
752
- for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
753
- return;
754
- }
755
- if (isPlainObject(before) && isPlainObject(after)) {
756
- for (const key of Object.keys(after)) {
757
- const p = joinKey(path, key);
758
- if (key in before) walk(p, before[key], after[key], out);
759
- else out.push({ path: p, kind: "added", after: after[key] });
760
- }
761
- for (const key of Object.keys(before)) {
762
- if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
763
- }
764
- return;
765
- }
766
- if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
767
- }
768
- function diffStateValues(before, after) {
769
- const out = [];
770
- walk("", before, after, out);
771
- return out;
772
- }
773
- function formatStateValue(value, maxLen = 60) {
774
- const s = value === void 0 ? "undefined" : JSON.stringify(value);
775
- return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
776
- }
777
- function summarizeStateChanges(changes) {
778
- return changes.map((c) => {
779
- const at = c.path === "" ? "(root)" : c.path;
780
- switch (c.kind) {
781
- case "added":
782
- return `+ ${at}: ${formatStateValue(c.after)}`;
783
- case "removed":
784
- return `\u2212 ${at}`;
785
- case "changed":
786
- return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
787
- }
788
- });
789
- }
790
-
791
- // ../executable-stories-core/dist/storyboard.js
792
- function findScreenshot(entries) {
793
- for (const entry of entries) {
794
- if (entry.kind === "screenshot") return entry;
795
- if (entry.children) {
796
- const nested = findScreenshot(entry.children);
797
- if (nested) return nested;
798
- }
799
- }
800
- return void 0;
801
- }
802
- function findStates(entries, out = []) {
803
- for (const entry of entries) {
804
- if (entry.kind === "state") out.push(entry);
805
- if (entry.children) findStates(entry.children, out);
806
- }
807
- return out;
808
- }
809
- var laneOf = (label) => label ?? "";
810
- function extractStoryboardFrames(scenario) {
811
- const frames = [];
812
- const laneOrder = [];
813
- const previous = /* @__PURE__ */ new Map();
814
- for (const step of scenario.steps) {
815
- const shot = findScreenshot(step.docEntries);
816
- const stateDocs = findStates(step.docEntries);
817
- if (!shot && stateDocs.length === 0) continue;
818
- const byLane = /* @__PURE__ */ new Map();
819
- for (const doc of stateDocs) {
820
- const lane = laneOf(doc.label);
821
- if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
822
- byLane.set(lane, doc);
823
- }
824
- const states = [];
825
- for (const lane of laneOrder) {
826
- const doc = byLane.get(lane);
827
- if (!doc) continue;
828
- const card = {
829
- ...doc.label !== void 0 && { label: doc.label },
830
- value: doc.value
831
- };
832
- if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
833
- previous.set(lane, doc.value);
834
- states.push(card);
835
- }
836
- frames.push({
837
- stepId: step.id,
838
- stepIndex: step.index,
839
- keyword: step.keyword,
840
- text: step.text,
841
- status: step.status,
842
- ...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
843
- states
844
- });
845
- }
846
- return frames;
847
- }
848
-
849
712
  // src/components/ReportStoryboard.tsx
713
+ var import_storyboard = require("executable-stories-core/storyboard");
714
+ var import_state_diff = require("executable-stories-core/state-diff");
715
+ var import_url6 = require("executable-stories-core/utils/url");
850
716
  var import_jsx_runtime20 = require("react/jsx-runtime");
851
717
  var FRAME_GLYPH = {
852
718
  passed: "\u2713",
@@ -861,7 +727,7 @@ var FRAME_GLYPH_COLOR = {
861
727
  pending: "text-pend"
862
728
  };
863
729
  function ReportStoryboard({ scenario }) {
864
- const frames = extractStoryboardFrames(scenario);
730
+ const frames = (0, import_storyboard.extractStoryboardFrames)(scenario);
865
731
  if (frames.length < 2) return null;
866
732
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
867
733
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
@@ -895,7 +761,7 @@ function StoryboardFrameItem({ frame }) {
895
761
  }
896
762
  function FrameScreenshot({ frame, label }) {
897
763
  const path = frame.screenshot?.path ?? "";
898
- const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
764
+ const src = (0, import_url6.isLocalFsPath)(path) ? void 0 : (0, import_url6.safeImageUrl)(path);
899
765
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
900
766
  "a",
901
767
  {
@@ -941,7 +807,7 @@ function StateCardView({ card }) {
941
807
  "rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
942
808
  CHANGE_TONE[change.kind]
943
809
  ),
944
- children: summarizeStateChanges([change])[0]
810
+ children: (0, import_state_diff.summarizeStateChanges)([change])[0]
945
811
  },
946
812
  i
947
813
  )) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
@@ -1001,6 +867,9 @@ function ReportAttachments({ attachments }) {
1001
867
  );
1002
868
  }
1003
869
 
870
+ // src/components/ReportTrace.tsx
871
+ var import_duration2 = require("executable-stories-core/utils/duration");
872
+
1004
873
  // src/lib/trace.ts
1005
874
  var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
1006
875
  var safeStatus = (s) => VALID.has(s) ? s : "unset";
@@ -1053,15 +922,15 @@ function toTraceRows(spans) {
1053
922
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
1054
923
  const rows = [];
1055
924
  const seen = /* @__PURE__ */ new Set();
1056
- const walk2 = (node, depth) => {
925
+ const walk = (node, depth) => {
1057
926
  if (seen.has(node.span.spanId)) return;
1058
927
  seen.add(node.span.spanId);
1059
928
  rows.push({ ...node.span, depth });
1060
- for (const child of node.children) walk2(child, depth + 1);
929
+ for (const child of node.children) walk(child, depth + 1);
1061
930
  };
1062
- for (const root of roots) walk2(root, 0);
931
+ for (const root of roots) walk(root, 0);
1063
932
  for (const node of byId.values()) {
1064
- if (!seen.has(node.span.spanId)) walk2(node, 0);
933
+ if (!seen.has(node.span.spanId)) walk(node, 0);
1065
934
  }
1066
935
  return rows;
1067
936
  }
@@ -1095,7 +964,7 @@ function ReportTrace({ spans }) {
1095
964
  " span",
1096
965
  rows.length === 1 ? "" : "s",
1097
966
  ", ",
1098
- formatDuration(totalMs),
967
+ (0, import_duration2.formatDuration)(totalMs),
1099
968
  ")"
1100
969
  ] }),
1101
970
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
@@ -1118,7 +987,7 @@ function ReportTrace({ spans }) {
1118
987
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
1119
988
  }
1120
989
  ) }),
1121
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
990
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: (0, import_duration2.formatDuration)(row.durationMs) })
1122
991
  ] }, `${row.spanId}-${i}`);
1123
992
  }) })
1124
993
  ] });
@@ -1229,6 +1098,7 @@ function useCollapse() {
1229
1098
 
1230
1099
  // src/interactive/scenario-actions.tsx
1231
1100
  var import_react7 = require("react");
1101
+ var import_scenario_markdown = require("executable-stories-core/utils/scenario-markdown");
1232
1102
  var ScenarioActionsContext = (0, import_react7.createContext)(null);
1233
1103
  var ScenarioActionsProvider = ScenarioActionsContext.Provider;
1234
1104
  function useScenarioActions() {
@@ -1374,7 +1244,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
1374
1244
  ] }),
1375
1245
  /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1376
1246
  /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1377
- scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1247
+ scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration3.formatDuration)(scenario.durationMs) }) : null,
1378
1248
  meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1379
1249
  actions ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenu, { children: [
1380
1250
  /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
@@ -1433,8 +1303,35 @@ function ReportScenarioList({ feature }) {
1433
1303
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_jsx_runtime27.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenario, { scenario }, scenario.id)) });
1434
1304
  }
1435
1305
 
1436
- // src/components/ReportFeature.tsx
1306
+ // src/components/ReportFeatureIntro.tsx
1437
1307
  var import_jsx_runtime28 = require("react/jsx-runtime");
1308
+ function ReportFeatureIntro({ feature }) {
1309
+ const hasNarrative = Boolean(feature.narrative?.trim());
1310
+ const hasGlossary = Boolean(feature.glossary?.length);
1311
+ if (!hasNarrative && !hasGlossary) return null;
1312
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-3 border-l-2 border-border pl-4 text-sm", children: [
1313
+ hasNarrative ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1314
+ "div",
1315
+ {
1316
+ className: "es-doc-prose prose prose-sm max-w-none text-muted-foreground",
1317
+ dangerouslySetInnerHTML: { __html: safeMarkdownHtml(dedent(feature.narrative)) }
1318
+ }
1319
+ ) : null,
1320
+ hasGlossary ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dl", { className: "grid gap-1.5", "aria-label": "Glossary", children: feature.glossary.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-wrap gap-x-2 text-xs", children: [
1321
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dt", { className: "font-medium text-foreground", children: entry.term }),
1322
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dd", { className: "flex-1 text-muted-foreground", children: entry.definition })
1323
+ ] }, entry.term)) }) : null
1324
+ ] });
1325
+ }
1326
+ function featureKindLabel(kind) {
1327
+ if (kind === "ability") return "Ability";
1328
+ if (kind === "business-need") return "Business need";
1329
+ if (kind === "feature") return "Feature";
1330
+ return null;
1331
+ }
1332
+
1333
+ // src/components/ReportFeature.tsx
1334
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1438
1335
  function ReportFeature({ feature }) {
1439
1336
  const titleId = `${feature.id}-title`;
1440
1337
  const bodyId = `${feature.id}-body`;
@@ -1442,10 +1339,11 @@ function ReportFeature({ feature }) {
1442
1339
  const skipped = s.skipped + s.pending;
1443
1340
  const collapse = useCollapse();
1444
1341
  const collapsed = collapse?.isCollapsed(feature.id) ?? false;
1342
+ const kindLabel = featureKindLabel(feature.kind);
1445
1343
  return (
1446
1344
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1447
1345
  // layer of nesting so the scenario cards below read as the primary unit.
1448
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1346
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1449
1347
  "section",
1450
1348
  {
1451
1349
  id: feature.id,
@@ -1453,9 +1351,9 @@ function ReportFeature({ feature }) {
1453
1351
  "aria-labelledby": titleId,
1454
1352
  className: "flex flex-col gap-3",
1455
1353
  children: [
1456
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1457
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "min-w-0", children: [
1458
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1354
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1355
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "min-w-0", children: [
1356
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1459
1357
  "button",
1460
1358
  {
1461
1359
  type: "button",
@@ -1464,31 +1362,34 @@ function ReportFeature({ feature }) {
1464
1362
  "aria-controls": bodyId,
1465
1363
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1466
1364
  children: [
1467
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1468
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate", children: feature.title })
1365
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1366
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "truncate", children: feature.title })
1469
1367
  ]
1470
1368
  }
1471
1369
  ) : feature.title }),
1472
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1370
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("p", { className: cn("mt-0.5 flex items-center gap-2 text-xs text-muted-foreground", collapse && "pl-5"), children: [
1371
+ kindLabel ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-medium text-foreground", children: kindLabel }) : null,
1372
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "truncate font-mono", children: feature.sourceFile })
1373
+ ] })
1473
1374
  ] }),
1474
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1375
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1475
1376
  "p",
1476
1377
  {
1477
1378
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1478
1379
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1479
1380
  children: [
1480
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
1381
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { children: [
1481
1382
  s.passed,
1482
1383
  " passed"
1483
1384
  ] }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1485
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1385
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1386
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1486
1387
  s.failed,
1487
1388
  " failed"
1488
1389
  ] }),
1489
- skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
1490
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1491
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
1390
+ skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
1391
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1392
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { children: [
1492
1393
  skipped,
1493
1394
  " skipped"
1494
1395
  ] })
@@ -1497,7 +1398,10 @@ function ReportFeature({ feature }) {
1497
1398
  }
1498
1399
  )
1499
1400
  ] }),
1500
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportScenarioList, { feature }) })
1401
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: [
1402
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ReportFeatureIntro, { feature }),
1403
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ReportScenarioList, { feature })
1404
+ ] })
1501
1405
  ]
1502
1406
  }
1503
1407
  )
@@ -1505,17 +1409,17 @@ function ReportFeature({ feature }) {
1505
1409
  }
1506
1410
 
1507
1411
  // src/components/ReportFeatureList.tsx
1508
- var import_jsx_runtime29 = require("react/jsx-runtime");
1412
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1509
1413
  function ReportFeatureList() {
1510
1414
  const report = useReport();
1511
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ReportFeature, { feature }, feature.id)) });
1415
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReportFeature, { feature }, feature.id)) });
1512
1416
  }
1513
1417
 
1514
1418
  // src/components/ui/empty.tsx
1515
1419
  var import_class_variance_authority2 = require("class-variance-authority");
1516
- var import_jsx_runtime30 = require("react/jsx-runtime");
1420
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1517
1421
  function Empty({ className, ...props }) {
1518
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1422
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1519
1423
  "div",
1520
1424
  {
1521
1425
  "data-slot": "empty",
@@ -1528,7 +1432,7 @@ function Empty({ className, ...props }) {
1528
1432
  );
1529
1433
  }
1530
1434
  function EmptyHeader({ className, ...props }) {
1531
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1435
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1532
1436
  "div",
1533
1437
  {
1534
1438
  "data-slot": "empty-header",
@@ -1555,7 +1459,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
1555
1459
  }
1556
1460
  );
1557
1461
  function EmptyTitle({ className, ...props }) {
1558
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1462
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1559
1463
  "div",
1560
1464
  {
1561
1465
  "data-slot": "empty-title",
@@ -1566,16 +1470,16 @@ function EmptyTitle({ className, ...props }) {
1566
1470
  }
1567
1471
 
1568
1472
  // src/components/ReportEmpty.tsx
1569
- var import_jsx_runtime31 = require("react/jsx-runtime");
1473
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1570
1474
  function ReportEmpty({ message }) {
1571
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1475
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1572
1476
  }
1573
1477
 
1574
1478
  // src/components/ReportSummary.tsx
1575
- var import_jsx_runtime32 = require("react/jsx-runtime");
1479
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1576
1480
  function ReportSummary({ className }) {
1577
1481
  const report = useReport();
1578
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1482
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1579
1483
  ReportSummaryView,
1580
1484
  {
1581
1485
  summary: report.summary,
@@ -1601,7 +1505,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1601
1505
  if (summary.pending > 0) {
1602
1506
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1603
1507
  }
1604
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1508
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1605
1509
  "dl",
1606
1510
  {
1607
1511
  className: cn(
@@ -1614,17 +1518,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1614
1518
  "aria-label": ariaLabel,
1615
1519
  children: cards.map((c) => {
1616
1520
  const tone = TONE[c.status];
1617
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
1521
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
1618
1522
  "div",
1619
1523
  {
1620
1524
  "data-status": c.status,
1621
1525
  className: "rounded-lg border bg-card px-4 py-3",
1622
1526
  children: [
1623
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1624
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1527
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1528
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1625
1529
  c.label
1626
1530
  ] }),
1627
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1531
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1628
1532
  ]
1629
1533
  },
1630
1534
  c.status
@@ -1634,6 +1538,9 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1634
1538
  );
1635
1539
  }
1636
1540
 
1541
+ // src/components/ReportMeta.tsx
1542
+ var import_duration4 = require("executable-stories-core/utils/duration");
1543
+
1637
1544
  // src/lib/provenance.ts
1638
1545
  var CI_DISPLAY_NAMES = {
1639
1546
  github: "GitHub Actions",
@@ -1665,7 +1572,7 @@ function prUrl(ci) {
1665
1572
  }
1666
1573
 
1667
1574
  // src/components/ReportMeta.tsx
1668
- var import_jsx_runtime33 = require("react/jsx-runtime");
1575
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1669
1576
  function ReportMeta() {
1670
1577
  const report = useReport();
1671
1578
  const items = [];
@@ -1674,7 +1581,7 @@ function ReportMeta() {
1674
1581
  items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
1675
1582
  }
1676
1583
  if (report.durationMs) {
1677
- items.push({ label: "Duration", value: formatDuration(report.durationMs) });
1584
+ items.push({ label: "Duration", value: (0, import_duration4.formatDuration)(report.durationMs) });
1678
1585
  }
1679
1586
  if (report.packageVersion) {
1680
1587
  items.push({ label: "Version", value: report.packageVersion });
@@ -1688,13 +1595,13 @@ function ReportMeta() {
1688
1595
  const short = sha.slice(0, 8);
1689
1596
  items.push({
1690
1597
  label: "Commit",
1691
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1598
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1692
1599
  });
1693
1600
  }
1694
1601
  if (report.ci) {
1695
1602
  items.push({
1696
1603
  label: "CI",
1697
- value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1604
+ value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1698
1605
  ciDisplayName(report.ci.name),
1699
1606
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1700
1607
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1705,7 +1612,7 @@ function ReportMeta() {
1705
1612
  const label = `#${report.ci.prNumber}`;
1706
1613
  items.push({
1707
1614
  label: "PR",
1708
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1615
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1709
1616
  });
1710
1617
  }
1711
1618
  if (items.length === 0) return null;
@@ -1713,48 +1620,48 @@ function ReportMeta() {
1713
1620
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1714
1621
  // collapsed disclosure so it doesn't push the result down. Native <details>
1715
1622
  // so it works with no JS (the SSR/no-hydration report still toggles).
1716
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1717
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("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: [
1718
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1623
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("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: [
1625
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1719
1626
  "Run details"
1720
1627
  ] }),
1721
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("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__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1722
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dt", { className: "font-medium", children: item.label }),
1723
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1628
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("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__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1629
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("dt", { className: "font-medium", children: item.label }),
1630
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1724
1631
  ] }, item.label)) })
1725
1632
  ] })
1726
1633
  );
1727
1634
  }
1728
1635
 
1729
1636
  // src/components/ReportSchemaError.tsx
1730
- var import_jsx_runtime34 = require("react/jsx-runtime");
1637
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1731
1638
  function ReportSchemaError({ error }) {
1732
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1733
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("strong", { children: "Report could not be displayed." }) }),
1734
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: error.message }),
1735
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { children: [
1639
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1640
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("strong", { children: "Report could not be displayed." }) }),
1641
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { children: error.message }),
1642
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("p", { children: [
1736
1643
  "The report bundle is newer than this version of ",
1737
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("code", { children: "executable-stories-react" }),
1644
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { children: "executable-stories-react" }),
1738
1645
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1739
1646
  ] }) : null,
1740
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("details", { children: [
1741
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("summary", { children: [
1647
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("details", { children: [
1648
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("summary", { children: [
1742
1649
  error.issues.length,
1743
1650
  " validation issue",
1744
1651
  error.issues.length === 1 ? "" : "s"
1745
1652
  ] }),
1746
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1653
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1747
1654
  ] }) : null
1748
1655
  ] });
1749
1656
  }
1750
1657
 
1751
1658
  // src/components/ReportShell.tsx
1752
- var import_jsx_runtime35 = require("react/jsx-runtime");
1659
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1753
1660
  function ReportTitleBlock({ title }) {
1754
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
1755
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { children: title ?? "Story Report" }),
1756
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportSummary, {}),
1757
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportMeta, {})
1661
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
1662
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h1", { children: title ?? "Story Report" }),
1663
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportSummary, {}),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportMeta, {})
1758
1665
  ] });
1759
1666
  }
1760
1667
  function ReportErrorShell({
@@ -1763,22 +1670,22 @@ function ReportErrorShell({
1763
1670
  title,
1764
1671
  dataTheme
1765
1672
  }) {
1766
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportSchemaError, { error }) });
1673
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportSchemaError, { error }) });
1767
1674
  }
1768
1675
 
1769
1676
  // src/components/Report.tsx
1770
- var import_jsx_runtime36 = require("react/jsx-runtime");
1677
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1771
1678
  function Report(props) {
1772
1679
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1773
1680
  const result = unwrapReport(report);
1774
1681
  if (!result.ok) {
1775
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1682
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1776
1683
  }
1777
1684
  const data = result.data;
1778
1685
  const hasContent = data.features.length > 0;
1779
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1780
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportTitleBlock, { title }) }),
1781
- hasContent ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportEmpty, {})
1686
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1687
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportTitleBlock, { title }) }),
1688
+ hasContent ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportEmpty, {})
1782
1689
  ] }) });
1783
1690
  }
1784
1691