executable-stories-react 0.15.0 → 0.17.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/index.cjs CHANGED
@@ -611,12 +611,29 @@ function DocVideo({ entry }) {
611
611
  }
612
612
 
613
613
  // src/components/doc/DocHtml.tsx
614
+ var import_react5 = require("react");
614
615
  var import_jsx_runtime14 = require("react/jsx-runtime");
616
+ var MEASURE_SCRIPT = "<script>(function(){if(parent===window)return;var last=0,queued=false;var measure=function(){var kids=document.body.children,h=0;for(var i=0;i<kids.length;i++)h=Math.max(h,kids[i].getBoundingClientRect().bottom);return Math.ceil(h||document.body.getBoundingClientRect().bottom)};var post=function(){queued=false;var h=measure();if(h===last)return;last=h;parent.postMessage({__esHtmlHeight:h},'*')};var schedule=function(){if(queued)return;queued=true;requestAnimationFrame(post)};var start=function(){new ResizeObserver(schedule).observe(document.body);new MutationObserver(schedule).observe(document.body,{subtree:true,childList:true,attributes:true,characterData:true});addEventListener('load',schedule);post()};if(document.body)start();else addEventListener('DOMContentLoaded',start)})();</script>";
617
+ var MAX_MEASURED_HEIGHT = 5e3;
615
618
  function DocHtml({ entry }) {
616
- const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
619
+ const declaredHeight = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
617
620
  const title = entry.title ?? "Embedded HTML";
618
621
  const safeHref = (0, import_url.safeUrl)(entry.url ?? entry.path);
619
- const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
622
+ const frameRef = (0, import_react5.useRef)(null);
623
+ const [measuredHeight, setMeasuredHeight] = (0, import_react5.useState)();
624
+ (0, import_react5.useEffect)(() => {
625
+ if (entry.content === void 0) return;
626
+ const onMessage = (event) => {
627
+ if (event.source !== frameRef.current?.contentWindow) return;
628
+ const reported = event.data?.__esHtmlHeight;
629
+ if (typeof reported !== "number" || !Number.isFinite(reported) || reported <= 0) return;
630
+ setMeasuredHeight(Math.min(reported, MAX_MEASURED_HEIGHT));
631
+ };
632
+ window.addEventListener("message", onMessage);
633
+ return () => window.removeEventListener("message", onMessage);
634
+ }, [entry.content]);
635
+ const height = measuredHeight === void 0 ? declaredHeight : `${measuredHeight}px`;
636
+ const frameProps = entry.content !== void 0 ? { srcDoc: entry.content + MEASURE_SCRIPT } : { src: safeHref ?? "" };
620
637
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
621
638
  /* @__PURE__ */ (0, import_jsx_runtime14.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: [
622
639
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: entry.title ?? "HTML" }),
@@ -636,6 +653,7 @@ function DocHtml({ entry }) {
636
653
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
637
654
  "iframe",
638
655
  {
656
+ ref: frameRef,
639
657
  ...frameProps,
640
658
  sandbox: "allow-scripts",
641
659
  loading: "lazy",
@@ -1089,11 +1107,11 @@ function ReportTrace({ spans }) {
1089
1107
  }
1090
1108
 
1091
1109
  // src/interactive/scenario-history-context.ts
1092
- var import_react5 = require("react");
1093
- var ScenarioHistoryContext = (0, import_react5.createContext)(null);
1110
+ var import_react6 = require("react");
1111
+ var ScenarioHistoryContext = (0, import_react6.createContext)(null);
1094
1112
  var ScenarioHistoryProvider = ScenarioHistoryContext.Provider;
1095
1113
  function useScenarioHistory() {
1096
- return (0, import_react5.useContext)(ScenarioHistoryContext);
1114
+ return (0, import_react6.useContext)(ScenarioHistoryContext);
1097
1115
  }
1098
1116
 
1099
1117
  // src/lib/run-history.ts
@@ -1184,7 +1202,7 @@ function ScenarioRunHistory({ scenarioId }) {
1184
1202
  }
1185
1203
 
1186
1204
  // src/components/ScenarioStaleness.tsx
1187
- var import_react7 = require("react");
1205
+ var import_react8 = require("react");
1188
1206
 
1189
1207
  // src/lib/provenance.ts
1190
1208
  function reportLastRunMs(report) {
@@ -1240,11 +1258,11 @@ function prUrl(ci) {
1240
1258
  }
1241
1259
 
1242
1260
  // src/interactive/scenario-freshness-context.tsx
1243
- var import_react6 = require("react");
1244
- var ScenarioFreshnessContext = (0, import_react6.createContext)(null);
1261
+ var import_react7 = require("react");
1262
+ var ScenarioFreshnessContext = (0, import_react7.createContext)(null);
1245
1263
  var ScenarioFreshnessProvider = ScenarioFreshnessContext.Provider;
1246
1264
  function useScenarioFreshness() {
1247
- return (0, import_react6.useContext)(ScenarioFreshnessContext);
1265
+ return (0, import_react7.useContext)(ScenarioFreshnessContext);
1248
1266
  }
1249
1267
 
1250
1268
  // src/components/ScenarioStaleness.tsx
@@ -1252,8 +1270,8 @@ var import_jsx_runtime24 = require("react/jsx-runtime");
1252
1270
  function ScenarioStaleness({ scenario }) {
1253
1271
  const freshness = useScenarioFreshness();
1254
1272
  const fixedNow = freshness?.nowMs;
1255
- const [now, setNow] = (0, import_react7.useState)(fixedNow);
1256
- (0, import_react7.useEffect)(() => {
1273
+ const [now, setNow] = (0, import_react8.useState)(fixedNow);
1274
+ (0, import_react8.useEffect)(() => {
1257
1275
  if (fixedNow === void 0) setNow(Date.now());
1258
1276
  }, [fixedNow]);
1259
1277
  if (!freshness || now === void 0) return null;
@@ -1267,20 +1285,20 @@ function ScenarioStaleness({ scenario }) {
1267
1285
  }
1268
1286
 
1269
1287
  // src/interactive/collapse-context.ts
1270
- var import_react8 = require("react");
1271
- var CollapseContext = (0, import_react8.createContext)(null);
1288
+ var import_react9 = require("react");
1289
+ var CollapseContext = (0, import_react9.createContext)(null);
1272
1290
  var CollapseProvider = CollapseContext.Provider;
1273
1291
  function useCollapse() {
1274
- return (0, import_react8.useContext)(CollapseContext);
1292
+ return (0, import_react9.useContext)(CollapseContext);
1275
1293
  }
1276
1294
 
1277
1295
  // src/interactive/scenario-actions.tsx
1278
- var import_react9 = require("react");
1296
+ var import_react10 = require("react");
1279
1297
  var import_scenario_markdown = require("executable-stories-core/utils/scenario-markdown");
1280
- var ScenarioActionsContext = (0, import_react9.createContext)(null);
1298
+ var ScenarioActionsContext = (0, import_react10.createContext)(null);
1281
1299
  var ScenarioActionsProvider = ScenarioActionsContext.Provider;
1282
1300
  function useScenarioActions() {
1283
- return (0, import_react9.useContext)(ScenarioActionsContext);
1301
+ return (0, import_react10.useContext)(ScenarioActionsContext);
1284
1302
  }
1285
1303
 
1286
1304
  // src/components/ui/card.tsx
@@ -1841,25 +1859,86 @@ function ReportErrorShell({
1841
1859
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportSchemaError, { error }) });
1842
1860
  }
1843
1861
 
1844
- // src/components/Report.tsx
1862
+ // src/components/ReportSpanGraph.tsx
1863
+ var import_span_graph = require("executable-stories-core/span-graph");
1864
+ var import_react11 = require("react");
1845
1865
  var import_jsx_runtime38 = require("react/jsx-runtime");
1866
+ var LANE_LABEL = {
1867
+ edge: "Edge",
1868
+ service: "Service",
1869
+ queue: "Queue",
1870
+ datastore: "Data"
1871
+ };
1872
+ var MARK_LABEL = {
1873
+ failing: "Failing",
1874
+ added: "New",
1875
+ changed: "Changed"
1876
+ };
1877
+ var MARK_CLASS = {
1878
+ failing: "text-fail",
1879
+ added: "text-pass",
1880
+ changed: "text-pend"
1881
+ };
1882
+ function MarkBadge({ node }) {
1883
+ const mark = (0, import_span_graph.spanGraphNodeMark)(node);
1884
+ if (!mark) return null;
1885
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: cn("ml-2 text-xs font-medium", MARK_CLASS[mark]), children: MARK_LABEL[mark] });
1886
+ }
1887
+ function ReportSpanGraph() {
1888
+ const report = useReport();
1889
+ const { code, graph, titleById } = (0, import_react11.useMemo)(() => {
1890
+ const scenarios = report.features.flatMap((feature) => feature.scenarios);
1891
+ const derived = (0, import_span_graph.deriveSpanGraph)(scenarios);
1892
+ return {
1893
+ graph: derived,
1894
+ code: (0, import_span_graph.spanGraphToMermaid)(derived),
1895
+ titleById: new Map(scenarios.map((scenario) => [scenario.id, scenario.title]))
1896
+ };
1897
+ }, [report]);
1898
+ if (code === "") return null;
1899
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("section", { className: "es-span-graph mt-6", "aria-labelledby": "es-span-graph-heading", children: [
1900
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("h2", { id: "es-span-graph-heading", className: "text-base font-semibold text-foreground", children: "Architecture, as it ran" }),
1901
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: "Derived from this run\u2019s traces. Every component was named by a span while a scenario ran, so nothing here is inferred from the code. Instrumented, exercised paths only: a component no scenario reaches does not appear." }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(DocMermaid, { entry: { kind: "mermaid", phase: "static", code } }),
1903
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("table", { className: "mt-2 w-full border-collapse text-left text-sm", children: [
1904
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("caption", { className: "sr-only", children: "Each component and the scenarios that exercised it" }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("tr", { className: "text-xs text-muted-foreground", children: [
1906
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Component" }),
1907
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Lane" }),
1908
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("th", { scope: "col", className: "py-1 font-medium", children: "Covered by" })
1909
+ ] }) }),
1910
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("tbody", { children: graph.nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("tr", { className: "border-t border-border align-top", children: [
1911
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("th", { scope: "row", className: "py-1.5 pr-4 font-mono text-xs font-normal", children: [
1912
+ node.id,
1913
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MarkBadge, { node })
1914
+ ] }),
1915
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("td", { className: "py-1.5 pr-4 text-xs text-muted-foreground", children: LANE_LABEL[node.kind] }),
1916
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("td", { className: "py-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: "flex flex-col gap-0.5", children: node.scenarioIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("a", { href: `#${id}`, className: "text-xs text-link underline underline-offset-2 hover:text-foreground", children: titleById.get(id) ?? id }) }, id)) }) })
1917
+ ] }, node.id)) })
1918
+ ] })
1919
+ ] });
1920
+ }
1921
+
1922
+ // src/components/Report.tsx
1923
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1846
1924
  function Report(props) {
1847
- const { report, customRenderers, renderers, className, title, dataTheme } = props;
1925
+ const { report, customRenderers, renderers, className, title, dataTheme, architecture = false } = props;
1848
1926
  const result = unwrapReport(report);
1849
1927
  if (!result.ok) {
1850
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1928
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1851
1929
  }
1852
1930
  const data = result.data;
1853
1931
  const hasContent = data.features.length > 0;
1854
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1855
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportTitleBlock, { title }) }),
1856
- hasContent ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportEmpty, {})
1932
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1933
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportTitleBlock, { title }) }),
1934
+ architecture ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportSpanGraph, {}) : null,
1935
+ hasContent ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportEmpty, {})
1857
1936
  ] }) });
