@shapesos/clay 0.17.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 (80) 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 +963 -34
  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 +677 -50
  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 +3 -1
  22. package/dist/chart.cjs.map +1 -1
  23. package/dist/chart.js +2 -2
  24. package/dist/chat.cjs +701 -74
  25. package/dist/chat.cjs.map +1 -1
  26. package/dist/chat.d.cts +2 -2
  27. package/dist/chat.d.ts +2 -2
  28. package/dist/chat.js +6 -6
  29. package/dist/{chunk-46ZYTBX5.js → chunk-7MY4X4YL.js} +3 -3
  30. package/dist/chunk-BHHJOG5X.js +1 -0
  31. package/dist/{chunk-B6GAPZ2R.js → chunk-CATIRDZP.js} +5 -5
  32. package/dist/{chunk-B4U37WIH.js → chunk-CFCLVJIO.js} +2 -2
  33. package/dist/{chunk-PYDVANWI.js → chunk-E36VI2HA.js} +2 -2
  34. package/dist/{chunk-PUVZ2S3F.js → chunk-G4NXVFXU.js} +2 -2
  35. package/dist/{chunk-JAGNXEWK.js → chunk-GK4XW4BC.js} +2 -2
  36. package/dist/{chunk-4VE6ZXXW.js → chunk-MQP57DOP.js} +3 -3
  37. package/dist/{chunk-6YZ65KPW.js → chunk-QR4VBGK4.js} +673 -42
  38. package/dist/chunk-QR4VBGK4.js.map +1 -0
  39. package/dist/{chunk-JF3P66JF.js → chunk-SN3ORQSJ.js} +4 -2
  40. package/dist/{chunk-JF3P66JF.js.map → chunk-SN3ORQSJ.js.map} +1 -1
  41. package/dist/{chunk-PGR2MDDU.js → chunk-W66OJM55.js} +2 -2
  42. package/dist/{chunk-7OYIDM42.js → chunk-XKURJ72I.js} +2 -2
  43. package/dist/{dom-to-image-NATF3446.js → dom-to-image-QB7KMTAE.js} +3 -3
  44. package/dist/icon.cjs +3 -1
  45. package/dist/icon.cjs.map +1 -1
  46. package/dist/icon.js +2 -2
  47. package/dist/index.cjs +767 -132
  48. package/dist/index.cjs.map +1 -1
  49. package/dist/index.d.cts +3 -3
  50. package/dist/index.d.ts +3 -3
  51. package/dist/index.js +19 -11
  52. package/dist/keyboard-shortcut.cjs +3 -1
  53. package/dist/keyboard-shortcut.cjs.map +1 -1
  54. package/dist/keyboard-shortcut.js +2 -2
  55. package/dist/text-area.cjs +3 -1
  56. package/dist/text-area.cjs.map +1 -1
  57. package/dist/text-area.js +2 -2
  58. package/dist/tokens.cjs +3 -1
  59. package/dist/tokens.cjs.map +1 -1
  60. package/dist/tokens.d.cts +1 -0
  61. package/dist/tokens.d.ts +1 -0
  62. package/dist/tokens.js +1 -1
  63. package/dist/{types-CW45GBXl.d.cts → types-BDYPVP2N.d.cts} +1 -1
  64. package/dist/{types-D1b8v7EY.d.ts → types-BMwa4bPW.d.ts} +1 -1
  65. package/dist/{types-GCkXbyFm.d.ts → types-C8JtnwNY.d.ts} +200 -4
  66. package/dist/{types-BzXPBy6s.d.cts → types-DTdDFU3O.d.cts} +200 -4
  67. package/package.json +1 -1
  68. package/dist/chunk-6YZ65KPW.js.map +0 -1
  69. package/dist/chunk-RSRNSWJN.js +0 -1
  70. /package/dist/{chunk-46ZYTBX5.js.map → chunk-7MY4X4YL.js.map} +0 -0
  71. /package/dist/{chunk-RSRNSWJN.js.map → chunk-BHHJOG5X.js.map} +0 -0
  72. /package/dist/{chunk-B6GAPZ2R.js.map → chunk-CATIRDZP.js.map} +0 -0
  73. /package/dist/{chunk-B4U37WIH.js.map → chunk-CFCLVJIO.js.map} +0 -0
  74. /package/dist/{chunk-PYDVANWI.js.map → chunk-E36VI2HA.js.map} +0 -0
  75. /package/dist/{chunk-PUVZ2S3F.js.map → chunk-G4NXVFXU.js.map} +0 -0
  76. /package/dist/{chunk-JAGNXEWK.js.map → chunk-GK4XW4BC.js.map} +0 -0
  77. /package/dist/{chunk-4VE6ZXXW.js.map → chunk-MQP57DOP.js.map} +0 -0
  78. /package/dist/{chunk-PGR2MDDU.js.map → chunk-W66OJM55.js.map} +0 -0
  79. /package/dist/{chunk-7OYIDM42.js.map → chunk-XKURJ72I.js.map} +0 -0
  80. /package/dist/{dom-to-image-NATF3446.js.map → dom-to-image-QB7KMTAE.js.map} +0 -0
@@ -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
  });
@@ -272,10 +274,14 @@ __export(artifacts_exports, {
272
274
  ArtifactServices: () => ArtifactServices,
273
275
  ChartArtifact: () => ChartArtifact,
274
276
  DEFAULT_CHART_ARTIFACT_LABELS: () => DEFAULT_CHART_ARTIFACT_LABELS,
277
+ DEFAULT_DECK_ARTIFACT_LABELS: () => DEFAULT_DECK_ARTIFACT_LABELS,
275
278
  DEFAULT_TABLE_ARTIFACT_LABELS: () => DEFAULT_TABLE_ARTIFACT_LABELS,
279
+ DeckArtifact: () => DeckArtifact,
276
280
  TableArtifact: () => TableArtifact,
277
281
  artifactToClipboardText: () => artifactToClipboardText,
278
282
  artifactTypes: () => artifactTypes,
283
+ deckBlockTypes: () => deckBlockTypes,
284
+ deckSlideKinds: () => deckSlideKinds,
279
285
  isSafeDownloadUrl: () => isSafeDownloadUrl
280
286
  });
281
287
  module.exports = __toCommonJS(artifacts_exports);
@@ -283,7 +289,8 @@ module.exports = __toCommonJS(artifacts_exports);
283
289
  // src/components/artifacts/artifact-base.ts
284
290
  var artifactTypes = {
285
291
  TABLE: "TABLE",
286
- CHART: "CHART"
292
+ CHART: "CHART",
293
+ DECK: "DECK"
287
294
  };
288
295
 
289
296
  // src/components/artifacts/chart-artifact/types.ts
@@ -308,6 +315,34 @@ var DEFAULT_TABLE_ARTIFACT_LABELS = {
308
315
  empty: "No rows to display."
309
316
  };
310
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
+
311
346
  // src/components/artifacts/chart-artifact/chart-artifact.tsx
312
347
  var import_react13 = require("react");
313
348
 
@@ -400,29 +435,45 @@ var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
400
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" }]];
401
436
  var IconAlertCircle = createReactComponent("outline", "alert-circle", "AlertCircle", __iconNode);
402
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
+
403
446
  // node_modules/@tabler/icons-react/dist/esm/icons/IconCheck.mjs
404
- var __iconNode2 = [["path", { "d": "M5 12l5 5l10 -10", "key": "svg-0" }]];
405
- 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);
406
457
 
407
458
  // node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.mjs
408
- 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" }]];
409
- 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);
410
461
 
411
462
  // node_modules/@tabler/icons-react/dist/esm/icons/IconDownload.mjs
412
- 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" }]];
413
- 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);
414
465
 
415
466
  // node_modules/@tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs
416
- 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" }]];
417
- 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);
418
469
 
419
470
  // node_modules/@tabler/icons-react/dist/esm/icons/IconLoader2.mjs
420
- var __iconNode6 = [["path", { "d": "M12 3a9 9 0 1 0 9 9", "key": "svg-0" }]];
421
- 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);
422
473
 
423
474
  // node_modules/@tabler/icons-react/dist/esm/icons/IconPhoto.mjs
424
- 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" }]];
425
- 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);
426
477
 
427
478
  // src/components/artifacts/artifact-copy-as-image-button/artifact-copy-as-image-button.tsx
428
479
  var import_react6 = require("react");
@@ -958,6 +1009,300 @@ function ChartTooltipContent({
958
1009
  // src/tokens/index.ts
959
1010
  init_colors();
960
1011
 
1012
+ // src/tokens/typography.ts
1013
+ var fontFamilies = {
1014
+ /** Geist — primary UI font for body text, labels, headings, and display. */
1015
+ GEIST: "Geist",
1016
+ /** Crimson Pro — editorial/serif font, mostly italic. Used for decorative headings and pull quotes. */
1017
+ CRIMSON_PRO: "Crimson Pro"
1018
+ };
1019
+ var typographyTypes = {
1020
+ // Geist Label Caption (12px)
1021
+ GEIST_LABEL_CAPTION_REGULAR: "GEIST_LABEL_CAPTION_REGULAR",
1022
+ GEIST_LABEL_CAPTION_MEDIUM: "GEIST_LABEL_CAPTION_MEDIUM",
1023
+ GEIST_LABEL_CAPTION_SEMI_BOLD: "GEIST_LABEL_CAPTION_SEMI_BOLD",
1024
+ // Geist Body Extra Small (14px)
1025
+ GEIST_BODY_XS_REGULAR: "GEIST_BODY_XS_REGULAR",
1026
+ GEIST_BODY_XS_MEDIUM: "GEIST_BODY_XS_MEDIUM",
1027
+ GEIST_BODY_XS_BOLD: "GEIST_BODY_XS_BOLD",
1028
+ // Geist Body Small (16px)
1029
+ GEIST_BODY_S_REGULAR: "GEIST_BODY_S_REGULAR",
1030
+ GEIST_BODY_S_MEDIUM: "GEIST_BODY_S_MEDIUM",
1031
+ GEIST_BODY_S_SEMI_BOLD: "GEIST_BODY_S_SEMI_BOLD",
1032
+ GEIST_BODY_S_BOLD: "GEIST_BODY_S_BOLD",
1033
+ // Geist Body Medium (18px)
1034
+ GEIST_BODY_M_LIGHT: "GEIST_BODY_M_LIGHT",
1035
+ GEIST_BODY_M_REGULAR: "GEIST_BODY_M_REGULAR",
1036
+ GEIST_BODY_M_MEDIUM: "GEIST_BODY_M_MEDIUM",
1037
+ GEIST_BODY_M_SEMI_BOLD: "GEIST_BODY_M_SEMI_BOLD",
1038
+ // Geist Body Large (20px)
1039
+ GEIST_BODY_L_REGULAR: "GEIST_BODY_L_REGULAR",
1040
+ GEIST_BODY_L_MEDIUM: "GEIST_BODY_L_MEDIUM",
1041
+ GEIST_BODY_L_SEMI_BOLD: "GEIST_BODY_L_SEMI_BOLD",
1042
+ GEIST_BODY_L_BOLD: "GEIST_BODY_L_BOLD",
1043
+ // Geist Heading Small (24px)
1044
+ GEIST_HEADING_S_REGULAR: "GEIST_HEADING_S_REGULAR",
1045
+ GEIST_HEADING_S_MEDIUM: "GEIST_HEADING_S_MEDIUM",
1046
+ GEIST_HEADING_S_BOLD: "GEIST_HEADING_S_BOLD",
1047
+ // Geist Heading Medium (28px)
1048
+ GEIST_HEADING_M_BOLD: "GEIST_HEADING_M_BOLD",
1049
+ // Geist Heading Large (32px)
1050
+ GEIST_HEADING_L_REGULAR: "GEIST_HEADING_L_REGULAR",
1051
+ GEIST_HEADING_L_MEDIUM: "GEIST_HEADING_L_MEDIUM",
1052
+ GEIST_HEADING_L_SEMI_BOLD: "GEIST_HEADING_L_SEMI_BOLD",
1053
+ GEIST_HEADING_L_BOLD: "GEIST_HEADING_L_BOLD",
1054
+ // Geist Display Large (36px)
1055
+ GEIST_DISPLAY_L_MEDIUM: "GEIST_DISPLAY_L_MEDIUM",
1056
+ // Crimson Pro Body Small (16px, italic)
1057
+ CRIMSON_PRO_BODY_S_LIGHT_ITALIC: "CRIMSON_PRO_BODY_S_LIGHT_ITALIC",
1058
+ // Crimson Pro Body Medium (18px, italic)
1059
+ CRIMSON_PRO_BODY_M_LIGHT_ITALIC: "CRIMSON_PRO_BODY_M_LIGHT_ITALIC",
1060
+ // Crimson Pro Heading Medium (24px, italic)
1061
+ CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC: "CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC",
1062
+ // Crimson Pro Display Large (40px, upright)
1063
+ CRIMSON_PRO_DISPLAY_L_REGULAR: "CRIMSON_PRO_DISPLAY_L_REGULAR",
1064
+ // Crimson Pro Display Extra Large (46px, italic)
1065
+ CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC: "CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC"
1066
+ };
1067
+ var typographyStyles = {
1068
+ // Geist Label Caption (12px)
1069
+ [typographyTypes.GEIST_LABEL_CAPTION_REGULAR]: {
1070
+ fontFamily: fontFamilies.GEIST,
1071
+ fontSize: 12,
1072
+ fontWeight: 400,
1073
+ lineHeight: 16
1074
+ },
1075
+ [typographyTypes.GEIST_LABEL_CAPTION_MEDIUM]: {
1076
+ fontFamily: fontFamilies.GEIST,
1077
+ fontSize: 12,
1078
+ fontWeight: 500,
1079
+ lineHeight: 16
1080
+ },
1081
+ [typographyTypes.GEIST_LABEL_CAPTION_SEMI_BOLD]: {
1082
+ fontFamily: fontFamilies.GEIST,
1083
+ fontSize: 12,
1084
+ fontWeight: 600,
1085
+ lineHeight: 16
1086
+ },
1087
+ // Geist Body Extra Small (14px)
1088
+ [typographyTypes.GEIST_BODY_XS_REGULAR]: {
1089
+ fontFamily: fontFamilies.GEIST,
1090
+ fontSize: 14,
1091
+ fontWeight: 400,
1092
+ lineHeight: 20
1093
+ },
1094
+ [typographyTypes.GEIST_BODY_XS_MEDIUM]: {
1095
+ fontFamily: fontFamilies.GEIST,
1096
+ fontSize: 14,
1097
+ fontWeight: 500,
1098
+ lineHeight: 20
1099
+ },
1100
+ [typographyTypes.GEIST_BODY_XS_BOLD]: {
1101
+ fontFamily: fontFamilies.GEIST,
1102
+ fontSize: 14,
1103
+ fontWeight: 600,
1104
+ lineHeight: 20
1105
+ },
1106
+ // Geist Body Small (16px)
1107
+ [typographyTypes.GEIST_BODY_S_REGULAR]: {
1108
+ fontFamily: fontFamilies.GEIST,
1109
+ fontSize: 16,
1110
+ fontWeight: 400,
1111
+ lineHeight: 24,
1112
+ letterSpacing: -0.08
1113
+ },
1114
+ [typographyTypes.GEIST_BODY_S_MEDIUM]: {
1115
+ fontFamily: fontFamilies.GEIST,
1116
+ fontSize: 16,
1117
+ fontWeight: 500,
1118
+ lineHeight: 24,
1119
+ letterSpacing: -0.08
1120
+ },
1121
+ [typographyTypes.GEIST_BODY_S_SEMI_BOLD]: {
1122
+ fontFamily: fontFamilies.GEIST,
1123
+ fontSize: 16,
1124
+ fontWeight: 600,
1125
+ lineHeight: 24,
1126
+ letterSpacing: -0.08
1127
+ },
1128
+ [typographyTypes.GEIST_BODY_S_BOLD]: {
1129
+ fontFamily: fontFamilies.GEIST,
1130
+ fontSize: 16,
1131
+ fontWeight: 700,
1132
+ lineHeight: 24,
1133
+ letterSpacing: -0.08
1134
+ },
1135
+ // Geist Body Medium (18px)
1136
+ [typographyTypes.GEIST_BODY_M_LIGHT]: {
1137
+ fontFamily: fontFamilies.GEIST,
1138
+ fontSize: 18,
1139
+ fontWeight: 300,
1140
+ lineHeight: 28,
1141
+ letterSpacing: -0.09
1142
+ },
1143
+ [typographyTypes.GEIST_BODY_M_REGULAR]: {
1144
+ fontFamily: fontFamilies.GEIST,
1145
+ fontSize: 18,
1146
+ fontWeight: 400,
1147
+ lineHeight: 28,
1148
+ letterSpacing: -0.09
1149
+ },
1150
+ [typographyTypes.GEIST_BODY_M_MEDIUM]: {
1151
+ fontFamily: fontFamilies.GEIST,
1152
+ fontSize: 18,
1153
+ fontWeight: 500,
1154
+ lineHeight: 28,
1155
+ letterSpacing: -0.09
1156
+ },
1157
+ [typographyTypes.GEIST_BODY_M_SEMI_BOLD]: {
1158
+ fontFamily: fontFamilies.GEIST,
1159
+ fontSize: 18,
1160
+ fontWeight: 600,
1161
+ lineHeight: 28,
1162
+ letterSpacing: -0.09
1163
+ },
1164
+ // Geist Body Large (20px)
1165
+ [typographyTypes.GEIST_BODY_L_REGULAR]: {
1166
+ fontFamily: fontFamilies.GEIST,
1167
+ fontSize: 20,
1168
+ fontWeight: 400,
1169
+ lineHeight: 30,
1170
+ letterSpacing: -0.2
1171
+ },
1172
+ [typographyTypes.GEIST_BODY_L_MEDIUM]: {
1173
+ fontFamily: fontFamilies.GEIST,
1174
+ fontSize: 20,
1175
+ fontWeight: 500,
1176
+ lineHeight: 30,
1177
+ letterSpacing: -0.2
1178
+ },
1179
+ [typographyTypes.GEIST_BODY_L_SEMI_BOLD]: {
1180
+ fontFamily: fontFamilies.GEIST,
1181
+ fontSize: 20,
1182
+ fontWeight: 600,
1183
+ lineHeight: 30,
1184
+ letterSpacing: -0.2
1185
+ },
1186
+ [typographyTypes.GEIST_BODY_L_BOLD]: {
1187
+ fontFamily: fontFamilies.GEIST,
1188
+ fontSize: 20,
1189
+ fontWeight: 700,
1190
+ lineHeight: 30,
1191
+ letterSpacing: -0.2
1192
+ },
1193
+ // Geist Heading Small (24px)
1194
+ [typographyTypes.GEIST_HEADING_S_REGULAR]: {
1195
+ fontFamily: fontFamilies.GEIST,
1196
+ fontSize: 24,
1197
+ fontWeight: 400,
1198
+ lineHeight: 32,
1199
+ letterSpacing: -0.48
1200
+ },
1201
+ [typographyTypes.GEIST_HEADING_S_MEDIUM]: {
1202
+ fontFamily: fontFamilies.GEIST,
1203
+ fontSize: 24,
1204
+ fontWeight: 500,
1205
+ lineHeight: 32,
1206
+ letterSpacing: -0.48
1207
+ },
1208
+ [typographyTypes.GEIST_HEADING_S_BOLD]: {
1209
+ fontFamily: fontFamilies.GEIST,
1210
+ fontSize: 24,
1211
+ fontWeight: 700,
1212
+ lineHeight: 32,
1213
+ letterSpacing: -0.48
1214
+ },
1215
+ // Geist Heading Medium (28px)
1216
+ [typographyTypes.GEIST_HEADING_M_BOLD]: {
1217
+ fontFamily: fontFamilies.GEIST,
1218
+ fontSize: 28,
1219
+ fontWeight: 700,
1220
+ lineHeight: 36,
1221
+ letterSpacing: -0.6
1222
+ },
1223
+ // Geist Heading Large (32px)
1224
+ [typographyTypes.GEIST_HEADING_L_REGULAR]: {
1225
+ fontFamily: fontFamilies.GEIST,
1226
+ fontSize: 32,
1227
+ fontWeight: 400,
1228
+ lineHeight: 40,
1229
+ letterSpacing: -0.64
1230
+ },
1231
+ [typographyTypes.GEIST_HEADING_L_MEDIUM]: {
1232
+ fontFamily: fontFamilies.GEIST,
1233
+ fontSize: 32,
1234
+ fontWeight: 500,
1235
+ lineHeight: 40,
1236
+ letterSpacing: -0.64
1237
+ },
1238
+ [typographyTypes.GEIST_HEADING_L_SEMI_BOLD]: {
1239
+ fontFamily: fontFamilies.GEIST,
1240
+ fontSize: 32,
1241
+ fontWeight: 600,
1242
+ lineHeight: 40,
1243
+ letterSpacing: -0.64
1244
+ },
1245
+ [typographyTypes.GEIST_HEADING_L_BOLD]: {
1246
+ fontFamily: fontFamilies.GEIST,
1247
+ fontSize: 32,
1248
+ fontWeight: 700,
1249
+ lineHeight: 40,
1250
+ letterSpacing: -0.64
1251
+ },
1252
+ // Geist Display Large (36px)
1253
+ [typographyTypes.GEIST_DISPLAY_L_MEDIUM]: {
1254
+ fontFamily: fontFamilies.GEIST,
1255
+ fontSize: 36,
1256
+ fontWeight: 500,
1257
+ lineHeight: 44,
1258
+ letterSpacing: -0.72
1259
+ },
1260
+ // Crimson Pro Body Small (16px, italic)
1261
+ [typographyTypes.CRIMSON_PRO_BODY_S_LIGHT_ITALIC]: {
1262
+ fontFamily: fontFamilies.CRIMSON_PRO,
1263
+ fontSize: 16,
1264
+ fontWeight: 300,
1265
+ lineHeight: 20,
1266
+ letterSpacing: -0.32,
1267
+ fontStyle: "italic"
1268
+ },
1269
+ // Crimson Pro Body Medium (18px, italic)
1270
+ [typographyTypes.CRIMSON_PRO_BODY_M_LIGHT_ITALIC]: {
1271
+ fontFamily: fontFamilies.CRIMSON_PRO,
1272
+ fontSize: 18,
1273
+ fontWeight: 300,
1274
+ lineHeight: 28,
1275
+ letterSpacing: 0,
1276
+ fontStyle: "italic"
1277
+ },
1278
+ // Crimson Pro Heading Medium (24px, italic)
1279
+ [typographyTypes.CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC]: {
1280
+ fontFamily: fontFamilies.CRIMSON_PRO,
1281
+ fontSize: 24,
1282
+ fontWeight: 400,
1283
+ lineHeight: 32,
1284
+ letterSpacing: -0.48,
1285
+ fontStyle: "italic"
1286
+ },
1287
+ // Crimson Pro Display Large (40px, upright)
1288
+ [typographyTypes.CRIMSON_PRO_DISPLAY_L_REGULAR]: {
1289
+ fontFamily: fontFamilies.CRIMSON_PRO,
1290
+ fontSize: 40,
1291
+ fontWeight: 300,
1292
+ lineHeight: 48,
1293
+ letterSpacing: -1.6
1294
+ },
1295
+ // Crimson Pro Display Extra Large (46px, italic)
1296
+ [typographyTypes.CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC]: {
1297
+ fontFamily: fontFamilies.CRIMSON_PRO,
1298
+ fontSize: 46,
1299
+ fontWeight: 400,
1300
+ lineHeight: 54,
1301
+ letterSpacing: -1.38,
1302
+ fontStyle: "italic"
1303
+ }
1304
+ };
1305
+
961
1306
  // src/components/chart/chart-palette.ts
962
1307
  var CHART_PALETTE = [
963
1308
  colors["blue-600"],
@@ -1690,8 +2035,13 @@ var ChartArtifactService = {
1690
2035
  toClipboardText: chartArtifactToClipboardText
1691
2036
  };
1692
2037
 
1693
- // src/components/artifacts/table-artifact/table-artifact.tsx
1694
- var import_react15 = require("react");
2038
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
2039
+ var import_react17 = require("react");
2040
+ var import_react_dom = require("react-dom");
2041
+ init_capture_exclude_attribute();
2042
+
2043
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
2044
+ var import_react16 = require("react");
1695
2045
 
1696
2046
  // src/components/ui/table.tsx
1697
2047
  var React3 = __toESM(require("react"), 1);
@@ -1838,9 +2188,333 @@ function renderEmptyRow(colSpan, emptyMessage) {
1838
2188
  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 }) });
