executable-stories-react 0.4.1 → 0.6.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
@@ -181,11 +181,15 @@ var badgeVariants = (0, import_class_variance_authority.cva)(
181
181
  outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
182
182
  ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
183
183
  link: "text-primary underline-offset-4 [a&]:hover:underline",
184
- passed: "border-pass-border bg-pass-bg text-pass font-mono uppercase",
184
+ // Pass/skip/pending are the quiet states: outline + coloured text, no
185
+ // fill, so a green report reads calm. Only `failed` keeps a tinted
186
+ // fill, making it the single loud badge on the page, so red pops the
187
+ // instant something breaks. Colour-as-accent, matching the KPI cards.
188
+ passed: "border-pass-border text-pass font-mono uppercase",
185
189
  failed: "border-fail-border bg-fail-bg text-fail font-mono uppercase",
186
- skipped: "border-skip-border bg-skip-bg text-skip font-mono uppercase",
187
- pending: "border-pend-border bg-pend-bg text-pend font-mono uppercase",
188
- tag: "border-pass-border bg-pass-bg text-pass font-mono font-medium"
190
+ skipped: "border-skip-border text-skip font-mono uppercase",
191
+ pending: "border-pend-border text-pend font-mono uppercase",
192
+ tag: "border-border text-muted-foreground font-mono font-medium [a&]:hover:bg-muted"
189
193
  }
190
194
  },
191
195
  defaultVariants: {
@@ -738,7 +742,7 @@ function ReportTrace({ spans }) {
738
742
  {
739
743
  className: "min-w-0 flex-1 truncate text-foreground",
740
744
  style: { paddingLeft: `${row.depth * 12}px` },
741
- title: row.statusMessage ? `${row.name} \u2014 ${row.statusMessage}` : row.name,
745
+ title: row.statusMessage ? `${row.name}: ${row.statusMessage}` : row.name,
742
746
  children: row.name
743
747
  }
744
748
  ),
@@ -875,7 +879,7 @@ function Card({ className, ...props }) {
875
879
  {
876
880
  "data-slot": "card",
877
881
  className: cn(
878
- "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm",
882
+ "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-xs",
879
883
  className
880
884
  ),
881
885
  ...props
@@ -906,52 +910,89 @@ function CardContent({ className, ...props }) {
906
910
  );
907
911
  }
908
912
 
909
- // src/components/ReportScenario.tsx
913
+ // src/components/ui/dropdown-menu.tsx
914
+ var React3 = require("react");
915
+ var import_menu = require("@base-ui/react/menu");
916
+ var import_lucide_react = require("lucide-react");
910
917
  var import_jsx_runtime22 = require("react/jsx-runtime");
911
- var STATUS_LABEL = {
912
- passed: "Passed",
913
- failed: "Failed",
914
- skipped: "Skipped",
915
- pending: "Pending"
916
- };
917
- var STATUS_GLYPH = {
918
- passed: "\u2713",
919
- failed: "\u2717",
920
- skipped: "\u25CB",
921
- pending: "\u25CB"
922
- };
923
- var STATUS_GLYPH_COLOR = {
924
- passed: "text-pass",
925
- failed: "text-fail",
926
- skipped: "text-skip",
927
- pending: "text-pend"
928
- };
929
- var STATUS_BADGE = {
930
- passed: "passed",
931
- failed: "failed",
932
- skipped: "skipped",
933
- pending: "pending"
918
+ 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";
919
+ function DropdownMenu(props) {
920
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
921
+ }
922
+ function DropdownMenuTrigger(props) {
923
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
924
+ }
925
+ function DropdownMenuContent({
926
+ className,
927
+ align = "end",
928
+ sideOffset = 4,
929
+ ...props
930
+ }) {
931
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
932
+ import_menu.Menu.Positioner,
933
+ {
934
+ "data-slot": "dropdown-menu-positioner",
935
+ className: "z-50",
936
+ align,
937
+ sideOffset,
938
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
939
+ import_menu.Menu.Popup,
940
+ {
941
+ "data-slot": "dropdown-menu-content",
942
+ className: cn(
943
+ "z-50 min-w-[11rem] origin-[var(--transform-origin)] overflow-hidden rounded-md border border-border bg-popover p-1 font-sans text-sm text-popover-foreground shadow-md transition-[opacity,transform] data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:scale-95 data-[starting-style]:opacity-0",
944
+ className
945
+ ),
946
+ ...props
947
+ }
948
+ )
949
+ }
950
+ ) });
951
+ }
952
+ function DropdownMenuItem({
953
+ className,
954
+ ...props
955
+ }) {
956
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
957
+ import_menu.Menu.Item,
958
+ {
959
+ "data-slot": "dropdown-menu-item",
960
+ className: cn(itemClasses, className),
961
+ ...props
962
+ }
963
+ );
964
+ }
965
+
966
+ // src/components/ReportScenario.tsx
967
+ var import_lucide_react2 = require("lucide-react");
968
+ var import_jsx_runtime23 = require("react/jsx-runtime");
969
+ var STATUS_META = {
970
+ passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
971
+ failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
972
+ skipped: { label: "Skipped", glyph: "\u25CB", glyphColor: "text-skip", badgeVariant: "skipped", showPill: true },
973
+ pending: { label: "Pending", glyph: "\u25CB", glyphColor: "text-pend", badgeVariant: "pending", showPill: true }
934
974
  };
