@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
@@ -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"],
@@ -1087,11 +1432,6 @@ function coerceNumericColumns(rows, numericKeys) {
1087
1432
 
1088
1433
  // src/components/chart/bar-chart/bar-chart.tsx
1089
1434
  var import_jsx_runtime12 = require("react/jsx-runtime");
1090
- var STACK_TOTAL_KEY = "__stackTotal";
1091
- var VALUE_LABEL_HEADROOM = 20;
1092
- function sumSeries(row, keys) {
1093
- return keys.reduce((sum, key) => sum + (Number(row[key]) || 0), 0);
1094
- }
1095
1435
  function BarChart({
1096
1436
  data,
1097
1437
  xKey,
@@ -1106,7 +1446,6 @@ function BarChart({
1106
1446
  showGrid = true,
1107
1447
  showXAxis = true,
1108
1448
  showYAxis = true,
1109
- showValueLabels,
1110
1449
  xAxisInterval = 0,
1111
1450
  xAxisAngle,
1112
1451
  xAxisTickFormatter
@@ -1117,24 +1456,14 @@ function BarChart({
1117
1456
  [data, seriesKeys]
1118
1457
  );
1119
1458
  const resolvedShowLegend = showLegend ?? series.length > 1;
1120
- const resolvedShowValueLabels = showValueLabels ?? true;
1121
- const plotData = (0, import_react9.useMemo)(() => {
1122
- if (!stacked || !resolvedShowValueLabels) return coercedData;
1123
- return coercedData.map((row) => ({ ...row, [STACK_TOTAL_KEY]: sumSeries(row, seriesKeys) }));
1124
- }, [coercedData, stacked, resolvedShowValueLabels, seriesKeys]);
1125
1459
  const resolvedAngle = xAxisAngle ?? (coercedData.length >= 8 ? -30 : 0);
1126
1460
  const resolvedTickFormatter = (0, import_react9.useMemo)(
1127
1461
  () => xAxisTickFormatter ?? defaultBarTickFormatter(coercedData.length),
1128
1462
  [xAxisTickFormatter, coercedData.length]
1129
1463
  );
1130
1464
  const angledLabelPad = resolvedAngle === 0 ? 0 : Math.min(Math.abs(resolvedAngle) * 0.7, 40);
1131
- const valueLabelHeadroom = resolvedShowValueLabels ? VALUE_LABEL_HEADROOM : 0;
1132
- const chartMargin = {
1133
- ...CHART_MARGIN,
1134
- top: CHART_MARGIN.top + valueLabelHeadroom,
1135
- bottom: CHART_MARGIN.bottom + angledLabelPad
1136
- };
1137
- 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: [
1465
+ const chartMargin = { ...CHART_MARGIN, bottom: CHART_MARGIN.bottom + angledLabelPad };
1466
+ 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: [
1138
1467
  showGrid ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_recharts2.CartesianGrid, { ...CHART_GRID_PROPS }) : null,
1139
1468
  showXAxis ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1140
1469
  import_recharts2.XAxis,
@@ -1161,23 +1490,17 @@ function BarChart({
1161
1490
  content: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChartLegendContent, { iconType: "square" })
1162
1491
  }
1163
1492
  ) : null,
1164
- series.map((s, i) => {
1165
- const isTopSegment = i === series.length - 1;
1166
- const labelDataKey = stacked ? STACK_TOTAL_KEY : s.key;
1167
- const showLabel = resolvedShowValueLabels && (!stacked || isTopSegment);
1168
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1169
- import_recharts2.Bar,
1170
- {
1171
- dataKey: s.key,
1172
- name: s.label,
1173
- fill: colorForSeriesIndex(i, palette),
1174
- stackId: stacked ? "default" : s.key,
1175
- radius: barRadius(stacked, i, series.length),
1176
- children: showLabel ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_recharts2.LabelList, { dataKey: labelDataKey, position: "top", style: CHART_VALUE_LABEL_STYLE }) : null
1177
- },
1178
- s.key
1179
- );
1180
- })
1493
+ series.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1494
+ import_recharts2.Bar,
1495
+ {
1496
+ dataKey: s.key,
1497
+ name: s.label,
1498
+ fill: colorForSeriesIndex(i, palette),
1499
+ stackId: stacked ? "default" : s.key,
1500
+ radius: barRadius(stacked, i, series.length)
1501
+ },
1502
+ s.key
1503
+ ))
1181
1504
  ] }) });
1182
1505
  }
1183
1506
  function barRadius(stacked, seriesIndex, seriesCount) {
@@ -1712,8 +2035,13 @@ var ChartArtifactService = {
1712
2035
  toClipboardText: chartArtifactToClipboardText
1713
2036
  };
1714
2037
 
1715
- // src/components/artifacts/table-artifact/table-artifact.tsx
1716
- 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");
1717
2045
 
1718
2046
  // src/components/ui/table.tsx
1719
2047
  var React3 = __toESM(require("react"), 1);
@@ -1860,9 +2188,333 @@ function renderEmptyRow(colSpan, emptyMessage) {
1860
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 }) });
1861
2189
  }
