@shapesos/clay 0.16.0 → 0.18.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 (83) 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 +976 -69
  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 +13 -5
  9. package/dist/blocks.cjs +690 -85
  10. package/dist/blocks.cjs.map +1 -1
  11. package/dist/blocks.css +1 -1
  12. package/dist/blocks.d.cts +3 -3
  13. package/dist/blocks.d.ts +3 -3
  14. package/dist/blocks.js +5 -5
  15. package/dist/button.cjs +3 -1
  16. package/dist/button.cjs.map +1 -1
  17. package/dist/button.js +2 -2
  18. package/dist/capture.cjs +3 -1
  19. package/dist/capture.cjs.map +1 -1
  20. package/dist/capture.js +2 -2
  21. package/dist/chart.cjs +16 -36
  22. package/dist/chart.cjs.map +1 -1
  23. package/dist/chart.d.cts +3 -11
  24. package/dist/chart.d.ts +3 -11
  25. package/dist/chart.js +2 -2
  26. package/dist/chat.cjs +714 -109
  27. package/dist/chat.cjs.map +1 -1
  28. package/dist/chat.d.cts +2 -2
  29. package/dist/chat.d.ts +2 -2
  30. package/dist/chat.js +6 -6
  31. package/dist/{chunk-UZKNSAAD.js → chunk-7MY4X4YL.js} +3 -3
  32. package/dist/chunk-BHHJOG5X.js +1 -0
  33. package/dist/{chunk-GAZRZZRF.js → chunk-CATIRDZP.js} +5 -5
  34. package/dist/{chunk-B4U37WIH.js → chunk-CFCLVJIO.js} +2 -2
  35. package/dist/{chunk-PYDVANWI.js → chunk-E36VI2HA.js} +2 -2
  36. package/dist/{chunk-U3IXCSV6.js → chunk-G4NXVFXU.js} +18 -40
  37. package/dist/chunk-G4NXVFXU.js.map +1 -0
  38. package/dist/{chunk-JAGNXEWK.js → chunk-GK4XW4BC.js} +2 -2
  39. package/dist/{chunk-4VE6ZXXW.js → chunk-MQP57DOP.js} +3 -3
  40. package/dist/{chunk-2YCBDSPK.js → chunk-QR4VBGK4.js} +673 -42
  41. package/dist/chunk-QR4VBGK4.js.map +1 -0
  42. package/dist/{chunk-JF3P66JF.js → chunk-SN3ORQSJ.js} +4 -2
  43. package/dist/{chunk-JF3P66JF.js.map → chunk-SN3ORQSJ.js.map} +1 -1
  44. package/dist/{chunk-PGR2MDDU.js → chunk-W66OJM55.js} +2 -2
  45. package/dist/{chunk-7OYIDM42.js → chunk-XKURJ72I.js} +2 -2
  46. package/dist/{dom-to-image-NATF3446.js → dom-to-image-QB7KMTAE.js} +3 -3
  47. package/dist/icon.cjs +3 -1
  48. package/dist/icon.cjs.map +1 -1
  49. package/dist/icon.js +2 -2
  50. package/dist/index.cjs +780 -167
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +3 -3
  53. package/dist/index.d.ts +3 -3
  54. package/dist/index.js +19 -11
  55. package/dist/keyboard-shortcut.cjs +3 -1
  56. package/dist/keyboard-shortcut.cjs.map +1 -1
  57. package/dist/keyboard-shortcut.js +2 -2
  58. package/dist/text-area.cjs +3 -1
  59. package/dist/text-area.cjs.map +1 -1
  60. package/dist/text-area.js +2 -2
  61. package/dist/tokens.cjs +3 -1
  62. package/dist/tokens.cjs.map +1 -1
  63. package/dist/tokens.d.cts +1 -0
  64. package/dist/tokens.d.ts +1 -0
  65. package/dist/tokens.js +1 -1
  66. package/dist/{types-CW45GBXl.d.cts → types-BDYPVP2N.d.cts} +1 -1
  67. package/dist/{types-D1b8v7EY.d.ts → types-BMwa4bPW.d.ts} +1 -1
  68. package/dist/{types-GCkXbyFm.d.ts → types-C8JtnwNY.d.ts} +200 -4
  69. package/dist/{types-BzXPBy6s.d.cts → types-DTdDFU3O.d.cts} +200 -4
  70. package/package.json +1 -1
  71. package/dist/chunk-2YCBDSPK.js.map +0 -1
  72. package/dist/chunk-RSRNSWJN.js +0 -1
  73. package/dist/chunk-U3IXCSV6.js.map +0 -1
  74. /package/dist/{chunk-UZKNSAAD.js.map → chunk-7MY4X4YL.js.map} +0 -0
  75. /package/dist/{chunk-RSRNSWJN.js.map → chunk-BHHJOG5X.js.map} +0 -0
  76. /package/dist/{chunk-GAZRZZRF.js.map → chunk-CATIRDZP.js.map} +0 -0
  77. /package/dist/{chunk-B4U37WIH.js.map → chunk-CFCLVJIO.js.map} +0 -0
  78. /package/dist/{chunk-PYDVANWI.js.map → chunk-E36VI2HA.js.map} +0 -0
  79. /package/dist/{chunk-JAGNXEWK.js.map → chunk-GK4XW4BC.js.map} +0 -0
  80. /package/dist/{chunk-4VE6ZXXW.js.map → chunk-MQP57DOP.js.map} +0 -0
  81. /package/dist/{chunk-PGR2MDDU.js.map → chunk-W66OJM55.js.map} +0 -0
  82. /package/dist/{chunk-7OYIDM42.js.map → chunk-XKURJ72I.js.map} +0 -0
  83. /package/dist/{dom-to-image-NATF3446.js.map → dom-to-image-QB7KMTAE.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,7 +278,7 @@ __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_react22 = require("react");
280
282
 
281
283
  // src/components/blocks/types.ts
282
284
  var blockTypes = {
@@ -287,7 +289,8 @@ var blockTypes = {
287
289
  // src/components/artifacts/artifact-base.ts
288
290
  var artifactTypes = {
289
291
  TABLE: "TABLE",
290
- CHART: "CHART"
292
+ CHART: "CHART",
293
+ DECK: "DECK"
291
294
  };
292
295
 
293
296
  // src/components/artifacts/chart-artifact/types.ts
@@ -312,6 +315,34 @@ var DEFAULT_TABLE_ARTIFACT_LABELS = {
312
315
  empty: "No rows to display."
313
316
  };
314
317
 
318
+ // src/components/artifacts/deck-artifact/types.ts
319
+ var deckBlockTypes = {
320
+ TEXT: "TEXT",
321
+ CHART: "CHART",
322
+ TABLE: "TABLE"
323
+ };
324
+ var deckSlideKinds = {
325
+ TITLE: "TITLE",
326
+ AGENDA: "AGENDA",
327
+ SECTION: "SECTION",
328
+ CONTENT: "CONTENT",
329
+ CLOSING: "CLOSING"
330
+ };
331
+ var DEFAULT_DECK_ARTIFACT_LABELS = {
332
+ previous: "Previous slide",
333
+ next: "Next slide",
334
+ position: "Slide {current} of {total}",
335
+ download: "Download",
336
+ unavailable: "Deck content is unavailable.",
337
+ enterFullscreen: "Fullscreen",
338
+ exitFullscreen: "Exit fullscreen",
339
+ thankYou: "Thank you",
340
+ questions: "Questions?",
341
+ agenda: "Agenda",
342
+ chart: DEFAULT_CHART_ARTIFACT_LABELS,
343
+ table: DEFAULT_TABLE_ARTIFACT_LABELS
344
+ };
345
+
315
346
  // src/components/artifacts/chart-artifact/chart-artifact.tsx
316
347
  var import_react13 = require("react");
317
348
 
@@ -404,37 +435,53 @@ var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
404
435
  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
436
  var IconAlertCircle = createReactComponent("outline", "alert-circle", "AlertCircle", __iconNode);
406
437
 
438
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconArrowsMaximize.mjs
439
+ 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" }]];
440
+ var IconArrowsMaximize = createReactComponent("outline", "arrows-maximize", "ArrowsMaximize", __iconNode2);
441
+
442
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconArrowsMinimize.mjs
443
+ 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" }]];
444
+ var IconArrowsMinimize = createReactComponent("outline", "arrows-minimize", "ArrowsMinimize", __iconNode3);
445
+
407
446
  // 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);
447
+ var __iconNode4 = [["path", { "d": "M5 12l5 5l10 -10", "key": "svg-0" }]];
448
+ var IconCheck = createReactComponent("outline", "check", "Check", __iconNode4);
449
+
450
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconChevronLeft.mjs
451
+ var __iconNode5 = [["path", { "d": "M15 6l-6 6l6 6", "key": "svg-0" }]];
452
+ var IconChevronLeft = createReactComponent("outline", "chevron-left", "ChevronLeft", __iconNode5);
453
+
454
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconChevronRight.mjs
455
+ var __iconNode6 = [["path", { "d": "M9 6l6 6l-6 6", "key": "svg-0" }]];
456
+ var IconChevronRight = createReactComponent("outline", "chevron-right", "ChevronRight", __iconNode6);
410
457
 
411
458
  // 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);
459
+ var __iconNode7 = [["path", { "d": "M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667l0 -8.666", "key": "svg-0" }], ["path", { "d": "M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1", "key": "svg-1" }]];
460
+ var IconCopy = createReactComponent("outline", "copy", "Copy", __iconNode7);
414
461
 
415
462
  // 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);
463
+ var __iconNode8 = [["path", { "d": "M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2", "key": "svg-0" }], ["path", { "d": "M7 11l5 5l5 -5", "key": "svg-1" }], ["path", { "d": "M12 4l0 12", "key": "svg-2" }]];
464
+ var IconDownload = createReactComponent("outline", "download", "Download", __iconNode8);
418
465
 
419
466
  // 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);
467
+ var __iconNode9 = [["path", { "d": "M14 3v4a1 1 0 0 0 1 1h4", "key": "svg-0" }], ["path", { "d": "M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2", "key": "svg-1" }], ["path", { "d": "M8 11h8v7h-8l0 -7", "key": "svg-2" }], ["path", { "d": "M8 15h8", "key": "svg-3" }], ["path", { "d": "M11 11v7", "key": "svg-4" }]];
468
+ var IconFileSpreadsheet = createReactComponent("outline", "file-spreadsheet", "FileSpreadsheet", __iconNode9);
422
469
 
423
470
  // 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);
471
+ var __iconNode10 = [["path", { "d": "M12 3a9 9 0 1 0 9 9", "key": "svg-0" }]];
472
+ var IconLoader2 = createReactComponent("outline", "loader-2", "Loader2", __iconNode10);
426
473
 
427
474
  // 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);
475
+ var __iconNode11 = [["path", { "d": "M15 8h.01", "key": "svg-0" }], ["path", { "d": "M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12", "key": "svg-1" }], ["path", { "d": "M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5", "key": "svg-2" }], ["path", { "d": "M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3", "key": "svg-3" }]];
476
+ var IconPhoto = createReactComponent("outline", "photo", "Photo", __iconNode11);
430
477
 
431
478
  // 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);
479
+ var __iconNode12 = [["path", { "d": "M7 13v-8a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h3a4 4 0 0 1 4 4v1a2 2 0 0 0 4 0v-5h3a2 2 0 0 0 2 -2l-1 -5a2 3 0 0 0 -2 -2h-7a3 3 0 0 0 -3 3", "key": "svg-0" }]];
480
+ var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode12);
434
481
 
435
482
  // 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);
483
+ var __iconNode13 = [["path", { "d": "M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3", "key": "svg-0" }]];
484
+ var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode13);
438
485
 
439
486
  // src/components/artifacts/artifact-copy-as-image-button/artifact-copy-as-image-button.tsx
440
487
  var import_react6 = require("react");
@@ -1404,11 +1451,6 @@ function coerceNumericColumns(rows, numericKeys) {
1404
1451
 
1405
1452
  // src/components/chart/bar-chart/bar-chart.tsx
1406
1453
  var import_jsx_runtime12 = require("react/jsx-runtime");
1407
- var STACK_TOTAL_KEY = "__stackTotal";
1408
- var VALUE_LABEL_HEADROOM = 20;
1409
- function sumSeries(row, keys) {
1410
- return keys.reduce((sum, key) => sum + (Number(row[key]) || 0), 0);
1411
- }
1412
1454
  function BarChart({
1413
1455
  data,
1414
1456
  xKey,
@@ -1423,7 +1465,6 @@ function BarChart({
1423
1465
  showGrid = true,
1424
1466
  showXAxis = true,
1425
1467
  showYAxis = true,
1426
- showValueLabels,
1427
1468
  xAxisInterval = 0,
1428
1469
  xAxisAngle,
1429
1470
  xAxisTickFormatter
@@ -1434,24 +1475,14 @@ function BarChart({
1434
1475
  [data, seriesKeys]
1435
1476
  );
1436
1477
  const resolvedShowLegend = showLegend ?? series.length > 1;
1437
- const resolvedShowValueLabels = showValueLabels ?? true;
1438
- const plotData = (0, import_react9.useMemo)(() => {
1439
- if (!stacked || !resolvedShowValueLabels) return coercedData;
1440
- return coercedData.map((row) => ({ ...row, [STACK_TOTAL_KEY]: sumSeries(row, seriesKeys) }));
1441
- }, [coercedData, stacked, resolvedShowValueLabels, seriesKeys]);
1442
1478
  const resolvedAngle = xAxisAngle ?? (coercedData.length >= 8 ? -30 : 0);
1443
1479
  const resolvedTickFormatter = (0, import_react9.useMemo)(
1444
1480
  () => xAxisTickFormatter ?? defaultBarTickFormatter(coercedData.length),
1445
1481
  [xAxisTickFormatter, coercedData.length]
1446
1482
  );
1447
1483
  const angledLabelPad = resolvedAngle === 0 ? 0 : Math.min(Math.abs(resolvedAngle) * 0.7, 40);
1448
- const valueLabelHeadroom = resolvedShowValueLabels ? VALUE_LABEL_HEADROOM : 0;
1449
- const chartMargin = {
1450
- ...CHART_MARGIN,
1451
- top: CHART_MARGIN.top + valueLabelHeadroom,
1452
- bottom: CHART_MARGIN.bottom + angledLabelPad
1453
- };
1454
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChartContainer, { height, width, className, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_recharts2.BarChart, { data: plotData, margin: chartMargin, barCategoryGap: "22%", children: [
1484
+ const chartMargin = { ...CHART_MARGIN, bottom: CHART_MARGIN.bottom + angledLabelPad };
1485
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChartContainer, { height, width, className, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_recharts2.BarChart, { data: coercedData, margin: chartMargin, barCategoryGap: "22%", children: [
1455
1486
  showGrid ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_recharts2.CartesianGrid, { ...CHART_GRID_PROPS }) : null,
1456
1487
  showXAxis ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1457
1488
  import_recharts2.XAxis,
@@ -1478,23 +1509,17 @@ function BarChart({
1478
1509
  content: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChartLegendContent, { iconType: "square" })
1479
1510
  }
1480
1511
  ) : null,
1481
- series.map((s, i) => {
1482
- const isTopSegment = i === series.length - 1;
1483
- const labelDataKey = stacked ? STACK_TOTAL_KEY : s.key;
1484
- const showLabel = resolvedShowValueLabels && (!stacked || isTopSegment);
1485
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1486
- import_recharts2.Bar,
1487
- {
1488
- dataKey: s.key,
1489
- name: s.label,
1490
- fill: colorForSeriesIndex(i, palette),
1491
- stackId: stacked ? "default" : s.key,
1492
- radius: barRadius(stacked, i, series.length),
1493
- children: showLabel ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_recharts2.LabelList, { dataKey: labelDataKey, position: "top", style: CHART_VALUE_LABEL_STYLE }) : null
1494
- },
1495
- s.key
1496
- );
1497
- })
1512
+ series.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1513
+ import_recharts2.Bar,
1514
+ {
1515
+ dataKey: s.key,
1516
+ name: s.label,
1517
+ fill: colorForSeriesIndex(i, palette),
1518
+ stackId: stacked ? "default" : s.key,
1519
+ radius: barRadius(stacked, i, series.length)
1520
+ },
1521
+ s.key
1522
+ ))
1498
1523
  ] }) });
1499
1524
  }
1500
1525
  function barRadius(stacked, seriesIndex, seriesCount) {
@@ -2029,8 +2054,13 @@ var ChartArtifactService = {
2029
2054
  toClipboardText: chartArtifactToClipboardText
2030
2055
  };
2031
2056
 
2032
- // src/components/artifacts/table-artifact/table-artifact.tsx
2033
- var import_react15 = require("react");
2057
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
2058
+ var import_react17 = require("react");
2059
+ var import_react_dom = require("react-dom");
2060
+ init_capture_exclude_attribute();
2061
+
2062
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
2063
+ var import_react16 = require("react");
2034
2064
 
2035
2065
  // src/components/ui/table.tsx
2036
2066
  var React3 = __toESM(require("react"), 1);
@@ -2177,9 +2207,333 @@ function renderEmptyRow(colSpan, emptyMessage) {
2177
2207
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) });
2178
2208
  }