935
975
  function ReportScenario({ scenario, hideTitle = false }) {
936
976
  const titleId = `${scenario.id}-title`;
937
977
  const bodyId = `${scenario.id}-body`;
938
- const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
978
+ const meta = STATUS_META[scenario.status];
979
+ const label = scenario.planned ? "Planned" : meta.label;
939
980
  const collapse = useCollapse();
940
981
  const collapsible = collapse !== null && !hideTitle;
941
982
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
942
983
  const actions = useScenarioActions();
943
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
984
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
944
985
  Card,
945
986
  {
946
987
  id: scenario.id,
947
988
  "data-status": scenario.status,
948
- ...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
989
+ ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
949
990
  className: "gap-0 py-0",
950
991
  children: [
951
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CardHeader, { className: "px-4 py-3", children: [
952
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
953
- hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
954
- collapsible ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
992
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardHeader, { className: "px-4 py-3", children: [
993
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
994
+ hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
995
+ collapsible ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
955
996
  "button",
956
997
  {
957
998
  type: "button",
@@ -960,60 +1001,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
960
1001
  "aria-controls": bodyId,
961
1002
  "aria-label": `Toggle ${scenario.title}`,
962
1003
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
963
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1004
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
964
1005
  }
965
1006
  ) : null,
966
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", STATUS_GLYPH_COLOR[scenario.status]), children: STATUS_GLYPH[scenario.status] }),
967
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: scenario.title })
1007
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1008
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: scenario.title })
968
1009
  ] }),
969
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
970
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
971
- scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
972
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: STATUS_BADGE[scenario.status], "aria-label": `Status: ${label}`, children: label }),
973
- actions ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-0.5", children: [
974
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
975
- "button",
976
- {
977
- type: "button",
978
- onClick: () => actions.copyLink(scenario),
979
- "aria-label": `Copy link to ${scenario.title}`,
980
- title: "Copy permalink",
981
- className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
982
- children: "link"
983
- }
984
- ),
985
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
986
- "button",
1010
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1011
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1012
+ scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1013
+ meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1014
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenu, { children: [
1015
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1016
+ DropdownMenuTrigger,
987
1017
  {
988
- type: "button",
989
- onClick: () => actions.copyMarkdown(scenario),
990
- "aria-label": `Copy ${scenario.title} as Markdown`,
991
- title: "Copy as Markdown",
992
- className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
993
- children: "md"
1018
+ "aria-label": `Actions for ${scenario.title}`,
1019
+ className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1020
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
994
1021
  }
995
1022
  ),
996
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
997
- "button",
998
- {
999
- type: "button",
1000
- onClick: () => actions.copyPrompt(scenario),
1001
- "aria-label": `Copy ${scenario.title} as an AI investigation prompt`,
1002
- title: "Copy as AI prompt",
1003
- className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
1004
- children: "ai"
1005
- }
1006
- )
1023
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuContent, { align: "end", children: [
1024
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1025
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.LinkIcon, {}),
1026
+ " Copy link"
1027
+ ] }),
1028
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1029
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.FileTextIcon, {}),
1030
+ " Copy as Markdown"
1031
+ ] }),
1032
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1033
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.SparklesIcon, {}),
1034
+ " Explain with AI"
1035
+ ] })
1036
+ ] })
1007
1037
  ] }) : null
1008
1038
  ] })
1009
1039
  ] }),
1010
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1011
- scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1012
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1040
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1041
+ scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1042
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1013
1043
  ] }) : null
1014
1044
  ] }),
1015
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1016
- scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1045
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1046
+ scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1017
1047
  "pre",
1018
1048
  {
1019
1049
  role: "alert",
@@ -1021,10 +1051,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
1021
1051
  children: scenario.errorMessage
1022
1052
  }
1023
1053
  ) : null,
1024
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportSteps, { scenario }),
1025
- scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1026
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1027
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportTrace, { spans: scenario.otelSpans })
1054
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportSteps, { scenario }),
1055
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1056
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1057
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportTrace, { spans: scenario.otelSpans })
1028
1058
  ] })
1029
1059
  ]
1030
1060
  }
@@ -1032,13 +1062,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1032
1062
  }
1033
1063
 
1034
1064
  // src/components/ReportScenarioList.tsx
1035
- var import_jsx_runtime23 = require("react/jsx-runtime");
1065
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1036
1066
  function ReportScenarioList({ feature }) {
1037
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportScenario, { scenario }, scenario.id)) });
1067
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenario, { scenario }, scenario.id)) });
1038
1068
  }
1039
1069
 
1040
1070
  // src/components/ReportFeature.tsx
1041
- var import_jsx_runtime24 = require("react/jsx-runtime");
1071
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1042
1072
  function ReportFeature({ feature }) {
1043
1073
  const titleId = `${feature.id}-title`;
1044
1074
  const bodyId = `${feature.id}-body`;
@@ -1046,74 +1076,80 @@ function ReportFeature({ feature }) {
1046
1076
  const skipped = s.skipped + s.pending;
1047
1077
  const collapse = useCollapse();
1048
1078
  const collapsed = collapse?.isCollapsed(feature.id) ?? false;
1049
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1050
- "section",
1051
- {
1052
- id: feature.id,
1053
- "data-slot": "feature",
1054
- "aria-labelledby": titleId,
1055
- className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
1056
- children: [
1057
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center justify-between gap-4 border-b border-border bg-muted/40 px-4 py-3", children: [
1058
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
1059
- collapse ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1060
- "button",
1079
+ return (
1080
+ // Suite = a section heading + a divider, NOT another bordered card. Drops a
1081
+ // layer of nesting so the scenario cards below read as the primary unit.
1082
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1083
+ "section",
1084
+ {
1085
+ id: feature.id,
1086
+ "data-slot": "feature",
1087
+ "aria-labelledby": titleId,
1088
+ className: "flex flex-col gap-3",
1089
+ children: [
1090
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1091
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "min-w-0", children: [
1092
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1093
+ "button",
1094
+ {
1095
+ type: "button",
1096
+ onClick: () => collapse.toggle(feature.id),
1097
+ "aria-expanded": !collapsed,
1098
+ "aria-controls": bodyId,
1099
+ className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1100
+ children: [
1101
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1102
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate", children: feature.title })
1103
+ ]
1104
+ }
1105
+ ) : feature.title }),
1106
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1107
+ ] }),
1108
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1109
+ "p",
1061
1110
  {
1062
- type: "button",
1063
- onClick: () => collapse.toggle(feature.id),
1064
- "aria-expanded": !collapsed,
1065
- "aria-controls": bodyId,
1066
- "aria-label": `Toggle ${feature.title}`,
1067
- className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1068
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1111
+ className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1112
+ "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1113
+ children: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1115
+ s.passed,
1116
+ " passed"
1117
+ ] }),
1118
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1119
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1120
+ s.failed,
1121
+ " failed"
1122
+ ] }),
1123
+ skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
1124
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1126
+ skipped,
1127
+ " skipped"
1128
+ ] })
1129
+ ] }) : null
1130
+ ]
1069
1131
  }
1070
- ) : null,
1071
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "min-w-0", children: [
1072
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { id: titleId, className: "text-sm font-semibold tracking-tight text-foreground", children: feature.title }),
1073
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-0.5 truncate font-mono text-xs text-muted-foreground", children: feature.sourceFile })
1074
- ] })
1132
+ )
1075
1133
  ] }),
1076
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1077
- "div",
1078
- {
1079
- role: "img",
1080
- className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
1081
- "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1082
- children: [
1083
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-pass", children: [
1084
- "\u2713",
1085
- s.passed
1086
- ] }),
1087
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-fail", children: [
1088
- "\u2717",
1089
- s.failed
1090
- ] }),
1091
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-skip", children: [
1092
- "\u25CB",
1093
- skipped
1094
- ] })
1095
- ]
1096
- }
1097
- )
1098
- ] }),
1099
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenarioList, { feature }) })
1100
- ]
1101
- }
1134
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenarioList, { feature }) })
1135
+ ]
1136
+ }
1137
+ )
1102
1138
  );
1103
1139
  }
1104
1140
 
1105
1141
  // src/components/ReportFeatureList.tsx
1106
- var import_jsx_runtime25 = require("react/jsx-runtime");
1142
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1107
1143
  function ReportFeatureList() {
1108
1144
  const report = useReport();
1109
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportFeature, { feature }, feature.id)) });
1145
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportFeature, { feature }, feature.id)) });
1110
1146
  }
1111
1147
 
1112
1148
  // src/components/ui/empty.tsx
1113
1149
  var import_class_variance_authority2 = require("class-variance-authority");
1114
- var import_jsx_runtime26 = require("react/jsx-runtime");
1150
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1115
1151
  function Empty({ className, ...props }) {
1116
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1152
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1117
1153
  "div",
1118
1154
  {
1119
1155
  "data-slot": "empty",
@@ -1126,7 +1162,7 @@ function Empty({ className, ...props }) {
1126
1162
  );
1127
1163
  }
1128
1164
  function EmptyHeader({ className, ...props }) {
1129
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1165
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1130
1166
  "div",
1131
1167
  {
1132
1168
  "data-slot": "empty-header",
@@ -1153,7 +1189,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
1153
1189
  }
1154
1190
  );
1155
1191
  function EmptyTitle({ className, ...props }) {
1156
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1192
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1157
1193
  "div",
1158
1194
  {
1159
1195
  "data-slot": "empty-title",
@@ -1164,16 +1200,16 @@ function EmptyTitle({ className, ...props }) {
1164
1200
  }
1165
1201
 
1166
1202
  // src/components/ReportEmpty.tsx
1167
- var import_jsx_runtime27 = require("react/jsx-runtime");
1203
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1168
1204
  function ReportEmpty({ message }) {
1169
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1205
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1170
1206
  }
1171
1207
 
1172
1208
  // src/components/ReportSummary.tsx
1173
- var import_jsx_runtime28 = require("react/jsx-runtime");
1209
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1174
1210
  function ReportSummary({ className }) {
1175
1211
  const report = useReport();
1176
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1212
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1177
1213
  ReportSummaryView,
1178
1214
  {
1179
1215
  summary: report.summary,
@@ -1182,38 +1218,54 @@ function ReportSummary({ className }) {
1182
1218
  }
1183
1219
  );
1184
1220
  }
1221
+ var TONE = {
1222
+ total: { num: "text-foreground", dot: "bg-muted-foreground/50" },
1223
+ passed: { num: "text-pass", dot: "bg-pass" },
1224
+ failed: { num: "text-fail", dot: "bg-fail" },
1225
+ skipped: { num: "text-skip", dot: "bg-skip" },
1226
+ pending: { num: "text-pend", dot: "bg-pend" }
1227
+ };
1185
1228
  function ReportSummaryView({ summary, className, ariaLabel }) {
1186
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { className: cn("text-sm text-muted-foreground", className), "aria-label": ariaLabel, children: [
1187
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
1188
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("strong", { className: "font-semibold text-foreground", children: summary.total }),
1189
- " scenario",
1190
- summary.total === 1 ? "" : "s"
1191
- ] }),
1192
- " \xB7 ",
1193
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "passed", className: "text-pass", children: [
1194
- summary.passed,
1195
- " passed"
1196
- ] }),
1197
- " \xB7 ",
1198
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "failed", className: "text-fail", children: [
1199
- summary.failed,
1200
- " failed"
1201
- ] }),
1202
- summary.skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
1203
- " \xB7 ",
1204
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "skipped", className: "text-skip", children: [
1205
- summary.skipped,
1206
- " skipped"
1207
- ] })
1208
- ] }) : null,
1209
- summary.pending > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
1210
- " \xB7 ",
1211
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "pending", className: "text-pend", children: [
1212
- summary.pending,
1213
- " pending"
1214
- ] })
1215
- ] }) : null
1216
- ] });
1229
+ const cards = [
1230
+ { status: "total", label: "Total", value: summary.total },
1231
+ { status: "passed", label: "Passed", value: summary.passed },
1232
+ { status: "failed", label: "Failed", value: summary.failed },
1233
+ { status: "skipped", label: "Skipped", value: summary.skipped }
1234
+ ];
1235
+ if (summary.pending > 0) {
1236
+ cards.push({ status: "pending", label: "Pending", value: summary.pending });
1237
+ }
1238
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1239
+ "dl",
1240
+ {
1241
+ className: cn(
1242
+ "grid grid-cols-2 gap-3",
1243
+ // Columns follow the card count so the row is always full — 5 statuses
1244
+ // (pending present) never leave a lone orphan card below a row of four.
1245
+ cards.length === 5 ? "sm:grid-cols-5" : "sm:grid-cols-4",
1246
+ className
1247
+ ),
1248
+ "aria-label": ariaLabel,
1249
+ children: cards.map((c) => {
1250
+ const tone = TONE[c.status];
1251
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1252
+ "div",
1253
+ {
1254
+ "data-status": c.status,
1255
+ className: "rounded-lg border bg-card px-4 py-3",
1256
+ children: [
1257
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1258
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1259
+ c.label
1260
+ ] }),
1261
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1262
+ ]
1263
+ },
1264
+ c.status
1265
+ );
1266
+ })
1267
+ }
1268
+ );
1217
1269
  }
1218
1270
 
1219
1271
  // src/lib/provenance.ts
@@ -1266,7 +1318,7 @@ function prUrl(ci) {
1266
1318
  }
1267
1319
 
1268
1320
  // src/components/ReportMeta.tsx
1269
- var import_jsx_runtime29 = require("react/jsx-runtime");
1321
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1270
1322
  function ReportMeta() {
1271
1323
  const report = useReport();
1272
1324
  const items = [];
@@ -1289,13 +1341,13 @@ function ReportMeta() {
1289
1341
  const short = sha.slice(0, 8);
1290
1342
  items.push({
1291
1343
  label: "Commit",
1292
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1344
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1293
1345
  });
1294
1346
  }
1295
1347
  if (report.ci) {
1296
1348
  items.push({
1297
1349
  label: "CI",
1298
- value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1350
+ value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1299
1351
  ciDisplayName(report.ci.name),
1300
1352
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1301
1353
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1306,45 +1358,56 @@ function ReportMeta() {
1306
1358
  const label = `#${report.ci.prNumber}`;
1307
1359
  items.push({
1308
1360
  label: "PR",
1309
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1361
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1310
1362
  });
1311
1363
  }
1312
1364
  if (items.length === 0) return null;
1313
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dl", { "aria-label": "Run metadata", className: "flex flex-wrap gap-x-6 gap-y-1 text-xs text-muted-foreground", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-1.5", children: [
1314
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dt", { className: "font-medium", children: item.label }),
1315
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1316
- ] }, item.label)) });
1365
+ return (
1366
+ // Run metadata is useful but secondary to "what failed" — tuck it into a
1367
+ // collapsed disclosure so it doesn't push the result down. Native <details>
1368
+ // so it works with no JS (the SSR/no-hydration report still toggles).
1369
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1370
+ /* @__PURE__ */ (0, import_jsx_runtime30.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: [
1371
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1372
+ "Run details"
1373
+ ] }),
1374
+ /* @__PURE__ */ (0, import_jsx_runtime30.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_runtime30.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1375
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "font-medium", children: item.label }),
1376
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1377
+ ] }, item.label)) })
1378
+ ] })
1379
+ );
1317
1380
  }
1318
1381
 
1319
1382
  // src/components/ReportSchemaError.tsx
1320
- var import_jsx_runtime30 = require("react/jsx-runtime");
1383
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1321
1384
  function ReportSchemaError({ error }) {
1322
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1323
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("strong", { children: "Report could not be displayed." }) }),
1324
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { children: error.message }),
1325
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("p", { children: [
1385
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1386
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: "Report could not be displayed." }) }),
1387
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: error.message }),
1388
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
1326
1389
  "The report bundle is newer than this version of ",
1327
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("code", { children: "executable-stories-react" }),
1390
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { children: "executable-stories-react" }),
1328
1391
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1329
1392
  ] }) : null,
1330
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { children: [
1331
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("summary", { children: [
1393
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { children: [
1394
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { children: [
1332
1395
  error.issues.length,
1333
1396
  " validation issue",
1334
1397
  error.issues.length === 1 ? "" : "s"
1335
1398
  ] }),
1336
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1399
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1337
1400
  ] }) : null
1338
1401
  ] });
1339
1402
  }
1340
1403
 
1341
1404
  // src/components/ReportShell.tsx
1342
- var import_jsx_runtime31 = require("react/jsx-runtime");
1405
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1343
1406
  function ReportTitleBlock({ title }) {
1344
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
1345
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h1", { children: title ?? "Story Report" }),
1346
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportSummary, {}),
1347
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportMeta, {})
1407
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
1408
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h1", { children: title ?? "Story Report" }),
1409
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSummary, {}),
1410
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportMeta, {})
1348
1411
  ] });
1349
1412
  }
1350
1413
  function ReportErrorShell({
@@ -1353,28 +1416,28 @@ function ReportErrorShell({
1353
1416
  title,
1354
1417
  dataTheme
1355
1418
  }) {
1356
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportSchemaError, { error }) });
1419
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSchemaError, { error }) });
1357
1420
  }
1358
1421
 
1359
1422
  // src/components/Report.tsx
1360
- var import_jsx_runtime32 = require("react/jsx-runtime");
1423
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1361
1424
  function Report(props) {
1362
1425
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1363
1426
  const result = unwrapReport(report);
1364
1427
  if (!result.ok) {
1365
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1428
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1366
1429
  }
1367
1430
  const data = result.data;
1368
1431
  const hasContent = data.features.length > 0;
1369
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1370
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportTitleBlock, { title }) }),
1371
- hasContent ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportEmpty, {})
1432
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1433
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportTitleBlock, { title }) }),
1434
+ hasContent ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportEmpty, {})
1372
1435
  ] }) });
1373
1436
  }
1374
1437
 
1375
1438
  // src/components/doc/MermaidView.tsx
1376
1439
  var import_react8 = require("react");
1377
- var import_jsx_runtime33 = require("react/jsx-runtime");
1440
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1378
1441
  function prefersDark(el) {
1379
1442
  const themed = el?.closest("[data-theme]");
1380
1443
  if (themed?.dataset.theme === "dark") return true;
@@ -1411,9 +1474,9 @@ function MermaidView({ entry, load }) {
1411
1474
  };
1412
1475
  }, [entry.code, load]);
1413
1476
  if (svg) {
1414
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("figure", { ref, className: "my-3", children: [
1415
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1416
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1477
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("figure", { ref, className: "my-3", children: [
1478
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1479
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1417
1480
  "div",
1418
1481
  {
1419
1482
  role: "img",
@@ -1424,33 +1487,33 @@ function MermaidView({ entry, load }) {
1424
1487
  )
1425
1488
  ] });
1426
1489
  }
1427
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(MermaidSource, { entry, ref });
1490
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MermaidSource, { entry, ref });
1428
1491
  }
1429
1492
 
1430
1493
  // src/components/doc/MermaidDiagram.tsx
1431
- var import_jsx_runtime34 = require("react/jsx-runtime");
1494
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1432
1495
  var mermaidLoader;
1433
1496
  function loadMermaid() {
1434
1497
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1435
1498
  return mermaidLoader;
1436
1499
  }
1437
1500
  function MermaidDiagram({ entry, load = loadMermaid }) {
1438
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MermaidView, { entry, load });
1501
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MermaidView, { entry, load });
1439
1502
  }
1440
1503
 
1441
1504
  // src/components/ScenarioExplorer.tsx
1442
1505
  var import_react9 = require("react");
1443
1506
 
1444
1507
  // src/components/ui/command.tsx
1445
- var React3 = require("react");
1508
+ var React4 = require("react");
1446
1509
  var import_cmdk = require("cmdk");
1447
- var import_lucide_react = require("lucide-react");
1448
- var import_jsx_runtime35 = require("react/jsx-runtime");
1510
+ var import_lucide_react3 = require("lucide-react");
1511
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1449
1512
  function Command({
1450
1513
  className,
1451
1514
  ...props
1452
1515
  }) {
1453
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1516
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1454
1517
  import_cmdk.Command,
1455
1518
  {
1456
1519
  "data-slot": "command",
@@ -1466,14 +1529,14 @@ function CommandInput({
1466
1529
  className,
1467
1530
  ...props
1468
1531
  }) {
1469
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
1532
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
1470
1533
  "div",
1471
1534
  {
1472
1535
  "data-slot": "command-input-wrapper",
1473
1536
  className: "flex h-9 items-center gap-2 border-b px-3",
1474
1537
  children: [
1475
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1476
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1538
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1539
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1477
1540
  import_cmdk.Command.Input,
1478
1541
  {
1479
1542
  "data-slot": "command-input",
@@ -1492,7 +1555,7 @@ function CommandList({
1492
1555
  className,
1493
1556
  ...props
1494
1557
  }) {
1495
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1558
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1496
1559
  import_cmdk.Command.List,
1497
1560
  {
1498
1561
  "data-slot": "command-list",
@@ -1507,7 +1570,7 @@ function CommandList({
1507
1570
  function CommandEmpty({
1508
1571
  ...props
1509
1572
  }) {
1510
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1573
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1511
1574
  import_cmdk.Command.Empty,
1512
1575
  {
1513
1576
  "data-slot": "command-empty",
@@ -1520,7 +1583,7 @@ function CommandGroup({
1520
1583
  className,
1521
1584
  ...props
1522
1585
  }) {
1523
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1586
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1524
1587
  import_cmdk.Command.Group,
1525
1588
  {
1526
1589
  "data-slot": "command-group",
@@ -1536,7 +1599,7 @@ function CommandItem({
1536
1599
  className,
1537
1600
  ...props
1538
1601
  }) {
1539
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1602
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1540
1603
  import_cmdk.Command.Item,
1541
1604
  {
1542
1605
  "data-slot": "command-item",
@@ -1550,7 +1613,7 @@ function CommandItem({
1550
1613
  }
1551
1614
 
1552
1615
  // src/components/ScenarioExplorer.tsx
1553
- var import_jsx_runtime36 = require("react/jsx-runtime");
1616
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1554
1617
  var STATUS_FILTERS = [
1555
1618
  { value: "all", label: "All" },
1556
1619
  { value: "passed", label: "Passed" },
@@ -1561,22 +1624,22 @@ var STATUS_FILTERS = [
1561
1624
  function ScenarioExplorer({ scenarios, summary }) {
1562
1625
  const [status, setStatus] = (0, import_react9.useState)("all");
1563
1626
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1564
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "font-sans text-foreground", children: [
1565
- summary ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1627
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "font-sans text-foreground", children: [
1628
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1566
1629
  summary.total,
1567
1630
  " scenarios \xB7 ",
1568
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "text-pass", children: [
1631
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-pass", children: [
1569
1632
  summary.passed,
1570
1633
  " passed"
1571
1634
  ] }),
1572
1635
  " \xB7",
1573
1636
  " ",
1574
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "text-fail", children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-fail", children: [
1575
1638
  summary.failed,
1576
1639
  " failed"
1577
1640
  ] })
1578
1641
  ] }) : null,
1579
- /* @__PURE__ */ (0, import_jsx_runtime36.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_runtime36.jsx)(
1642
+ /* @__PURE__ */ (0, import_jsx_runtime37.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_runtime37.jsx)(
1580
1643
  "button",
1581
1644
  {
1582
1645
  type: "button",
@@ -1591,26 +1654,26 @@ function ScenarioExplorer({ scenarios, summary }) {
1591
1654
  },
1592
1655
  f.value
1593
1656
  )) }),
1594
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
1657
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1595
1658
  Command,
1596
1659
  {
1597
1660
  className: "rounded-lg border border-border bg-card",
1598
1661
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1599
1662
  children: [
1600
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
1601
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(CommandList, { className: "max-h-none", children: [
1602
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
1603
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1663
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(CommandList, { className: "max-h-none", children: [
1665
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1604
1667
  CommandItem,
1605
1668
  {
1606
1669
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1607
1670
  asChild: true,
1608
1671
  className: "cursor-pointer",
1609
- children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
1610
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Badge, { variant: s.status, children: s.status }),
1611
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1612
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1613
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1672
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
1673
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Badge, { variant: s.status, children: s.status }),
1674
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1675
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1614
1677
  ] })
1615
1678
  },
1616
1679
  s.id