executable-stories-react 0.10.0 → 0.10.1

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");
@@ -419,28 +407,13 @@ function DocLink({ entry }) {
419
407
  // src/components/doc/DocSection.tsx
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
413
  // src/components/doc/DocSection.tsx
441
414
  var import_jsx_runtime9 = require("react/jsx-runtime");
442
415
  function neutralizeUrl(value) {
443
- return safeUrl(value) ?? "#";
416
+ return (0, import_url.safeUrl)(value) ?? "#";
444
417
  }
445
418
  function safeMarkdownHtml(markdown) {
446
419
  const raw = import_marked.marked.parse(markdown, { async: false });
@@ -491,7 +464,7 @@ function DocMermaid({ entry }) {
491
464
  // src/components/doc/DocScreenshot.tsx
492
465
  var import_jsx_runtime11 = require("react/jsx-runtime");
493
466
  function DocScreenshot({ entry }) {
494
- const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
467
+ const src = (0, import_url.isLocalFsPath)(entry.path) ? void 0 : (0, import_url.safeImageUrl)(entry.path);
495
468
  if (!src) {
496
469
  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
470
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
@@ -516,15 +489,15 @@ function DocScreenshot({ entry }) {
516
489
  // src/components/doc/DocVideo.tsx
517
490
  var import_jsx_runtime12 = require("react/jsx-runtime");
518
491
  function DocVideo({ entry }) {
519
- if (isLocalFsPath(entry.path)) {
492
+ if ((0, import_url.isLocalFsPath)(entry.path)) {
520
493
  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
494
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
522
495
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
523
496
  entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
524
497
  ] });
525
498
  }
526
- const src = safeUrl(entry.path);
527
- const poster = safeUrl(entry.poster);
499
+ const src = (0, import_url.safeUrl)(entry.path);
500
+ const poster = (0, import_url.safeUrl)(entry.poster);
528
501
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3", children: [
529
502
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
530
503
  "video",
@@ -545,7 +518,7 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
545
518
  function DocHtml({ entry }) {
546
519
  const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
547
520
  const title = entry.title ?? "Embedded HTML";
548
- const safeHref = safeUrl(entry.url ?? entry.path);
521
+ const safeHref = (0, import_url.safeUrl)(entry.url ?? entry.path);
549
522
  const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
550
523
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
551
524
  /* @__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 +685,7 @@ function ReportStepItem({ step }) {
712
685
  }
713
686
  ),
714
687
  /* @__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
688
+ 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
689
  ] }),
717
690
  step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
718
691
  "pre",
@@ -728,125 +701,10 @@ function ReportStepItem({ step }) {
728
701
  );
729
702
  }
730
703
 
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
704
  // src/components/ReportStoryboard.tsx
705
+ var import_storyboard = require("executable-stories-core/storyboard");
706
+ var import_state_diff = require("executable-stories-core/state-diff");
707
+ var import_url6 = require("executable-stories-core/utils/url");
850
708
  var import_jsx_runtime20 = require("react/jsx-runtime");
851
709
  var FRAME_GLYPH = {
852
710
  passed: "\u2713",
@@ -861,7 +719,7 @@ var FRAME_GLYPH_COLOR = {
861
719
  pending: "text-pend"
862
720
  };
863
721
  function ReportStoryboard({ scenario }) {
864
- const frames = extractStoryboardFrames(scenario);
722
+ const frames = (0, import_storyboard.extractStoryboardFrames)(scenario);
865
723
  if (frames.length < 2) return null;
866
724
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
867
725
  /* @__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 +753,7 @@ function StoryboardFrameItem({ frame }) {
895
753
  }
896
754
  function FrameScreenshot({ frame, label }) {
897
755
  const path = frame.screenshot?.path ?? "";
898
- const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
756
+ const src = (0, import_url6.isLocalFsPath)(path) ? void 0 : (0, import_url6.safeImageUrl)(path);
899
757
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
900
758
  "a",
901
759
  {
@@ -941,7 +799,7 @@ function StateCardView({ card }) {
941
799
  "rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
942
800
  CHANGE_TONE[change.kind]
943
801
  ),
944
- children: summarizeStateChanges([change])[0]
802
+ children: (0, import_state_diff.summarizeStateChanges)([change])[0]
945
803
  },
946
804
  i
947
805
  )) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
@@ -1001,6 +859,9 @@ function ReportAttachments({ attachments }) {
1001
859
  );
1002
860
  }
1003
861
 
862
+ // src/components/ReportTrace.tsx
863
+ var import_duration2 = require("executable-stories-core/utils/duration");
864
+
1004
865
  // src/lib/trace.ts
1005
866
  var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
1006
867
  var safeStatus = (s) => VALID.has(s) ? s : "unset";
@@ -1053,15 +914,15 @@ function toTraceRows(spans) {
1053
914
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
1054
915
  const rows = [];
1055
916
  const seen = /* @__PURE__ */ new Set();
1056
- const walk2 = (node, depth) => {
917
+ const walk = (node, depth) => {
1057
918
  if (seen.has(node.span.spanId)) return;
1058
919
  seen.add(node.span.spanId);
1059
920
  rows.push({ ...node.span, depth });
1060
- for (const child of node.children) walk2(child, depth + 1);
921
+ for (const child of node.children) walk(child, depth + 1);
1061
922
  };
1062
- for (const root of roots) walk2(root, 0);
923
+ for (const root of roots) walk(root, 0);
1063
924
  for (const node of byId.values()) {
1064
- if (!seen.has(node.span.spanId)) walk2(node, 0);
925
+ if (!seen.has(node.span.spanId)) walk(node, 0);
1065
926
  }
1066
927
  return rows;
1067
928
  }
@@ -1095,7 +956,7 @@ function ReportTrace({ spans }) {
1095
956
  " span",
1096
957
  rows.length === 1 ? "" : "s",
1097
958
  ", ",
1098
- formatDuration(totalMs),
959
+ (0, import_duration2.formatDuration)(totalMs),
1099
960
  ")"
1100
961
  ] }),
1101
962
  /* @__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 +979,7 @@ function ReportTrace({ spans }) {
1118
979
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
1119
980
  }
1120
981
  ) }),
1121
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
982
+ /* @__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
983
  ] }, `${row.spanId}-${i}`);
1123
984
  }) })
1124
985
  ] });
@@ -1229,6 +1090,7 @@ function useCollapse() {
1229
1090
 
1230
1091
  // src/interactive/scenario-actions.tsx
1231
1092
  var import_react7 = require("react");
1093
+ var import_scenario_markdown = require("executable-stories-core/utils/scenario-markdown");
1232
1094
  var ScenarioActionsContext = (0, import_react7.createContext)(null);
1233
1095
  var ScenarioActionsProvider = ScenarioActionsContext.Provider;
1234
1096
  function useScenarioActions() {
@@ -1374,7 +1236,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
1374
1236
  ] }),
1375
1237
  /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1376
1238
  /* @__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,
1239
+ 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
1240
  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
1241
  actions ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenu, { children: [
1380
1242
  /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
@@ -1634,6 +1496,9 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1634
1496
  );
1635
1497
  }
1636
1498
 
1499
+ // src/components/ReportMeta.tsx
1500
+ var import_duration4 = require("executable-stories-core/utils/duration");
1501
+
1637
1502
  // src/lib/provenance.ts
1638
1503
  var CI_DISPLAY_NAMES = {
1639
1504
  github: "GitHub Actions",
@@ -1674,7 +1539,7 @@ function ReportMeta() {
1674
1539
  items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
1675
1540
  }
1676
1541
  if (report.durationMs) {
1677
- items.push({ label: "Duration", value: formatDuration(report.durationMs) });
1542
+ items.push({ label: "Duration", value: (0, import_duration4.formatDuration)(report.durationMs) });
1678
1543
  }
1679
1544
  if (report.packageVersion) {
1680
1545
  items.push({ label: "Version", value: report.packageVersion });