2179
2209
 
2180
- // src/components/artifacts/table-artifact/use-table-artifact-data.ts
2181
- function useTableArtifactData(presignedUrl, columns) {
2182
- return useRowsArtifactData(presignedUrl, columns, parseCsv);
2210
+ // src/components/artifacts/deck-artifact/deck-markdown.tsx
2211
+ var import_react_markdown = __toESM(require("react-markdown"), 1);
2212
+ var import_remark_breaks = __toESM(require("remark-breaks"), 1);
2213
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
2214
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2215
+ function sanitize(text) {
2216
+ return text.split("\n").filter((line) => {
2217
+ const t = line.trim();
2218
+ return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
2219
+ }).join("\n");
2220
+ }
2221
+ var MARKDOWN_COMPONENTS = {
2222
+ h1: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { className: "text-[30px] font-semibold leading-tight text-foreground mb-3", ...props }),
2223
+ h2: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { className: "text-[26px] font-semibold leading-tight text-foreground mb-2", ...props }),
2224
+ h3: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2225
+ h4: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h4", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2226
+ h5: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h5", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2227
+ h6: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h6", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2228
+ p: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[22px] leading-relaxed text-foreground my-2", ...props }),
2229
+ ul: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "list-disc pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2230
+ ol: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ol", { className: "list-decimal pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
2231
+ // react-markdown injects list metadata (`ordered` / `index` / `checked`) that must not leak to the DOM.
2232
+ li: ({ node: _node, ordered: _ordered, index: _index, checked: _checked, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { className: "my-1", ...props }),
2233
+ strong: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { className: "font-semibold", ...props }),
2234
+ em: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("em", { className: "italic", ...props }),
2235
+ // Gate `<img src>` against an http(s) allowlist. react-markdown v8 percent-encodes the URL but
2236
+ // does NOT protocol-filter image src (unlike link href), so an LLM-authored
2237
+ // `![](javascript:…)` / `![](data:…)` or a tracking-pixel `![](http://…)` would otherwise render
2238
+ // with the raw URL. Unsafe src → render nothing.
2239
+ img: ({ node: _node, src, ...props }) => typeof src === "string" && isSafeDownloadUrl(src) ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("img", { src, className: "max-w-full", ...props }) : null,
2240
+ a: ({ node: _node, ...props }) => (
2241
+ // `rel` is forced AFTER `{...props}` so it can't be overridden — if a consumer ever adds
2242
+ // `linkTarget="_blank"`, LLM-authored links still can't reach `window.opener`.
2243
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { className: "underline underline-offset-2", ...props, rel: "noopener noreferrer" })
2244
+ ),
2245
+ // react-markdown passes `inline` to distinguish inline code from fenced blocks — strip it from the DOM.
2246
+ code: ({ node: _node, inline: _inline, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("code", { className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[18px]", ...props }),
2247
+ blockquote: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("blockquote", { className: "border-l-2 border-brown-alpha-12 pl-4 text-[22px] text-muted-foreground", ...props }),
2248
+ hr: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("hr", { className: "my-4 border-brown-alpha-12", ...props }),
2249
+ table: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("table", { className: "w-full border-collapse text-[20px]", ...props }) }),
2250
+ // react-markdown passes `isHeader` to cell renderers — strip it so it never reaches the DOM.
2251
+ th: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { className: "border-b border-brown-alpha-12 px-3 py-1.5 text-left font-medium", ...props }),
2252
+ td: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "border-b border-brown-alpha-12 px-3 py-1.5", ...props })
2253
+ };
2254
+ function DeckMarkdown({ markdown }) {
2255
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default, import_remark_breaks.default], components: MARKDOWN_COMPONENTS, children: sanitize(markdown) });
2256
+ }
2257
+
2258
+ // src/components/artifacts/deck-artifact/slide-renderers.tsx
2259
+ var import_react15 = require("react");
2260
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2261
+ function safeLogoUrl(meta) {
2262
+ return meta?.logoUrl && isSafeDownloadUrl(meta.logoUrl) ? meta.logoUrl : null;
2263
+ }
2264
+ var DESIGN_W = 1280;
2265
+ var DESIGN_H = 720;
2266
+ var EYEBROW_H = 84;
2267
+ var CANVAS_LOGO_MAX_H = 48;
2268
+ var ACCENT_FONT = { fontFamily: `"${fontFamilies.CRIMSON_PRO}", serif`, fontStyle: "italic" };
2269
+ function SlideFrame({ meta, children, accent = false, bare = false }) {
2270
+ const frameRef = (0, import_react15.useRef)(null);
2271
+ const [scale, setScale] = (0, import_react15.useState)(null);
2272
+ (0, import_react15.useLayoutEffect)(() => {
2273
+ const el = frameRef.current;
2274
+ if (!el) return;
2275
+ const apply = (width) => {
2276
+ if (width > 0) setScale(width / DESIGN_W);
2277
+ };
2278
+ apply(el.clientWidth);
2279
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.width ?? 0));
2280
+ ro.observe(el);
2281
+ return () => ro.disconnect();
2282
+ }, []);
2283
+ const bg = accent ? "bg-indigo-600" : "bg-deck-canvas";
2284
+ const eyebrowColor = accent ? "text-white/70" : "text-brown-60";
2285
+ const borderColor = accent ? "border-white/20" : "border-brown-alpha-12";
2286
+ const logoSrc = safeLogoUrl(meta);
2287
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref: frameRef, className: `relative aspect-[16/9] w-full overflow-hidden rounded-lg ${bg}`, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2288
+ "div",
2289
+ {
2290
+ className: "absolute left-0 top-0 origin-top-left",
2291
+ style: {
2292
+ width: DESIGN_W,
2293
+ height: DESIGN_H,
2294
+ transform: `scale(${scale ?? 0})`,
2295
+ visibility: scale === null ? "hidden" : "visible"
2296
+ },
2297
+ children: [
2298
+ !bare ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2299
+ "div",
2300
+ {
2301
+ className: `absolute inset-x-0 top-0 flex items-center justify-between border-b px-16 ${borderColor}`,
2302
+ style: { height: EYEBROW_H },
2303
+ children: [
2304
+ meta?.eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: eyebrowColor, style: { ...ACCENT_FONT, fontSize: 22 }, children: meta.eyebrow }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", {}),
2305
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("img", { src: logoSrc, alt: "", className: "object-contain", style: { maxHeight: CANVAS_LOGO_MAX_H } }) : null
2306
+ ]
2307
+ }
2308
+ ) : null,
2309
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "absolute inset-x-0 bottom-0 overflow-hidden", style: { top: bare ? 0 : EYEBROW_H }, children })
2310
+ ]
2311
+ }
2312
+ ) });
2313
+ }
2314
+ function TitleSlide({ slide, meta }) {
2315
+ const logoSrc = safeLogoUrl(meta);
2316
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, bare: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex h-full flex-col justify-center px-24 py-16", children: [
2317
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2318
+ "img",
2319
+ {
2320
+ src: logoSrc,
2321
+ alt: "",
2322
+ className: "mb-16 object-contain object-left",
2323
+ style: { maxHeight: 56, maxWidth: 380 }
2324
+ }
2325
+ ) : null,
2326
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2327
+ "h1",
2328
+ {
2329
+ className: "font-bold tracking-tight text-brown-100",
2330
+ style: { fontSize: 92, lineHeight: 1.04, maxWidth: 1060 },
2331
+ children: slide.title
2332
+ }
2333
+ ),
2334
+ slide.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-7 text-brown-70", style: { ...ACCENT_FONT, fontSize: 34 }, children: slide.subtitle }) : null,
2335
+ slide.description ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-4 leading-relaxed text-brown-70", style: { fontSize: 24, maxWidth: 880 }, children: slide.description }) : null,
2336
+ meta?.date ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-10 text-brown-70", style: { ...ACCENT_FONT, fontSize: 30 }, children: meta.date }) : null
2337
+ ] }) });
2338
+ }
2339
+ function AgendaSlide({ slide, meta, labels }) {
2340
+ const items = slide.items ?? [];
2341
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "h-full px-24 py-14", children: [
2342
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "mb-10 font-bold text-brown-90", style: { fontSize: 40 }, children: slide.title || labels.agenda }),
2343
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-col", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-baseline gap-6 border-b border-brown-alpha-12 py-5", children: [
2344
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "shrink-0 text-indigo-600", style: { ...ACCENT_FONT, fontSize: 28, width: 64 }, children: String(i + 1).padStart(2, "0") }),
2345
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-brown-90", style: { fontSize: 28 }, children: item })
2346
+ ] }, i)) })
2347
+ ] }) });
2348
+ }
2349
+ function SectionSlide({ slide, meta }) {
2350
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, accent: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex h-full flex-col justify-center gap-6 px-24", children: [
2351
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "font-bold text-white", style: { fontSize: 72, lineHeight: 1.05, maxWidth: 940 }, children: slide.title }),
2352
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-2 bg-white/50", style: { width: 96, height: 5 } })
2353
+ ] }) });
2354
+ }
2355
+ function ClosingSlide({ meta, labels }) {
2356
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex h-full flex-col items-center justify-center gap-6 px-24 text-center", children: [
2357
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "font-bold text-brown-100", style: { fontSize: 72 }, children: labels.thankYou }),
2358
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-indigo-600", style: { ...ACCENT_FONT, fontSize: 36 }, children: labels.questions })
2359
+ ] }) });
2360
+ }
2361
+
2362
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
2363
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2364
+ var TABLE_BLOCK_MAX_SHIMMER_ROWS = 10;
2365
+ var TABLE_CHROME_RESERVE = 56;
2366
+ var VISUAL_FALLBACK_HEIGHT = 360;
2367
+ function DeckArtifactContent({
2368
+ slides,
2369
+ labels,
2370
+ onNavigate,
2371
+ meta,
2372
+ onDark = false,
2373
+ currentSlide,
2374
+ onSlideChange
2375
+ }) {
2376
+ const navBtnClass = onDark ? "[&_svg]:!text-white hover:!bg-white/20 disabled:opacity-40" : void 0;
2377
+ const navBtnSize = onDark ? "medium" : "small";
2378
+ const isControlled = currentSlide !== void 0;
2379
+ const [internalIndex, setInternalIndex] = (0, import_react16.useState)(0);
2380
+ const index = isControlled ? currentSlide : internalIndex;
2381
+ const current = Math.min(index, slides.length - 1);
2382
+ const slide = slides[current];
2383
+ const goTo = (0, import_react16.useCallback)(
2384
+ (next) => {
2385
+ const clamped = Math.max(0, Math.min(next, slides.length - 1));
2386
+ if (isControlled) onSlideChange?.(clamped);
2387
+ else setInternalIndex(clamped);
2388
+ onNavigate?.(clamped);
2389
+ },
2390
+ [slides.length, onNavigate, isControlled, onSlideChange]
2391
+ );
2392
+ const position = labels.position.replace("{current}", String(current + 1)).replace("{total}", String(slides.length));
2393
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-3 p-4", children: [
2394
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideDispatch, { slide, labels, meta }),
2395
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2396
+ "div",
2397
+ {
2398
+ className: `flex items-center justify-between border-t pt-2 ${onDark ? "border-white/20" : "border-brown-alpha-12"}`,
2399
+ children: [
2400
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2401
+ IconButton,
2402
+ {
2403
+ icon: IconChevronLeft,
2404
+ size: navBtnSize,
2405
+ className: navBtnClass,
2406
+ "aria-label": labels.previous,
2407
+ disabled: current === 0,
2408
+ onClick: () => goTo(current - 1)
2409
+ }
2410
+ ),
2411
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: `text-xs font-medium ${onDark ? "text-white/70" : "text-brown-70"}`, children: position }),
2412
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2413
+ IconButton,
2414
+ {
2415
+ icon: IconChevronRight,
2416
+ size: navBtnSize,
2417
+ className: navBtnClass,
2418
+ "aria-label": labels.next,
2419
+ disabled: current === slides.length - 1,
2420
+ onClick: () => goTo(current + 1)
2421
+ }
2422
+ )
2423
+ ]
2424
+ }
2425
+ )
2426
+ ] });
2427
+ }
2428
+ function SlideDispatch({ slide, labels, meta }) {
2429
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
2430
+ switch (kind) {
2431
+ case deckSlideKinds.TITLE:
2432
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TitleSlide, { slide, meta });
2433
+ case deckSlideKinds.AGENDA:
2434
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AgendaSlide, { slide, meta, labels });
2435
+ case deckSlideKinds.SECTION:
2436
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SectionSlide, { slide, meta });
2437
+ case deckSlideKinds.CLOSING:
2438
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ClosingSlide, { meta, labels });
2439
+ case deckSlideKinds.CONTENT:
2440
+ default:
2441
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ContentSlide, { slide, meta, labels });
2442
+ }
2443
+ }
2444
+ function isVisualBlock(block) {
2445
+ return block.type === deckBlockTypes.CHART || block.type === deckBlockTypes.TABLE;
2446
+ }
2447
+ function ContentSlide({ slide, meta, labels }) {
2448
+ const content = slide.content ?? [];
2449
+ const visuals = content.filter(isVisualBlock);
2450
+ const texts = content.filter(
2451
+ (b) => b.type === deckBlockTypes.TEXT
2452
+ );
2453
+ if (visuals.length === 1 && texts.length > 0) {
2454
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex h-full items-stretch gap-12 px-16 py-12", children: [
2455
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex w-[42%] shrink-0 flex-col overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(AutoFit, { children: [
2456
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "mb-5 font-bold leading-tight text-foreground", style: { fontSize: 34 }, children: slide.title }),
2457
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2458
+ ] }) }),
2459
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(FillVisual, { block: visuals[0], labels }) })
2460
+ ] }) });
2461
+ }
2462
+ if (visuals.length > 0) {
2463
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex h-full flex-col gap-5 px-16 py-10", children: [
2464
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "shrink-0 font-bold leading-tight text-foreground", style: { fontSize: 32 }, children: slide.title }),
2465
+ content.map(
2466
+ (block, i) => isVisualBlock(block) ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(FillVisual, { block, labels }) }, i) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "shrink-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }) }, i)
2467
+ )
2468
+ ] }) });
2469
+ }
2470
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideFrame, { meta, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "h-full px-24 py-12", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(AutoFit, { children: [
2471
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "mb-6 font-bold leading-tight text-foreground", style: { fontSize: 38 }, children: slide.title }),
2472
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2473
+ ] }) }) });
2474
+ }
2475
+ function AutoFit({ children }) {
2476
+ const boxRef = (0, import_react16.useRef)(null);
2477
+ const contentRef = (0, import_react16.useRef)(null);
2478
+ const [fit, setFit] = (0, import_react16.useState)({ scale: 1, height: 0 });
2479
+ (0, import_react16.useLayoutEffect)(() => {
2480
+ const boxEl = boxRef.current;
2481
+ const contentEl = contentRef.current;
2482
+ if (!boxEl || !contentEl) return;
2483
+ const measure = () => {
2484
+ const avail = boxEl.clientHeight;
2485
+ const natural = contentEl.offsetHeight;
2486
+ const scale = avail > 0 && natural > avail ? avail / natural : 1;
2487
+ setFit({ scale, height: natural * scale });
2488
+ };
2489
+ measure();
2490
+ const ro = new ResizeObserver(measure);
2491
+ ro.observe(boxEl);
2492
+ ro.observe(contentEl);
2493
+ return () => ro.disconnect();
2494
+ }, []);
2495
+ const scaled = fit.scale < 1;
2496
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: boxRef, className: "flex h-full min-h-0 w-full flex-col justify-center overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: scaled ? { height: fit.height } : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2497
+ "div",
2498
+ {
2499
+ ref: contentRef,
2500
+ className: "w-full origin-top-left",
2501
+ style: scaled ? { transform: `scale(${fit.scale})` } : void 0,
2502
+ children
2503
+ }
2504
+ ) }) });
2505
+ }
2506
+ function FillVisual({ block, labels }) {
2507
+ const ref = (0, import_react16.useRef)(null);
2508
+ const [height, setHeight] = (0, import_react16.useState)(VISUAL_FALLBACK_HEIGHT);
2509
+ (0, import_react16.useLayoutEffect)(() => {
2510
+ const el = ref.current;
2511
+ if (!el) return;
2512
+ const apply = (h) => {
2513
+ if (h > 0) setHeight(h);
2514
+ };
2515
+ apply(el.clientHeight);
2516
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.height ?? 0));
2517
+ ro.observe(el);
2518
+ return () => ro.disconnect();
2519
+ }, []);
2520
+ const chartLabels = labels.chart ?? DEFAULT_CHART_ARTIFACT_LABELS;
2521
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref, className: "h-full min-h-0 w-full overflow-hidden", children: block.type === deckBlockTypes.CHART ? (
2522
+ // ChartArtifactContent assumes a non-empty rowset (the standalone ChartArtifact guards
2523
+ // `rows.length > 0` upstream); mirror that guard here so an empty inline chart shows the
2524
+ // localized empty status instead of a blank chart area.
2525
+ block.rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(StatusMessage, { $tone: "info", children: chartLabels.empty }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChartArtifactContent, { config: block.config, rows: block.rows, labels: chartLabels }) })
2526
+ ) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2527
+ TableArtifactContent,
2528
+ {
2529
+ columns: block.config.columns,
2530
+ data: { status: "ready", rows: block.rows, error: null },
2531
+ knownRowCount: block.config.stats?.rowCount ?? block.rows.length,
2532
+ maxShimmerRows: TABLE_BLOCK_MAX_SHIMMER_ROWS,
2533
+ maxBodyHeight: Math.max(0, height - TABLE_CHROME_RESERVE),
2534
+ labels: labels.table ?? DEFAULT_TABLE_ARTIFACT_LABELS
2535
+ }
2536
+ ) });
2183
2537
  }
2184
2538
 
2185
2539
  // src/components/artifacts/table-artifact/validate.ts
@@ -2198,19 +2552,265 @@ function isValidTableColumn(column) {
2198
2552
  return true;
2199
2553
  }
2200
2554
 
2201
- // src/components/artifacts/table-artifact/table-artifact.tsx
2202
- var import_jsx_runtime22 = require("react/jsx-runtime");
2555
+ // src/components/artifacts/deck-artifact/validate.ts
2556
+ function isValidDeckConfig(config) {
2557
+ if (!config || typeof config !== "object") return false;
2558
+ const candidate = config;
2559
+ if (!Array.isArray(candidate.slides)) return false;
2560
+ if (candidate.slides.length === 0) return false;
2561
+ return candidate.slides.every(isValidDeckSlide);
2562
+ }
2563
+ function isValidDeckSlide(slide) {
2564
+ if (!slide || typeof slide !== "object") return false;
2565
+ const candidate = slide;
2566
+ if (typeof candidate.title !== "string") return false;
2567
+ const kind = typeof candidate.kind === "string" ? candidate.kind : deckSlideKinds.CONTENT;
2568
+ if (kind === deckSlideKinds.CONTENT && !Array.isArray(candidate.content)) return false;
2569
+ const content = Array.isArray(candidate.content) ? candidate.content : [];
2570
+ if (candidate.items != null) {
2571
+ if (!Array.isArray(candidate.items)) return false;
2572
+ if (!candidate.items.every((item) => typeof item === "string")) return false;
2573
+ }
2574
+ return content.every(isValidDeckBlock);
2575
+ }
2576
+ function isValidDeckBlock(block) {
2577
+ if (!block || typeof block !== "object") return false;
2578
+ const candidate = block;
2579
+ switch (candidate.type) {
2580
+ case deckBlockTypes.TEXT:
2581
+ return typeof candidate.markdown === "string";
2582
+ case deckBlockTypes.CHART:
2583
+ return isValidChartConfig(candidate.config) && Array.isArray(candidate.rows);
2584
+ case deckBlockTypes.TABLE:
2585
+ return isValidTableConfig(candidate.config) && Array.isArray(candidate.rows);
2586
+ default:
2587
+ return false;
2588
+ }
2589
+ }
2590
+
2591
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
2592
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2203
2593
  var TITLE_CLASSES2 = "text-sm font-semibold text-foreground";
2594
+ function DeckArtifact({ artifact, labels, callbacks }) {
2595
+ const validConfig = isValidDeckConfig(artifact.config);
2596
+ const [isFullscreen, setIsFullscreen] = (0, import_react17.useState)(false);
2597
+ const [currentSlide, setCurrentSlide] = (0, import_react17.useState)(0);
2598
+ (0, import_react17.useEffect)(() => {
2599
+ if (validConfig) return;
2600
+ console.warn("[clay] DeckArtifact: malformed `config` \u2014 skipping render.");
2601
+ }, [validConfig]);
2602
+ (0, import_react17.useEffect)(() => {
2603
+ if (!isFullscreen) return;
2604
+ const handleKey = (e) => {
2605
+ if (e.key === "Escape") setIsFullscreen(false);
2606
+ };
2607
+ document.addEventListener("keydown", handleKey);
2608
+ const previousOverflow = document.documentElement.style.overflow;
2609
+ document.documentElement.style.overflow = "hidden";
2610
+ return () => {
2611
+ document.removeEventListener("keydown", handleKey);
2612
+ document.documentElement.style.overflow = previousOverflow;
2613
+ };
2614
+ }, [isFullscreen]);
2615
+ const resolvedLabels = (0, import_react17.useMemo)(
2616
+ () => ({
2617
+ ...DEFAULT_DECK_ARTIFACT_LABELS,
2618
+ ...labels ?? {},
2619
+ chart: { ...DEFAULT_CHART_ARTIFACT_LABELS, ...labels?.chart ?? {} },
2620
+ table: { ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels?.table ?? {} }
2621
+ }),
2622
+ [labels]
2623
+ );
2624
+ const onNavigate = callbacks?.onNavigate;
2625
+ const handleNavigate = onNavigate ? (slideIndex) => onNavigate(artifact, slideIndex) : void 0;
2626
+ const onDownload = callbacks?.onDownload;
2627
+ const handleDownload = onDownload ? () => onDownload(artifact) : void 0;
2628
+ const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
2629
+ const showDownload = presignedUrl !== null && isSafeDownloadUrl(presignedUrl);
2630
+ const meta = artifact.config?.meta;
2631
+ const handleOpenFullscreen = () => setIsFullscreen(true);
2632
+ const handleCloseFullscreen = () => setIsFullscreen(false);
2633
+ const actions = /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactActions, { ...{ [CAPTURE_EXCLUDE_ATTRIBUTE]: "" }, children: [
2634
+ showDownload ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactDownloadButton, { href: presignedUrl ?? "", label: resolvedLabels.download, onClick: handleDownload }) : null,
2635
+ validConfig ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2636
+ IconButton,
2637
+ {
2638
+ icon: IconArrowsMaximize,
2639
+ size: "small",
2640
+ "aria-label": resolvedLabels.enterFullscreen,
2641
+ onClick: handleOpenFullscreen
2642
+ }
2643
+ ) : null
2644
+ ] });
2645
+ if (!validConfig) {
2646
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2647
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2648
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2649
+ actions
2650
+ ] }),
2651
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2652
+ ] });
2653
+ }
2654
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
2655
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2656
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2657
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2658
+ actions
2659
+ ] }),
2660
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2661
+ DeckArtifactContent,
2662
+ {
2663
+ slides: artifact.config.slides,
2664
+ labels: resolvedLabels,
2665
+ onNavigate: handleNavigate,
2666
+ meta,
2667
+ currentSlide,
2668
+ onSlideChange: setCurrentSlide
2669
+ }
2670
+ ) })
2671
+ ] }),
2672
+ isFullscreen && (0, import_react_dom.createPortal)(
2673
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2674
+ FullscreenOverlay,
2675
+ {
2676
+ artifact,
2677
+ resolvedLabels,
2678
+ onNavigate: handleNavigate,
2679
+ currentSlide,
2680
+ onSlideChange: setCurrentSlide,
2681
+ onClose: handleCloseFullscreen
2682
+ }
2683
+ ),
2684
+ document.body
2685
+ )
2686
+ ] });
2687
+ }
2688
+ function FullscreenOverlay({
2689
+ artifact,
2690
+ resolvedLabels,
2691
+ onNavigate,
2692
+ currentSlide,
2693
+ onSlideChange,
2694
+ onClose
2695
+ }) {
2696
+ const meta = artifact.config?.meta;
2697
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2698
+ "div",
2699
+ {
2700
+ className: "fixed inset-0 z-[2147483647] flex items-center justify-center bg-black/80",
2701
+ role: "dialog",
2702
+ "aria-modal": "true",
2703
+ "aria-label": resolvedLabels.exitFullscreen,
2704
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "relative", style: { width: "min(94vw, calc(82vh * 16 / 9))" }, children: [
2705
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2706
+ DeckArtifactContent,
2707
+ {
2708
+ slides: artifact.config.slides,
2709
+ labels: resolvedLabels,
2710
+ onNavigate,
2711
+ meta,
2712
+ currentSlide,
2713
+ onSlideChange,
2714
+ onDark: true
2715
+ }
2716
+ ),
2717
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2718
+ "button",
2719
+ {
2720
+ className: "absolute -top-10 right-6 flex items-center gap-1.5 text-sm text-white/80 hover:text-white",
2721
+ "aria-label": resolvedLabels.exitFullscreen,
2722
+ onClick: onClose,
2723
+ children: [
2724
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(IconArrowsMinimize, { size: 16 }),
2725
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: resolvedLabels.exitFullscreen })
2726
+ ]
2727
+ }
2728
+ )
2729
+ ] })
2730
+ }
2731
+ );
2732
+ }
2733
+
2734
+ // src/components/artifacts/deck-artifact/to-clipboard-text.ts
2735
+ function deckArtifactToClipboardText(artifact) {
2736
+ const header = artifact.title?.trim() || "Deck";
2737
+ const slides = artifact.config?.slides ?? [];
2738
+ const body = slides.map((slide, i) => slideToText(slide, i)).join("\n\n");
2739
+ return body ? `${header}
2740
+
2741
+ ${body}` : header;
2742
+ }
2743
+ function slideToText(slide, index) {
2744
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
2745
+ const prefix = `Slide ${index + 1}: `;
2746
+ switch (kind) {
2747
+ case deckSlideKinds.TITLE: {
2748
+ const parts = [slide.title];
2749
+ if (slide.subtitle) parts.push(slide.subtitle);
2750
+ if (slide.description) parts.push(slide.description);
2751
+ return `${prefix}${parts.join(" \u2014 ")}`.trim();
2752
+ }
2753
+ case deckSlideKinds.AGENDA: {
2754
+ const items = (slide.items ?? []).map((item, i) => ` ${String(i + 1).padStart(2, "0")}. ${item}`).join("\n");
2755
+ return `${prefix}${slide.title || "Agenda"}${items ? `
2756
+ ${items}` : ""}`.trim();
2757
+ }
2758
+ case deckSlideKinds.SECTION:
2759
+ return `${prefix}${slide.title}`.trim();
2760
+ case deckSlideKinds.CLOSING:
2761
+ return `${prefix}Thank you`.trim();
2762
+ case deckSlideKinds.CONTENT:
2763
+ default: {
2764
+ const blocks = (slide.content ?? []).map(blockToText).filter(Boolean).join("\n\n");
2765
+ return `${prefix}${slide.title}${blocks ? `
2766
+ ${blocks}` : ""}`.trim();
2767
+ }
2768
+ }
2769
+ }
2770
+ function blockToText(block) {
2771
+ switch (block.type) {
2772
+ case deckBlockTypes.TEXT:
2773
+ return block.markdown.trim();
2774
+ case deckBlockTypes.CHART:
2775
+ return `[Chart: ${block.config.variant}]`;
2776
+ case deckBlockTypes.TABLE: {
2777
+ const columnCount = block.config.columns.length;
2778
+ const rowCount = block.rows.length;
2779
+ return `[Table: ${columnCount} column${columnCount === 1 ? "" : "s"} \xD7 ${rowCount} row${rowCount === 1 ? "" : "s"}]`;
2780
+ }
2781
+ default:
2782
+ return "";
2783
+ }
2784
+ }
2785
+
2786
+ // src/components/artifacts/artifact-services/deck-artifact-service.ts
2787
+ var DeckArtifactService = {
2788
+ type: artifactTypes.DECK,
2789
+ Component: DeckArtifact,
2790
+ toClipboardText: deckArtifactToClipboardText
2791
+ };
2792
+
2793
+ // src/components/artifacts/table-artifact/table-artifact.tsx
2794
+ var import_react18 = require("react");
2795
+
2796
+ // src/components/artifacts/table-artifact/use-table-artifact-data.ts
2797
+ function useTableArtifactData(presignedUrl, columns) {
2798
+ return useRowsArtifactData(presignedUrl, columns, parseCsv);
2799
+ }
2800
+
2801
+ // src/components/artifacts/table-artifact/table-artifact.tsx
2802
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2803
+ var TITLE_CLASSES3 = "text-sm font-semibold text-foreground";
2204
2804
  var TABLE_MAX_BODY_HEIGHT = 480;