1862
2190
 
1863
- // src/components/artifacts/table-artifact/use-table-artifact-data.ts
1864
- function useTableArtifactData(presignedUrl, columns) {
1865
- 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
+ ) });
1866
2518
  }
1867
2519
 
1868
2520
  // src/components/artifacts/table-artifact/validate.ts
@@ -1881,19 +2533,265 @@ function isValidTableColumn(column) {
1881
2533
  return true;
1882
2534
  }
1883
2535
 
1884
- // src/components/artifacts/table-artifact/table-artifact.tsx
1885
- 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");
1886
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";
1887
2785
  var TABLE_MAX_BODY_HEIGHT = 480;
1888
2786
  var MAX_SHIMMER_ROWS = 10;
1889
2787
  function TableArtifact({ artifact, labels, callbacks }) {
1890
2788
  const validConfig = isValidTableConfig(artifact.config);
1891
2789
  const validColumns = validConfig ? artifact.config.columns : null;
1892
- (0, import_react15.useEffect)(() => {
2790
+ (0, import_react18.useEffect)(() => {
1893
2791
  if (validConfig) return;
1894
2792
  console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
1895
2793
  }, [validConfig]);
1896
- const resolvedLabels = (0, import_react15.useMemo)(
2794
+ const resolvedLabels = (0, import_react18.useMemo)(
1897
2795
  () => ({ ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels ?? {} }),
1898
2796
  [labels]
1899
2797
  );
@@ -1905,10 +2803,10 @@ function TableArtifact({ artifact, labels, callbacks }) {
1905
2803
  const onDownload = callbacks?.onDownload;
1906
2804
  const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
1907
2805
  if (!validConfig || !validColumns) {
1908
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1909
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
1910
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
1911
- 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)(
1912
2810
  ArtifactDownloadButton,
1913
2811
  {
1914
2812
  href: presignedUrl,
@@ -1917,17 +2815,17 @@ function TableArtifact({ artifact, labels, callbacks }) {
1917
2815
  }
1918
2816
  ) }) : null
1919
2817
  ] }),
1920
- /* @__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 }) })
1921
2819
  ] });
1922
2820
  }
1923
2821
  return (
1924
2822
  // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
1925
2823
  // Disable the outer overflow container so only one scroll context exists — this prevents
1926
2824
  // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
1927
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1928
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
1929
- artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", {}),
1930
- /* @__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)(
1931
2829
  ArtifactDownloadButton,
1932
2830
  {
1933
2831
  href: presignedUrl ?? "",
@@ -1936,7 +2834,7 @@ function TableArtifact({ artifact, labels, callbacks }) {
1936
2834
  }
1937
2835
  ) })
1938
2836
  ] }),
1939
- /* @__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)(
1940
2838
  TableArtifactContent,
1941
2839
  {
1942
2840
  columns: validColumns,
@@ -1967,7 +2865,8 @@ var TableArtifactService = {
1967
2865
  // src/components/artifacts/artifact-services/index.ts
1968
2866
  var ArtifactServices = {
1969
2867
  [artifactTypes.TABLE]: TableArtifactService,
1970
- [artifactTypes.CHART]: ChartArtifactService
2868
+ [artifactTypes.CHART]: ChartArtifactService,
2869
+ [artifactTypes.DECK]: DeckArtifactService
1971
2870
  };
1972
2871
  function artifactToClipboardText(artifact) {
1973
2872
  const entry = ArtifactServices[artifact.type];
@@ -1984,10 +2883,14 @@ function artifactToClipboardText(artifact) {
1984
2883
  ArtifactServices,
1985
2884
  ChartArtifact,
1986
2885
  DEFAULT_CHART_ARTIFACT_LABELS,
2886
+ DEFAULT_DECK_ARTIFACT_LABELS,
1987
2887
  DEFAULT_TABLE_ARTIFACT_LABELS,
2888
+ DeckArtifact,
1988
2889
  TableArtifact,
1989
2890
  artifactToClipboardText,
1990
2891
  artifactTypes,
2892
+ deckBlockTypes,
2893
+ deckSlideKinds,
1991
2894
  isSafeDownloadUrl
1992
2895
  });
1993
2896
  /*! Bundled license information:
@@ -1995,7 +2898,11 @@ function artifactToClipboardText(artifact) {
1995
2898
  @tabler/icons-react/dist/esm/defaultAttributes.mjs:
1996
2899
  @tabler/icons-react/dist/esm/createReactComponent.mjs:
1997
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:
1998
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:
1999
2906
  @tabler/icons-react/dist/esm/icons/IconCopy.mjs:
2000
2907
  @tabler/icons-react/dist/esm/icons/IconDownload.mjs:
2001
2908
  @tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs: