@shapesos/clay 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/ai-elements.cjs +3 -1
  2. package/dist/ai-elements.cjs.map +1 -1
  3. package/dist/ai-elements.js +4 -4
  4. package/dist/artifacts.cjs +1010 -60
  5. package/dist/artifacts.cjs.map +1 -1
  6. package/dist/artifacts.d.cts +20 -3
  7. package/dist/artifacts.d.ts +20 -3
  8. package/dist/artifacts.js +15 -6
  9. package/dist/badge.cjs +70 -0
  10. package/dist/badge.cjs.map +1 -0
  11. package/dist/badge.d.cts +28 -0
  12. package/dist/badge.d.ts +28 -0
  13. package/dist/badge.js +9 -0
  14. package/dist/blocks.cjs +981 -96
  15. package/dist/blocks.cjs.map +1 -1
  16. package/dist/blocks.css +1 -1
  17. package/dist/blocks.d.cts +15 -4
  18. package/dist/blocks.d.ts +15 -4
  19. package/dist/blocks.js +20 -8
  20. package/dist/button.cjs +3 -1
  21. package/dist/button.cjs.map +1 -1
  22. package/dist/button.js +2 -2
  23. package/dist/capture.cjs +3 -1
  24. package/dist/capture.cjs.map +1 -1
  25. package/dist/capture.js +2 -2
  26. package/dist/chart.cjs +3 -1
  27. package/dist/chart.cjs.map +1 -1
  28. package/dist/chart.js +2 -2
  29. package/dist/chat.cjs +986 -151
  30. package/dist/chat.cjs.map +1 -1
  31. package/dist/chat.d.cts +2 -2
  32. package/dist/chat.d.ts +2 -2
  33. package/dist/chat.js +13 -8
  34. package/dist/{chunk-JGMN6W72.js → chunk-2X4KUXYP.js} +1 -1
  35. package/dist/chunk-BHHJOG5X.js +1 -0
  36. package/dist/{chunk-B4U37WIH.js → chunk-CFCLVJIO.js} +2 -2
  37. package/dist/chunk-CSTCTO3B.js +161 -0
  38. package/dist/chunk-CSTCTO3B.js.map +1 -0
  39. package/dist/{chunk-6YZ65KPW.js → chunk-DC5KYT2G.js} +669 -171
  40. package/dist/chunk-DC5KYT2G.js.map +1 -0
  41. package/dist/{chunk-PYDVANWI.js → chunk-E36VI2HA.js} +2 -2
  42. package/dist/chunk-EIAWZXE4.js +69 -0
  43. package/dist/chunk-EIAWZXE4.js.map +1 -0
  44. package/dist/chunk-EXRNGIQ2.js +41 -0
  45. package/dist/chunk-EXRNGIQ2.js.map +1 -0
  46. package/dist/{chunk-B6GAPZ2R.js → chunk-FCSYVF4Z.js} +12 -46
  47. package/dist/chunk-FCSYVF4Z.js.map +1 -0
  48. package/dist/{chunk-PUVZ2S3F.js → chunk-G4NXVFXU.js} +2 -2
  49. package/dist/{chunk-JAGNXEWK.js → chunk-GK4XW4BC.js} +2 -2
  50. package/dist/{chunk-4MZZH3WX.js → chunk-HU5W7CGE.js} +37 -2
  51. package/dist/chunk-HU5W7CGE.js.map +1 -0
  52. package/dist/chunk-JMHE3Q5K.js +406 -0
  53. package/dist/chunk-JMHE3Q5K.js.map +1 -0
  54. package/dist/{chunk-4VE6ZXXW.js → chunk-MQP57DOP.js} +3 -3
  55. package/dist/{chunk-JF3P66JF.js → chunk-SN3ORQSJ.js} +4 -2
  56. package/dist/{chunk-JF3P66JF.js.map → chunk-SN3ORQSJ.js.map} +1 -1
  57. package/dist/{chunk-PGR2MDDU.js → chunk-W66OJM55.js} +2 -2
  58. package/dist/{chunk-7OYIDM42.js → chunk-XKURJ72I.js} +2 -2
  59. package/dist/copy-button.cjs +439 -0
  60. package/dist/copy-button.cjs.map +1 -0
  61. package/dist/copy-button.d.cts +20 -0
  62. package/dist/copy-button.d.ts +20 -0
  63. package/dist/copy-button.js +12 -0
  64. package/dist/copy-button.js.map +1 -0
  65. package/dist/{dom-to-image-NATF3446.js → dom-to-image-QB7KMTAE.js} +3 -3
  66. package/dist/dom-to-image-QB7KMTAE.js.map +1 -0
  67. package/dist/icon.cjs +3 -1
  68. package/dist/icon.cjs.map +1 -1
  69. package/dist/icon.js +2 -2
  70. package/dist/index.cjs +1070 -209
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/index.d.cts +6 -4
  73. package/dist/index.d.ts +6 -4
  74. package/dist/index.js +42 -17
  75. package/dist/keyboard-shortcut.cjs +3 -1
  76. package/dist/keyboard-shortcut.cjs.map +1 -1
  77. package/dist/keyboard-shortcut.js +2 -2
  78. package/dist/table.cjs +40 -0
  79. package/dist/table.cjs.map +1 -1
  80. package/dist/table.d.cts +37 -2
  81. package/dist/table.d.ts +37 -2
  82. package/dist/table.js +11 -1
  83. package/dist/text-area.cjs +3 -1
  84. package/dist/text-area.cjs.map +1 -1
  85. package/dist/text-area.js +2 -2
  86. package/dist/tokens.cjs +3 -1
  87. package/dist/tokens.cjs.map +1 -1
  88. package/dist/tokens.d.cts +1 -0
  89. package/dist/tokens.d.ts +1 -0
  90. package/dist/tokens.js +1 -1
  91. package/dist/{types-CW45GBXl.d.cts → types-Bhg0_ES8.d.cts} +75 -3
  92. package/dist/{types-GCkXbyFm.d.ts → types-C8JtnwNY.d.ts} +200 -4
  93. package/dist/{types-BzXPBy6s.d.cts → types-DTdDFU3O.d.cts} +200 -4
  94. package/dist/{types-D1b8v7EY.d.ts → types-orOQcI2z.d.ts} +75 -3
  95. package/package.json +11 -1
  96. package/dist/chunk-46ZYTBX5.js +0 -250
  97. package/dist/chunk-46ZYTBX5.js.map +0 -1
  98. package/dist/chunk-4MZZH3WX.js.map +0 -1
  99. package/dist/chunk-6YZ65KPW.js.map +0 -1
  100. package/dist/chunk-B6GAPZ2R.js.map +0 -1
  101. package/dist/chunk-RSRNSWJN.js +0 -1
  102. /package/dist/{chunk-RSRNSWJN.js.map → badge.js.map} +0 -0
  103. /package/dist/{chunk-JGMN6W72.js.map → chunk-2X4KUXYP.js.map} +0 -0
  104. /package/dist/{dom-to-image-NATF3446.js.map → chunk-BHHJOG5X.js.map} +0 -0
  105. /package/dist/{chunk-B4U37WIH.js.map → chunk-CFCLVJIO.js.map} +0 -0
  106. /package/dist/{chunk-PYDVANWI.js.map → chunk-E36VI2HA.js.map} +0 -0
  107. /package/dist/{chunk-PUVZ2S3F.js.map → chunk-G4NXVFXU.js.map} +0 -0
  108. /package/dist/{chunk-JAGNXEWK.js.map → chunk-GK4XW4BC.js.map} +0 -0
  109. /package/dist/{chunk-4VE6ZXXW.js.map → chunk-MQP57DOP.js.map} +0 -0
  110. /package/dist/{chunk-PGR2MDDU.js.map → chunk-W66OJM55.js.map} +0 -0
  111. /package/dist/{chunk-7OYIDM42.js.map → chunk-XKURJ72I.js.map} +0 -0
package/dist/chat.cjs CHANGED
@@ -128,7 +128,9 @@ var init_colors = __esm({
128
128
  "red-200": "#FECACA",
129
129
  "red-400": "#F7776C",
130
130
  "red-500": "#EF4444",
131
- "red-600": "#DC2626"
131
+ "red-600": "#DC2626",
132
+ // Deck
133
+ "deck-canvas": "#faf8f5"
132
134
  };
133
135
  }
134
136
  });
@@ -276,18 +278,20 @@ __export(chat_exports, {
276
278
  module.exports = __toCommonJS(chat_exports);
277
279
 
278
280
  // src/components/chat/chat-message/chat-message.tsx
279
- var import_react19 = require("react");
281
+ var import_react23 = require("react");
280
282
 
281
283
  // src/components/blocks/types.ts
282
284
  var blockTypes = {
283
285
  TEXT: "TEXT",
284
- ARTIFACT_REF: "ARTIFACT_REF"
286
+ ARTIFACT_REF: "ARTIFACT_REF",
287
+ NOTIFICATION_DRAFT: "NOTIFICATION_DRAFT"
285
288
  };
286
289
 
287
290
  // src/components/artifacts/artifact-base.ts
288
291
  var artifactTypes = {
289
292
  TABLE: "TABLE",
290
- CHART: "CHART"
293
+ CHART: "CHART",
294
+ DECK: "DECK"
291
295
  };
292
296
 
293
297
  // src/components/artifacts/chart-artifact/types.ts
@@ -312,6 +316,34 @@ var DEFAULT_TABLE_ARTIFACT_LABELS = {
312
316
  empty: "No rows to display."
313
317
  };
314
318
 
319
+ // src/components/artifacts/deck-artifact/types.ts
320
+ var deckBlockTypes = {
321
+ TEXT: "TEXT",
322
+ CHART: "CHART",
323
+ TABLE: "TABLE"
324
+ };
325
+ var deckSlideKinds = {
326
+ TITLE: "TITLE",
327
+ AGENDA: "AGENDA",
328
+ SECTION: "SECTION",
329
+ CONTENT: "CONTENT",
330
+ CLOSING: "CLOSING"
331
+ };
332
+ var DEFAULT_DECK_ARTIFACT_LABELS = {
333
+ previous: "Previous slide",
334
+ next: "Next slide",
335
+ position: "Slide {current} of {total}",
336
+ download: "Download",
337
+ unavailable: "Deck content is unavailable.",
338
+ enterFullscreen: "Fullscreen",
339
+ exitFullscreen: "Exit fullscreen",
340
+ thankYou: "Thank you",
341
+ questions: "Questions?",
342
+ agenda: "Agenda",
343
+ chart: DEFAULT_CHART_ARTIFACT_LABELS,
344
+ table: DEFAULT_TABLE_ARTIFACT_LABELS
345
+ };
346
+
315
347
  // src/components/artifacts/chart-artifact/chart-artifact.tsx
316
348
  var import_react13 = require("react");
317
349
 
@@ -404,37 +436,61 @@ var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
404
436
  var __iconNode = [["path", { "d": "M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0", "key": "svg-0" }], ["path", { "d": "M12 8v4", "key": "svg-1" }], ["path", { "d": "M12 16h.01", "key": "svg-2" }]];
405
437
  var IconAlertCircle = createReactComponent("outline", "alert-circle", "AlertCircle", __iconNode);
406
438
 
439
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconArrowsMaximize.mjs
440
+ var __iconNode2 = [["path", { "d": "M16 4l4 0l0 4", "key": "svg-0" }], ["path", { "d": "M14 10l6 -6", "key": "svg-1" }], ["path", { "d": "M8 20l-4 0l0 -4", "key": "svg-2" }], ["path", { "d": "M4 20l6 -6", "key": "svg-3" }], ["path", { "d": "M16 20l4 0l0 -4", "key": "svg-4" }], ["path", { "d": "M14 14l6 6", "key": "svg-5" }], ["path", { "d": "M8 4l-4 0l0 4", "key": "svg-6" }], ["path", { "d": "M4 4l6 6", "key": "svg-7" }]];
441
+ var IconArrowsMaximize = createReactComponent("outline", "arrows-maximize", "ArrowsMaximize", __iconNode2);
442
+
443
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconArrowsMinimize.mjs
444
+ var __iconNode3 = [["path", { "d": "M5 9l4 0l0 -4", "key": "svg-0" }], ["path", { "d": "M3 3l6 6", "key": "svg-1" }], ["path", { "d": "M5 15l4 0l0 4", "key": "svg-2" }], ["path", { "d": "M3 21l6 -6", "key": "svg-3" }], ["path", { "d": "M19 9l-4 0l0 -4", "key": "svg-4" }], ["path", { "d": "M15 9l6 -6", "key": "svg-5" }], ["path", { "d": "M19 15l-4 0l0 4", "key": "svg-6" }], ["path", { "d": "M15 15l6 6", "key": "svg-7" }]];
445
+ var IconArrowsMinimize = createReactComponent("outline", "arrows-minimize", "ArrowsMinimize", __iconNode3);
446
+
407
447
  // node_modules/@tabler/icons-react/dist/esm/icons/IconCheck.mjs
408
- var __iconNode2 = [["path", { "d": "M5 12l5 5l10 -10", "key": "svg-0" }]];
409
- var IconCheck = createReactComponent("outline", "check", "Check", __iconNode2);
448
+ var __iconNode4 = [["path", { "d": "M5 12l5 5l10 -10", "key": "svg-0" }]];
449
+ var IconCheck = createReactComponent("outline", "check", "Check", __iconNode4);
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
+
455
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconChevronLeft.mjs
456
+ var __iconNode6 = [["path", { "d": "M15 6l-6 6l6 6", "key": "svg-0" }]];
457
+ var IconChevronLeft = createReactComponent("outline", "chevron-left", "ChevronLeft", __iconNode6);
458
+
459
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconChevronRight.mjs
460
+ var __iconNode7 = [["path", { "d": "M9 6l6 6l-6 6", "key": "svg-0" }]];
461
+ var IconChevronRight = createReactComponent("outline", "chevron-right", "ChevronRight", __iconNode7);
410
462
 
411
463
  // node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.mjs
412
- var __iconNode3 = [["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" }]];
413
- var IconCopy = createReactComponent("outline", "copy", "Copy", __iconNode3);
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);
414
466
 
415
467
  // node_modules/@tabler/icons-react/dist/esm/icons/IconDownload.mjs
416
- var __iconNode4 = [["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" }]];
417
- var IconDownload = createReactComponent("outline", "download", "Download", __iconNode4);
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);
418
470
 
419
471
  // node_modules/@tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs
420
- var __iconNode5 = [["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" }]];
421
- var IconFileSpreadsheet = createReactComponent("outline", "file-spreadsheet", "FileSpreadsheet", __iconNode5);
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);
422
474
 
423
475
  // node_modules/@tabler/icons-react/dist/esm/icons/IconLoader2.mjs
424
- var __iconNode6 = [["path", { "d": "M12 3a9 9 0 1 0 9 9", "key": "svg-0" }]];
425
- var IconLoader2 = createReactComponent("outline", "loader-2", "Loader2", __iconNode6);
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);
426
478
 
427
479
  // node_modules/@tabler/icons-react/dist/esm/icons/IconPhoto.mjs
428
- var __iconNode7 = [["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" }]];
429
- var IconPhoto = createReactComponent("outline", "photo", "Photo", __iconNode7);
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);
430
482
 
431
483
  // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbDown.mjs
432
- var __iconNode8 = [["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" }]];
433
- var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode8);
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);
434
486
 
435
487
  // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbUp.mjs
436
- var __iconNode9 = [["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" }]];
437
- var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode9);
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);
438
494
 
439
495
  // src/components/artifacts/artifact-copy-as-image-button/artifact-copy-as-image-button.tsx
440
496
  var import_react6 = require("react");
@@ -2007,8 +2063,13 @@ var ChartArtifactService = {
2007
2063
  toClipboardText: chartArtifactToClipboardText
2008
2064
  };
2009
2065
 
2010
- // src/components/artifacts/table-artifact/table-artifact.tsx
2011
- var import_react15 = require("react");
2066
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
2067
+ var import_react17 = require("react");
2068
+ var import_react_dom = require("react-dom");
2069
+ init_capture_exclude_attribute();
2070
+
2071
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
2072
+ var import_react16 = require("react");
2012
2073
 
2013
2074
  // src/components/ui/table.tsx
2014
2075
  var React3 = __toESM(require("react"), 1);
@@ -2087,6 +2148,36 @@ function useScrollShadow() {
2087
2148
  return { targetRef, isScrolled };
2088
2149
  }
2089
2150
 
2151
+ // src/components/table/data-table.tsx
2152
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2153
+ var DATA_TABLE_HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
2154
+ var DATA_TABLE_CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
2155
+ var DATA_TABLE_ROW_CLASS = "border-b-brown-30 bg-background/70 hover:bg-secondary";
2156
+ var DATA_TABLE_SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";
2157
+ function DataTable({ header, children, maxBodyHeight, className }) {
2158
+ const { targetRef, isScrolled } = useScrollShadow();
2159
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2160
+ "div",
2161
+ {
2162
+ ref: targetRef,
2163
+ className: cn("overscroll-none", className),
2164
+ style: maxBodyHeight !== void 0 ? { maxHeight: maxBodyHeight, overflowY: "auto" } : void 0,
2165
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Table, { containerClassName: "overflow-visible", children: [
2166
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2167
+ TableHeader,
2168
+ {
2169
+ "data-scrolled": isScrolled ? "true" : void 0,
2170
+ className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
2171
+ style: isScrolled ? { boxShadow: DATA_TABLE_SCROLL_SHADOW } : void 0,
2172
+ children: header
2173
+ }
2174
+ ),
2175
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableBody, { children })
2176
+ ] })
2177
+ }
2178
+ );
2179
+ }
2180
+
2090
2181
  // src/components/artifacts/table-artifact/table-artifact-content.constants.ts
2091
2182
  var TABLE_STATUS = {
2092
2183
  LOADING: "loading",
@@ -2099,14 +2190,10 @@ var TABLE_STATUS = {
2099
2190
  function formatCell(row, column) {
2100
2191
  return row[column.key] ?? "";
2101
2192
  }
2102
- var HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
2103
- var CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
2104
- var ROW_CLASSES = "border-b-brown-30 bg-background/70 hover:bg-secondary";
2105
- var DATA_ROW_CLASSES = `${ROW_CLASSES} animate-in fade-in duration-300`;
2106
- var SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";
2193
+ var DATA_ROW_CLASSES = `${DATA_TABLE_ROW_CLASS} animate-in fade-in duration-300`;
2107
2194
 
2108
2195
  // src/components/artifacts/table-artifact/table-artifact-content.tsx
2109
- var import_jsx_runtime21 = require("react/jsx-runtime");
2196
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2110
2197
  function TableArtifactContent({
2111
2198
  columns,
2112
2199
  data,
@@ -2116,48 +2203,367 @@ function TableArtifactContent({
2116
2203
  labels
2117
2204
  }) {
2118
2205
  if (data.status === TABLE_STATUS.ERROR) {
2119
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusMessage, { $tone: "error", children: labels.loadError });
2206
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StatusMessage, { $tone: "error", children: labels.loadError });
2120
2207
  }
2121
2208
  if (data.status === TABLE_STATUS.UNAVAILABLE) {
2122
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
2209
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
2123
2210
  }
2124
2211
  if (data.status === TABLE_STATUS.LOADING) {
2125
2212
  if (typeof knownRowCount === "number" && knownRowCount > 0) {
2126
2213
  const shimmerCount = Math.min(knownRowCount, maxShimmerRows);
2127
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ArtifactTable, { columns, maxBodyHeight, children: renderShimmerRows(columns, shimmerCount) });
2214
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTable, { columns, maxBodyHeight, children: renderShimmerRows(columns, shimmerCount) });
2128
2215
  }
2129
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusMessage, { $tone: "info", children: labels.loading });
2216
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StatusMessage, { $tone: "info", children: labels.loading });
2130
2217
  }
2131
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ArtifactTable, { columns, maxBodyHeight, children: data.rows.length === 0 ? renderEmptyRow(columns.length, labels.empty) : renderDataRows(columns, data.rows) });
2218
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTable, { columns, maxBodyHeight, children: data.rows.length === 0 ? renderEmptyRow(columns.length, labels.empty) : renderDataRows(columns, data.rows) });
2132
2219
  }
2133
2220
  function ArtifactTable({ columns, maxBodyHeight, children }) {
2134
- const { targetRef, isScrolled } = useScrollShadow();
2135
- 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: [
2136
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2137
- TableHeader,
2221
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2222
+ DataTable,
2223
+ {
2224
+ maxBodyHeight,
2225
+ header: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: column.label }, column.key)) }),
2226
+ children
2227
+ }
2228
+ );
2229
+ }
2230
+ function renderShimmerRows(columns, count) {
2231
+ return Array.from({ length: count }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableRow, { className: DATA_TABLE_ROW_CLASS, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index}`));
2232
+ }
2233
+ function renderDataRows(columns, rows) {
2234
+ return rows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index));
2235
+ }
2236
+ function renderEmptyRow(colSpan, emptyMessage) {
2237
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) });
2238
+ }
2239
+
2240
+ // src/components/artifacts/deck-artifact/deck-markdown.tsx
2241
+ var import_react_markdown = __toESM(require("react-markdown"), 1);
2242
+ var import_remark_breaks = __toESM(require("remark-breaks"), 1);
2243
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
2244
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2245
+ function sanitize(text) {
2246
+ return text.split("\n").filter((line) => {
2247
+ const t = line.trim();
2248
+ return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
2249
+ }).join("\n");
2250
+ }
2251
+ var MARKDOWN_COMPONENTS = {
2252
+ h1: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "text-[30px] font-semibold leading-tight text-foreground mb-3", ...props }),
2253
+ h2: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "text-[26px] font-semibold leading-tight text-foreground mb-2", ...props }),
2254
+ h3: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2255
+ h4: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h4", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2256
+ h5: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h5", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2257
+ h6: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h6", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2258
+ p: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[22px] leading-relaxed text-foreground my-2", ...props }),
2259
+ ul: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: "list-disc pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2260
+ ol: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ol", { className: "list-decimal pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2261
+ // react-markdown injects list metadata (`ordered` / `index` / `checked`) that must not leak to the DOM.
2262
+ li: ({ node: _node, ordered: _ordered, index: _index, checked: _checked, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { className: "my-1", ...props }),
2263
+ strong: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { className: "font-semibold", ...props }),
2264
+ em: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("em", { className: "italic", ...props }),
2265
+ // Gate `<img src>` against an http(s) allowlist. react-markdown v8 percent-encodes the URL but
2266
+ // does NOT protocol-filter image src (unlike link href), so an LLM-authored
2267
+ // `![](javascript:…)` / `![](data:…)` or a tracking-pixel `![](http://…)` would otherwise render
2268
+ // with the raw URL. Unsafe src → render nothing.
2269
+ img: ({ node: _node, src, ...props }) => typeof src === "string" && isSafeDownloadUrl(src) ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("img", { src, className: "max-w-full", ...props }) : null,
2270
+ a: ({ node: _node, ...props }) => (
2271
+ // `rel` is forced AFTER `{...props}` so it can't be overridden — if a consumer ever adds
2272
+ // `linkTarget="_blank"`, LLM-authored links still can't reach `window.opener`.
2273
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { className: "underline underline-offset-2", ...props, rel: "noopener noreferrer" })
2274
+ ),
2275
+ // react-markdown passes `inline` to distinguish inline code from fenced blocks — strip it from the DOM.
2276
+ code: ({ node: _node, inline: _inline, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("code", { className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[18px]", ...props }),
2277
+ blockquote: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("blockquote", { className: "border-l-2 border-brown-alpha-12 pl-4 text-[22px] text-muted-foreground", ...props }),
2278
+ hr: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("hr", { className: "my-4 border-brown-alpha-12", ...props }),
2279
+ table: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("table", { className: "w-full border-collapse text-[20px]", ...props }) }),
2280
+ // react-markdown passes `isHeader` to cell renderers — strip it so it never reaches the DOM.
2281
+ th: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "border-b border-brown-alpha-12 px-3 py-1.5 text-left font-medium", ...props }),
2282
+ td: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "border-b border-brown-alpha-12 px-3 py-1.5", ...props })
2283
+ };
2284
+ function DeckMarkdown({ markdown }) {
2285
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default, import_remark_breaks.default], components: MARKDOWN_COMPONENTS, children: sanitize(markdown) });
2286
+ }
2287
+
2288
+ // src/components/artifacts/deck-artifact/slide-renderers.tsx
2289
+ var import_react15 = require("react");
2290
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2291
+ function safeLogoUrl(meta) {
2292
+ return meta?.logoUrl && isSafeDownloadUrl(meta.logoUrl) ? meta.logoUrl : null;
2293
+ }
2294
+ var DESIGN_W = 1280;
2295
+ var DESIGN_H = 720;
2296
+ var EYEBROW_H = 84;
2297
+ var CANVAS_LOGO_MAX_H = 48;
2298
+ var ACCENT_FONT = { fontFamily: `"${fontFamilies.CRIMSON_PRO}", serif`, fontStyle: "italic" };
2299
+ function SlideFrame({ meta, children, accent = false, bare = false }) {
2300
+ const frameRef = (0, import_react15.useRef)(null);
2301
+ const [scale, setScale] = (0, import_react15.useState)(null);
2302
+ (0, import_react15.useLayoutEffect)(() => {
2303
+ const el = frameRef.current;
2304
+ if (!el) return;
2305
+ const apply = (width) => {
2306
+ if (width > 0) setScale(width / DESIGN_W);
2307
+ };
2308
+ apply(el.clientWidth);
2309
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.width ?? 0));
2310
+ ro.observe(el);
2311
+ return () => ro.disconnect();
2312
+ }, []);
2313
+ const bg = accent ? "bg-indigo-600" : "bg-deck-canvas";
2314
+ const eyebrowColor = accent ? "text-white/70" : "text-brown-60";
2315
+ const borderColor = accent ? "border-white/20" : "border-brown-alpha-12";
2316
+ const logoSrc = safeLogoUrl(meta);
2317
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: frameRef, className: `relative aspect-[16/9] w-full overflow-hidden rounded-lg ${bg}`, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2318
+ "div",
2319
+ {
2320
+ className: "absolute left-0 top-0 origin-top-left",
2321
+ style: {
2322
+ width: DESIGN_W,
2323
+ height: DESIGN_H,
2324
+ transform: `scale(${scale ?? 0})`,
2325
+ visibility: scale === null ? "hidden" : "visible"
2326
+ },
2327
+ children: [
2328
+ !bare ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2329
+ "div",
2330
+ {
2331
+ className: `absolute inset-x-0 top-0 flex items-center justify-between border-b px-16 ${borderColor}`,
2332
+ style: { height: EYEBROW_H },
2333
+ children: [
2334
+ meta?.eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: eyebrowColor, style: { ...ACCENT_FONT, fontSize: 22 }, children: meta.eyebrow }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", {}),
2335
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("img", { src: logoSrc, alt: "", className: "object-contain", style: { maxHeight: CANVAS_LOGO_MAX_H } }) : null
2336
+ ]
2337
+ }
2338
+ ) : null,
2339
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute inset-x-0 bottom-0 overflow-hidden", style: { top: bare ? 0 : EYEBROW_H }, children })
2340
+ ]
2341
+ }
2342
+ ) });
2343
+ }
2344
+ function TitleSlide({ slide, meta }) {
2345
+ const logoSrc = safeLogoUrl(meta);
2346
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, bare: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex h-full flex-col justify-center px-24 py-16", children: [
2347
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2348
+ "img",
2138
2349
  {
2139
- "data-scrolled": isScrolled ? "true" : void 0,
2140
- className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
2141
- style: isScrolled ? { boxShadow: SCROLL_SHADOW } : void 0,
2142
- 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)) })
2350
+ src: logoSrc,
2351
+ alt: "",
2352
+ className: "mb-16 object-contain object-left",
2353
+ style: { maxHeight: 56, maxWidth: 380 }
2354
+ }
2355
+ ) : null,
2356
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2357
+ "h1",
2358
+ {
2359
+ className: "font-bold tracking-tight text-brown-100",
2360
+ style: { fontSize: 92, lineHeight: 1.04, maxWidth: 1060 },
2361
+ children: slide.title
2143
2362
  }
2144
2363
  ),
2145
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableBody, { children })
2364
+ slide.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-7 text-brown-70", style: { ...ACCENT_FONT, fontSize: 34 }, children: slide.subtitle }) : null,
2365
+ slide.description ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-4 leading-relaxed text-brown-70", style: { fontSize: 24, maxWidth: 880 }, children: slide.description }) : null,
2366
+ meta?.date ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-10 text-brown-70", style: { ...ACCENT_FONT, fontSize: 30 }, children: meta.date }) : null
2146
2367
  ] }) });
2147
2368
  }
2148
- function renderShimmerRows(columns, count) {
2149
- 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}`));
2369
+ function AgendaSlide({ slide, meta, labels }) {
2370
+ const items = slide.items ?? [];
2371
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "h-full px-24 py-14", children: [
2372
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { className: "mb-10 font-bold text-brown-90", style: { fontSize: 40 }, children: slide.title || labels.agenda }),
2373
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex flex-col", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-baseline gap-6 border-b border-brown-alpha-12 py-5", children: [
2374
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "shrink-0 text-indigo-600", style: { ...ACCENT_FONT, fontSize: 28, width: 64 }, children: String(i + 1).padStart(2, "0") }),
2375
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-brown-90", style: { fontSize: 28 }, children: item })
2376
+ ] }, i)) })
2377
+ ] }) });
2150
2378
  }
2151
- function renderDataRows(columns, rows) {
2152
- 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));
2379
+ function SectionSlide({ slide, meta }) {
2380
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, accent: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex h-full flex-col justify-center gap-6 px-24", children: [
2381
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { className: "font-bold text-white", style: { fontSize: 72, lineHeight: 1.05, maxWidth: 940 }, children: slide.title }),
2382
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "mt-2 bg-white/50", style: { width: 96, height: 5 } })
2383
+ ] }) });
2153
2384
  }
2154
- function renderEmptyRow(colSpan, emptyMessage) {
2155
- 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 }) });
2385
+ function ClosingSlide({ meta, labels }) {
2386
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex h-full flex-col items-center justify-center gap-6 px-24 text-center", children: [
2387
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h1", { className: "font-bold text-brown-100", style: { fontSize: 72 }, children: labels.thankYou }),
2388
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-indigo-600", style: { ...ACCENT_FONT, fontSize: 36 }, children: labels.questions })
2389
+ ] }) });
2156
2390
  }
2157
2391
 
2158
- // src/components/artifacts/table-artifact/use-table-artifact-data.ts
2159
- function useTableArtifactData(presignedUrl, columns) {
2160
- return useRowsArtifactData(presignedUrl, columns, parseCsv);
2392
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
2393
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2394
+ var TABLE_BLOCK_MAX_SHIMMER_ROWS = 10;
2395
+ var TABLE_CHROME_RESERVE = 56;
2396
+ var VISUAL_FALLBACK_HEIGHT = 360;
2397
+ function DeckArtifactContent({
2398
+ slides,
2399
+ labels,
2400
+ onNavigate,
2401
+ meta,
2402
+ onDark = false,
2403
+ currentSlide,
2404
+ onSlideChange
2405
+ }) {
2406
+ const navBtnClass = onDark ? "[&_svg]:!text-white hover:!bg-white/20 disabled:opacity-40" : void 0;
2407
+ const navBtnSize = onDark ? "medium" : "small";
2408
+ const isControlled = currentSlide !== void 0;
2409
+ const [internalIndex, setInternalIndex] = (0, import_react16.useState)(0);
2410
+ const index = isControlled ? currentSlide : internalIndex;
2411
+ const current = Math.min(index, slides.length - 1);
2412
+ const slide = slides[current];
2413
+ const goTo = (0, import_react16.useCallback)(
2414
+ (next) => {
2415
+ const clamped = Math.max(0, Math.min(next, slides.length - 1));
2416
+ if (isControlled) onSlideChange?.(clamped);
2417
+ else setInternalIndex(clamped);
2418
+ onNavigate?.(clamped);
2419
+ },
2420
+ [slides.length, onNavigate, isControlled, onSlideChange]
2421
+ );
2422
+ const position = labels.position.replace("{current}", String(current + 1)).replace("{total}", String(slides.length));
2423
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 p-4", children: [
2424
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideDispatch, { slide, labels, meta }),
2425
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2426
+ "div",
2427
+ {
2428
+ className: `flex items-center justify-between border-t pt-2 ${onDark ? "border-white/20" : "border-brown-alpha-12"}`,
2429
+ children: [
2430
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2431
+ IconButton,
2432
+ {
2433
+ icon: IconChevronLeft,
2434
+ size: navBtnSize,
2435
+ className: navBtnClass,
2436
+ "aria-label": labels.previous,
2437
+ disabled: current === 0,
2438
+ onClick: () => goTo(current - 1)
2439
+ }
2440
+ ),
2441
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: `text-xs font-medium ${onDark ? "text-white/70" : "text-brown-70"}`, children: position }),
2442
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2443
+ IconButton,
2444
+ {
2445
+ icon: IconChevronRight,
2446
+ size: navBtnSize,
2447
+ className: navBtnClass,
2448
+ "aria-label": labels.next,
2449
+ disabled: current === slides.length - 1,
2450
+ onClick: () => goTo(current + 1)
2451
+ }
2452
+ )
2453
+ ]
2454
+ }
2455
+ )
2456
+ ] });
2457
+ }
2458
+ function SlideDispatch({ slide, labels, meta }) {
2459
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
2460
+ switch (kind) {
2461
+ case deckSlideKinds.TITLE:
2462
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TitleSlide, { slide, meta });
2463
+ case deckSlideKinds.AGENDA:
2464
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AgendaSlide, { slide, meta, labels });
2465
+ case deckSlideKinds.SECTION:
2466
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SectionSlide, { slide, meta });
2467
+ case deckSlideKinds.CLOSING:
2468
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ClosingSlide, { meta, labels });
2469
+ case deckSlideKinds.CONTENT:
2470
+ default:
2471
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ContentSlide, { slide, meta, labels });
2472
+ }
2473
+ }
2474
+ function isVisualBlock(block) {
2475
+ return block.type === deckBlockTypes.CHART || block.type === deckBlockTypes.TABLE;
2476
+ }
2477
+ function ContentSlide({ slide, meta, labels }) {
2478
+ const content = slide.content ?? [];
2479
+ const visuals = content.filter(isVisualBlock);
2480
+ const texts = content.filter(
2481
+ (b) => b.type === deckBlockTypes.TEXT
2482
+ );
2483
+ if (visuals.length === 1 && texts.length > 0) {
2484
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex h-full items-stretch gap-12 px-16 py-12", children: [
2485
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex w-[42%] shrink-0 flex-col overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(AutoFit, { children: [
2486
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { className: "mb-5 font-bold leading-tight text-foreground", style: { fontSize: 34 }, children: slide.title }),
2487
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2488
+ ] }) }),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FillVisual, { block: visuals[0], labels }) })
2490
+ ] }) });
2491
+ }
2492
+ if (visuals.length > 0) {
2493
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex h-full flex-col gap-5 px-16 py-10", children: [
2494
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { className: "shrink-0 font-bold leading-tight text-foreground", style: { fontSize: 32 }, children: slide.title }),
2495
+ content.map(
2496
+ (block, i) => isVisualBlock(block) ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FillVisual, { block, labels }) }, i) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "shrink-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DeckMarkdown, { markdown: block.markdown }) }, i)
2497
+ )
2498
+ ] }) });
2499
+ }
2500
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-full px-24 py-12", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(AutoFit, { children: [
2501
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { className: "mb-6 font-bold leading-tight text-foreground", style: { fontSize: 38 }, children: slide.title }),
2502
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2503
+ ] }) }) });
2504
+ }
2505
+ function AutoFit({ children }) {
2506
+ const boxRef = (0, import_react16.useRef)(null);
2507
+ const contentRef = (0, import_react16.useRef)(null);
2508
+ const [fit, setFit] = (0, import_react16.useState)({ scale: 1, height: 0 });
2509
+ (0, import_react16.useLayoutEffect)(() => {
2510
+ const boxEl = boxRef.current;
2511
+ const contentEl = contentRef.current;
2512
+ if (!boxEl || !contentEl) return;
2513
+ const measure = () => {
2514
+ const avail = boxEl.clientHeight;
2515
+ const natural = contentEl.offsetHeight;
2516
+ const scale = avail > 0 && natural > avail ? avail / natural : 1;
2517
+ setFit({ scale, height: natural * scale });
2518
+ };
2519
+ measure();
2520
+ const ro = new ResizeObserver(measure);
2521
+ ro.observe(boxEl);
2522
+ ro.observe(contentEl);
2523
+ return () => ro.disconnect();
2524
+ }, []);
2525
+ const scaled = fit.scale < 1;
2526
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref: boxRef, className: "flex h-full min-h-0 w-full flex-col justify-center overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: scaled ? { height: fit.height } : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2527
+ "div",
2528
+ {
2529
+ ref: contentRef,
2530
+ className: "w-full origin-top-left",
2531
+ style: scaled ? { transform: `scale(${fit.scale})` } : void 0,
2532
+ children
2533
+ }
2534
+ ) }) });
2535
+ }
2536
+ function FillVisual({ block, labels }) {
2537
+ const ref = (0, import_react16.useRef)(null);
2538
+ const [height, setHeight] = (0, import_react16.useState)(VISUAL_FALLBACK_HEIGHT);
2539
+ (0, import_react16.useLayoutEffect)(() => {
2540
+ const el = ref.current;
2541
+ if (!el) return;
2542
+ const apply = (h) => {
2543
+ if (h > 0) setHeight(h);
2544
+ };
2545
+ apply(el.clientHeight);
2546
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.height ?? 0));
2547
+ ro.observe(el);
2548
+ return () => ro.disconnect();
2549
+ }, []);
2550
+ const chartLabels = labels.chart ?? DEFAULT_CHART_ARTIFACT_LABELS;
2551
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref, className: "h-full min-h-0 w-full overflow-hidden", children: block.type === deckBlockTypes.CHART ? (
2552
+ // ChartArtifactContent assumes a non-empty rowset (the standalone ChartArtifact guards
2553
+ // `rows.length > 0` upstream); mirror that guard here so an empty inline chart shows the
2554
+ // localized empty status instead of a blank chart area.
2555
+ block.rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusMessage, { $tone: "info", children: chartLabels.empty }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ChartArtifactContent, { config: block.config, rows: block.rows, labels: chartLabels }) })
2556
+ ) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2557
+ TableArtifactContent,
2558
+ {
2559
+ columns: block.config.columns,
2560
+ data: { status: "ready", rows: block.rows, error: null },
2561
+ knownRowCount: block.config.stats?.rowCount ?? block.rows.length,
2562
+ maxShimmerRows: TABLE_BLOCK_MAX_SHIMMER_ROWS,
2563
+ maxBodyHeight: Math.max(0, height - TABLE_CHROME_RESERVE),
2564
+ labels: labels.table ?? DEFAULT_TABLE_ARTIFACT_LABELS
2565
+ }
2566
+ ) });
2161
2567
  }
2162
2568
 
2163
2569
  // src/components/artifacts/table-artifact/validate.ts
@@ -2176,19 +2582,265 @@ function isValidTableColumn(column) {
2176
2582
  return true;
2177
2583
  }
2178
2584
 
2179
- // src/components/artifacts/table-artifact/table-artifact.tsx
2180
- var import_jsx_runtime22 = require("react/jsx-runtime");
2585
+ // src/components/artifacts/deck-artifact/validate.ts
2586
+ function isValidDeckConfig(config) {
2587
+ if (!config || typeof config !== "object") return false;
2588
+ const candidate = config;
2589
+ if (!Array.isArray(candidate.slides)) return false;
2590
+ if (candidate.slides.length === 0) return false;
2591
+ return candidate.slides.every(isValidDeckSlide);
2592
+ }
2593
+ function isValidDeckSlide(slide) {
2594
+ if (!slide || typeof slide !== "object") return false;
2595
+ const candidate = slide;
2596
+ if (typeof candidate.title !== "string") return false;
2597
+ const kind = typeof candidate.kind === "string" ? candidate.kind : deckSlideKinds.CONTENT;
2598
+ if (kind === deckSlideKinds.CONTENT && !Array.isArray(candidate.content)) return false;
2599
+ const content = Array.isArray(candidate.content) ? candidate.content : [];
2600
+ if (candidate.items != null) {
2601
+ if (!Array.isArray(candidate.items)) return false;
2602
+ if (!candidate.items.every((item) => typeof item === "string")) return false;
2603
+ }
2604
+ return content.every(isValidDeckBlock);
2605
+ }
2606
+ function isValidDeckBlock(block) {
2607
+ if (!block || typeof block !== "object") return false;
2608
+ const candidate = block;
2609
+ switch (candidate.type) {
2610
+ case deckBlockTypes.TEXT:
2611
+ return typeof candidate.markdown === "string";
2612
+ case deckBlockTypes.CHART:
2613
+ return isValidChartConfig(candidate.config) && Array.isArray(candidate.rows);
2614
+ case deckBlockTypes.TABLE:
2615
+ return isValidTableConfig(candidate.config) && Array.isArray(candidate.rows);
2616
+ default:
2617
+ return false;
2618
+ }
2619
+ }
2620
+
2621
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
2622
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2181
2623
  var TITLE_CLASSES2 = "text-sm font-semibold text-foreground";
2624
+ function DeckArtifact({ artifact, labels, callbacks }) {
2625
+ const validConfig = isValidDeckConfig(artifact.config);
2626
+ const [isFullscreen, setIsFullscreen] = (0, import_react17.useState)(false);
2627
+ const [currentSlide, setCurrentSlide] = (0, import_react17.useState)(0);
2628
+ (0, import_react17.useEffect)(() => {
2629
+ if (validConfig) return;
2630
+ console.warn("[clay] DeckArtifact: malformed `config` \u2014 skipping render.");
2631
+ }, [validConfig]);
2632
+ (0, import_react17.useEffect)(() => {
2633
+ if (!isFullscreen) return;
2634
+ const handleKey = (e) => {
2635
+ if (e.key === "Escape") setIsFullscreen(false);
2636
+ };
2637
+ document.addEventListener("keydown", handleKey);
2638
+ const previousOverflow = document.documentElement.style.overflow;
2639
+ document.documentElement.style.overflow = "hidden";
2640
+ return () => {
2641
+ document.removeEventListener("keydown", handleKey);
2642
+ document.documentElement.style.overflow = previousOverflow;
2643
+ };
2644
+ }, [isFullscreen]);
2645
+ const resolvedLabels = (0, import_react17.useMemo)(
2646
+ () => ({
2647
+ ...DEFAULT_DECK_ARTIFACT_LABELS,
2648
+ ...labels ?? {},
2649
+ chart: { ...DEFAULT_CHART_ARTIFACT_LABELS, ...labels?.chart ?? {} },
2650
+ table: { ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels?.table ?? {} }
2651
+ }),
2652
+ [labels]
2653
+ );
2654
+ const onNavigate = callbacks?.onNavigate;
2655
+ const handleNavigate = onNavigate ? (slideIndex) => onNavigate(artifact, slideIndex) : void 0;
2656
+ const onDownload = callbacks?.onDownload;
2657
+ const handleDownload = onDownload ? () => onDownload(artifact) : void 0;
2658
+ const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
2659
+ const showDownload = presignedUrl !== null && isSafeDownloadUrl(presignedUrl);
2660
+ const meta = artifact.config?.meta;
2661
+ const handleOpenFullscreen = () => setIsFullscreen(true);
2662
+ const handleCloseFullscreen = () => setIsFullscreen(false);
2663
+ const actions = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactActions, { ...{ [CAPTURE_EXCLUDE_ATTRIBUTE]: "" }, children: [
2664
+ showDownload ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactDownloadButton, { href: presignedUrl ?? "", label: resolvedLabels.download, onClick: handleDownload }) : null,
2665
+ validConfig ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2666
+ IconButton,
2667
+ {
2668
+ icon: IconArrowsMaximize,
2669
+ size: "small",
2670
+ "aria-label": resolvedLabels.enterFullscreen,
2671
+ onClick: handleOpenFullscreen
2672
+ }
2673
+ ) : null
2674
+ ] });
2675
+ if (!validConfig) {
2676
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2677
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2678
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", {}),
2679
+ actions
2680
+ ] }),
2681
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2682
+ ] });
2683
+ }
2684
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
2685
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2686
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2687
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", {}),
2688
+ actions
2689
+ ] }),
2690
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2691
+ DeckArtifactContent,
2692
+ {
2693
+ slides: artifact.config.slides,
2694
+ labels: resolvedLabels,
2695
+ onNavigate: handleNavigate,
2696
+ meta,
2697
+ currentSlide,
2698
+ onSlideChange: setCurrentSlide
2699
+ }
2700
+ ) })
2701
+ ] }),
2702
+ isFullscreen && (0, import_react_dom.createPortal)(
2703
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2704
+ FullscreenOverlay,
2705
+ {
2706
+ artifact,
2707
+ resolvedLabels,
2708
+ onNavigate: handleNavigate,
2709
+ currentSlide,
2710
+ onSlideChange: setCurrentSlide,
2711
+ onClose: handleCloseFullscreen
2712
+ }
2713
+ ),
2714
+ document.body
2715
+ )
2716
+ ] });
2717
+ }
2718
+ function FullscreenOverlay({
2719
+ artifact,
2720
+ resolvedLabels,
2721
+ onNavigate,
2722
+ currentSlide,
2723
+ onSlideChange,
2724
+ onClose
2725
+ }) {
2726
+ const meta = artifact.config?.meta;
2727
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2728
+ "div",
2729
+ {
2730
+ className: "fixed inset-0 z-[2147483647] flex items-center justify-center bg-black/80",
2731
+ role: "dialog",
2732
+ "aria-modal": "true",
2733
+ "aria-label": resolvedLabels.exitFullscreen,
2734
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "relative", style: { width: "min(94vw, calc(82vh * 16 / 9))" }, children: [
2735
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2736
+ DeckArtifactContent,
2737
+ {
2738
+ slides: artifact.config.slides,
2739
+ labels: resolvedLabels,
2740
+ onNavigate,
2741
+ meta,
2742
+ currentSlide,
2743
+ onSlideChange,
2744
+ onDark: true
2745
+ }
2746
+ ),
2747
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
2748
+ "button",
2749
+ {
2750
+ className: "absolute -top-10 right-6 flex items-center gap-1.5 text-sm text-white/80 hover:text-white",
2751
+ "aria-label": resolvedLabels.exitFullscreen,
2752
+ onClick: onClose,
2753
+ children: [
2754
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(IconArrowsMinimize, { size: 16 }),
2755
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: resolvedLabels.exitFullscreen })
2756
+ ]
2757
+ }
2758
+ )
2759
+ ] })
2760
+ }
2761
+ );
2762
+ }
2763
+
2764
+ // src/components/artifacts/deck-artifact/to-clipboard-text.ts
2765
+ function deckArtifactToClipboardText(artifact) {
2766
+ const header = artifact.title?.trim() || "Deck";
2767
+ const slides = artifact.config?.slides ?? [];
2768
+ const body = slides.map((slide, i) => slideToText(slide, i)).join("\n\n");
2769
+ return body ? `${header}
2770
+
2771
+ ${body}` : header;
2772
+ }
2773
+ function slideToText(slide, index) {
2774
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
2775
+ const prefix = `Slide ${index + 1}: `;
2776
+ switch (kind) {
2777
+ case deckSlideKinds.TITLE: {
2778
+ const parts = [slide.title];
2779
+ if (slide.subtitle) parts.push(slide.subtitle);
2780
+ if (slide.description) parts.push(slide.description);
2781
+ return `${prefix}${parts.join(" \u2014 ")}`.trim();
2782
+ }
2783
+ case deckSlideKinds.AGENDA: {
2784
+ const items = (slide.items ?? []).map((item, i) => ` ${String(i + 1).padStart(2, "0")}. ${item}`).join("\n");
2785
+ return `${prefix}${slide.title || "Agenda"}${items ? `
2786
+ ${items}` : ""}`.trim();
2787
+ }
2788
+ case deckSlideKinds.SECTION:
2789
+ return `${prefix}${slide.title}`.trim();
2790
+ case deckSlideKinds.CLOSING:
2791
+ return `${prefix}Thank you`.trim();
2792
+ case deckSlideKinds.CONTENT:
2793
+ default: {
2794
+ const blocks = (slide.content ?? []).map(blockToText).filter(Boolean).join("\n\n");
2795
+ return `${prefix}${slide.title}${blocks ? `
2796
+ ${blocks}` : ""}`.trim();
2797
+ }
2798
+ }
2799
+ }
2800
+ function blockToText(block) {
2801
+ switch (block.type) {
2802
+ case deckBlockTypes.TEXT:
2803
+ return block.markdown.trim();
2804
+ case deckBlockTypes.CHART:
2805
+ return `[Chart: ${block.config.variant}]`;
2806
+ case deckBlockTypes.TABLE: {
2807
+ const columnCount = block.config.columns.length;
2808
+ const rowCount = block.rows.length;
2809
+ return `[Table: ${columnCount} column${columnCount === 1 ? "" : "s"} \xD7 ${rowCount} row${rowCount === 1 ? "" : "s"}]`;
2810
+ }
2811
+ default:
2812
+ return "";
2813
+ }
2814
+ }
2815
+
2816
+ // src/components/artifacts/artifact-services/deck-artifact-service.ts
2817
+ var DeckArtifactService = {
2818
+ type: artifactTypes.DECK,
2819
+ Component: DeckArtifact,
2820
+ toClipboardText: deckArtifactToClipboardText
2821
+ };
2822
+
2823
+ // src/components/artifacts/table-artifact/table-artifact.tsx
2824
+ var import_react18 = require("react");
2825
+
2826
+ // src/components/artifacts/table-artifact/use-table-artifact-data.ts
2827
+ function useTableArtifactData(presignedUrl, columns) {
2828
+ return useRowsArtifactData(presignedUrl, columns, parseCsv);
2829
+ }
2830
+
2831
+ // src/components/artifacts/table-artifact/table-artifact.tsx
2832
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2833
+ var TITLE_CLASSES3 = "text-sm font-semibold text-foreground";
2182
2834
  var TABLE_MAX_BODY_HEIGHT = 480;
2183
2835
  var MAX_SHIMMER_ROWS = 10;
2184
2836
  function TableArtifact({ artifact, labels, callbacks }) {
2185
2837
  const validConfig = isValidTableConfig(artifact.config);
2186
2838
  const validColumns = validConfig ? artifact.config.columns : null;
2187
- (0, import_react15.useEffect)(() => {
2839
+ (0, import_react18.useEffect)(() => {
2188
2840
  if (validConfig) return;
2189
2841
  console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
2190
2842
  }, [validConfig]);
2191
- const resolvedLabels = (0, import_react15.useMemo)(
2843
+ const resolvedLabels = (0, import_react18.useMemo)(
2192
2844
  () => ({ ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels ?? {} }),
2193
2845
  [labels]
2194
2846
  );
@@ -2200,10 +2852,10 @@ function TableArtifact({ artifact, labels, callbacks }) {
2200
2852
  const onDownload = callbacks?.onDownload;
2201
2853
  const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
2202
2854
  if (!validConfig || !validColumns) {
2203
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2204
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2205
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
2206
- presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2855
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2856
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2857
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", {}),
2858
+ presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2207
2859
  ArtifactDownloadButton,
2208
2860
  {
2209
2861
  href: presignedUrl,
@@ -2212,17 +2864,17 @@ function TableArtifact({ artifact, labels, callbacks }) {
2212
2864
  }
2213
2865
  ) }) : null
2214
2866
  ] }),
2215
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2867
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2216
2868
  ] });
2217
2869
  }
2218
2870
  return (
2219
2871
  // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
2220
2872
  // Disable the outer overflow container so only one scroll context exists — this prevents
2221
2873
  // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
2222
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2223
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2224
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
2225
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2874
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2875
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2876
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", {}),
2877
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2226
2878
  ArtifactDownloadButton,
2227
2879
  {
2228
2880
  href: presignedUrl ?? "",
@@ -2231,7 +2883,7 @@ function TableArtifact({ artifact, labels, callbacks }) {
2231
2883
  }
2232
2884
  ) })
2233
2885
  ] }),
2234
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2886
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2235
2887
  TableArtifactContent,
2236
2888
  {
2237
2889
  columns: validColumns,
@@ -2262,7 +2914,8 @@ var TableArtifactService = {
2262
2914
  // src/components/artifacts/artifact-services/index.ts
2263
2915
  var ArtifactServices = {
2264
2916
  [artifactTypes.TABLE]: TableArtifactService,
2265
- [artifactTypes.CHART]: ChartArtifactService
2917
+ [artifactTypes.CHART]: ChartArtifactService,
2918
+ [artifactTypes.DECK]: DeckArtifactService
2266
2919
  };
2267
2920
  function artifactToClipboardText(artifact) {
2268
2921
  const entry = ArtifactServices[artifact.type];
@@ -2273,13 +2926,13 @@ function artifactToClipboardText(artifact) {
2273
2926
  }
2274
2927
 
2275
2928
  // src/components/blocks/artifact-ref-block/artifact-ref-block.tsx
2276
- var import_jsx_runtime23 = require("react/jsx-runtime");
2929
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2277
2930
  function ArtifactRefBlock({ block }) {
2278
2931
  const { artifact, labels, callbacks } = block.payload;
2279
2932
  const entry = ArtifactServices[artifact.type];
2280
2933
  if (!entry) return null;
2281
2934
  const Component = entry.Component;
2282
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Component, { artifact, labels, callbacks });
2935
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Component, { artifact, labels, callbacks });
2283
2936
  }
2284
2937
 
2285
2938
  // src/components/blocks/block-services/artifact-ref-block-service.ts
@@ -2294,29 +2947,102 @@ var ArtifactRefBlockService = {
2294
2947
  toClipboardText: (block) => artifactToClipboardText(block.payload.artifact)
2295
2948
  };
2296
2949
 
2297
- // src/utils/markdown-to-plain-text.ts
2298
- var PLACEHOLDER_PREFIX = "\u200B\u200BIC";
2299
- var PLACEHOLDER_SUFFIX = "\u200B\u200B";
2300
- var PLACEHOLDER_REGEX = new RegExp(`${PLACEHOLDER_PREFIX}(\\d+)${PLACEHOLDER_SUFFIX}`, "g");
2301
- function stripInlineMarks(text) {
2302
- 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");
2950
+ // src/components/blocks/notification-draft-block/notification-draft-block.tsx
2951
+ var import_react20 = require("react");
2952
+
2953
+ // src/components/badge/badge.tsx
2954
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2955
+ var BASE = "inline-flex items-center whitespace-nowrap rounded-full";
2956
+ var SIZES = {
2957
+ // `sm` is a uniform scale-down of `md` (text 10/12 of caption): padding and line-height keep
2958
+ // md's proportions (caption is 12px text on a 16px line = 1.333 ratio) so the pill shape matches.
2959
+ md: "px-2.5 py-0.5 text-geist-label-caption-medium",
2960
+ sm: "px-2 py-0.5 text-[11px]/[1.333] font-medium"
2961
+ };
2962
+ var SUBTLE = {
2963
+ neutral: "bg-brown-20 text-brown-70",
2964
+ warning: "bg-orange-50 text-orange-600",
2965
+ violet: "bg-violet-50 text-violet-600"
2966
+ };
2967
+ var OUTLINE = {
2968
+ neutral: "border border-brown-30 bg-white text-brown-100",
2969
+ warning: "border border-orange-200 bg-white text-orange-600",
2970
+ violet: "border border-violet-400 bg-white text-violet-600"
2971
+ };
2972
+ var VARIANTS = {
2973
+ subtle: SUBTLE,
2974
+ outline: OUTLINE
2975
+ };
2976
+ function Badge({
2977
+ variant = "subtle",
2978
+ tone = "neutral",
2979
+ size = "md",
2980
+ className,
2981
+ children
2982
+ }) {
2983
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn(BASE, SIZES[size], VARIANTS[variant][tone], className), children });
2303
2984
  }
2304
- function markdownToPlainText(markdown) {
2305
- if (!markdown) return "";
2306
- const inlineCodeSnippets = [];
2307
- let result = markdown.replace(/^<!--[\s\S]*?--!?>\n?/gm, "").replace(/```[\s\S]*?```/g, "").replace(/`([^`]+)`/g, (_match, code) => {
2308
- inlineCodeSnippets.push(code);
2309
- return `${PLACEHOLDER_PREFIX}${inlineCodeSnippets.length - 1}${PLACEHOLDER_SUFFIX}`;
2310
- }).replace(/^#{1,6}\s+/gm, "").replace(/^(?:---|\*\*\*|___)\s*$/gm, "");
2311
- 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();
2312
- result = result.replace(PLACEHOLDER_REGEX, (_match, index) => inlineCodeSnippets[Number(index)]);
2313
- return result;
2985
+
2986
+ // src/components/chat/hooks/use-copy-to-clipboard.ts
2987
+ var import_react19 = require("react");
2988
+
2989
+ // src/utils/clipboard.ts
2990
+ function copyToClipboard(text, options) {
2991
+ navigator.clipboard.writeText(text).then(
2992
+ () => options?.onSuccess?.(),
2993
+ (error) => options?.onFailure?.(error)
2994
+ );
2314
2995
  }
2315
2996
 
2316
- // src/components/blocks/text-block/text-block.tsx
2317
- var import_react_markdown = __toESM(require("react-markdown"), 1);
2318
- var import_remark_breaks = __toESM(require("remark-breaks"), 1);
2319
- var import_remark_gfm = __toESM(require("remark-gfm"), 1);
2997
+ // src/components/chat/hooks/use-copy-to-clipboard.ts
2998
+ var RESET_DELAY_MS = 2e3;
2999
+ function useCopyToClipboard() {
3000
+ const [isCopied, setIsCopied] = (0, import_react19.useState)(false);
3001
+ const timeoutRef = (0, import_react19.useRef)(null);
3002
+ (0, import_react19.useEffect)(() => {
3003
+ return () => {
3004
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
3005
+ };
3006
+ }, []);
3007
+ const copy = (0, import_react19.useCallback)((text) => {
3008
+ copyToClipboard(text, {
3009
+ onSuccess: () => {
3010
+ setIsCopied(true);
3011
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
3012
+ timeoutRef.current = setTimeout(() => {
3013
+ setIsCopied(false);
3014
+ timeoutRef.current = null;
3015
+ }, RESET_DELAY_MS);
3016
+ }
3017
+ });
3018
+ }, []);
3019
+ return { isCopied, copy };
3020
+ }
3021
+
3022
+ // src/components/copy-button/copy-button.tsx
3023
+ var import_jsx_runtime30 = require("react/jsx-runtime");
3024
+ function CopyButton({
3025
+ text,
3026
+ copyLabel = "Copy",
3027
+ copiedLabel = "Copied",
3028
+ className
3029
+ }) {
3030
+ const { isCopied, copy } = useCopyToClipboard();
3031
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3032
+ IconButton,
3033
+ {
3034
+ icon: isCopied ? IconCheck : IconCopy,
3035
+ onClick: () => copy(text),
3036
+ "aria-label": isCopied ? copiedLabel : copyLabel,
3037
+ className
3038
+ }
3039
+ );
3040
+ }
3041
+
3042
+ // src/components/blocks/markdown/markdown.tsx
3043
+ var import_react_markdown2 = __toESM(require("react-markdown"), 1);
3044
+ var import_remark_breaks2 = __toESM(require("remark-breaks"), 1);
3045
+ var import_remark_gfm2 = __toESM(require("remark-gfm"), 1);
2320
3046
 
2321
3047
  // src/components/blocks/scrollable-table/scrollable-table-styles.ts
2322
3048
  var import_styled_components3 = __toESM(require("styled-components"), 1);
@@ -2331,13 +3057,13 @@ var TableScroll = import_styled_components3.default.div`
2331
3057
  `;
2332
3058
 
2333
3059
  // src/components/blocks/scrollable-table/scrollable-table.tsx
2334
- var import_jsx_runtime24 = require("react/jsx-runtime");
3060
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2335
3061
  function ScrollableTable({ node: _node, ...props }) {
2336
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TableContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TableScroll, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("table", { ...props }) }) });
3062
+ 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 }) }) });
2337
3063
  }