2205
2805
  var MAX_SHIMMER_ROWS = 10;
2206
2806
  function TableArtifact({ artifact, labels, callbacks }) {
2207
2807
  const validConfig = isValidTableConfig(artifact.config);
2208
2808
  const validColumns = validConfig ? artifact.config.columns : null;
2209
- (0, import_react15.useEffect)(() => {
2809
+ (0, import_react18.useEffect)(() => {
2210
2810
  if (validConfig) return;
2211
2811
  console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
2212
2812
  }, [validConfig]);
2213
- const resolvedLabels = (0, import_react15.useMemo)(
2813
+ const resolvedLabels = (0, import_react18.useMemo)(
2214
2814
  () => ({ ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels ?? {} }),
2215
2815
  [labels]
2216
2816
  );
@@ -2222,10 +2822,10 @@ function TableArtifact({ artifact, labels, callbacks }) {
2222
2822
  const onDownload = callbacks?.onDownload;
2223
2823
  const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
2224
2824
  if (!validConfig || !validColumns) {
2225
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2226
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2227
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
2228
- presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2825
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2826
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2827
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", {}),
2828
+ presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2229
2829
  ArtifactDownloadButton,
2230
2830
  {
2231
2831
  href: presignedUrl,
@@ -2234,17 +2834,17 @@ function TableArtifact({ artifact, labels, callbacks }) {
2234
2834
  }
2235
2835
  ) }) : null
2236
2836
  ] }),
2237
- /* @__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 }) })
2837
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2238
2838
  ] });
2239
2839
  }
2240
2840
  return (
2241
2841
  // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
2242
2842
  // Disable the outer overflow container so only one scroll context exists — this prevents
2243
2843
  // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
2244
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2245
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2246
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
2247
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2844
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2845
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2846
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", {}),
2847
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2248
2848
  ArtifactDownloadButton,
2249
2849
  {
2250
2850
  href: presignedUrl ?? "",
@@ -2253,7 +2853,7 @@ function TableArtifact({ artifact, labels, callbacks }) {
2253
2853
  }
2254
2854
  ) })
2255
2855
  ] }),
2256
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2856
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2257
2857
  TableArtifactContent,
2258
2858
  {
2259
2859
  columns: validColumns,
@@ -2284,7 +2884,8 @@ var TableArtifactService = {
2284
2884
  // src/components/artifacts/artifact-services/index.ts
2285
2885
  var ArtifactServices = {
2286
2886
  [artifactTypes.TABLE]: TableArtifactService,
2287
- [artifactTypes.CHART]: ChartArtifactService
2887
+ [artifactTypes.CHART]: ChartArtifactService,
2888
+ [artifactTypes.DECK]: DeckArtifactService
2288
2889
  };
2289
2890
  function artifactToClipboardText(artifact) {
2290
2891
  const entry = ArtifactServices[artifact.type];
@@ -2295,13 +2896,13 @@ function artifactToClipboardText(artifact) {
2295
2896
  }
2296
2897
 
2297
2898
  // src/components/blocks/artifact-ref-block/artifact-ref-block.tsx
2298
- var import_jsx_runtime23 = require("react/jsx-runtime");
2899
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2299
2900
  function ArtifactRefBlock({ block }) {
2300
2901
  const { artifact, labels, callbacks } = block.payload;
2301
2902
  const entry = ArtifactServices[artifact.type];
2302
2903
  if (!entry) return null;
2303
2904
  const Component = entry.Component;
2304
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Component, { artifact, labels, callbacks });
2905
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Component, { artifact, labels, callbacks });
2305
2906
  }
2306
2907
 
2307
2908
  // src/components/blocks/block-services/artifact-ref-block-service.ts
@@ -2336,9 +2937,9 @@ function markdownToPlainText(markdown) {
2336
2937
  }
2337
2938
 
2338
2939
  // src/components/blocks/text-block/text-block.tsx
2339
- var import_react_markdown = __toESM(require("react-markdown"), 1);
2340
- var import_remark_breaks = __toESM(require("remark-breaks"), 1);
2341
- var import_remark_gfm = __toESM(require("remark-gfm"), 1);
2940
+ var import_react_markdown2 = __toESM(require("react-markdown"), 1);
2941
+ var import_remark_breaks2 = __toESM(require("remark-breaks"), 1);
2942
+ var import_remark_gfm2 = __toESM(require("remark-gfm"), 1);
2342
2943
 
2343
2944
  // src/components/blocks/scrollable-table/scrollable-table-styles.ts
2344
2945
  var import_styled_components3 = __toESM(require("styled-components"), 1);
@@ -2353,13 +2954,13 @@ var TableScroll = import_styled_components3.default.div`
2353
2954
  `;
2354
2955
 
2355
2956
  // src/components/blocks/scrollable-table/scrollable-table.tsx
2356
- var import_jsx_runtime24 = require("react/jsx-runtime");
2957
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2357
2958
  function ScrollableTable({ node: _node, ...props }) {
2358
- 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 }) }) });
2959
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TableContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TableScroll, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("table", { ...props }) }) });
2359
2960
  }
2360
2961
 
2361
2962
  // src/components/blocks/text-block/sanitize.ts
2362
- function sanitize(text) {
2963
+ function sanitize2(text) {
2363
2964
  return text.split("\n").filter((line) => {
2364
2965
  const t = line.trim();
2365
2966
  return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
@@ -2499,12 +3100,12 @@ var TextBlockWrapper = import_styled_components4.default.div`
2499
3100
  `;
2500
3101
 
2501
3102
  // src/components/blocks/text-block/text-block.tsx
2502
- var import_jsx_runtime25 = require("react/jsx-runtime");
3103
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2503
3104
  var markdownComponents = {
2504
- table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScrollableTable, { ...tableProps }))
3105
+ table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ScrollableTable, { ...tableProps }))
2505
3106
  };
2506
3107
  function TextBlock({ block }) {
2507
- 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) }) });
3108
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TextBlockWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_markdown2.default, { remarkPlugins: [import_remark_gfm2.default, import_remark_breaks2.default], components: markdownComponents, children: sanitize2(block.payload.text) }) });
2508
3109
  }
2509
3110
 
2510
3111
  // src/components/blocks/block-services/text-block-service.ts
@@ -2526,12 +3127,12 @@ var BlockServices = {
2526
3127
  };
2527
3128
 
2528
3129
  // src/components/blocks/block/block.tsx
2529
- var import_jsx_runtime26 = require("react/jsx-runtime");
3130
+ var import_jsx_runtime30 = require("react/jsx-runtime");
2530
3131
  function Block({ block }) {
2531
3132
  const service = BlockServices[block.type];
2532
3133
  if (!service) return null;
2533
3134
  const { Component } = service;
2534
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Component, { block });
3135
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Component, { block });
2535
3136
  }
2536
3137
 
2537
3138
  // src/components/chat/hooks/copy-message-text.ts
@@ -2549,13 +3150,13 @@ function copyMessageText(message) {
2549
3150
  }
2550
3151
 
2551
3152
  // src/components/chat/chat-message-actions/chat-message-actions.tsx
2552
- var import_react18 = require("react");
3153
+ var import_react21 = require("react");
2553
3154
 
2554
3155
  // src/components/chat/chat-context/chat-context.ts
2555
- var import_react16 = require("react");
2556
- var ChatContext = (0, import_react16.createContext)(null);
3156
+ var import_react19 = require("react");
3157
+ var ChatContext = (0, import_react19.createContext)(null);
2557
3158
  function useChatContext() {
2558
- const context = (0, import_react16.useContext)(ChatContext);
3159
+ const context = (0, import_react19.useContext)(ChatContext);
2559
3160
  if (!context) {
2560
3161
  throw new Error("useChatContext must be used within a Chat.Root component");
2561
3162
  }
@@ -2563,7 +3164,7 @@ function useChatContext() {
2563
3164
  }
2564
3165
 
2565
3166
  // src/components/chat/hooks/use-copy-to-clipboard.ts
2566
- var import_react17 = require("react");
3167
+ var import_react20 = require("react");
2567
3168
 
2568
3169
  // src/utils/clipboard.ts
2569
3170
  function copyToClipboard(text, options) {
@@ -2576,14 +3177,14 @@ function copyToClipboard(text, options) {
2576
3177
  // src/components/chat/hooks/use-copy-to-clipboard.ts
2577
3178
  var RESET_DELAY_MS = 2e3;
2578
3179
  function useCopyToClipboard() {
2579
- const [isCopied, setIsCopied] = (0, import_react17.useState)(false);
2580
- const timeoutRef = (0, import_react17.useRef)(null);
2581
- (0, import_react17.useEffect)(() => {
3180
+ const [isCopied, setIsCopied] = (0, import_react20.useState)(false);
3181
+ const timeoutRef = (0, import_react20.useRef)(null);
3182
+ (0, import_react20.useEffect)(() => {
2582
3183
  return () => {
2583
3184
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2584
3185
  };
2585
3186
  }, []);
2586
- const copy = (0, import_react17.useCallback)((text) => {
3187
+ const copy = (0, import_react20.useCallback)((text) => {
2587
3188
  copyToClipboard(text, {
2588
3189
  onSuccess: () => {
2589
3190
  setIsCopied(true);
@@ -2623,24 +3224,24 @@ var AnimatedAction = import_styled_components5.default.div`
2623
3224
  `;
2624
3225
 
2625
3226
  // src/components/chat/chat-message-actions/chat-message-actions.tsx
2626
- var import_jsx_runtime27 = require("react/jsx-runtime");
3227
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2627
3228
  function ChatMessageActions({ className, messageId, content, role, isHelpful }) {
2628
3229
  const { onCopyMessage, onThumbUpClick, onThumbDownClick } = useChatContext();
2629
3230
  const { isCopied, copy } = useCopyToClipboard();
2630
- const handleCopy = (0, import_react18.useCallback)(() => {
3231
+ const handleCopy = (0, import_react21.useCallback)(() => {
2631
3232
  copy(content);
2632
3233
  onCopyMessage?.(messageId);
2633
3234
  }, [content, messageId, copy, onCopyMessage]);
2634
- const handleThumbUp = (0, import_react18.useCallback)(() => {
3235
+ const handleThumbUp = (0, import_react21.useCallback)(() => {
2635
3236
  onThumbUpClick?.(messageId, isHelpful === true ? null : true);
2636
3237
  }, [messageId, isHelpful, onThumbUpClick]);
2637
- const handleThumbDown = (0, import_react18.useCallback)(() => {
3238
+ const handleThumbDown = (0, import_react21.useCallback)(() => {
2638
3239
  onThumbDownClick?.(messageId, isHelpful === false ? null : false);
2639
3240
  }, [messageId, isHelpful, onThumbDownClick]);
2640
3241
  const isAssistant = role === MESSAGE_ROLE.ASSISTANT;
2641
3242
  const hasFeedback = isAssistant && (onThumbUpClick || onThumbDownClick);
2642
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(ActionsContainer, { $role: role, className, children: [
2643
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3243
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(ActionsContainer, { $role: role, className, children: [
3244
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2644
3245
  IconButton,
2645
3246
  {
2646
3247
  icon: isCopied ? IconCheck : IconCopy,
@@ -2648,7 +3249,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
2648
3249
  "aria-label": isCopied ? "Copied" : "Copy message"
2649
3250
  }
2650
3251
  ),
2651
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3252
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2652
3253
  IconButton,
2653
3254
  {
2654
3255
  icon: IconThumbUp,
@@ -2657,7 +3258,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
2657
3258
  "aria-label": "Good response"
2658
3259
  }
2659
3260
  ) }),
2660
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3261
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2661
3262
  IconButton,
2662
3263
  {
2663
3264
  icon: IconThumbDown,
@@ -2708,12 +3309,12 @@ var MessageBubble = import_styled_components6.default.div`
2708
3309
  `;
2709
3310
 
2710
3311
  // src/components/chat/chat-message/chat-message.tsx
2711
- var import_jsx_runtime28 = require("react/jsx-runtime");
3312
+ var import_jsx_runtime32 = require("react/jsx-runtime");
2712
3313
  function ChatMessage({ message }) {
2713
- const clipboardText = (0, import_react19.useMemo)(() => copyMessageText(message), [message]);
2714
- 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: [
2715
- /* @__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)) }),
2716
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3314
+ const clipboardText = (0, import_react22.useMemo)(() => copyMessageText(message), [message]);
3315
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(MessageContainer, { $role: message.role, children: [
3316
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(MessageBubble, { $role: message.role, "data-testid": "message-bubble", children: message.blocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Block, { block }, index)) }),
3317
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2717
3318
  ChatMessageActions,
2718
3319
  {
2719
3320
  messageId: message.id,
@@ -2738,7 +3339,11 @@ function ChatMessage({ message }) {
2738
3339
  @tabler/icons-react/dist/esm/defaultAttributes.mjs:
2739
3340
  @tabler/icons-react/dist/esm/createReactComponent.mjs:
2740
3341
  @tabler/icons-react/dist/esm/icons/IconAlertCircle.mjs:
3342
+ @tabler/icons-react/dist/esm/icons/IconArrowsMaximize.mjs:
3343
+ @tabler/icons-react/dist/esm/icons/IconArrowsMinimize.mjs:
2741
3344
  @tabler/icons-react/dist/esm/icons/IconCheck.mjs:
3345
+ @tabler/icons-react/dist/esm/icons/IconChevronLeft.mjs:
3346
+ @tabler/icons-react/dist/esm/icons/IconChevronRight.mjs:
2742
3347
  @tabler/icons-react/dist/esm/icons/IconCopy.mjs:
2743
3348
  @tabler/icons-react/dist/esm/icons/IconDownload.mjs:
2744
3349
  @tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs: