executable-stories-react 0.17.1 → 0.19.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
@@ -430,11 +430,11 @@ function formatValue(value) {
430
430
  return String(value);
431
431
  }
432
432
  }
433
- function DocKv({ entry }) {
434
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
433
+ function DocKv({ entries }) {
434
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dl", { className: "my-2 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-sm", children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "contents", children: [
435
435
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
436
436
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { className: "min-w-0 break-words font-mono text-foreground", children: formatValue(entry.value) })
437
- ] });
437
+ ] }, i)) });
438
438
  }
439
439
 
440
440
  // src/hooks/useRenderers.ts
@@ -521,7 +521,7 @@ function DocSection({ entry }) {
521
521
  if (renderers.section) {
522
522
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: renderers.section(entry) });
523
523
  }
524
- const html = safeMarkdownHtml(entry.markdown);
524
+ const html = safeMarkdownHtml(dedent(entry.markdown));
525
525
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
526
526
  entry.title ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
527
527
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -707,7 +707,7 @@ function DocEntry({ entry }) {
707
707
  case "tag":
708
708
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocTag, { entry });
709
709
  case "kv":
710
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocKv, { entry });
710
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocKv, { entries: [entry] });
711
711
  case "code":
712
712
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocCode, { entry });
713
713
  case "table":
@@ -735,7 +735,15 @@ function DocEntry({ entry }) {
735
735
  var import_jsx_runtime18 = require("react/jsx-runtime");
736
736
  function ReportDocEntries({ entries }) {
737
737
  if (entries.length === 0) return null;
738
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DocEntry, { entry }, i)) });
738
+ const groups = [];
739
+ for (const entry of entries) {
740
+ const last = groups[groups.length - 1];
741
+ if (entry.kind === "kv" && Array.isArray(last)) last.push(entry);
742
+ else groups.push(entry.kind === "kv" ? [entry] : entry);
743
+ }
744
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: groups.map(
745
+ (g, i) => Array.isArray(g) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DocKv, { entries: g }, i) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DocEntry, { entry: g }, i)
746
+ ) });
739
747
  }
740
748
 
741
749
  // src/components/ReportSteps.tsx
@@ -940,42 +948,76 @@ function StateCardView({ card }) {
940
948
 
941
949
  // src/components/ReportAttachments.tsx
942
950
  var import_jsx_runtime21 = require("react/jsx-runtime");
951
+ function attachmentText(att) {
952
+ if (att.contentEncoding !== "BASE64") return att.body;
953
+ try {
954
+ return new TextDecoder().decode(Uint8Array.from(atob(att.body), (c) => c.charCodeAt(0)));
955
+ } catch {
956
+ return void 0;
957
+ }
958
+ }
959
+ function preview(att) {
960
+ const type = att.mediaType.split(";")[0].trim().toLowerCase();
961
+ const text = attachmentText(att);
962
+ if (text === void 0) return null;
963
+ if (type === "text/plain") {
964
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { className: "max-h-96 overflow-auto rounded-md border border-border bg-muted/40 p-3 text-xs whitespace-pre-wrap", children: text });
965
+ }
966
+ if (type === "text/markdown") {
967
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
968
+ "div",
969
+ {
970
+ className: "es-doc-prose prose prose-sm max-w-none rounded-md border border-border p-3",
971
+ dangerouslySetInnerHTML: { __html: safeMarkdownHtml(text) }
972
+ }
973
+ );
974
+ }
975
+ if (type === "text/html") {
976
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DocHtml, { entry: { kind: "html", content: text, title: att.name, phase: "runtime" } });
977
+ }
978
+ return null;
979
+ }
943
980
  function ReportAttachments({ attachments }) {
944
981
  if (attachments.length === 0) return null;
945
982
  return (
946
983
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
947
984
  // blocks don't create duplicate "Attachments" region landmarks.
948
985
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
949
- const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
950
- const isImage = att.mediaType.startsWith("image/");
986
+ const dataUri = att.external ? void 0 : att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
987
+ const href = dataUri ?? (0, import_url.safeUrl)(att.body);
988
+ const imageSrc = dataUri ?? (0, import_url.safeImageUrl)(att.body);
989
+ const isImage = att.mediaType.startsWith("image/") && imageSrc !== void 0;
951
990
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
952
991
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
953
992
  "img",
954
993
  {
955
- src: dataUri,
994
+ src: imageSrc,
956
995
  alt: att.name,
957
996
  loading: "lazy",
958
997
  className: "max-w-full rounded-md border border-border"
959
998
  }
960
999
  ),
961
1000
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
962
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
963
- "a",
964
- {
965
- href: dataUri,
966
- download: att.name,
967
- className: "text-xs text-link underline underline-offset-2",
968
- children: [
969
- att.name,
970
- " ",
971
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-muted-foreground", children: [
972
- "(",
973
- att.mediaType,
974
- ")"
975
- ] })
976
- ]
977
- }
978
- ) }, `${att.name}-${i}`);
1001
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1002
+ att.external ? null : preview(att),
1003
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1004
+ "a",
1005
+ {
1006
+ href,
1007
+ download: att.name,
1008
+ className: "text-xs text-link underline underline-offset-2",
1009
+ children: [
1010
+ att.name,
1011
+ " ",
1012
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-muted-foreground", children: [
1013
+ "(",
1014
+ att.mediaType,
1015
+ ")"
1016
+ ] })
1017
+ ]
1018
+ }
1019
+ )
1020
+ ] }) }, `${att.name}-${i}`);
979
1021
  }) })