2338
3064
 
2339
3065
  // src/components/blocks/text-block/sanitize.ts
2340
- function sanitize(text) {
3066
+ function sanitize2(text) {
2341
3067
  return text.split("\n").filter((line) => {
2342
3068
  const t = line.trim();
2343
3069
  return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
@@ -2476,13 +3202,151 @@ var TextBlockWrapper = import_styled_components4.default.div`
2476
3202
  }
2477
3203
  `;
2478
3204
 
2479
- // src/components/blocks/text-block/text-block.tsx
2480
- var import_jsx_runtime25 = require("react/jsx-runtime");
3205
+ // src/components/blocks/markdown/markdown.tsx
3206
+ var import_jsx_runtime32 = require("react/jsx-runtime");
2481
3207
  var markdownComponents = {
2482
- table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScrollableTable, { ...tableProps }))
3208
+ table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ScrollableTable, { ...tableProps }))
3209
+ };
3210
+ function Markdown({ children }) {
3211
+ 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) }) });
3212
+ }
3213
+
3214
+ // src/utils/markdown-to-plain-text.ts
3215
+ var PLACEHOLDER_PREFIX = "\u200B\u200BIC";
3216
+ var PLACEHOLDER_SUFFIX = "\u200B\u200B";
3217
+ var PLACEHOLDER_REGEX = new RegExp(`${PLACEHOLDER_PREFIX}(\\d+)${PLACEHOLDER_SUFFIX}`, "g");
3218
+ function stripInlineMarks(text) {
3219
+ 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");
3220
+ }
3221
+ function markdownToPlainText(markdown) {
3222
+ if (!markdown) return "";
3223
+ const inlineCodeSnippets = [];
3224
+ let result = markdown.replace(/^<!--[\s\S]*?--!?>\n?/gm, "").replace(/```[\s\S]*?```/g, "").replace(/`([^`]+)`/g, (_match, code) => {
3225
+ inlineCodeSnippets.push(code);
3226
+ return `${PLACEHOLDER_PREFIX}${inlineCodeSnippets.length - 1}${PLACEHOLDER_SUFFIX}`;
3227
+ }).replace(/^#{1,6}\s+/gm, "").replace(/^(?:---|\*\*\*|___)\s*$/gm, "");
3228
+ 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();
3229
+ result = result.replace(PLACEHOLDER_REGEX, (_match, index) => inlineCodeSnippets[Number(index)]);
3230
+ return result;
3231
+ }
3232
+
3233
+ // src/components/blocks/notification-draft-block/types.ts
3234
+ var notificationChannels = {
3235
+ /** Branded email — renders a From/subject header. */
3236
+ EMAIL: "email",
3237
+ /** Slack DM — renders as a chat bubble, no subject. */
3238
+ SLACK: "slack",
3239
+ /** Microsoft Teams DM — renders as a chat bubble, no subject. */
3240
+ TEAMS: "teams"
2483
3241
  };
3242
+
3243
+ // src/components/blocks/notification-draft-block/to-text.ts
3244
+ function notificationDraftToText(payload) {
3245
+ const { channel, subject, body } = payload;
3246
+ const text = markdownToPlainText(body);
3247
+ return channel === notificationChannels.EMAIL && subject ? `${subject}
3248
+
3249
+ ${text}` : text;
3250
+ }
3251
+
3252
+ // src/components/blocks/notification-draft-block/notification-draft-block.tsx
3253
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3254
+ var CHIP_LIMIT = 3;
3255
+ var RECIPIENTS_MAX_HEIGHT = 320;
3256
+ function chipLabel(recipient) {
3257
+ return recipient.name ?? recipient.email ?? recipient.employeeId;
3258
+ }
3259
+ function channelCellText(recipient) {
3260
+ return recipient.fallback ? `${recipient.channelLabel} (fallback)` : recipient.channelLabel;
3261
+ }
3262
+ function FieldLabel({ children }) {
3263
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-geist-label-caption-medium tracking-wide text-brown-60", children });
3264
+ }
3265
+ function RecipientChips({ recipients }) {
3266
+ const shown = recipients.slice(0, CHIP_LIMIT);
3267
+ const overflow = recipients.length - shown.length;
3268
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", children: [
3269
+ shown.map((recipient) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { variant: "outline", children: chipLabel(recipient) }, recipient.employeeId)),
3270
+ overflow > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { variant: "subtle", children: `+${overflow}` })
3271
+ ] });
3272
+ }
3273
+ function RecipientsTable({ recipients }) {
3274
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3275
+ DataTable,
3276
+ {
3277
+ maxBodyHeight: RECIPIENTS_MAX_HEIGHT,
3278
+ header: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TableRow, { className: "hover:bg-transparent", children: [
3279
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: "Name" }),
3280
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: "Email" }),
3281
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: "Channel" })
3282
+ ] }),
3283
+ children: recipients.map((recipient) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TableRow, { className: DATA_TABLE_ROW_CLASS, children: [
3284
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: recipient.name ?? "\u2014" }),
3285
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableCell, { className: DATA_TABLE_CELL_CLASS, children: recipient.email ?? "\u2014" }),
3286
+ /* @__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) }) })
3287
+ ] }, recipient.employeeId))
3288
+ }
3289
+ );
3290
+ }
3291
+ function NotificationDraftBlock({ block }) {
3292
+ const { channel, subject, body, recipients } = block.payload;
3293
+ const [detailsOpen, setDetailsOpen] = (0, import_react20.useState)(false);
3294
+ const showSubject = channel === notificationChannels.EMAIL && subject;
3295
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "overflow-hidden rounded-2xl border border-brown-30 bg-white", children: [
3296
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-3 border-b border-brown-30 px-4 py-3", children: [
3297
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
3298
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center gap-2", children: [
3299
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-geist-body-s-semi-bold text-brown-100", children: "Notification draft" }),
3300
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Badge, { tone: "violet", variant: "subtle", size: "sm", className: "gap-1 py-1", children: [
3301
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { icon: IconFlask2Filled, size: 12 }),
3302
+ "Labs"
3303
+ ] })
3304
+ ] }),
3305
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CopyButton, { text: notificationDraftToText(block.payload), copyLabel: "Copy draft", copiedLabel: "Copied" })
3306
+ ] }),
3307
+ showSubject && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
3308
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldLabel, { children: "Title" }),
3309
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-geist-body-s-medium text-brown-100", children: subject })
3310
+ ] }),
3311
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-1", children: [
3312
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
3313
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldLabel, { children: `Recipients (${recipients.length})` }),
3314
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
3315
+ "button",
3316
+ {
3317
+ type: "button",
3318
+ "aria-expanded": detailsOpen,
3319
+ onClick: () => setDetailsOpen((open) => !open),
3320
+ className: "inline-flex items-center gap-1 text-geist-label-caption-medium text-brown-70 transition-colors hover:text-brown-100",
3321
+ children: [
3322
+ "Details",
3323
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { icon: IconChevronDown, size: 14, className: detailsOpen ? "rotate-180" : void 0 })
3324
+ ]
3325
+ }
3326
+ )
3327
+ ] }),
3328
+ detailsOpen ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(RecipientsTable, { recipients }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(RecipientChips, { recipients })
3329
+ ] })
3330
+ ] }),
3331
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Markdown, { children: body }) })
3332
+ ] });
3333
+ }
3334
+
3335
+ // src/components/blocks/block-services/notification-draft-block-service.ts
3336
+ var NotificationDraftBlockService = {
3337
+ type: blockTypes.NOTIFICATION_DRAFT,
3338
+ Component: NotificationDraftBlock,
3339
+ /**
3340
+ * Plain-text clipboard form of the drafted notification — shared with the in-block copy button
3341
+ * via {@link notificationDraftToText} so both copy the same text.
3342
+ */
3343
+ toClipboardText: (block) => notificationDraftToText(block.payload)
3344
+ };
3345
+
3346
+ // src/components/blocks/text-block/text-block.tsx
3347
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2484
3348
  function TextBlock({ block }) {
2485
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TextBlockWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default, import_remark_breaks.default], components: markdownComponents, children: sanitize(block.payload.text) }) });
3349
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Markdown, { children: block.payload.text });
2486
3350
  }
2487
3351
 
2488
3352
  // src/components/blocks/block-services/text-block-service.ts
@@ -2500,16 +3364,17 @@ var TextBlockService = {
2500
3364
  // src/components/blocks/block-services/index.ts
2501
3365
  var BlockServices = {
2502
3366
  [blockTypes.TEXT]: TextBlockService,
2503
- [blockTypes.ARTIFACT_REF]: ArtifactRefBlockService
3367
+ [blockTypes.ARTIFACT_REF]: ArtifactRefBlockService,
3368
+ [blockTypes.NOTIFICATION_DRAFT]: NotificationDraftBlockService
2504
3369
  };
2505
3370
 
2506
3371
  // src/components/blocks/block/block.tsx
2507
- var import_jsx_runtime26 = require("react/jsx-runtime");
3372
+ var import_jsx_runtime35 = require("react/jsx-runtime");
2508
3373
  function Block({ block }) {
2509
3374
  const service = BlockServices[block.type];
2510
3375
  if (!service) return null;
2511
3376
  const { Component } = service;
2512
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Component, { block });
3377
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Component, { block });
2513
3378
  }
2514
3379
 
2515
3380
  // src/components/chat/hooks/copy-message-text.ts
@@ -2527,55 +3392,19 @@ function copyMessageText(message) {
2527
3392
  }
2528
3393
 
2529
3394
  // src/components/chat/chat-message-actions/chat-message-actions.tsx
2530
- var import_react18 = require("react");
3395
+ var import_react22 = require("react");
2531
3396
 
2532
3397
  // src/components/chat/chat-context/chat-context.ts
2533
- var import_react16 = require("react");
2534
- var ChatContext = (0, import_react16.createContext)(null);
3398
+ var import_react21 = require("react");
3399
+ var ChatContext = (0, import_react21.createContext)(null);
2535
3400
  function useChatContext() {
2536
- const context = (0, import_react16.useContext)(ChatContext);
3401
+ const context = (0, import_react21.useContext)(ChatContext);
2537
3402
  if (!context) {
2538
3403
  throw new Error("useChatContext must be used within a Chat.Root component");
2539
3404
  }
2540
3405
  return context;
2541
3406
  }
2542
3407
 
2543
- // src/components/chat/hooks/use-copy-to-clipboard.ts
2544
- var import_react17 = require("react");
2545
-
2546
- // src/utils/clipboard.ts
2547
- function copyToClipboard(text, options) {
2548
- navigator.clipboard.writeText(text).then(
2549
- () => options?.onSuccess?.(),
2550
- (error) => options?.onFailure?.(error)
2551
- );
2552
- }
2553
-
2554
- // src/components/chat/hooks/use-copy-to-clipboard.ts
2555
- var RESET_DELAY_MS = 2e3;
2556
- function useCopyToClipboard() {
2557
- const [isCopied, setIsCopied] = (0, import_react17.useState)(false);
2558
- const timeoutRef = (0, import_react17.useRef)(null);
2559
- (0, import_react17.useEffect)(() => {
2560
- return () => {
2561
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
2562
- };
2563
- }, []);
2564
- const copy = (0, import_react17.useCallback)((text) => {
2565
- copyToClipboard(text, {
2566
- onSuccess: () => {
2567
- setIsCopied(true);
2568
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
2569
- timeoutRef.current = setTimeout(() => {
2570
- setIsCopied(false);
2571
- timeoutRef.current = null;
2572
- }, RESET_DELAY_MS);
2573
- }
2574
- });
2575
- }, []);
2576
- return { isCopied, copy };
2577
- }
2578
-
2579
3408
  // src/components/chat/constants.ts
2580
3409
  var MESSAGE_ROLE = {
2581
3410
  USER: "user",
@@ -2601,24 +3430,24 @@ var AnimatedAction = import_styled_components5.default.div`
2601
3430
  `;
2602
3431
 
2603
3432
  // src/components/chat/chat-message-actions/chat-message-actions.tsx
2604
- var import_jsx_runtime27 = require("react/jsx-runtime");
3433
+ var import_jsx_runtime36 = require("react/jsx-runtime");
2605
3434
  function ChatMessageActions({ className, messageId, content, role, isHelpful }) {
2606
3435
  const { onCopyMessage, onThumbUpClick, onThumbDownClick } = useChatContext();
2607
3436
  const { isCopied, copy } = useCopyToClipboard();
2608
- const handleCopy = (0, import_react18.useCallback)(() => {
3437
+ const handleCopy = (0, import_react22.useCallback)(() => {
2609
3438
  copy(content);
2610
3439
  onCopyMessage?.(messageId);
2611
3440
  }, [content, messageId, copy, onCopyMessage]);
2612
- const handleThumbUp = (0, import_react18.useCallback)(() => {
3441
+ const handleThumbUp = (0, import_react22.useCallback)(() => {
2613
3442
  onThumbUpClick?.(messageId, isHelpful === true ? null : true);
2614
3443
  }, [messageId, isHelpful, onThumbUpClick]);
2615
- const handleThumbDown = (0, import_react18.useCallback)(() => {
3444
+ const handleThumbDown = (0, import_react22.useCallback)(() => {
2616
3445
  onThumbDownClick?.(messageId, isHelpful === false ? null : false);
2617
3446
  }, [messageId, isHelpful, onThumbDownClick]);
2618
3447
  const isAssistant = role === MESSAGE_ROLE.ASSISTANT;
2619
3448
  const hasFeedback = isAssistant && (onThumbUpClick || onThumbDownClick);
2620
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(ActionsContainer, { $role: role, className, children: [
2621
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3449
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(ActionsContainer, { $role: role, className, children: [
3450
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2622
3451
  IconButton,
2623
3452
  {
2624
3453
  icon: isCopied ? IconCheck : IconCopy,
@@ -2626,7 +3455,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
2626
3455
  "aria-label": isCopied ? "Copied" : "Copy message"
2627
3456
  }
2628
3457
  ),
2629
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3458
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2630
3459
  IconButton,
2631
3460
  {
2632
3461
  icon: IconThumbUp,
@@ -2635,7 +3464,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
2635
3464
  "aria-label": "Good response"
2636
3465
  }
2637
3466
  ) }),
2638
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3467
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2639
3468
  IconButton,
2640
3469
  {
2641
3470
  icon: IconThumbDown,
@@ -2686,12 +3515,12 @@ var MessageBubble = import_styled_components6.default.div`
2686
3515
  `;
2687
3516
 
2688
3517
  // src/components/chat/chat-message/chat-message.tsx
2689
- var import_jsx_runtime28 = require("react/jsx-runtime");
3518
+ var import_jsx_runtime37 = require("react/jsx-runtime");
2690
3519
  function ChatMessage({ message }) {
2691
- const clipboardText = (0, import_react19.useMemo)(() => copyMessageText(message), [message]);
2692
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(MessageContainer, { $role: message.role, children: [
2693
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MessageBubble, { $role: message.role, "data-testid": "message-bubble", children: message.blocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Block, { block }, index)) }),
2694
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3520
+ const clipboardText = (0, import_react23.useMemo)(() => copyMessageText(message), [message]);
3521
+ 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: [
3522
+ /* @__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)) }),
3523
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2695
3524
  ChatMessageActions,
2696
3525
  {
2697
3526
  messageId: message.id,
@@ -2716,7 +3545,12 @@ function ChatMessage({ message }) {
2716
3545
  @tabler/icons-react/dist/esm/defaultAttributes.mjs:
2717
3546
  @tabler/icons-react/dist/esm/createReactComponent.mjs:
2718
3547
  @tabler/icons-react/dist/esm/icons/IconAlertCircle.mjs:
3548
+ @tabler/icons-react/dist/esm/icons/IconArrowsMaximize.mjs:
3549
+ @tabler/icons-react/dist/esm/icons/IconArrowsMinimize.mjs:
2719
3550
  @tabler/icons-react/dist/esm/icons/IconCheck.mjs:
3551
+ @tabler/icons-react/dist/esm/icons/IconChevronDown.mjs:
3552
+ @tabler/icons-react/dist/esm/icons/IconChevronLeft.mjs:
3553
+ @tabler/icons-react/dist/esm/icons/IconChevronRight.mjs:
2720
3554
  @tabler/icons-react/dist/esm/icons/IconCopy.mjs:
2721
3555
  @tabler/icons-react/dist/esm/icons/IconDownload.mjs:
2722
3556
  @tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs:
@@ -2724,6 +3558,7 @@ function ChatMessage({ message }) {
2724
3558
  @tabler/icons-react/dist/esm/icons/IconPhoto.mjs:
2725
3559
  @tabler/icons-react/dist/esm/icons/IconThumbDown.mjs:
2726
3560
  @tabler/icons-react/dist/esm/icons/IconThumbUp.mjs:
3561
+ @tabler/icons-react/dist/esm/icons/IconFlask2Filled.mjs:
2727
3562
  @tabler/icons-react/dist/esm/tabler-icons-react.mjs:
2728
3563
  (**
2729
3564
  * @license @tabler/icons-react v3.37.1 - MIT