1858
1937
  }
1859
1938
 
1860
1939
  // src/components/doc/MermaidView.tsx
1861
- var import_react10 = require("react");
1862
- var import_jsx_runtime39 = require("react/jsx-runtime");
1940
+ var import_react12 = require("react");
1941
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1863
1942
  function prefersDark(el) {
1864
1943
  const themed = el?.closest("[data-theme]");
1865
1944
  if (themed?.dataset.theme === "dark") return true;
@@ -1867,10 +1946,10 @@ function prefersDark(el) {
1867
1946
  return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
1868
1947
  }
1869
1948
  function MermaidView({ entry, load }) {
1870
- const ref = (0, import_react10.useRef)(null);
1871
- const [svg, setSvg] = (0, import_react10.useState)(null);
1872
- const [error, setError] = (0, import_react10.useState)(null);
1873
- (0, import_react10.useEffect)(() => {
1949
+ const ref = (0, import_react12.useRef)(null);
1950
+ const [svg, setSvg] = (0, import_react12.useState)(null);
1951
+ const [error, setError] = (0, import_react12.useState)(null);
1952
+ (0, import_react12.useEffect)(() => {
1874
1953
  let cancelled = false;
1875
1954
  const draw = async () => {
1876
1955
  let mermaid;
@@ -1887,7 +1966,10 @@ function MermaidView({ entry, load }) {
1887
1966
  mermaid.initialize({
1888
1967
  startOnLoad: false,
1889
1968
  securityLevel: "strict",
1890
- theme: prefersDark(ref.current) ? "dark" : "default"
1969
+ // "neutral" in light: the same theme the static, no-JS render uses
1970
+ // in ssr-entry, so a diagram keeps its colours when the island takes
1971
+ // over.
1972
+ theme: prefersDark(ref.current) ? "dark" : "neutral"
1891
1973
  });
1892
1974
  await mermaid.parse(entry.code);
1893
1975
  const id = `es-mermaid-${Math.random().toString(36).slice(2)}`;
@@ -1913,9 +1995,9 @@ function MermaidView({ entry, load }) {
1913
1995
  };
1914
1996
  }, [entry.code, load]);
1915
1997
  if (svg) {
1916
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("figure", { ref, className: "my-3", children: [
1917
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1918
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1998
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("figure", { ref, className: "my-3", children: [
1999
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
2000
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
1919
2001
  "div",
1920
2002
  {
1921
2003
  role: "img",
@@ -1926,8 +2008,8 @@ function MermaidView({ entry, load }) {
1926
2008
  )
1927
2009
  ] });
1928
2010
  }
1929
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
1930
- error ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
2011
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
2012
+ error ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
1931
2013
  "p",
1932
2014
  {
1933
2015
  role: "alert",
@@ -1939,34 +2021,34 @@ function MermaidView({ entry, load }) {
1939
2021
  ]
1940
2022
  }
1941
2023
  ) : null,
1942
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MermaidSource, { entry, ref })
2024
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MermaidSource, { entry, ref })
1943
2025
  ] });
1944
2026
  }
1945
2027
 
1946
2028
  // src/components/doc/MermaidDiagram.tsx
1947
- var import_jsx_runtime40 = require("react/jsx-runtime");
2029
+ var import_jsx_runtime41 = require("react/jsx-runtime");
1948
2030
  var mermaidLoader;
1949
2031
  function loadMermaid() {
1950
2032
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1951
2033
  return mermaidLoader;
1952
2034
  }
1953
2035
  function MermaidDiagram({ entry, load = loadMermaid }) {
1954
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MermaidView, { entry, load });
2036
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(MermaidView, { entry, load });
1955
2037
  }
1956
2038
 
1957
2039
  // src/components/ScenarioExplorer.tsx
1958
- var import_react11 = require("react");
2040
+ var import_react13 = require("react");
1959
2041
 
1960
2042
  // src/components/ui/command.tsx
1961
2043
  var React4 = require("react");
1962
2044
  var import_cmdk = require("cmdk");
1963
2045
  var import_lucide_react3 = require("lucide-react");
1964
- var import_jsx_runtime41 = require("react/jsx-runtime");
2046
+ var import_jsx_runtime42 = require("react/jsx-runtime");
1965
2047
  function Command({
1966
2048
  className,
1967
2049
  ...props
1968
2050
  }) {
1969
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2051
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
1970
2052
  import_cmdk.Command,
1971
2053
  {
1972
2054
  "data-slot": "command",
@@ -1982,14 +2064,14 @@ function CommandInput({
1982
2064
  className,
1983
2065
  ...props
1984
2066
  }) {
1985
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
2067
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
1986
2068
  "div",
1987
2069
  {
1988
2070
  "data-slot": "command-input-wrapper",
1989
2071
  className: "flex h-9 items-center gap-2 border-b px-3",
1990
2072
  children: [
1991
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1992
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2073
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
2074
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
1993
2075
  import_cmdk.Command.Input,
1994
2076
  {
1995
2077
  "data-slot": "command-input",
@@ -2008,7 +2090,7 @@ function CommandList({
2008
2090
  className,
2009
2091
  ...props
2010
2092
  }) {
2011
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2093
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2012
2094
  import_cmdk.Command.List,
2013
2095
  {
2014
2096
  "data-slot": "command-list",
@@ -2023,7 +2105,7 @@ function CommandList({
2023
2105
  function CommandEmpty({
2024
2106
  ...props
2025
2107
  }) {
2026
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2108
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2027
2109
  import_cmdk.Command.Empty,
2028
2110
  {
2029
2111
  "data-slot": "command-empty",
@@ -2036,7 +2118,7 @@ function CommandGroup({
2036
2118
  className,
2037
2119
  ...props
2038
2120
  }) {
2039
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2121
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2040
2122
  import_cmdk.Command.Group,
2041
2123
  {
2042
2124
  "data-slot": "command-group",
@@ -2052,7 +2134,7 @@ function CommandItem({
2052
2134
  className,
2053
2135
  ...props
2054
2136
  }) {
2055
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2137
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2056
2138
  import_cmdk.Command.Item,
2057
2139
  {
2058
2140
  "data-slot": "command-item",
@@ -2066,7 +2148,7 @@ function CommandItem({
2066
2148
  }
2067
2149
 
2068
2150
  // src/components/ScenarioExplorer.tsx
2069
- var import_jsx_runtime42 = require("react/jsx-runtime");
2151
+ var import_jsx_runtime43 = require("react/jsx-runtime");
2070
2152
  var STATUS_FILTERS = [
2071
2153
  { value: "all", label: "All" },
2072
2154
  { value: "passed", label: "Passed" },
@@ -2075,24 +2157,24 @@ var STATUS_FILTERS = [
2075
2157
  { value: "pending", label: "Pending" }
2076
2158
  ];
2077
2159
  function ScenarioExplorer({ scenarios, summary }) {
2078
- const [status, setStatus] = (0, import_react11.useState)("all");
2160
+ const [status, setStatus] = (0, import_react13.useState)("all");
2079
2161
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
2080
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "font-sans text-foreground", children: [
2081
- summary ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
2162
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "font-sans text-foreground", children: [
2163
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
2082
2164
  summary.total,
2083
2165
  " scenarios \xB7 ",
2084
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-pass", children: [
2166
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-pass", children: [
2085
2167
  summary.passed,
2086
2168
  " passed"
2087
2169
  ] }),
2088
2170
  " \xB7",
2089
2171
  " ",
2090
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-fail", children: [
2172
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-fail", children: [
2091
2173
  summary.failed,
2092
2174
  " failed"
2093
2175
  ] })
2094
2176
  ] }) : null,
2095
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2177
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2096
2178
  "button",
2097
2179
  {
2098
2180
  type: "button",
@@ -2107,26 +2189,26 @@ function ScenarioExplorer({ scenarios, summary }) {
2107
2189
  },
2108
2190
  f.value
2109
2191
  )) }),
2110
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2192
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
2111
2193
  Command,
2112
2194
  {
2113
2195
  className: "rounded-lg border border-border bg-card",
2114
2196
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
2115
2197
  children: [
2116
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
2117
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(CommandList, { className: "max-h-none", children: [
2118
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
2119
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2198
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
2199
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(CommandList, { className: "max-h-none", children: [
2200
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
2201
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2120
2202
  CommandItem,
2121
2203
  {
2122
2204
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
2123
2205
  asChild: true,
2124
2206
  className: "cursor-pointer",
2125
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
2126
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Badge, { variant: s.status, children: s.status }),
2127
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
2128
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
2129
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
2207
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
2208
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, { variant: s.status, children: s.status }),
2209
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
2210
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
2211
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
2130
2212
  ] })
2131
2213
  },
2132
2214
  s.id