980
1022
  );
981
1023
  }
@@ -1525,10 +1567,17 @@ function ReportFeatureIntro({ feature }) {
1525
1567
  dangerouslySetInnerHTML: { __html: safeMarkdownHtml(dedent(feature.narrative)) }
1526
1568
  }
1527
1569
  ) : null,
1528
- hasGlossary ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dl", { className: "grid gap-1.5", "aria-label": "Glossary", children: feature.glossary.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-wrap gap-x-2 text-xs", children: [
1529
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dt", { className: "font-medium text-foreground", children: entry.term }),
1530
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: "flex-1 text-muted-foreground", children: entry.definition })
1531
- ] }, entry.term)) }) : null
1570
+ hasGlossary ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1571
+ "dl",
1572
+ {
1573
+ className: "grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1.5 text-xs",
1574
+ "aria-label": "Glossary",
1575
+ children: feature.glossary.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "contents", children: [
1576
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dt", { className: "font-medium text-foreground", children: entry.term }),
1577
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: "text-muted-foreground", children: entry.definition })
1578
+ ] }, entry.term))
1579
+ }
1580
+ ) : null
1532
1581
  ] });
1533
1582
  }
1534
1583
  function featureKindLabel(kind) {
@@ -1544,7 +1593,6 @@ function ReportFeature({ feature }) {
1544
1593
  const titleId = `${feature.id}-title`;
1545
1594
  const bodyId = `${feature.id}-body`;
1546
1595
  const s = feature.summary;
1547
- const skipped = s.skipped + s.pending;
1548
1596
  const collapse = useCollapse();
1549
1597
  const collapsed = collapse?.isCollapsed(feature.id) ?? false;
1550
1598
  const kindLabel = featureKindLabel(feature.kind);
@@ -1584,7 +1632,12 @@ function ReportFeature({ feature }) {
1584
1632
  "p",
1585
1633
  {
1586
1634
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1587
- "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1635
+ "aria-label": [
1636
+ `${s.passed} passed`,
1637
+ `${s.failed} failed`,
1638
+ s.skipped > 0 && `${s.skipped} skipped`,
1639
+ s.pending > 0 && `${s.pending} pending`
1640
+ ].filter(Boolean).join(", "),
1588
1641
  children: [
1589
1642
  /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { children: [
1590
1643
  s.passed,
@@ -1595,12 +1648,19 @@ function ReportFeature({ feature }) {
1595
1648
  s.failed,
1596
1649
  " failed"
1597
1650
  ] }),
1598
- skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
1651
+ s.skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
1599
1652
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1600
1653
  /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { children: [
1601
- skipped,
1654
+ s.skipped,
1602
1655
  " skipped"
1603
1656
  ] })
1657
+ ] }) : null,
1658
+ s.pending > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
1659
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1660
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { children: [
1661
+ s.pending,
1662
+ " pending"
1663
+ ] })
1604
1664
  ] }) : null
1605
1665
  ]
1606
1666
  }
@@ -2591,6 +2651,10 @@ var story_report_v1_default = {
2591
2651
  contentEncoding: {
2592
2652
  type: "string",
2593
2653
  enum: ["BASE64", "IDENTITY"]
2654
+ },
2655
+ external: {
2656
+ const: true,
2657
+ description: "body holds the file's path or URL (file missing or too large to embed)."
2594
2658
  }
2595
2659
  },
2596
2660
  required: ["name", "mediaType", "body", "contentEncoding"],