@shapesos/clay 0.18.0 → 0.19.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.
Files changed (60) hide show
  1. package/dist/artifacts.cjs +207 -139
  2. package/dist/artifacts.cjs.map +1 -1
  3. package/dist/artifacts.js +5 -2
  4. package/dist/badge.cjs +70 -0
  5. package/dist/badge.cjs.map +1 -0
  6. package/dist/badge.d.cts +28 -0
  7. package/dist/badge.d.ts +28 -0
  8. package/dist/badge.js +9 -0
  9. package/dist/badge.js.map +1 -0
  10. package/dist/blocks.cjs +452 -185
  11. package/dist/blocks.cjs.map +1 -1
  12. package/dist/blocks.css +1 -1
  13. package/dist/blocks.d.cts +14 -3
  14. package/dist/blocks.d.ts +14 -3
  15. package/dist/blocks.js +17 -5
  16. package/dist/chat.cjs +457 -240
  17. package/dist/chat.cjs.map +1 -1
  18. package/dist/chat.d.cts +1 -1
  19. package/dist/chat.d.ts +1 -1
  20. package/dist/chat.js +10 -5
  21. package/dist/{chunk-JGMN6W72.js → chunk-2X4KUXYP.js} +1 -1
  22. package/dist/{chunk-QR4VBGK4.js → chunk-63AGNGKG.js} +81 -200
  23. package/dist/chunk-63AGNGKG.js.map +1 -0
  24. package/dist/chunk-CSTCTO3B.js +161 -0
  25. package/dist/chunk-CSTCTO3B.js.map +1 -0
  26. package/dist/chunk-EIAWZXE4.js +69 -0
  27. package/dist/chunk-EIAWZXE4.js.map +1 -0
  28. package/dist/chunk-EXRNGIQ2.js +41 -0
  29. package/dist/chunk-EXRNGIQ2.js.map +1 -0
  30. package/dist/{chunk-4MZZH3WX.js → chunk-HU5W7CGE.js} +37 -2
  31. package/dist/chunk-HU5W7CGE.js.map +1 -0
  32. package/dist/chunk-PISZYS2H.js +406 -0
  33. package/dist/chunk-PISZYS2H.js.map +1 -0
  34. package/dist/{chunk-CATIRDZP.js → chunk-PWSEEUVL.js} +10 -44
  35. package/dist/chunk-PWSEEUVL.js.map +1 -0
  36. package/dist/copy-button.cjs +439 -0
  37. package/dist/copy-button.cjs.map +1 -0
  38. package/dist/copy-button.d.cts +20 -0
  39. package/dist/copy-button.d.ts +20 -0
  40. package/dist/copy-button.js +12 -0
  41. package/dist/copy-button.js.map +1 -0
  42. package/dist/index.cjs +533 -298
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.cts +4 -2
  45. package/dist/index.d.ts +4 -2
  46. package/dist/index.js +26 -9
  47. package/dist/table.cjs +40 -0
  48. package/dist/table.cjs.map +1 -1
  49. package/dist/table.d.cts +37 -2
  50. package/dist/table.d.ts +37 -2
  51. package/dist/table.js +11 -1
  52. package/dist/{types-BDYPVP2N.d.cts → types-Bhg0_ES8.d.cts} +74 -2
  53. package/dist/{types-BMwa4bPW.d.ts → types-orOQcI2z.d.ts} +74 -2
  54. package/package.json +11 -1
  55. package/dist/chunk-4MZZH3WX.js.map +0 -1
  56. package/dist/chunk-7MY4X4YL.js +0 -250
  57. package/dist/chunk-7MY4X4YL.js.map +0 -1
  58. package/dist/chunk-CATIRDZP.js.map +0 -1
  59. package/dist/chunk-QR4VBGK4.js.map +0 -1
  60. /package/dist/{chunk-JGMN6W72.js.map → chunk-2X4KUXYP.js.map} +0 -0
package/dist/chat.cjs CHANGED
@@ -278,12 +278,13 @@ __export(chat_exports, {
278
278
  module.exports = __toCommonJS(chat_exports);
279
279
 
280
280
  // src/components/chat/chat-message/chat-message.tsx
281
- var import_react22 = require("react");
281
+ var import_react23 = require("react");
282
282
 
283
283
  // src/components/blocks/types.ts
284
284
  var blockTypes = {
285
285
  TEXT: "TEXT",
286
- ARTIFACT_REF: "ARTIFACT_REF"
286
+ ARTIFACT_REF: "ARTIFACT_REF",
287
+ NOTIFICATION_DRAFT: "NOTIFICATION_DRAFT"
287
288
  };
288
289
 
289
290
  // src/components/artifacts/artifact-base.ts
@@ -447,41 +448,49 @@ var IconArrowsMinimize = createReactComponent("outline", "arrows-minimize", "Arr
447
448
  var __iconNode4 = [["path", { "d": "M5 12l5 5l10 -10", "key": "svg-0" }]];
448
449
  var IconCheck = createReactComponent("outline", "check", "Check", __iconNode4);
449
450
 
451
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconChevronDown.mjs
452
+ var __iconNode5 = [["path", { "d": "M6 9l6 6l6 -6", "key": "svg-0" }]];
453
+ var IconChevronDown = createReactComponent("outline", "chevron-down", "ChevronDown", __iconNode5);
454
+
450
455
  // node_modules/@tabler/icons-react/dist/esm/icons/IconChevronLeft.mjs
451
- var __iconNode5 = [["path", { "d": "M15 6l-6 6l6 6", "key": "svg-0" }]];
452
- var IconChevronLeft = createReactComponent("outline", "chevron-left", "ChevronLeft", __iconNode5);
456
+ var __iconNode6 = [["path", { "d": "M15 6l-6 6l6 6", "key": "svg-0" }]];
457
+ var IconChevronLeft = createReactComponent("outline", "chevron-left", "ChevronLeft", __iconNode6);
453
458
 
454
459
  // node_modules/@tabler/icons-react/dist/esm/icons/IconChevronRight.mjs
455
- var __iconNode6 = [["path", { "d": "M9 6l6 6l-6 6", "key": "svg-0" }]];
456
- var IconChevronRight = createReactComponent("outline", "chevron-right", "ChevronRight", __iconNode6);
460
+ var __iconNode7 = [["path", { "d": "M9 6l6 6l-6 6", "key": "svg-0" }]];
461
+ var IconChevronRight = createReactComponent("outline", "chevron-right", "ChevronRight", __iconNode7);
457
462
 
458
463
  // node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.mjs
459
- var __iconNode7 = [["path", { "d": "M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667l0 -8.666", "key": "svg-0" }], ["path", { "d": "M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1", "key": "svg-1" }]];
460
- var IconCopy = createReactComponent("outline", "copy", "Copy", __iconNode7);
464
+ var __iconNode8 = [["path", { "d": "M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667l0 -8.666", "key": "svg-0" }], ["path", { "d": "M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1", "key": "svg-1" }]];
465
+ var IconCopy = createReactComponent("outline", "copy", "Copy", __iconNode8);
461
466
 
462
467
  // node_modules/@tabler/icons-react/dist/esm/icons/IconDownload.mjs
463
- var __iconNode8 = [["path", { "d": "M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2", "key": "svg-0" }], ["path", { "d": "M7 11l5 5l5 -5", "key": "svg-1" }], ["path", { "d": "M12 4l0 12", "key": "svg-2" }]];
464
- var IconDownload = createReactComponent("outline", "download", "Download", __iconNode8);
468
+ var __iconNode9 = [["path", { "d": "M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2", "key": "svg-0" }], ["path", { "d": "M7 11l5 5l5 -5", "key": "svg-1" }], ["path", { "d": "M12 4l0 12", "key": "svg-2" }]];
469
+ var IconDownload = createReactComponent("outline", "download", "Download", __iconNode9);
465
470
 
466
471
  // node_modules/@tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs
467
- var __iconNode9 = [["path", { "d": "M14 3v4a1 1 0 0 0 1 1h4", "key": "svg-0" }], ["path", { "d": "M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2", "key": "svg-1" }], ["path", { "d": "M8 11h8v7h-8l0 -7", "key": "svg-2" }], ["path", { "d": "M8 15h8", "key": "svg-3" }], ["path", { "d": "M11 11v7", "key": "svg-4" }]];
468
- var IconFileSpreadsheet = createReactComponent("outline", "file-spreadsheet", "FileSpreadsheet", __iconNode9);
472
+ var __iconNode10 = [["path", { "d": "M14 3v4a1 1 0 0 0 1 1h4", "key": "svg-0" }], ["path", { "d": "M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2", "key": "svg-1" }], ["path", { "d": "M8 11h8v7h-8l0 -7", "key": "svg-2" }], ["path", { "d": "M8 15h8", "key": "svg-3" }], ["path", { "d": "M11 11v7", "key": "svg-4" }]];
473
+ var IconFileSpreadsheet = createReactComponent("outline", "file-spreadsheet", "FileSpreadsheet", __iconNode10);
469
474
 
470
475
  // node_modules/@tabler/icons-react/dist/esm/icons/IconLoader2.mjs
471
- var __iconNode10 = [["path", { "d": "M12 3a9 9 0 1 0 9 9", "key": "svg-0" }]];
472
- var IconLoader2 = createReactComponent("outline", "loader-2", "Loader2", __iconNode10);
476
+ var __iconNode11 = [["path", { "d": "M12 3a9 9 0 1 0 9 9", "key": "svg-0" }]];
477
+ var IconLoader2 = createReactComponent("outline", "loader-2", "Loader2", __iconNode11);
473
478
 
474
479
  // node_modules/@tabler/icons-react/dist/esm/icons/IconPhoto.mjs
475
- var __iconNode11 = [["path", { "d": "M15 8h.01", "key": "svg-0" }], ["path", { "d": "M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12", "key": "svg-1" }], ["path", { "d": "M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5", "key": "svg-2" }], ["path", { "d": "M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3", "key": "svg-3" }]];
476
- var IconPhoto = createReactComponent("outline", "photo", "Photo", __iconNode11);
480
+ var __iconNode12 = [["path", { "d": "M15 8h.01", "key": "svg-0" }], ["path", { "d": "M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12", "key": "svg-1" }], ["path", { "d": "M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5", "key": "svg-2" }], ["path", { "d": "M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3", "key": "svg-3" }]];
481
+ var IconPhoto = createReactComponent("outline", "photo", "Photo", __iconNode12);
477
482
 
478
483
  // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbDown.mjs
479
- var __iconNode12 = [["path", { "d": "M7 13v-8a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h3a4 4 0 0 1 4 4v1a2 2 0 0 0 4 0v-5h3a2 2 0 0 0 2 -2l-1 -5a2 3 0 0 0 -2 -2h-7a3 3 0 0 0 -3 3", "key": "svg-0" }]];
480
- var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode12);
484
+ var __iconNode13 = [["path", { "d": "M7 13v-8a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h3a4 4 0 0 1 4 4v1a2 2 0 0 0 4 0v-5h3a2 2 0 0 0 2 -2l-1 -5a2 3 0 0 0 -2 -2h-7a3 3 0 0 0 -3 3", "key": "svg-0" }]];
485
+ var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode13);
481
486
 
482
487
  // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbUp.mjs
483
- var __iconNode13 = [["path", { "d": "M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3", "key": "svg-0" }]];
484
- var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode13);
488
+ var __iconNode14 = [["path", { "d": "M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3", "key": "svg-0" }]];
489
+ var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode14);
490
+
491
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconFlask2Filled.mjs
492
+ var __iconNode15 = [["path", { "d": "M15 2a1 1 0 0 1 0 2v5.674l.062 .03a7 7 0 0 1 3.85 5.174l.037 .262a7 7 0 0 1 -3.078 6.693a1 1 0 0 1 -.553 .167h-6.635a1 1 0 0 1 -.552 -.166a7 7 0 0 1 .807 -12.134l.062 -.028v-5.672a1 1 0 1 1 0 -2h6zm-2 2h-2v6.34a1 1 0 0 1 -.551 .894l-.116 .049a5 5 0 0 0 -2.92 2.717h9.172a5 5 0 0 0 -2.918 -2.715a1 1 0 0 1 -.667 -.943v-6.342z", "key": "svg-0" }]];
493
+ var IconFlask2Filled = createReactComponent("filled", "flask-2-filled", "Flask2Filled", __iconNode15);
485
494
 
486
495
  // src/components/artifacts/artifact-copy-as-image-button/artifact-copy-as-image-button.tsx
487
496
  var import_react6 = require("react");
@@ -2057,6 +2066,41 @@ var ChartArtifactService = {
2057
2066
  // src/components/artifacts/deck-artifact/deck-artifact.tsx
2058
2067
  var import_react17 = require("react");
2059
2068
  var import_react_dom = require("react-dom");
2069
+
2070
+ // src/components/badge/badge.tsx
2071
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2072
+ var BASE = "inline-flex items-center whitespace-nowrap rounded-full";
2073
+ var SIZES = {
2074
+ // `sm` is a uniform scale-down of `md` (text 10/12 of caption): padding and line-height keep
2075
+ // md's proportions (caption is 12px text on a 16px line = 1.333 ratio) so the pill shape matches.
2076
+ md: "px-2.5 py-0.5 text-geist-label-caption-medium",
2077
+ sm: "px-2 py-0.5 text-[11px]/[1.333] font-medium"
2078
+ };
2079
+ var SUBTLE = {
2080
+ neutral: "bg-brown-20 text-brown-70",
2081
+ warning: "bg-orange-50 text-orange-600",
2082
+ violet: "bg-violet-50 text-violet-600"
2083
+ };
2084
+ var OUTLINE = {
2085
+ neutral: "border border-brown-30 bg-white text-brown-100",
2086
+ warning: "border border-orange-200 bg-white text-orange-600",
2087
+ violet: "border border-violet-400 bg-white text-violet-600"
2088
+ };
2089
+ var VARIANTS = {
2090
+ subtle: SUBTLE,
2091
+ outline: OUTLINE
2092
+ };
2093
+ function Badge({
2094
+ variant = "subtle",
2095
+ tone = "neutral",
2096
+ size = "md",
2097
+ className,
2098
+ children
2099
+ }) {
2100
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: cn(BASE, SIZES[size], VARIANTS[variant][tone], className), children });
2101
+ }
2102
+
2103
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
2060
2104
  init_capture_exclude_attribute();
2061
2105
 
2062
2106
  // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
@@ -2064,23 +2108,23 @@ var import_react16 = require("react");
2064
2108
 
2065
2109
  // src/components/ui/table.tsx
2066
2110
  var React3 = __toESM(require("react"), 1);
2067
- var import_jsx_runtime20 = require("react/jsx-runtime");
2068
- var Table = React3.forwardRef(({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("relative w-full overflow-auto", containerClassName), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props }) }));
2111
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2112
+ var Table = React3.forwardRef(({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: cn("relative w-full overflow-auto", containerClassName), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props }) }));
2069
2113
  Table.displayName = "Table";
2070
2114
  var TableHeader = React3.forwardRef(
2071
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("thead", { ref, className: cn("[&_tr]:border-b", className), ...props })
2115
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("thead", { ref, className: cn("[&_tr]:border-b", className), ...props })
2072
2116
  );
2073
2117
  TableHeader.displayName = "TableHeader";
2074
2118
  var TableBody = React3.forwardRef(
2075
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props })
2119
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props })
2076
2120
  );
2077
2121
  TableBody.displayName = "TableBody";
2078
2122
  var TableFooter = React3.forwardRef(
2079
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tfoot", { ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props })
2123
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tfoot", { ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props })
2080
2124
  );
2081
2125
  TableFooter.displayName = "TableFooter";
2082
2126
  var TableRow = React3.forwardRef(
2083
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2127
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2084
2128
  "tr",
2085
2129
  {
2086
2130
  ref,
@@ -2091,7 +2135,7 @@ var TableRow = React3.forwardRef(
2091
2135
  );
2092
2136
  TableRow.displayName = "TableRow";
2093
2137
  var TableHead = React3.forwardRef(
2094
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2138
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2095
2139
  "th",
2096
2140
  {
2097
2141
  ref,
@@ -2105,11 +2149,11 @@ var TableHead = React3.forwardRef(
2105
2149
  );
2106
2150
  TableHead.displayName = "TableHead";
2107
2151
  var TableCell = React3.forwardRef(
2108
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className), ...props })
2152
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className), ...props })
2109
2153
  );
2110
2154
  TableCell.displayName = "TableCell";
2111
2155
  var TableCaption = React3.forwardRef(
2112
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })
2156
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })
2113
2157
  );
2114
2158
  TableCaption.displayName = "TableCaption";
2115
2159
 
@@ -2139,6 +2183,36 @@ function useScrollShadow() {
2139
2183
  return { targetRef, isScrolled };
2140
2184
  }
2141
2185
 
2186
+ // src/components/table/data-table.tsx
2187
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2188
+ var DATA_TABLE_HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
2189
+ var DATA_TABLE_CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
2190
+ var DATA_TABLE_ROW_CLASS = "border-b-brown-30 bg-background/70 hover:bg-secondary";
2191
+ var DATA_TABLE_SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";
2192
+ function DataTable({ header, children, maxBodyHeight, className }) {
2193
+ const { targetRef, isScrolled } = useScrollShadow();
2194
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2195
+ "div",
2196
+ {
2197
+ ref: targetRef,
2198
+ className: cn("overscroll-none", className),
2199
+ style: maxBodyHeight !== void 0 ? { maxHeight: maxBodyHeight, overflowY: "auto" } : void 0,
2200
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Table, { containerClassName: "overflow-visible", children: [
2201
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2202
+ TableHeader,
2203
+ {
2204
+ "data-scrolled": isScrolled ? "true" : void 0,
2205
+ className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
2206
+ style: isScrolled ? { boxShadow: DATA_TABLE_SCROLL_SHADOW } : void 0,
2207
+ children: header
2208
+ }
2209
+ ),
2210
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableBody, { children })
2211
+ ] })
2212
+ }
2213
+ );
2214
+ }
2215
+
2142
2216
  // src/components/artifacts/table-artifact/table-artifact-content.constants.ts
2143
2217
  var TABLE_STATUS = {
2144
2218
  LOADING: "loading",
@@ -2151,14 +2225,10 @@ var TABLE_STATUS = {
2151
2225
  function formatCell(row, column) {
2152
2226
  return row[column.key] ?? "";
2153
2227
  }
2154
- var HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
2155
- var CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
2156
- var ROW_CLASSES = "border-b-brown-30 bg-background/70 hover:bg-secondary";
2157
- var DATA_ROW_CLASSES = `${ROW_CLASSES} animate-in fade-in duration-300`;
2158
- var SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";
2228
+ var DATA_ROW_CLASSES = `${DATA_TABLE_ROW_CLASS} animate-in fade-in duration-300`;
2159
2229
 
2160
2230
  // src/components/artifacts/table-artifact/table-artifact-content.tsx
2161
- var import_jsx_runtime21 = require("react/jsx-runtime");
2231
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2162
2232
  function TableArtifactContent({
2163
2233
  columns,
2164
2234
  data,
@@ -2168,50 +2238,45 @@ function TableArtifactContent({
2168
2238
  labels
2169
2239
  }) {
2170
2240
  if (data.status === TABLE_STATUS.ERROR) {
2171
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusMessage, { $tone: "error", children: labels.loadError });
2241
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StatusMessage, { $tone: "error", children: labels.loadError });
2172
2242
  }
2173
2243
  if (data.status === TABLE_STATUS.UNAVAILABLE) {
2174
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
2244
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
2175
2245
  }
2176
2246
  if (data.status === TABLE_STATUS.LOADING) {
2177
2247
  if (typeof knownRowCount === "number" && knownRowCount > 0) {
2178
2248
  const shimmerCount = Math.min(knownRowCount, maxShimmerRows);
2179
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ArtifactTable, { columns, maxBodyHeight, children: renderShimmerRows(columns, shimmerCount) });
2249
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ArtifactTable, { columns, maxBodyHeight, children: renderShimmerRows(columns, shimmerCount) });
2180
2250
  }
2181
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusMessage, { $tone: "info", children: labels.loading });
2251
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StatusMessage, { $tone: "info", children: labels.loading });
2182
2252
  }
2183
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ArtifactTable, { columns, maxBodyHeight, children: data.rows.length === 0 ? renderEmptyRow(columns.length, labels.empty) : renderDataRows(columns, data.rows) });
2253
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ArtifactTable, { columns, maxBodyHeight, children: data.rows.length === 0 ? renderEmptyRow(columns.length, labels.empty) : renderDataRows(columns, data.rows) });
2184
2254
  }
2185
2255
  function ArtifactTable({ columns, maxBodyHeight, children }) {
2186
- const { targetRef, isScrolled } = useScrollShadow();
2187
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref: targetRef, className: "overscroll-none", style: { maxHeight: maxBodyHeight, overflowY: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Table, { containerClassName: "overflow-visible", children: [
2188
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2189
- TableHeader,
2190
- {
2191
- "data-scrolled": isScrolled ? "true" : void 0,
2192
- className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
2193
- style: isScrolled ? { boxShadow: SCROLL_SHADOW } : void 0,
2194
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableHead, { scope: "col", className: HEAD_CLASS, children: column.label }, column.key)) })
2195
- }
2196
- ),
2197
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableBody, { children })
2198
- ] }) });
2256
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2257
+ DataTable,
2258
+ {
2259
+ maxBodyHeight,
2260
+ header: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: column.label }, column.key)) }),
2261
+ children
2262
+ }
2263
+ );
2199
2264
  }
2200
2265
  function renderShimmerRows(columns, count) {
2201
- return Array.from({ length: count }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableRow, { className: ROW_CLASSES, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableCell, { className: CELL_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index}`));
2266
+ return Array.from({ length: count }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableRow, { className: DATA_TABLE_ROW_CLASS, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index}`));
2202
2267
  }
2203
2268
  function renderDataRows(columns, rows) {
2204
- return rows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableCell, { className: CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index));
2269
+ return rows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index));
2205
2270
  }
2206
2271
  function renderEmptyRow(colSpan, emptyMessage) {
2207
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) });
2272
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) });
2208
2273
  }
2209
2274
 
2210
2275
  // src/components/artifacts/deck-artifact/deck-markdown.tsx
2211
2276
  var import_react_markdown = __toESM(require("react-markdown"), 1);
2212
2277
  var import_remark_breaks = __toESM(require("remark-breaks"), 1);
2213
2278
  var import_remark_gfm = __toESM(require("remark-gfm"), 1);
2214
- var import_jsx_runtime22 = require("react/jsx-runtime");
2279
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2215
2280
  function sanitize(text) {
2216
2281
  return text.split("\n").filter((line) => {
2217
2282
  const t = line.trim();
@@ -2219,45 +2284,45 @@ function sanitize(text) {
2219
2284
  }).join("\n");
2220
2285
  }
2221
2286
  var MARKDOWN_COMPONENTS = {
2222
- h1: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { className: "text-[30px] font-semibold leading-tight text-foreground mb-3", ...props }),
2223
- h2: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { className: "text-[26px] font-semibold leading-tight text-foreground mb-2", ...props }),
2224
- h3: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2225
- h4: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h4", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2226
- h5: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h5", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2227
- h6: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h6", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2228
- p: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[22px] leading-relaxed text-foreground my-2", ...props }),
2229
- ul: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "list-disc pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2230
- ol: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ol", { className: "list-decimal pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2287
+ h1: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h1", { className: "text-[30px] font-semibold leading-tight text-foreground mb-3", ...props }),
2288
+ h2: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { className: "text-[26px] font-semibold leading-tight text-foreground mb-2", ...props }),
2289
+ h3: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2290
+ h4: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h4", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2291
+ h5: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h5", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2292
+ h6: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h6", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2293
+ p: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-[22px] leading-relaxed text-foreground my-2", ...props }),
2294
+ ul: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { className: "list-disc pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2295
+ ol: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ol", { className: "list-decimal pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2231
2296
  // react-markdown injects list metadata (`ordered` / `index` / `checked`) that must not leak to the DOM.
2232
- li: ({ node: _node, ordered: _ordered, index: _index, checked: _checked, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { className: "my-1", ...props }),
2233
- strong: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { className: "font-semibold", ...props }),
2234
- em: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("em", { className: "italic", ...props }),
2297
+ li: ({ node: _node, ordered: _ordered, index: _index, checked: _checked, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { className: "my-1", ...props }),
2298
+ strong: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { className: "font-semibold", ...props }),
2299
+ em: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("em", { className: "italic", ...props }),
2235
2300
  // Gate `<img src>` against an http(s) allowlist. react-markdown v8 percent-encodes the URL but
2236
2301
  // does NOT protocol-filter image src (unlike link href), so an LLM-authored
2237
2302
  // `![](javascript:…)` / `![](data:…)` or a tracking-pixel `![](http://…)` would otherwise render
2238
2303
  // with the raw URL. Unsafe src → render nothing.
2239
- img: ({ node: _node, src, ...props }) => typeof src === "string" && isSafeDownloadUrl(src) ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("img", { src, className: "max-w-full", ...props }) : null,
2304
+ img: ({ node: _node, src, ...props }) => typeof src === "string" && isSafeDownloadUrl(src) ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("img", { src, className: "max-w-full", ...props }) : null,
2240
2305
  a: ({ node: _node, ...props }) => (
2241
2306
  // `rel` is forced AFTER `{...props}` so it can't be overridden — if a consumer ever adds
2242
2307
  // `linkTarget="_blank"`, LLM-authored links still can't reach `window.opener`.
2243
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { className: "underline underline-offset-2", ...props, rel: "noopener noreferrer" })
2308
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { className: "underline underline-offset-2", ...props, rel: "noopener noreferrer" })
2244
2309
  ),
2245
2310
  // react-markdown passes `inline` to distinguish inline code from fenced blocks — strip it from the DOM.
2246
- code: ({ node: _node, inline: _inline, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("code", { className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[18px]", ...props }),
2247
- blockquote: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("blockquote", { className: "border-l-2 border-brown-alpha-12 pl-4 text-[22px] text-muted-foreground", ...props }),
2248
- hr: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("hr", { className: "my-4 border-brown-alpha-12", ...props }),
2249
- table: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("table", { className: "w-full border-collapse text-[20px]", ...props }) }),
2311
+ code: ({ node: _node, inline: _inline, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("code", { className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[18px]", ...props }),
2312
+ blockquote: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("blockquote", { className: "border-l-2 border-brown-alpha-12 pl-4 text-[22px] text-muted-foreground", ...props }),
2313
+ hr: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("hr", { className: "my-4 border-brown-alpha-12", ...props }),
2314
+ table: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("table", { className: "w-full border-collapse text-[20px]", ...props }) }),
2250
2315
  // react-markdown passes `isHeader` to cell renderers — strip it so it never reaches the DOM.
2251
- th: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { className: "border-b border-brown-alpha-12 px-3 py-1.5 text-left font-medium", ...props }),
2252
- td: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "border-b border-brown-alpha-12 px-3 py-1.5", ...props })
2316
+ th: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { className: "border-b border-brown-alpha-12 px-3 py-1.5 text-left font-medium", ...props }),
2317
+ td: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "border-b border-brown-alpha-12 px-3 py-1.5", ...props })
2253
2318
  };
2254
2319
  function DeckMarkdown({ markdown }) {
2255
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default, import_remark_breaks.default], components: MARKDOWN_COMPONENTS, children: sanitize(markdown) });
2320
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default, import_remark_breaks.default], components: MARKDOWN_COMPONENTS, children: sanitize(markdown) });
2256
2321
  }
2257
2322
 
2258
2323
  // src/components/artifacts/deck-artifact/slide-renderers.tsx
2259
2324
  var import_react15 = require("react");
2260
- var import_jsx_runtime23 = require("react/jsx-runtime");
2325
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2261
2326
  function safeLogoUrl(meta) {
2262
2327
  return meta?.logoUrl && isSafeDownloadUrl(meta.logoUrl) ? meta.logoUrl : null;
2263
2328
  }
@@ -2284,7 +2349,7 @@ function SlideFrame({ meta, children, accent = false, bare = false }) {
2284
2349
  const eyebrowColor = accent ? "text-white/70" : "text-brown-60";
2285
2350
  const borderColor = accent ? "border-white/20" : "border-brown-alpha-12";
2286
2351
  const logoSrc = safeLogoUrl(meta);
2287
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref: frameRef, className: `relative aspect-[16/9] w-full overflow-hidden rounded-lg ${bg}`, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2352
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref: frameRef, className: `relative aspect-[16/9] w-full overflow-hidden rounded-lg ${bg}`, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2288
2353
  "div",
2289
2354
  {
2290
2355
  className: "absolute left-0 top-0 origin-top-left",
@@ -2295,26 +2360,26 @@ function SlideFrame({ meta, children, accent = false, bare = false }) {
2295
2360
  visibility: scale === null ? "hidden" : "visible"
2296
2361
  },
2297
2362
  children: [
2298
- !bare ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2363
+ !bare ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2299
2364
  "div",
2300
2365
  {
2301
2366
  className: `absolute inset-x-0 top-0 flex items-center justify-between border-b px-16 ${borderColor}`,
2302
2367
  style: { height: EYEBROW_H },
2303
2368
  children: [
2304
- meta?.eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: eyebrowColor, style: { ...ACCENT_FONT, fontSize: 22 }, children: meta.eyebrow }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", {}),
2305
- logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("img", { src: logoSrc, alt: "", className: "object-contain", style: { maxHeight: CANVAS_LOGO_MAX_H } }) : null
2369
+ meta?.eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: eyebrowColor, style: { ...ACCENT_FONT, fontSize: 22 }, children: meta.eyebrow }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2370
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("img", { src: logoSrc, alt: "", className: "object-contain", style: { maxHeight: CANVAS_LOGO_MAX_H } }) : null
2306
2371
  ]
2307
2372
  }
2308
2373
  ) : null,
2309
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "absolute inset-x-0 bottom-0 overflow-hidden", style: { top: bare ? 0 : EYEBROW_H }, children })
2374
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "absolute inset-x-0 bottom-0 overflow-hidden", style: { top: bare ? 0 : EYEBROW_H }, children })
2310
2375
  ]
2311
2376
  }
2312
2377
  ) });
2313
2378
  }
2314
2379
  function TitleSlide({ slide, meta }) {
2315
2380
  const logoSrc = safeLogoUrl(meta);
2316
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, bare: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex h-full flex-col justify-center px-24 py-16", children: [
2317
- logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2381
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideFrame, { meta, bare: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex h-full flex-col justify-center px-24 py-16", children: [
2382
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2318
2383
  "img",
2319
2384
  {
2320
2385
  src: logoSrc,
@@ -2323,7 +2388,7 @@ function TitleSlide({ slide, meta }) {
2323
2388
  style: { maxHeight: 56, maxWidth: 380 }
2324
2389
  }
2325
2390
  ) : null,
2326
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2391
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2327
2392
  "h1",
2328
2393
  {
2329
2394
  className: "font-bold tracking-tight text-brown-100",
@@ -2331,36 +2396,36 @@ function TitleSlide({ slide, meta }) {
2331
2396
  children: slide.title
2332
2397
  }
2333
2398
  ),
2334
- slide.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-7 text-brown-70", style: { ...ACCENT_FONT, fontSize: 34 }, children: slide.subtitle }) : null,
2335
- slide.description ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-4 leading-relaxed text-brown-70", style: { fontSize: 24, maxWidth: 880 }, children: slide.description }) : null,
2336
- meta?.date ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-10 text-brown-70", style: { ...ACCENT_FONT, fontSize: 30 }, children: meta.date }) : null
2399
+ slide.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "mt-7 text-brown-70", style: { ...ACCENT_FONT, fontSize: 34 }, children: slide.subtitle }) : null,
2400
+ slide.description ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "mt-4 leading-relaxed text-brown-70", style: { fontSize: 24, maxWidth: 880 }, children: slide.description }) : null,
2401
+ meta?.date ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "mt-10 text-brown-70", style: { ...ACCENT_FONT, fontSize: 30 }, children: meta.date }) : null
2337
2402
  ] }) });
2338
2403
  }
2339
2404
  function AgendaSlide({ slide, meta, labels }) {
2340
2405
  const items = slide.items ?? [];
2341
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "h-full px-24 py-14", children: [
2342
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "mb-10 font-bold text-brown-90", style: { fontSize: 40 }, children: slide.title || labels.agenda }),
2343
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-col", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-baseline gap-6 border-b border-brown-alpha-12 py-5", children: [
2344
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "shrink-0 text-indigo-600", style: { ...ACCENT_FONT, fontSize: 28, width: 64 }, children: String(i + 1).padStart(2, "0") }),
2345
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-brown-90", style: { fontSize: 28 }, children: item })
2406
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "h-full px-24 py-14", children: [
2407
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { className: "mb-10 font-bold text-brown-90", style: { fontSize: 40 }, children: slide.title || labels.agenda }),
2408
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex flex-col", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-baseline gap-6 border-b border-brown-alpha-12 py-5", children: [
2409
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "shrink-0 text-indigo-600", style: { ...ACCENT_FONT, fontSize: 28, width: 64 }, children: String(i + 1).padStart(2, "0") }),
2410
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-brown-90", style: { fontSize: 28 }, children: item })
2346
2411
  ] }, i)) })
2347
2412
  ] }) });
2348
2413
  }
2349
2414
  function SectionSlide({ slide, meta }) {
2350
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, accent: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex h-full flex-col justify-center gap-6 px-24", children: [
2351
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "font-bold text-white", style: { fontSize: 72, lineHeight: 1.05, maxWidth: 940 }, children: slide.title }),
2352
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-2 bg-white/50", style: { width: 96, height: 5 } })
2415
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideFrame, { meta, accent: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex h-full flex-col justify-center gap-6 px-24", children: [
2416
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { className: "font-bold text-white", style: { fontSize: 72, lineHeight: 1.05, maxWidth: 940 }, children: slide.title }),
2417
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-2 bg-white/50", style: { width: 96, height: 5 } })
2353
2418
  ] }) });
2354
2419
  }
2355
2420
  function ClosingSlide({ meta, labels }) {
2356
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex h-full flex-col items-center justify-center gap-6 px-24 text-center", children: [
2357
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "font-bold text-brown-100", style: { fontSize: 72 }, children: labels.thankYou }),
2358
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-indigo-600", style: { ...ACCENT_FONT, fontSize: 36 }, children: labels.questions })
2421
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex h-full flex-col items-center justify-center gap-6 px-24 text-center", children: [
2422
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "font-bold text-brown-100", style: { fontSize: 72 }, children: labels.thankYou }),
2423
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-indigo-600", style: { ...ACCENT_FONT, fontSize: 36 }, children: labels.questions })
2359
2424
  ] }) });
2360
2425
  }
2361
2426
 
2362
2427
  // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
2363
- var import_jsx_runtime24 = require("react/jsx-runtime");
2428
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2364
2429
  var TABLE_BLOCK_MAX_SHIMMER_ROWS = 10;
2365
2430
  var TABLE_CHROME_RESERVE = 56;
2366
2431
  var VISUAL_FALLBACK_HEIGHT = 360;
@@ -2390,14 +2455,14 @@ function DeckArtifactContent({
2390
2455
  [slides.length, onNavigate, isControlled, onSlideChange]
2391
2456
  );
2392
2457
  const position = labels.position.replace("{current}", String(current + 1)).replace("{total}", String(slides.length));
2393
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-3 p-4", children: [
2394
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideDispatch, { slide, labels, meta }),
2395
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2458
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3 p-4", children: [
2459
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SlideDispatch, { slide, labels, meta }),
2460
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
2396
2461
  "div",
2397
2462
  {
2398
2463
  className: `flex items-center justify-between border-t pt-2 ${onDark ? "border-white/20" : "border-brown-alpha-12"}`,
2399
2464
  children: [
2400
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2465
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2401
2466
  IconButton,
2402
2467
  {
2403
2468
  icon: IconChevronLeft,
@@ -2408,8 +2473,8 @@ function DeckArtifactContent({
2408
2473
  onClick: () => goTo(current - 1)
2409
2474
  }
2410
2475
  ),
2411
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: `text-xs font-medium ${onDark ? "text-white/70" : "text-brown-70"}`, children: position }),
2412
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2476
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: `text-xs font-medium ${onDark ? "text-white/70" : "text-brown-70"}`, children: position }),
2477
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2413
2478
  IconButton,
2414
2479
  {
2415
2480
  icon: IconChevronRight,
@@ -2429,16 +2494,16 @@ function SlideDispatch({ slide, labels, meta }) {
2429
2494
  const kind = slide.kind ?? deckSlideKinds.CONTENT;
2430
2495
  switch (kind) {
2431
2496
  case deckSlideKinds.TITLE:
2432
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TitleSlide, { slide, meta });
2497
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TitleSlide, { slide, meta });
2433
2498
  case deckSlideKinds.AGENDA:
2434
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AgendaSlide, { slide, meta, labels });
2499
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AgendaSlide, { slide, meta, labels });
2435
2500
  case deckSlideKinds.SECTION:
2436
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SectionSlide, { slide, meta });
2501
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SectionSlide, { slide, meta });
2437
2502
  case deckSlideKinds.CLOSING:
2438
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ClosingSlide, { meta, labels });
2503
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ClosingSlide, { meta, labels });
2439
2504
  case deckSlideKinds.CONTENT:
2440
2505
  default:
2441
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ContentSlide, { slide, meta, labels });
2506
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ContentSlide, { slide, meta, labels });
2442
2507
  }
2443
2508
  }
2444
2509
  function isVisualBlock(block) {
@@ -2451,25 +2516,25 @@ function ContentSlide({ slide, meta, labels }) {
2451
2516
  (b) => b.type === deckBlockTypes.TEXT
2452
2517
  );
2453
2518
  if (visuals.length === 1 && texts.length > 0) {
2454
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex h-full items-stretch gap-12 px-16 py-12", children: [
2455
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex w-[42%] shrink-0 flex-col overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(AutoFit, { children: [
2456
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "mb-5 font-bold leading-tight text-foreground", style: { fontSize: 34 }, children: slide.title }),
2457
- texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2519
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex h-full items-stretch gap-12 px-16 py-12", children: [
2520
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex w-[42%] shrink-0 flex-col overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(AutoFit, { children: [
2521
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { className: "mb-5 font-bold leading-tight text-foreground", style: { fontSize: 34 }, children: slide.title }),
2522
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2458
2523
  ] }) }),
2459
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(FillVisual, { block: visuals[0], labels }) })
2524
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(FillVisual, { block: visuals[0], labels }) })
2460
2525
  ] }) });
2461
2526
  }
2462
2527
  if (visuals.length > 0) {
2463
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex h-full flex-col gap-5 px-16 py-10", children: [
2464
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "shrink-0 font-bold leading-tight text-foreground", style: { fontSize: 32 }, children: slide.title }),
2528
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex h-full flex-col gap-5 px-16 py-10", children: [
2529
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { className: "shrink-0 font-bold leading-tight text-foreground", style: { fontSize: 32 }, children: slide.title }),
2465
2530
  content.map(
2466
- (block, i) => isVisualBlock(block) ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(FillVisual, { block, labels }) }, i) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "shrink-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }) }, i)
2531
+ (block, i) => isVisualBlock(block) ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(FillVisual, { block, labels }) }, i) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "shrink-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DeckMarkdown, { markdown: block.markdown }) }, i)
2467
2532
  )
2468
2533
  ] }) });
2469
2534
  }
2470
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "h-full px-24 py-12", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(AutoFit, { children: [
2471
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "mb-6 font-bold leading-tight text-foreground", style: { fontSize: 38 }, children: slide.title }),
2472
- texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2535
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "h-full px-24 py-12", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(AutoFit, { children: [
2536
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { className: "mb-6 font-bold leading-tight text-foreground", style: { fontSize: 38 }, children: slide.title }),
2537
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2473
2538
  ] }) }) });
2474
2539
  }
2475
2540
  function AutoFit({ children }) {
@@ -2493,7 +2558,7 @@ function AutoFit({ children }) {
2493
2558
  return () => ro.disconnect();
2494
2559
  }, []);
2495
2560
  const scaled = fit.scale < 1;
2496
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: boxRef, className: "flex h-full min-h-0 w-full flex-col justify-center overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: scaled ? { height: fit.height } : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2561
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: boxRef, className: "flex h-full min-h-0 w-full flex-col justify-center overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: scaled ? { height: fit.height } : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2497
2562
  "div",
2498
2563
  {
2499
2564
  ref: contentRef,
@@ -2518,12 +2583,12 @@ function FillVisual({ block, labels }) {
2518
2583
  return () => ro.disconnect();
2519
2584
  }, []);
2520
2585
  const chartLabels = labels.chart ?? DEFAULT_CHART_ARTIFACT_LABELS;
2521
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref, className: "h-full min-h-0 w-full overflow-hidden", children: block.type === deckBlockTypes.CHART ? (
2586
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: "h-full min-h-0 w-full overflow-hidden", children: block.type === deckBlockTypes.CHART ? (
2522
2587
  // ChartArtifactContent assumes a non-empty rowset (the standalone ChartArtifact guards
2523
2588
  // `rows.length > 0` upstream); mirror that guard here so an empty inline chart shows the
2524
2589
  // localized empty status instead of a blank chart area.
2525
- block.rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(StatusMessage, { $tone: "info", children: chartLabels.empty }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChartArtifactContent, { config: block.config, rows: block.rows, labels: chartLabels }) })
2526
- ) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2590
+ block.rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(StatusMessage, { $tone: "info", children: chartLabels.empty }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ChartArtifactContent, { config: block.config, rows: block.rows, labels: chartLabels }) })
2591
+ ) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2527
2592
  TableArtifactContent,
2528
2593
  {
2529
2594
  columns: block.config.columns,
@@ -2589,7 +2654,7 @@ function isValidDeckBlock(block) {
2589
2654
  }
2590
2655
 
2591
2656
  // src/components/artifacts/deck-artifact/deck-artifact.tsx
2592
- var import_jsx_runtime25 = require("react/jsx-runtime");
2657
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2593
2658
  var TITLE_CLASSES2 = "text-sm font-semibold text-foreground";
2594
2659
  function DeckArtifact({ artifact, labels, callbacks }) {
2595
2660
  const validConfig = isValidDeckConfig(artifact.config);
@@ -2630,9 +2695,9 @@ function DeckArtifact({ artifact, labels, callbacks }) {
2630
2695
  const meta = artifact.config?.meta;
2631
2696
  const handleOpenFullscreen = () => setIsFullscreen(true);
2632
2697
  const handleCloseFullscreen = () => setIsFullscreen(false);
2633
- const actions = /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactActions, { ...{ [CAPTURE_EXCLUDE_ATTRIBUTE]: "" }, children: [
2634
- showDownload ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactDownloadButton, { href: presignedUrl ?? "", label: resolvedLabels.download, onClick: handleDownload }) : null,
2635
- validConfig ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2698
+ const actions = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(ArtifactActions, { ...{ [CAPTURE_EXCLUDE_ATTRIBUTE]: "" }, children: [
2699
+ showDownload ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactDownloadButton, { href: presignedUrl ?? "", label: resolvedLabels.download, onClick: handleDownload }) : null,
2700
+ validConfig ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2636
2701
  IconButton,
2637
2702
  {
2638
2703
  icon: IconArrowsMaximize,
@@ -2642,22 +2707,29 @@ function DeckArtifact({ artifact, labels, callbacks }) {
2642
2707
  }
2643
2708
  ) : null
2644
2709
  ] });
2710
+ const heading = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2", children: [
2711
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : null,
2712
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Badge, { tone: "violet", variant: "subtle", size: "sm", className: "gap-1 py-1", children: [
2713
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Icon, { icon: IconFlask2Filled, size: 12 }),
2714
+ "Labs"
2715
+ ] })
2716
+ ] });
2645
2717
  if (!validConfig) {
2646
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2647
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2648
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2718
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2719
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2720
+ heading,
2649
2721
  actions
2650
2722
  ] }),
2651
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2723
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2652
2724
  ] });
2653
2725
  }
2654
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
2655
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2656
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2657
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2726
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
2727
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2728
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2729
+ heading,
2658
2730
  actions
2659
2731
  ] }),
2660
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2732
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2661
2733
  DeckArtifactContent,
2662
2734
  {
2663
2735
  slides: artifact.config.slides,
@@ -2670,7 +2742,7 @@ function DeckArtifact({ artifact, labels, callbacks }) {
2670
2742
  ) })
2671
2743
  ] }),
2672
2744
  isFullscreen && (0, import_react_dom.createPortal)(
2673
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2745
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2674
2746
  FullscreenOverlay,
2675
2747
  {
2676
2748
  artifact,
@@ -2694,15 +2766,15 @@ function FullscreenOverlay({
2694
2766
  onClose
2695
2767
  }) {
2696
2768
  const meta = artifact.config?.meta;
2697
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2769
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2698
2770
  "div",
2699
2771
  {
2700
2772
  className: "fixed inset-0 z-[2147483647] flex items-center justify-center bg-black/80",
2701
2773
  role: "dialog",
2702
2774
  "aria-modal": "true",
2703
2775
  "aria-label": resolvedLabels.exitFullscreen,
2704
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "relative", style: { width: "min(94vw, calc(82vh * 16 / 9))" }, children: [
2705
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2776
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "relative", style: { width: "min(94vw, calc(82vh * 16 / 9))" }, children: [
2777
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2706
2778
  DeckArtifactContent,
2707
2779
  {
2708
2780
  slides: artifact.config.slides,
@@ -2714,15 +2786,15 @@ function FullscreenOverlay({
2714
2786
  onDark: true
2715
2787
  }
2716
2788
  ),
2717
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2789
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
2718
2790
  "button",
2719
2791
  {
2720
2792
  className: "absolute -top-10 right-6 flex items-center gap-1.5 text-sm text-white/80 hover:text-white",
2721
2793
  "aria-label": resolvedLabels.exitFullscreen,
2722
2794
  onClick: onClose,
2723
2795
  children: [
2724
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(IconArrowsMinimize, { size: 16 }),
2725
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: resolvedLabels.exitFullscreen })
2796
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(IconArrowsMinimize, { size: 16 }),
2797
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: resolvedLabels.exitFullscreen })
2726
2798
  ]
2727
2799
  }
2728
2800
  )
@@ -2799,7 +2871,7 @@ function useTableArtifactData(presignedUrl, columns) {
2799
2871
  }
2800
2872
 
2801
2873
  // src/components/artifacts/table-artifact/table-artifact.tsx
2802
- var import_jsx_runtime26 = require("react/jsx-runtime");
2874
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2803
2875
  var TITLE_CLASSES3 = "text-sm font-semibold text-foreground";
2804
2876
  var TABLE_MAX_BODY_HEIGHT = 480;
2805
2877
  var MAX_SHIMMER_ROWS = 10;
@@ -2822,10 +2894,10 @@ function TableArtifact({ artifact, labels, callbacks }) {
2822
2894
  const onDownload = callbacks?.onDownload;
2823
2895
  const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
2824
2896
  if (!validConfig || !validColumns) {
2825
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2826
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2827
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", {}),
2828
- presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2897
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2898
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2899
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", {}),
2900
+ presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2829
2901
  ArtifactDownloadButton,
2830
2902
  {
2831
2903
  href: presignedUrl,
@@ -2834,17 +2906,17 @@ function TableArtifact({ artifact, labels, callbacks }) {
2834
2906
  }
2835
2907
  ) }) : null
2836
2908
  ] }),
2837
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2909
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2838
2910
  ] });
2839
2911
  }
2840
2912
  return (
2841
2913
  // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
2842
2914
  // Disable the outer overflow container so only one scroll context exists — this prevents
2843
2915
  // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
2844
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2845
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2846
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", {}),
2847
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2916
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2917
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2918
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", {}),
2919
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2848
2920
  ArtifactDownloadButton,
2849
2921
  {
2850
2922
  href: presignedUrl ?? "",
@@ -2853,7 +2925,7 @@ function TableArtifact({ artifact, labels, callbacks }) {
2853
2925
  }
2854
2926
  ) })
2855
2927
  ] }),
2856
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2928
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2857
2929
  TableArtifactContent,
2858
2930
  {
2859
2931
  columns: validColumns,
@@ -2896,13 +2968,13 @@ function artifactToClipboardText(artifact) {
2896
2968
  }
2897
2969
 
2898
2970
  // src/components/blocks/artifact-ref-block/artifact-ref-block.tsx
2899
- var import_jsx_runtime27 = require("react/jsx-runtime");
2971
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2900
2972
  function ArtifactRefBlock({ block }) {
2901
2973
  const { artifact, labels, callbacks } = block.payload;
2902
2974
  const entry = ArtifactServices[artifact.type];
2903
2975
  if (!entry) return null;
2904
2976
  const Component = entry.Component;
2905
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Component, { artifact, labels, callbacks });
2977
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Component, { artifact, labels, callbacks });
2906
2978
  }
2907
2979
 
2908
2980
  // src/components/blocks/block-services/artifact-ref-block-service.ts
@@ -2917,26 +2989,66 @@ var ArtifactRefBlockService = {
2917
2989
  toClipboardText: (block) => artifactToClipboardText(block.payload.artifact)
2918
2990
  };
2919
2991
 
2920
- // src/utils/markdown-to-plain-text.ts
2921
- var PLACEHOLDER_PREFIX = "\u200B\u200BIC";
2922
- var PLACEHOLDER_SUFFIX = "\u200B\u200B";
2923
- var PLACEHOLDER_REGEX = new RegExp(`${PLACEHOLDER_PREFIX}(\\d+)${PLACEHOLDER_SUFFIX}`, "g");
2924
- function stripInlineMarks(text) {
2925
- return text.replace(/\*{3}(.+?)\*{3}/g, "$1").replace(/\*{2}(.+?)\*{2}/g, "$1").replace(/_{2}(.+?)_{2}/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/_(.+?)_/g, "$1").replace(/~~(.+?)~~/g, "$1");
2992
+ // src/components/blocks/notification-draft-block/notification-draft-block.tsx
2993
+ var import_react20 = require("react");
2994
+
2995
+ // src/components/chat/hooks/use-copy-to-clipboard.ts
2996
+ var import_react19 = require("react");
2997
+
2998
+ // src/utils/clipboard.ts
2999
+ function copyToClipboard(text, options) {
3000
+ navigator.clipboard.writeText(text).then(
3001
+ () => options?.onSuccess?.(),
3002
+ (error) => options?.onFailure?.(error)
3003
+ );
2926
3004
  }
2927
- function markdownToPlainText(markdown) {
2928
- if (!markdown) return "";
2929
- const inlineCodeSnippets = [];
2930
- let result = markdown.replace(/^<!--[\s\S]*?--!?>\n?/gm, "").replace(/```[\s\S]*?```/g, "").replace(/`([^`]+)`/g, (_match, code) => {
2931
- inlineCodeSnippets.push(code);
2932
- return `${PLACEHOLDER_PREFIX}${inlineCodeSnippets.length - 1}${PLACEHOLDER_SUFFIX}`;
2933
- }).replace(/^#{1,6}\s+/gm, "").replace(/^(?:---|\*\*\*|___)\s*$/gm, "");
2934
- result = stripInlineMarks(result).replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^>\s?/gm, "").replace(/^\|[-:\s|]+\|\s*$/gm, "").replace(/^\|\s?/gm, "").replace(/\s?\|$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
2935
- result = result.replace(PLACEHOLDER_REGEX, (_match, index) => inlineCodeSnippets[Number(index)]);
2936
- return result;
3005
+
3006
+ // src/components/chat/hooks/use-copy-to-clipboard.ts
3007
+ var RESET_DELAY_MS = 2e3;
3008
+ function useCopyToClipboard() {
3009
+ const [isCopied, setIsCopied] = (0, import_react19.useState)(false);
3010
+ const timeoutRef = (0, import_react19.useRef)(null);
3011
+ (0, import_react19.useEffect)(() => {
3012
+ return () => {
3013
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
3014
+ };
3015
+ }, []);
3016
+ const copy = (0, import_react19.useCallback)((text) => {
3017
+ copyToClipboard(text, {
3018
+ onSuccess: () => {
3019
+ setIsCopied(true);
3020
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
3021
+ timeoutRef.current = setTimeout(() => {
3022
+ setIsCopied(false);
3023
+ timeoutRef.current = null;
3024
+ }, RESET_DELAY_MS);
3025
+ }
3026
+ });
3027
+ }, []);
3028
+ return { isCopied, copy };
2937
3029
  }
2938
3030
 
2939
- // src/components/blocks/text-block/text-block.tsx
3031
+ // src/components/copy-button/copy-button.tsx
3032
+ var import_jsx_runtime30 = require("react/jsx-runtime");
3033
+ function CopyButton({
3034
+ text,
3035
+ copyLabel = "Copy",
3036
+ copiedLabel = "Copied",
3037
+ className
3038
+ }) {
3039
+ const { isCopied, copy } = useCopyToClipboard();
3040
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3041
+ IconButton,
3042
+ {
3043
+ icon: isCopied ? IconCheck : IconCopy,
3044
+ onClick: () => copy(text),
3045
+ "aria-label": isCopied ? copiedLabel : copyLabel,
3046
+ className
3047
+ }
3048
+ );
3049
+ }
3050
+
3051
+ // src/components/blocks/markdown/markdown.tsx
2940
3052
  var import_react_markdown2 = __toESM(require("react-markdown"), 1);
2941
3053
  var import_remark_breaks2 = __toESM(require("remark-breaks"), 1);
2942
3054
  var import_remark_gfm2 = __toESM(require("remark-gfm"), 1);
@@ -2954,9 +3066,9 @@ var TableScroll = import_styled_components3.default.div`
2954
3066
  `;
2955
3067
 
2956
3068
  // src/components/blocks/scrollable-table/scrollable-table.tsx
2957
- var import_jsx_runtime28 = require("react/jsx-runtime");
3069
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2958
3070
  function ScrollableTable({ node: _node, ...props }) {
2959
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TableContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TableScroll, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("table", { ...props }) }) });
3071
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(TableContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(TableScroll, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("table", { ...props }) }) });
2960
3072
  }
2961
3073
 
2962
3074
  // src/components/blocks/text-block/sanitize.ts
@@ -3099,13 +3211,151 @@ var TextBlockWrapper = import_styled_components4.default.div`
3099
3211
  }
3100
3212
  `;
3101
3213
 
3102
- // src/components/blocks/text-block/text-block.tsx
3103
- var import_jsx_runtime29 = require("react/jsx-runtime");
3214
+ // src/components/blocks/markdown/markdown.tsx
3215
+ var import_jsx_runtime32 = require("react/jsx-runtime");
3104
3216
  var markdownComponents = {
3105
- table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ScrollableTable, { ...tableProps }))
3217
+ table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ScrollableTable, { ...tableProps }))
3218
+ };
3219
+ function Markdown({ children }) {
3220
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TextBlockWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_markdown2.default, { remarkPlugins: [import_remark_gfm2.default, import_remark_breaks2.default], components: markdownComponents, children: sanitize2(children) }) });
3221
+ }
3222
+
3223
+ // src/utils/markdown-to-plain-text.ts
3224
+ var PLACEHOLDER_PREFIX = "\u200B\u200BIC";
3225
+ var PLACEHOLDER_SUFFIX = "\u200B\u200B";
3226
+ var PLACEHOLDER_REGEX = new RegExp(`${PLACEHOLDER_PREFIX}(\\d+)${PLACEHOLDER_SUFFIX}`, "g");
3227
+ function stripInlineMarks(text) {
3228
+ return text.replace(/\*{3}(.+?)\*{3}/g, "$1").replace(/\*{2}(.+?)\*{2}/g, "$1").replace(/_{2}(.+?)_{2}/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/_(.+?)_/g, "$1").replace(/~~(.+?)~~/g, "$1");
3229
+ }
3230
+ function markdownToPlainText(markdown) {
3231
+ if (!markdown) return "";
3232
+ const inlineCodeSnippets = [];
3233
+ let result = markdown.replace(/^<!--[\s\S]*?--!?>\n?/gm, "").replace(/```[\s\S]*?```/g, "").replace(/`([^`]+)`/g, (_match, code) => {
3234
+ inlineCodeSnippets.push(code);
3235
+ return `${PLACEHOLDER_PREFIX}${inlineCodeSnippets.length - 1}${PLACEHOLDER_SUFFIX}`;
3236
+ }).replace(/^#{1,6}\s+/gm, "").replace(/^(?:---|\*\*\*|___)\s*$/gm, "");
3237
+ result = stripInlineMarks(result).replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^>\s?/gm, "").replace(/^\|[-:\s|]+\|\s*$/gm, "").replace(/^\|\s?/gm, "").replace(/\s?\|$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
3238
+ result = result.replace(PLACEHOLDER_REGEX, (_match, index) => inlineCodeSnippets[Number(index)]);
3239
+ return result;
3240
+ }
3241
+
3242
+ // src/components/blocks/notification-draft-block/types.ts
3243
+ var notificationChannels = {
3244
+ /** Branded email — renders a From/subject header. */
3245
+ EMAIL: "email",
3246
+ /** Slack DM — renders as a chat bubble, no subject. */
3247
+ SLACK: "slack",
3248
+ /** Microsoft Teams DM — renders as a chat bubble, no subject. */
3249
+ TEAMS: "teams"
3250
+ };
3251
+
3252
+ // src/components/blocks/notification-draft-block/to-text.ts
3253
+ function notificationDraftToText(payload) {
3254
+ const { channel, subject, body } = payload;
3255
+ const text = markdownToPlainText(body);
3256
+ return channel === notificationChannels.EMAIL && subject ? `${subject}
3257
+
3258
+ ${text}` : text;
3259
+ }
3260
+
3261
+ // src/components/blocks/notification-draft-block/notification-draft-block.tsx
3262
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3263
+ var CHIP_LIMIT = 3;
3264
+ var RECIPIENTS_MAX_HEIGHT = 320;
3265
+ function chipLabel(recipient) {
3266
+ return recipient.name ?? recipient.email ?? recipient.employeeId;
3267
+ }
3268
+ function channelCellText(recipient) {
3269
+ return recipient.fallback ? `${recipient.channelLabel} (fallback)` : recipient.channelLabel;
3270
+ }
3271
+ function FieldLabel({ children }) {
3272
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-geist-label-caption-medium tracking-wide text-brown-60", children });
3273
+ }
3274
+ function RecipientChips({ recipients }) {
3275
+ const shown = recipients.slice(0, CHIP_LIMIT);
3276
+ const overflow = recipients.length - shown.length;
3277
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", children: [
3278
+ shown.map((recipient) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { variant: "outline", children: chipLabel(recipient) }, recipient.employeeId)),
3279
+ overflow > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { variant: "subtle", children: `+${overflow}` })
3280
+ ] });
3281
+ }
3282
+ function RecipientsTable({ recipients }) {
3283
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3284
+ DataTable,
3285
+ {
3286
+ maxBodyHeight: RECIPIENTS_MAX_HEIGHT,
3287
+ header: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TableRow, { className: "hover:bg-transparent", children: [
3288
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: "Name" }),
3289
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: "Email" }),
3290
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: "Channel" })
3291
+ ] }),
3292
+ children: recipients.map((recipient) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TableRow, { className: DATA_TABLE_ROW_CLASS, children: [
3293
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: recipient.name ?? "\u2014" }),
3294
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: recipient.email ?? "\u2014" }),
3295
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { tone: recipient.fallback ? "warning" : "neutral", variant: "subtle", children: channelCellText(recipient) }) })
3296
+ ] }, recipient.employeeId))
3297
+ }
3298
+ );
3299
+ }
3300
+ function NotificationDraftBlock({ block }) {
3301
+ const { channel, subject, body, recipients } = block.payload;
3302
+ const [detailsOpen, setDetailsOpen] = (0, import_react20.useState)(false);
3303
+ const showSubject = channel === notificationChannels.EMAIL && subject;
3304
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "overflow-hidden rounded-2xl border border-brown-30 bg-white", children: [
3305
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-3 border-b border-brown-30 px-4 py-3", children: [
3306
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
3307
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center gap-2", children: [
3308
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-geist-body-s-semi-bold text-brown-100", children: "Notification draft" }),
3309
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Badge, { tone: "violet", variant: "subtle", size: "sm", className: "gap-1 py-1", children: [
3310
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { icon: IconFlask2Filled, size: 12 }),
3311
+ "Labs"
3312
+ ] })
3313
+ ] }),
3314
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CopyButton, { text: notificationDraftToText(block.payload), copyLabel: "Copy draft", copiedLabel: "Copied" })
3315
+ ] }),
3316
+ showSubject && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
3317
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldLabel, { children: "Title" }),
3318
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-geist-body-s-medium text-brown-100", children: subject })
3319
+ ] }),
3320
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-1", children: [
3321
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
3322
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldLabel, { children: `Recipients (${recipients.length})` }),
3323
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
3324
+ "button",
3325
+ {
3326
+ type: "button",
3327
+ "aria-expanded": detailsOpen,
3328
+ onClick: () => setDetailsOpen((open) => !open),
3329
+ className: "inline-flex items-center gap-1 text-geist-label-caption-medium text-brown-70 transition-colors hover:text-brown-100",
3330
+ children: [
3331
+ "Details",
3332
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { icon: IconChevronDown, size: 14, className: detailsOpen ? "rotate-180" : void 0 })
3333
+ ]
3334
+ }
3335
+ )
3336
+ ] }),
3337
+ detailsOpen ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(RecipientsTable, { recipients }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(RecipientChips, { recipients })
3338
+ ] })
3339
+ ] }),
3340
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Markdown, { children: body }) })
3341
+ ] });
3342
+ }
3343
+
3344
+ // src/components/blocks/block-services/notification-draft-block-service.ts
3345
+ var NotificationDraftBlockService = {
3346
+ type: blockTypes.NOTIFICATION_DRAFT,
3347
+ Component: NotificationDraftBlock,
3348
+ /**
3349
+ * Plain-text clipboard form of the drafted notification — shared with the in-block copy button
3350
+ * via {@link notificationDraftToText} so both copy the same text.
3351
+ */
3352
+ toClipboardText: (block) => notificationDraftToText(block.payload)
3106
3353
  };
3354
+
3355
+ // src/components/blocks/text-block/text-block.tsx
3356
+ var import_jsx_runtime34 = require("react/jsx-runtime");
3107
3357
  function TextBlock({ block }) {
3108
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TextBlockWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_markdown2.default, { remarkPlugins: [import_remark_gfm2.default, import_remark_breaks2.default], components: markdownComponents, children: sanitize2(block.payload.text) }) });
3358
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Markdown, { children: block.payload.text });
3109
3359
  }
3110
3360
 
3111
3361
  // src/components/blocks/block-services/text-block-service.ts
@@ -3123,16 +3373,17 @@ var TextBlockService = {
3123
3373
  // src/components/blocks/block-services/index.ts
3124
3374
  var BlockServices = {
3125
3375
  [blockTypes.TEXT]: TextBlockService,
3126
- [blockTypes.ARTIFACT_REF]: ArtifactRefBlockService
3376
+ [blockTypes.ARTIFACT_REF]: ArtifactRefBlockService,
3377
+ [blockTypes.NOTIFICATION_DRAFT]: NotificationDraftBlockService
3127
3378
  };
3128
3379
 
3129
3380
  // src/components/blocks/block/block.tsx
3130
- var import_jsx_runtime30 = require("react/jsx-runtime");
3381
+ var import_jsx_runtime35 = require("react/jsx-runtime");
3131
3382
  function Block({ block }) {
3132
3383
  const service = BlockServices[block.type];
3133
3384
  if (!service) return null;
3134
3385
  const { Component } = service;
3135
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Component, { block });
3386
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Component, { block });
3136
3387
  }
3137
3388
 
3138
3389
  // src/components/chat/hooks/copy-message-text.ts
@@ -3150,55 +3401,19 @@ function copyMessageText(message) {
3150
3401
  }
3151
3402
 
3152
3403
  // src/components/chat/chat-message-actions/chat-message-actions.tsx
3153
- var import_react21 = require("react");
3404
+ var import_react22 = require("react");
3154
3405
 
3155
3406
  // src/components/chat/chat-context/chat-context.ts
3156
- var import_react19 = require("react");
3157
- var ChatContext = (0, import_react19.createContext)(null);
3407
+ var import_react21 = require("react");
3408
+ var ChatContext = (0, import_react21.createContext)(null);
3158
3409
  function useChatContext() {
3159
- const context = (0, import_react19.useContext)(ChatContext);
3410
+ const context = (0, import_react21.useContext)(ChatContext);
3160
3411
  if (!context) {
3161
3412
  throw new Error("useChatContext must be used within a Chat.Root component");
3162
3413
  }
3163
3414
  return context;
3164
3415
  }
3165
3416
 
3166
- // src/components/chat/hooks/use-copy-to-clipboard.ts
3167
- var import_react20 = require("react");
3168
-
3169
- // src/utils/clipboard.ts
3170
- function copyToClipboard(text, options) {
3171
- navigator.clipboard.writeText(text).then(
3172
- () => options?.onSuccess?.(),
3173
- (error) => options?.onFailure?.(error)
3174
- );
3175
- }
3176
-
3177
- // src/components/chat/hooks/use-copy-to-clipboard.ts
3178
- var RESET_DELAY_MS = 2e3;
3179
- function useCopyToClipboard() {
3180
- const [isCopied, setIsCopied] = (0, import_react20.useState)(false);
3181
- const timeoutRef = (0, import_react20.useRef)(null);
3182
- (0, import_react20.useEffect)(() => {
3183
- return () => {
3184
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
3185
- };
3186
- }, []);
3187
- const copy = (0, import_react20.useCallback)((text) => {
3188
- copyToClipboard(text, {
3189
- onSuccess: () => {
3190
- setIsCopied(true);
3191
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
3192
- timeoutRef.current = setTimeout(() => {
3193
- setIsCopied(false);
3194
- timeoutRef.current = null;
3195
- }, RESET_DELAY_MS);
3196
- }
3197
- });
3198
- }, []);
3199
- return { isCopied, copy };
3200
- }
3201
-
3202
3417
  // src/components/chat/constants.ts
3203
3418
  var MESSAGE_ROLE = {
3204
3419
  USER: "user",
@@ -3224,24 +3439,24 @@ var AnimatedAction = import_styled_components5.default.div`
3224
3439
  `;
3225
3440
 
3226
3441
  // src/components/chat/chat-message-actions/chat-message-actions.tsx
3227
- var import_jsx_runtime31 = require("react/jsx-runtime");
3442
+ var import_jsx_runtime36 = require("react/jsx-runtime");
3228
3443
  function ChatMessageActions({ className, messageId, content, role, isHelpful }) {
3229
3444
  const { onCopyMessage, onThumbUpClick, onThumbDownClick } = useChatContext();
3230
3445
  const { isCopied, copy } = useCopyToClipboard();
3231
- const handleCopy = (0, import_react21.useCallback)(() => {
3446
+ const handleCopy = (0, import_react22.useCallback)(() => {
3232
3447
  copy(content);
3233
3448
  onCopyMessage?.(messageId);
3234
3449
  }, [content, messageId, copy, onCopyMessage]);
3235
- const handleThumbUp = (0, import_react21.useCallback)(() => {
3450
+ const handleThumbUp = (0, import_react22.useCallback)(() => {
3236
3451
  onThumbUpClick?.(messageId, isHelpful === true ? null : true);
3237
3452
  }, [messageId, isHelpful, onThumbUpClick]);
3238
- const handleThumbDown = (0, import_react21.useCallback)(() => {
3453
+ const handleThumbDown = (0, import_react22.useCallback)(() => {
3239
3454
  onThumbDownClick?.(messageId, isHelpful === false ? null : false);
3240
3455
  }, [messageId, isHelpful, onThumbDownClick]);
3241
3456
  const isAssistant = role === MESSAGE_ROLE.ASSISTANT;
3242
3457
  const hasFeedback = isAssistant && (onThumbUpClick || onThumbDownClick);
3243
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(ActionsContainer, { $role: role, className, children: [
3244
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3458
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(ActionsContainer, { $role: role, className, children: [
3459
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3245
3460
  IconButton,
3246
3461
  {
3247
3462
  icon: isCopied ? IconCheck : IconCopy,
@@ -3249,7 +3464,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
3249
3464
  "aria-label": isCopied ? "Copied" : "Copy message"
3250
3465
  }
3251
3466
  ),
3252
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3467
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3253
3468
  IconButton,
3254
3469
  {
3255
3470
  icon: IconThumbUp,
@@ -3258,7 +3473,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
3258
3473
  "aria-label": "Good response"
3259
3474
  }
3260
3475
  ) }),
3261
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3476
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3262
3477
  IconButton,
3263
3478
  {
3264
3479
  icon: IconThumbDown,
@@ -3309,12 +3524,12 @@ var MessageBubble = import_styled_components6.default.div`
3309
3524
  `;
3310
3525
 
3311
3526
  // src/components/chat/chat-message/chat-message.tsx
3312
- var import_jsx_runtime32 = require("react/jsx-runtime");
3527
+ var import_jsx_runtime37 = require("react/jsx-runtime");
3313
3528
  function ChatMessage({ message }) {
3314
- const clipboardText = (0, import_react22.useMemo)(() => copyMessageText(message), [message]);
3315
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(MessageContainer, { $role: message.role, children: [
3316
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(MessageBubble, { $role: message.role, "data-testid": "message-bubble", children: message.blocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Block, { block }, index)) }),
3317
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3529
+ const clipboardText = (0, import_react23.useMemo)(() => copyMessageText(message), [message]);
3530
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(MessageContainer, { $role: message.role, children: [
3531
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MessageBubble, { $role: message.role, "data-testid": "message-bubble", children: message.blocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Block, { block }, index)) }),
3532
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3318
3533
  ChatMessageActions,
3319
3534
  {
3320
3535
  messageId: message.id,
@@ -3342,6 +3557,7 @@ function ChatMessage({ message }) {
3342
3557
  @tabler/icons-react/dist/esm/icons/IconArrowsMaximize.mjs:
3343
3558
  @tabler/icons-react/dist/esm/icons/IconArrowsMinimize.mjs:
3344
3559
  @tabler/icons-react/dist/esm/icons/IconCheck.mjs:
3560
+ @tabler/icons-react/dist/esm/icons/IconChevronDown.mjs:
3345
3561
  @tabler/icons-react/dist/esm/icons/IconChevronLeft.mjs:
3346
3562
  @tabler/icons-react/dist/esm/icons/IconChevronRight.mjs:
3347
3563
  @tabler/icons-react/dist/esm/icons/IconCopy.mjs:
@@ -3351,6 +3567,7 @@ function ChatMessage({ message }) {
3351
3567
  @tabler/icons-react/dist/esm/icons/IconPhoto.mjs:
3352
3568
  @tabler/icons-react/dist/esm/icons/IconThumbDown.mjs:
3353
3569
  @tabler/icons-react/dist/esm/icons/IconThumbUp.mjs:
3570
+ @tabler/icons-react/dist/esm/icons/IconFlask2Filled.mjs:
3354
3571
  @tabler/icons-react/dist/esm/tabler-icons-react.mjs:
3355
3572
  (**
3356
3573
  * @license @tabler/icons-react v3.37.1 - MIT