1839
2189
  }
1840
2190
 
1841
- // src/components/artifacts/table-artifact/use-table-artifact-data.ts
1842
- function useTableArtifactData(presignedUrl, columns) {
1843
- return useRowsArtifactData(presignedUrl, columns, parseCsv);
2191
+ // src/components/artifacts/deck-artifact/deck-markdown.tsx
2192
+ var import_react_markdown = __toESM(require("react-markdown"), 1);
2193
+ var import_remark_breaks = __toESM(require("remark-breaks"), 1);
2194
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
2195
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2196
+ function sanitize(text) {
2197
+ return text.split("\n").filter((line) => {
2198
+ const t = line.trim();
2199
+ return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
2200
+ }).join("\n");
2201
+ }
2202
+ var MARKDOWN_COMPONENTS = {
2203
+ h1: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { className: "text-[30px] font-semibold leading-tight text-foreground mb-3", ...props }),
2204
+ h2: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { className: "text-[26px] font-semibold leading-tight text-foreground mb-2", ...props }),
2205
+ h3: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2206
+ h4: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h4", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2207
+ h5: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h5", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2208
+ h6: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h6", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
2209
+ p: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[22px] leading-relaxed text-foreground my-2", ...props }),
2210
+ 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 }),
2211
+ 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 }),
2212
+ // react-markdown injects list metadata (`ordered` / `index` / `checked`) that must not leak to the DOM.
2213
+ li: ({ node: _node, ordered: _ordered, index: _index, checked: _checked, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { className: "my-1", ...props }),
2214
+ strong: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { className: "font-semibold", ...props }),
2215
+ em: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("em", { className: "italic", ...props }),
2216
+ // Gate `<img src>` against an http(s) allowlist. react-markdown v8 percent-encodes the URL but
2217
+ // does NOT protocol-filter image src (unlike link href), so an LLM-authored
2218
+ // `![](javascript:…)` / `![](data:…)` or a tracking-pixel `![](http://…)` would otherwise render
2219
+ // with the raw URL. Unsafe src → render nothing.
2220
+ img: ({ node: _node, src, ...props }) => typeof src === "string" && isSafeDownloadUrl(src) ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("img", { src, className: "max-w-full", ...props }) : null,
2221
+ a: ({ node: _node, ...props }) => (
2222
+ // `rel` is forced AFTER `{...props}` so it can't be overridden — if a consumer ever adds
2223
+ // `linkTarget="_blank"`, LLM-authored links still can't reach `window.opener`.
2224
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { className: "underline underline-offset-2", ...props, rel: "noopener noreferrer" })
2225
+ ),
2226
+ // react-markdown passes `inline` to distinguish inline code from fenced blocks — strip it from the DOM.
2227
+ 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 }),
2228
+ 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 }),
2229
+ hr: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("hr", { className: "my-4 border-brown-alpha-12", ...props }),
2230
+ 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 }) }),
2231
+ // react-markdown passes `isHeader` to cell renderers — strip it so it never reaches the DOM.
2232
+ 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 }),
2233
+ 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 })
2234
+ };
2235
+ function DeckMarkdown({ markdown }) {
2236
+ 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) });
2237
+ }
2238
+
2239
+ // src/components/artifacts/deck-artifact/slide-renderers.tsx
2240
+ var import_react15 = require("react");
2241
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2242
+ function safeLogoUrl(meta) {
2243
+ return meta?.logoUrl && isSafeDownloadUrl(meta.logoUrl) ? meta.logoUrl : null;
2244
+ }
2245
+ var DESIGN_W = 1280;
2246
+ var DESIGN_H = 720;
2247
+ var EYEBROW_H = 84;
2248
+ var CANVAS_LOGO_MAX_H = 48;
2249
+ var ACCENT_FONT = { fontFamily: `"${fontFamilies.CRIMSON_PRO}", serif`, fontStyle: "italic" };
2250
+ function SlideFrame({ meta, children, accent = false, bare = false }) {
2251
+ const frameRef = (0, import_react15.useRef)(null);
2252
+ const [scale, setScale] = (0, import_react15.useState)(null);
2253
+ (0, import_react15.useLayoutEffect)(() => {
2254
+ const el = frameRef.current;
2255
+ if (!el) return;
2256
+ const apply = (width) => {
2257
+ if (width > 0) setScale(width / DESIGN_W);
2258
+ };
2259
+ apply(el.clientWidth);
2260
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.width ?? 0));
2261
+ ro.observe(el);
2262
+ return () => ro.disconnect();
2263
+ }, []);
2264
+ const bg = accent ? "bg-indigo-600" : "bg-deck-canvas";
2265
+ const eyebrowColor = accent ? "text-white/70" : "text-brown-60";
2266
+ const borderColor = accent ? "border-white/20" : "border-brown-alpha-12";
2267
+ const logoSrc = safeLogoUrl(meta);
2268
+ 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)(
2269
+ "div",
2270
+ {
2271
+ className: "absolute left-0 top-0 origin-top-left",
2272
+ style: {
2273
+ width: DESIGN_W,
2274
+ height: DESIGN_H,
2275
+ transform: `scale(${scale ?? 0})`,
2276
+ visibility: scale === null ? "hidden" : "visible"
2277
+ },
2278
+ children: [
2279
+ !bare ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2280
+ "div",
2281
+ {
2282
+ className: `absolute inset-x-0 top-0 flex items-center justify-between border-b px-16 ${borderColor}`,
2283
+ style: { height: EYEBROW_H },
2284
+ children: [
2285
+ 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", {}),
2286
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("img", { src: logoSrc, alt: "", className: "object-contain", style: { maxHeight: CANVAS_LOGO_MAX_H } }) : null
2287
+ ]
2288
+ }
2289
+ ) : null,
2290
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "absolute inset-x-0 bottom-0 overflow-hidden", style: { top: bare ? 0 : EYEBROW_H }, children })
2291
+ ]
2292
+ }
2293
+ ) });
2294
+ }
2295
+ function TitleSlide({ slide, meta }) {
2296
+ const logoSrc = safeLogoUrl(meta);
2297
+ 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: [
2298
+ logoSrc ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2299
+ "img",
2300
+ {
2301
+ src: logoSrc,
2302
+ alt: "",
2303
+ className: "mb-16 object-contain object-left",
2304
+ style: { maxHeight: 56, maxWidth: 380 }
2305
+ }
2306
+ ) : null,
2307
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2308
+ "h1",
2309
+ {
2310
+ className: "font-bold tracking-tight text-brown-100",
2311
+ style: { fontSize: 92, lineHeight: 1.04, maxWidth: 1060 },
2312
+ children: slide.title
2313
+ }
2314
+ ),
2315
+ slide.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-7 text-brown-70", style: { ...ACCENT_FONT, fontSize: 34 }, children: slide.subtitle }) : null,
2316
+ 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,
2317
+ meta?.date ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-10 text-brown-70", style: { ...ACCENT_FONT, fontSize: 30 }, children: meta.date }) : null
2318
+ ] }) });
2319
+ }
2320
+ function AgendaSlide({ slide, meta, labels }) {
2321
+ const items = slide.items ?? [];
2322
+ 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: [
2323
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "mb-10 font-bold text-brown-90", style: { fontSize: 40 }, children: slide.title || labels.agenda }),
2324
+ /* @__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: [
2325
+ /* @__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") }),
2326
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-brown-90", style: { fontSize: 28 }, children: item })
2327
+ ] }, i)) })
2328
+ ] }) });
2329
+ }
2330
+ function SectionSlide({ slide, meta }) {
2331
+ 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: [
2332
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "font-bold text-white", style: { fontSize: 72, lineHeight: 1.05, maxWidth: 940 }, children: slide.title }),
2333
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-2 bg-white/50", style: { width: 96, height: 5 } })
2334
+ ] }) });
2335
+ }
2336
+ function ClosingSlide({ meta, labels }) {
2337
+ 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: [
2338
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "font-bold text-brown-100", style: { fontSize: 72 }, children: labels.thankYou }),
2339
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-indigo-600", style: { ...ACCENT_FONT, fontSize: 36 }, children: labels.questions })
2340
+ ] }) });
2341
+ }
2342
+
2343
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
2344
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2345
+ var TABLE_BLOCK_MAX_SHIMMER_ROWS = 10;
2346
+ var TABLE_CHROME_RESERVE = 56;
2347
+ var VISUAL_FALLBACK_HEIGHT = 360;
2348
+ function DeckArtifactContent({
2349
+ slides,
2350
+ labels,
2351
+ onNavigate,
2352
+ meta,
2353
+ onDark = false,
2354
+ currentSlide,
2355
+ onSlideChange
2356
+ }) {
2357
+ const navBtnClass = onDark ? "[&_svg]:!text-white hover:!bg-white/20 disabled:opacity-40" : void 0;
2358
+ const navBtnSize = onDark ? "medium" : "small";
2359
+ const isControlled = currentSlide !== void 0;
2360
+ const [internalIndex, setInternalIndex] = (0, import_react16.useState)(0);
2361
+ const index = isControlled ? currentSlide : internalIndex;
2362
+ const current = Math.min(index, slides.length - 1);
2363
+ const slide = slides[current];
2364
+ const goTo = (0, import_react16.useCallback)(
2365
+ (next) => {
2366
+ const clamped = Math.max(0, Math.min(next, slides.length - 1));
2367
+ if (isControlled) onSlideChange?.(clamped);
2368
+ else setInternalIndex(clamped);
2369
+ onNavigate?.(clamped);
2370
+ },
2371
+ [slides.length, onNavigate, isControlled, onSlideChange]
2372
+ );
2373
+ const position = labels.position.replace("{current}", String(current + 1)).replace("{total}", String(slides.length));
2374
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-3 p-4", children: [
2375
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SlideDispatch, { slide, labels, meta }),
2376
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2377
+ "div",
2378
+ {
2379
+ className: `flex items-center justify-between border-t pt-2 ${onDark ? "border-white/20" : "border-brown-alpha-12"}`,
2380
+ children: [
2381
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2382
+ IconButton,
2383
+ {
2384
+ icon: IconChevronLeft,
2385
+ size: navBtnSize,
2386
+ className: navBtnClass,
2387
+ "aria-label": labels.previous,
2388
+ disabled: current === 0,
2389
+ onClick: () => goTo(current - 1)
2390
+ }
2391
+ ),
2392
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: `text-xs font-medium ${onDark ? "text-white/70" : "text-brown-70"}`, children: position }),
2393
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2394
+ IconButton,
2395
+ {
2396
+ icon: IconChevronRight,
2397
+ size: navBtnSize,
2398
+ className: navBtnClass,
2399
+ "aria-label": labels.next,
2400
+ disabled: current === slides.length - 1,
2401
+ onClick: () => goTo(current + 1)
2402
+ }
2403
+ )
2404
+ ]
2405
+ }
2406
+ )
2407
+ ] });
2408
+ }
2409
+ function SlideDispatch({ slide, labels, meta }) {
2410
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
2411
+ switch (kind) {
2412
+ case deckSlideKinds.TITLE:
2413
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TitleSlide, { slide, meta });
2414
+ case deckSlideKinds.AGENDA:
2415
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AgendaSlide, { slide, meta, labels });
2416
+ case deckSlideKinds.SECTION:
2417
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SectionSlide, { slide, meta });
2418
+ case deckSlideKinds.CLOSING:
2419
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ClosingSlide, { meta, labels });
2420
+ case deckSlideKinds.CONTENT:
2421
+ default:
2422
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ContentSlide, { slide, meta, labels });
2423
+ }
2424
+ }
2425
+ function isVisualBlock(block) {
2426
+ return block.type === deckBlockTypes.CHART || block.type === deckBlockTypes.TABLE;
2427
+ }
2428
+ function ContentSlide({ slide, meta, labels }) {
2429
+ const content = slide.content ?? [];
2430
+ const visuals = content.filter(isVisualBlock);
2431
+ const texts = content.filter(
2432
+ (b) => b.type === deckBlockTypes.TEXT
2433
+ );
2434
+ if (visuals.length === 1 && texts.length > 0) {
2435
+ 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: [
2436
+ /* @__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: [
2437
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "mb-5 font-bold leading-tight text-foreground", style: { fontSize: 34 }, children: slide.title }),
2438
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2439
+ ] }) }),
2440
+ /* @__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 }) })
2441
+ ] }) });
2442
+ }
2443
+ if (visuals.length > 0) {
2444
+ 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: [
2445
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "shrink-0 font-bold leading-tight text-foreground", style: { fontSize: 32 }, children: slide.title }),
2446
+ content.map(
2447
+ (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)
2448
+ )
2449
+ ] }) });
2450
+ }
2451
+ 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: [
2452
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "mb-6 font-bold leading-tight text-foreground", style: { fontSize: 38 }, children: slide.title }),
2453
+ texts.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DeckMarkdown, { markdown: block.markdown }, i))
2454
+ ] }) }) });
2455
+ }
2456
+ function AutoFit({ children }) {
2457
+ const boxRef = (0, import_react16.useRef)(null);
2458
+ const contentRef = (0, import_react16.useRef)(null);
2459
+ const [fit, setFit] = (0, import_react16.useState)({ scale: 1, height: 0 });
2460
+ (0, import_react16.useLayoutEffect)(() => {
2461
+ const boxEl = boxRef.current;
2462
+ const contentEl = contentRef.current;
2463
+ if (!boxEl || !contentEl) return;
2464
+ const measure = () => {
2465
+ const avail = boxEl.clientHeight;
2466
+ const natural = contentEl.offsetHeight;
2467
+ const scale = avail > 0 && natural > avail ? avail / natural : 1;
2468
+ setFit({ scale, height: natural * scale });
2469
+ };
2470
+ measure();
2471
+ const ro = new ResizeObserver(measure);
2472
+ ro.observe(boxEl);
2473
+ ro.observe(contentEl);
2474
+ return () => ro.disconnect();
2475
+ }, []);
2476
+ const scaled = fit.scale < 1;
2477
+ 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)(
2478
+ "div",
2479
+ {
2480
+ ref: contentRef,
2481
+ className: "w-full origin-top-left",
2482
+ style: scaled ? { transform: `scale(${fit.scale})` } : void 0,
2483
+ children
2484
+ }
2485
+ ) }) });
2486
+ }
2487
+ function FillVisual({ block, labels }) {
2488
+ const ref = (0, import_react16.useRef)(null);
2489
+ const [height, setHeight] = (0, import_react16.useState)(VISUAL_FALLBACK_HEIGHT);
2490
+ (0, import_react16.useLayoutEffect)(() => {
2491
+ const el = ref.current;
2492
+ if (!el) return;
2493
+ const apply = (h) => {
2494
+ if (h > 0) setHeight(h);
2495
+ };
2496
+ apply(el.clientHeight);
2497
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.height ?? 0));
2498
+ ro.observe(el);
2499
+ return () => ro.disconnect();
2500
+ }, []);
2501
+ const chartLabels = labels.chart ?? DEFAULT_CHART_ARTIFACT_LABELS;
2502
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref, className: "h-full min-h-0 w-full overflow-hidden", children: block.type === deckBlockTypes.CHART ? (
2503
+ // ChartArtifactContent assumes a non-empty rowset (the standalone ChartArtifact guards
2504
+ // `rows.length > 0` upstream); mirror that guard here so an empty inline chart shows the
2505
+ // localized empty status instead of a blank chart area.
2506
+ 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 }) })
2507
+ ) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2508
+ TableArtifactContent,
2509
+ {
2510
+ columns: block.config.columns,
2511
+ data: { status: "ready", rows: block.rows, error: null },
2512
+ knownRowCount: block.config.stats?.rowCount ?? block.rows.length,
2513
+ maxShimmerRows: TABLE_BLOCK_MAX_SHIMMER_ROWS,
2514
+ maxBodyHeight: Math.max(0, height - TABLE_CHROME_RESERVE),
2515
+ labels: labels.table ?? DEFAULT_TABLE_ARTIFACT_LABELS
2516
+ }
2517
+ ) });
1844
2518
  }
1845
2519
 
1846
2520
  // src/components/artifacts/table-artifact/validate.ts
@@ -1859,19 +2533,265 @@ function isValidTableColumn(column) {
1859
2533
  return true;
1860
2534
  }
1861
2535
 
1862
- // src/components/artifacts/table-artifact/table-artifact.tsx
1863
- var import_jsx_runtime22 = require("react/jsx-runtime");
2536
+ // src/components/artifacts/deck-artifact/validate.ts
2537
+ function isValidDeckConfig(config) {
2538
+ if (!config || typeof config !== "object") return false;
2539
+ const candidate = config;
2540
+ if (!Array.isArray(candidate.slides)) return false;
2541
+ if (candidate.slides.length === 0) return false;
2542
+ return candidate.slides.every(isValidDeckSlide);
2543
+ }
2544
+ function isValidDeckSlide(slide) {
2545
+ if (!slide || typeof slide !== "object") return false;
2546
+ const candidate = slide;
2547
+ if (typeof candidate.title !== "string") return false;
2548
+ const kind = typeof candidate.kind === "string" ? candidate.kind : deckSlideKinds.CONTENT;
2549
+ if (kind === deckSlideKinds.CONTENT && !Array.isArray(candidate.content)) return false;
2550
+ const content = Array.isArray(candidate.content) ? candidate.content : [];
2551
+ if (candidate.items != null) {
2552
+ if (!Array.isArray(candidate.items)) return false;
2553
+ if (!candidate.items.every((item) => typeof item === "string")) return false;
2554
+ }
2555
+ return content.every(isValidDeckBlock);
2556
+ }
2557
+ function isValidDeckBlock(block) {
2558
+ if (!block || typeof block !== "object") return false;
2559
+ const candidate = block;
2560
+ switch (candidate.type) {
2561
+ case deckBlockTypes.TEXT:
2562
+ return typeof candidate.markdown === "string";
2563
+ case deckBlockTypes.CHART:
2564
+ return isValidChartConfig(candidate.config) && Array.isArray(candidate.rows);
2565
+ case deckBlockTypes.TABLE:
2566
+ return isValidTableConfig(candidate.config) && Array.isArray(candidate.rows);
2567
+ default:
2568
+ return false;
2569
+ }
2570
+ }
2571
+
2572
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
2573
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1864
2574
  var TITLE_CLASSES2 = "text-sm font-semibold text-foreground";
2575
+ function DeckArtifact({ artifact, labels, callbacks }) {
2576
+ const validConfig = isValidDeckConfig(artifact.config);
2577
+ const [isFullscreen, setIsFullscreen] = (0, import_react17.useState)(false);
2578
+ const [currentSlide, setCurrentSlide] = (0, import_react17.useState)(0);
2579
+ (0, import_react17.useEffect)(() => {
2580
+ if (validConfig) return;
2581
+ console.warn("[clay] DeckArtifact: malformed `config` \u2014 skipping render.");
2582
+ }, [validConfig]);
2583
+ (0, import_react17.useEffect)(() => {
2584
+ if (!isFullscreen) return;
2585
+ const handleKey = (e) => {
2586
+ if (e.key === "Escape") setIsFullscreen(false);
2587
+ };
2588
+ document.addEventListener("keydown", handleKey);
2589
+ const previousOverflow = document.documentElement.style.overflow;
2590
+ document.documentElement.style.overflow = "hidden";
2591
+ return () => {
2592
+ document.removeEventListener("keydown", handleKey);
2593
+ document.documentElement.style.overflow = previousOverflow;
2594
+ };
2595
+ }, [isFullscreen]);
2596
+ const resolvedLabels = (0, import_react17.useMemo)(
2597
+ () => ({
2598
+ ...DEFAULT_DECK_ARTIFACT_LABELS,
2599
+ ...labels ?? {},
2600
+ chart: { ...DEFAULT_CHART_ARTIFACT_LABELS, ...labels?.chart ?? {} },
2601
+ table: { ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels?.table ?? {} }
2602
+ }),
2603
+ [labels]
2604
+ );
2605
+ const onNavigate = callbacks?.onNavigate;
2606
+ const handleNavigate = onNavigate ? (slideIndex) => onNavigate(artifact, slideIndex) : void 0;
2607
+ const onDownload = callbacks?.onDownload;
2608
+ const handleDownload = onDownload ? () => onDownload(artifact) : void 0;
2609
+ const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
2610
+ const showDownload = presignedUrl !== null && isSafeDownloadUrl(presignedUrl);
2611
+ const meta = artifact.config?.meta;
2612
+ const handleOpenFullscreen = () => setIsFullscreen(true);
2613
+ const handleCloseFullscreen = () => setIsFullscreen(false);
2614
+ const actions = /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactActions, { ...{ [CAPTURE_EXCLUDE_ATTRIBUTE]: "" }, children: [
2615
+ showDownload ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactDownloadButton, { href: presignedUrl ?? "", label: resolvedLabels.download, onClick: handleDownload }) : null,
2616
+ validConfig ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2617
+ IconButton,
2618
+ {
2619
+ icon: IconArrowsMaximize,
2620
+ size: "small",
2621
+ "aria-label": resolvedLabels.enterFullscreen,
2622
+ onClick: handleOpenFullscreen
2623
+ }
2624
+ ) : null
2625
+ ] });
2626
+ if (!validConfig) {
2627
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2628
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2629
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2630
+ actions
2631
+ ] }),
2632
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
2633
+ ] });
2634
+ }
2635
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
2636
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2637
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2638
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2639
+ actions
2640
+ ] }),
2641
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2642
+ DeckArtifactContent,
2643
+ {
2644
+ slides: artifact.config.slides,
2645
+ labels: resolvedLabels,
2646
+ onNavigate: handleNavigate,
2647
+ meta,
2648
+ currentSlide,
2649
+ onSlideChange: setCurrentSlide
2650
+ }
2651
+ ) })
2652
+ ] }),
2653
+ isFullscreen && (0, import_react_dom.createPortal)(
2654
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2655
+ FullscreenOverlay,
2656
+ {
2657
+ artifact,
2658
+ resolvedLabels,
2659
+ onNavigate: handleNavigate,
2660
+ currentSlide,
2661
+ onSlideChange: setCurrentSlide,
2662
+ onClose: handleCloseFullscreen
2663
+ }
2664
+ ),
2665
+ document.body
2666
+ )
2667
+ ] });
2668
+ }
2669
+ function FullscreenOverlay({
2670
+ artifact,
2671
+ resolvedLabels,
2672
+ onNavigate,
2673
+ currentSlide,
2674
+ onSlideChange,
2675
+ onClose
2676
+ }) {
2677
+ const meta = artifact.config?.meta;
2678
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2679
+ "div",
2680
+ {
2681
+ className: "fixed inset-0 z-[2147483647] flex items-center justify-center bg-black/80",
2682
+ role: "dialog",
2683
+ "aria-modal": "true",
2684
+ "aria-label": resolvedLabels.exitFullscreen,
2685
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "relative", style: { width: "min(94vw, calc(82vh * 16 / 9))" }, children: [
2686
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2687
+ DeckArtifactContent,
2688
+ {
2689
+ slides: artifact.config.slides,
2690
+ labels: resolvedLabels,
2691
+ onNavigate,
2692
+ meta,
2693
+ currentSlide,
2694
+ onSlideChange,
2695
+ onDark: true
2696
+ }
2697
+ ),
2698
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2699
+ "button",
2700
+ {
2701
+ className: "absolute -top-10 right-6 flex items-center gap-1.5 text-sm text-white/80 hover:text-white",
2702
+ "aria-label": resolvedLabels.exitFullscreen,
2703
+ onClick: onClose,
2704
+ children: [
2705
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(IconArrowsMinimize, { size: 16 }),
2706
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: resolvedLabels.exitFullscreen })
2707
+ ]
2708
+ }
2709
+ )
2710
+ ] })
2711
+ }
2712
+ );
2713
+ }
2714
+
2715
+ // src/components/artifacts/deck-artifact/to-clipboard-text.ts
2716
+ function deckArtifactToClipboardText(artifact) {
2717
+ const header = artifact.title?.trim() || "Deck";
2718
+ const slides = artifact.config?.slides ?? [];
2719
+ const body = slides.map((slide, i) => slideToText(slide, i)).join("\n\n");
2720
+ return body ? `${header}
2721
+
2722
+ ${body}` : header;
2723
+ }
2724
+ function slideToText(slide, index) {
2725
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
2726
+ const prefix = `Slide ${index + 1}: `;
2727
+ switch (kind) {
2728
+ case deckSlideKinds.TITLE: {
2729
+ const parts = [slide.title];
2730
+ if (slide.subtitle) parts.push(slide.subtitle);
2731
+ if (slide.description) parts.push(slide.description);
2732
+ return `${prefix}${parts.join(" \u2014 ")}`.trim();
2733
+ }
2734
+ case deckSlideKinds.AGENDA: {
2735
+ const items = (slide.items ?? []).map((item, i) => ` ${String(i + 1).padStart(2, "0")}. ${item}`).join("\n");
2736
+ return `${prefix}${slide.title || "Agenda"}${items ? `
2737
+ ${items}` : ""}`.trim();
2738
+ }
2739
+ case deckSlideKinds.SECTION:
2740
+ return `${prefix}${slide.title}`.trim();
2741
+ case deckSlideKinds.CLOSING:
2742
+ return `${prefix}Thank you`.trim();
2743
+ case deckSlideKinds.CONTENT:
2744
+ default: {
2745
+ const blocks = (slide.content ?? []).map(blockToText).filter(Boolean).join("\n\n");
2746
+ return `${prefix}${slide.title}${blocks ? `
2747
+ ${blocks}` : ""}`.trim();
2748
+ }
2749
+ }
2750
+ }
2751
+ function blockToText(block) {
2752
+ switch (block.type) {
2753
+ case deckBlockTypes.TEXT:
2754
+ return block.markdown.trim();
2755
+ case deckBlockTypes.CHART:
2756
+ return `[Chart: ${block.config.variant}]`;
2757
+ case deckBlockTypes.TABLE: {
2758
+ const columnCount = block.config.columns.length;
2759
+ const rowCount = block.rows.length;
2760
+ return `[Table: ${columnCount} column${columnCount === 1 ? "" : "s"} \xD7 ${rowCount} row${rowCount === 1 ? "" : "s"}]`;
2761
+ }
2762
+ default:
2763
+ return "";
2764
+ }
2765
+ }
2766
+
2767
+ // src/components/artifacts/artifact-services/deck-artifact-service.ts
2768
+ var DeckArtifactService = {
2769
+ type: artifactTypes.DECK,
2770
+ Component: DeckArtifact,
2771
+ toClipboardText: deckArtifactToClipboardText
2772
+ };
2773
+
2774
+ // src/components/artifacts/table-artifact/table-artifact.tsx
2775
+ var import_react18 = require("react");
2776
+
2777
+ // src/components/artifacts/table-artifact/use-table-artifact-data.ts
2778
+ function useTableArtifactData(presignedUrl, columns) {
2779
+ return useRowsArtifactData(presignedUrl, columns, parseCsv);
2780
+ }
2781
+
2782
+ // src/components/artifacts/table-artifact/table-artifact.tsx
2783
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2784
+ var TITLE_CLASSES3 = "text-sm font-semibold text-foreground";
1865
2785
  var TABLE_MAX_BODY_HEIGHT = 480;
1866
2786
  var MAX_SHIMMER_ROWS = 10;
1867
2787
  function TableArtifact({ artifact, labels, callbacks }) {
1868
2788
  const validConfig = isValidTableConfig(artifact.config);
1869
2789
  const validColumns = validConfig ? artifact.config.columns : null;
1870
- (0, import_react15.useEffect)(() => {
2790
+ (0, import_react18.useEffect)(() => {
1871
2791
  if (validConfig) return;
1872
2792
  console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
1873
2793
  }, [validConfig]);
1874
- const resolvedLabels = (0, import_react15.useMemo)(
2794
+ const resolvedLabels = (0, import_react18.useMemo)(
1875
2795
  () => ({ ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels ?? {} }),
1876
2796
  [labels]
1877
2797
  );
@@ -1883,10 +2803,10 @@ function TableArtifact({ artifact, labels, callbacks }) {
1883
2803
  const onDownload = callbacks?.onDownload;
1884
2804
  const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
1885
2805
  if (!validConfig || !validColumns) {
1886
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1887
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
1888
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
1889
- presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2806
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
2807
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
2808
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", {}),
2809
+ presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1890
2810
  ArtifactDownloadButton,
1891
2811
  {
1892
2812
  href: presignedUrl,
@@ -1895,17 +2815,17 @@ function TableArtifact({ artifact, labels, callbacks }) {
1895
2815
  }
1896
2816
  ) }) : null
1897
2817
  ] }),
1898
- /* @__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 }) })
2818
+ /* @__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 }) })
1899
2819
  ] });
1900
2820
  }
1901
2821
  return (
1902
2822
  // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
1903
2823
  // Disable the outer overflow container so only one scroll context exists — this prevents
1904
2824
  // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
1905
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1906
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
1907
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
1908
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2825
+ /* @__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
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1909
2829
  ArtifactDownloadButton,
1910
2830
  {
1911
2831
  href: presignedUrl ?? "",
@@ -1914,7 +2834,7 @@ function TableArtifact({ artifact, labels, callbacks }) {
1914
2834
  }
1915
2835
  ) })
1916
2836
  ] }),
1917
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2837
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1918
2838
  TableArtifactContent,
1919
2839
  {
1920
2840
  columns: validColumns,
@@ -1945,7 +2865,8 @@ var TableArtifactService = {
1945
2865
  // src/components/artifacts/artifact-services/index.ts
1946
2866
  var ArtifactServices = {
1947
2867
  [artifactTypes.TABLE]: TableArtifactService,
1948
- [artifactTypes.CHART]: ChartArtifactService
2868
+ [artifactTypes.CHART]: ChartArtifactService,
2869
+ [artifactTypes.DECK]: DeckArtifactService
1949
2870
  };
1950
2871
  function artifactToClipboardText(artifact) {
1951
2872
  const entry = ArtifactServices[artifact.type];
@@ -1962,10 +2883,14 @@ function artifactToClipboardText(artifact) {
1962
2883
  ArtifactServices,
1963
2884
  ChartArtifact,
1964
2885
  DEFAULT_CHART_ARTIFACT_LABELS,
2886
+ DEFAULT_DECK_ARTIFACT_LABELS,
1965
2887
  DEFAULT_TABLE_ARTIFACT_LABELS,
2888
+ DeckArtifact,
1966
2889
  TableArtifact,
1967
2890
  artifactToClipboardText,
1968
2891
  artifactTypes,
2892
+ deckBlockTypes,
2893
+ deckSlideKinds,
1969
2894
  isSafeDownloadUrl
1970
2895
  });
1971
2896
  /*! Bundled license information:
@@ -1973,7 +2898,11 @@ function artifactToClipboardText(artifact) {
1973
2898
  @tabler/icons-react/dist/esm/defaultAttributes.mjs:
1974
2899
  @tabler/icons-react/dist/esm/createReactComponent.mjs:
1975
2900
  @tabler/icons-react/dist/esm/icons/IconAlertCircle.mjs:
2901
+ @tabler/icons-react/dist/esm/icons/IconArrowsMaximize.mjs:
2902
+ @tabler/icons-react/dist/esm/icons/IconArrowsMinimize.mjs:
1976
2903
  @tabler/icons-react/dist/esm/icons/IconCheck.mjs:
2904
+ @tabler/icons-react/dist/esm/icons/IconChevronLeft.mjs:
2905
+ @tabler/icons-react/dist/esm/icons/IconChevronRight.mjs:
1977
2906
  @tabler/icons-react/dist/esm/icons/IconCopy.mjs:
1978
2907
  @tabler/icons-react/dist/esm/icons/IconDownload.mjs:
1979
2908
  @tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs: