@shapesos/clay 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/ai-elements.cjs +3 -1
  2. package/dist/ai-elements.cjs.map +1 -1
  3. package/dist/ai-elements.js +4 -4
  4. package/dist/artifacts.cjs +1010 -60
  5. package/dist/artifacts.cjs.map +1 -1
  6. package/dist/artifacts.d.cts +20 -3
  7. package/dist/artifacts.d.ts +20 -3
  8. package/dist/artifacts.js +15 -6
  9. package/dist/badge.cjs +70 -0
  10. package/dist/badge.cjs.map +1 -0
  11. package/dist/badge.d.cts +28 -0
  12. package/dist/badge.d.ts +28 -0
  13. package/dist/badge.js +9 -0
  14. package/dist/blocks.cjs +981 -96
  15. package/dist/blocks.cjs.map +1 -1
  16. package/dist/blocks.css +1 -1
  17. package/dist/blocks.d.cts +15 -4
  18. package/dist/blocks.d.ts +15 -4
  19. package/dist/blocks.js +20 -8
  20. package/dist/button.cjs +3 -1
  21. package/dist/button.cjs.map +1 -1
  22. package/dist/button.js +2 -2
  23. package/dist/capture.cjs +3 -1
  24. package/dist/capture.cjs.map +1 -1
  25. package/dist/capture.js +2 -2
  26. package/dist/chart.cjs +3 -1
  27. package/dist/chart.cjs.map +1 -1
  28. package/dist/chart.js +2 -2
  29. package/dist/chat.cjs +986 -151
  30. package/dist/chat.cjs.map +1 -1
  31. package/dist/chat.d.cts +2 -2
  32. package/dist/chat.d.ts +2 -2
  33. package/dist/chat.js +13 -8
  34. package/dist/{chunk-JGMN6W72.js → chunk-2X4KUXYP.js} +1 -1
  35. package/dist/chunk-BHHJOG5X.js +1 -0
  36. package/dist/{chunk-B4U37WIH.js → chunk-CFCLVJIO.js} +2 -2
  37. package/dist/chunk-CSTCTO3B.js +161 -0
  38. package/dist/chunk-CSTCTO3B.js.map +1 -0
  39. package/dist/{chunk-6YZ65KPW.js → chunk-DC5KYT2G.js} +669 -171
  40. package/dist/chunk-DC5KYT2G.js.map +1 -0
  41. package/dist/{chunk-PYDVANWI.js → chunk-E36VI2HA.js} +2 -2
  42. package/dist/chunk-EIAWZXE4.js +69 -0
  43. package/dist/chunk-EIAWZXE4.js.map +1 -0
  44. package/dist/chunk-EXRNGIQ2.js +41 -0
  45. package/dist/chunk-EXRNGIQ2.js.map +1 -0
  46. package/dist/{chunk-B6GAPZ2R.js → chunk-FCSYVF4Z.js} +12 -46
  47. package/dist/chunk-FCSYVF4Z.js.map +1 -0
  48. package/dist/{chunk-PUVZ2S3F.js → chunk-G4NXVFXU.js} +2 -2
  49. package/dist/{chunk-JAGNXEWK.js → chunk-GK4XW4BC.js} +2 -2
  50. package/dist/{chunk-4MZZH3WX.js → chunk-HU5W7CGE.js} +37 -2
  51. package/dist/chunk-HU5W7CGE.js.map +1 -0
  52. package/dist/chunk-JMHE3Q5K.js +406 -0
  53. package/dist/chunk-JMHE3Q5K.js.map +1 -0
  54. package/dist/{chunk-4VE6ZXXW.js → chunk-MQP57DOP.js} +3 -3
  55. package/dist/{chunk-JF3P66JF.js → chunk-SN3ORQSJ.js} +4 -2
  56. package/dist/{chunk-JF3P66JF.js.map → chunk-SN3ORQSJ.js.map} +1 -1
  57. package/dist/{chunk-PGR2MDDU.js → chunk-W66OJM55.js} +2 -2
  58. package/dist/{chunk-7OYIDM42.js → chunk-XKURJ72I.js} +2 -2
  59. package/dist/copy-button.cjs +439 -0
  60. package/dist/copy-button.cjs.map +1 -0
  61. package/dist/copy-button.d.cts +20 -0
  62. package/dist/copy-button.d.ts +20 -0
  63. package/dist/copy-button.js +12 -0
  64. package/dist/copy-button.js.map +1 -0
  65. package/dist/{dom-to-image-NATF3446.js → dom-to-image-QB7KMTAE.js} +3 -3
  66. package/dist/dom-to-image-QB7KMTAE.js.map +1 -0
  67. package/dist/icon.cjs +3 -1
  68. package/dist/icon.cjs.map +1 -1
  69. package/dist/icon.js +2 -2
  70. package/dist/index.cjs +1070 -209
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/index.d.cts +6 -4
  73. package/dist/index.d.ts +6 -4
  74. package/dist/index.js +42 -17
  75. package/dist/keyboard-shortcut.cjs +3 -1
  76. package/dist/keyboard-shortcut.cjs.map +1 -1
  77. package/dist/keyboard-shortcut.js +2 -2
  78. package/dist/table.cjs +40 -0
  79. package/dist/table.cjs.map +1 -1
  80. package/dist/table.d.cts +37 -2
  81. package/dist/table.d.ts +37 -2
  82. package/dist/table.js +11 -1
  83. package/dist/text-area.cjs +3 -1
  84. package/dist/text-area.cjs.map +1 -1
  85. package/dist/text-area.js +2 -2
  86. package/dist/tokens.cjs +3 -1
  87. package/dist/tokens.cjs.map +1 -1
  88. package/dist/tokens.d.cts +1 -0
  89. package/dist/tokens.d.ts +1 -0
  90. package/dist/tokens.js +1 -1
  91. package/dist/{types-CW45GBXl.d.cts → types-Bhg0_ES8.d.cts} +75 -3
  92. package/dist/{types-GCkXbyFm.d.ts → types-C8JtnwNY.d.ts} +200 -4
  93. package/dist/{types-BzXPBy6s.d.cts → types-DTdDFU3O.d.cts} +200 -4
  94. package/dist/{types-D1b8v7EY.d.ts → types-orOQcI2z.d.ts} +75 -3
  95. package/package.json +11 -1
  96. package/dist/chunk-46ZYTBX5.js +0 -250
  97. package/dist/chunk-46ZYTBX5.js.map +0 -1
  98. package/dist/chunk-4MZZH3WX.js.map +0 -1
  99. package/dist/chunk-6YZ65KPW.js.map +0 -1
  100. package/dist/chunk-B6GAPZ2R.js.map +0 -1
  101. package/dist/chunk-RSRNSWJN.js +0 -1
  102. /package/dist/{chunk-RSRNSWJN.js.map → badge.js.map} +0 -0
  103. /package/dist/{chunk-JGMN6W72.js.map → chunk-2X4KUXYP.js.map} +0 -0
  104. /package/dist/{dom-to-image-NATF3446.js.map → chunk-BHHJOG5X.js.map} +0 -0
  105. /package/dist/{chunk-B4U37WIH.js.map → chunk-CFCLVJIO.js.map} +0 -0
  106. /package/dist/{chunk-PYDVANWI.js.map → chunk-E36VI2HA.js.map} +0 -0
  107. /package/dist/{chunk-PUVZ2S3F.js.map → chunk-G4NXVFXU.js.map} +0 -0
  108. /package/dist/{chunk-JAGNXEWK.js.map → chunk-GK4XW4BC.js.map} +0 -0
  109. /package/dist/{chunk-4VE6ZXXW.js.map → chunk-MQP57DOP.js.map} +0 -0
  110. /package/dist/{chunk-PGR2MDDU.js.map → chunk-W66OJM55.js.map} +0 -0
  111. /package/dist/{chunk-7OYIDM42.js.map → chunk-XKURJ72I.js.map} +0 -0
@@ -1,6 +1,19 @@
1
+ import {
2
+ IconAlertCircle,
3
+ IconArrowsMaximize,
4
+ IconArrowsMinimize,
5
+ IconCheck,
6
+ IconChevronLeft,
7
+ IconChevronRight,
8
+ IconCopy,
9
+ IconDownload,
10
+ IconFileSpreadsheet,
11
+ IconLoader2,
12
+ IconPhoto
13
+ } from "./chunk-CSTCTO3B.js";
1
14
  import {
2
15
  IconButton
3
- } from "./chunk-PYDVANWI.js";
16
+ } from "./chunk-E36VI2HA.js";
4
17
  import {
5
18
  CAPTURE_EXCLUDE_ATTRIBUTE
6
19
  } from "./chunk-LXYCT4YO.js";
@@ -8,16 +21,19 @@ import {
8
21
  BarChart,
9
22
  LineChart,
10
23
  PieChart
11
- } from "./chunk-PUVZ2S3F.js";
24
+ } from "./chunk-G4NXVFXU.js";
12
25
  import {
13
- Table,
14
- TableBody,
26
+ fontFamilies
27
+ } from "./chunk-UXT2H3FM.js";
28
+ import {
29
+ DATA_TABLE_CELL_CLASS,
30
+ DATA_TABLE_HEAD_CLASS,
31
+ DATA_TABLE_ROW_CLASS,
32
+ DataTable,
15
33
  TableCell,
16
34
  TableHead,
17
- TableHeader,
18
- TableRow,
19
- useScrollShadow
20
- } from "./chunk-4MZZH3WX.js";
35
+ TableRow
36
+ } from "./chunk-HU5W7CGE.js";
21
37
  import {
22
38
  cn
23
39
  } from "./chunk-P6GUNIAE.js";
@@ -25,7 +41,8 @@ import {
25
41
  // src/components/artifacts/artifact-base.ts
26
42
  var artifactTypes = {
27
43
  TABLE: "TABLE",
28
- CHART: "CHART"
44
+ CHART: "CHART",
45
+ DECK: "DECK"
29
46
  };
30
47
 
31
48
  // src/components/artifacts/chart-artifact/types.ts
@@ -50,97 +67,33 @@ var DEFAULT_TABLE_ARTIFACT_LABELS = {
50
67
  empty: "No rows to display."
51
68
  };
52
69
 
53
- // node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
54
- import { forwardRef, createElement } from "react";
55
-
56
- // node_modules/@tabler/icons-react/dist/esm/defaultAttributes.mjs
57
- var defaultAttributes = {
58
- outline: {
59
- xmlns: "http://www.w3.org/2000/svg",
60
- width: 24,
61
- height: 24,
62
- viewBox: "0 0 24 24",
63
- fill: "none",
64
- stroke: "currentColor",
65
- strokeWidth: 2,
66
- strokeLinecap: "round",
67
- strokeLinejoin: "round"
68
- },
69
- filled: {
70
- xmlns: "http://www.w3.org/2000/svg",
71
- width: 24,
72
- height: 24,
73
- viewBox: "0 0 24 24",
74
- fill: "currentColor",
75
- stroke: "none"
76
- }
70
+ // src/components/artifacts/deck-artifact/types.ts
71
+ var deckBlockTypes = {
72
+ TEXT: "TEXT",
73
+ CHART: "CHART",
74
+ TABLE: "TABLE"
77
75
  };
78
-
79
- // node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
80
- var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
81
- const Component = forwardRef(
82
- ({ color = "currentColor", size = 24, stroke = 2, title, className, children, ...rest }, ref) => createElement(
83
- "svg",
84
- {
85
- ref,
86
- ...defaultAttributes[type],
87
- width: size,
88
- height: size,
89
- className: [`tabler-icon`, `tabler-icon-${iconName}`, className].join(" "),
90
- ...type === "filled" ? {
91
- fill: color
92
- } : {
93
- strokeWidth: stroke,
94
- stroke: color
95
- },
96
- ...rest
97
- },
98
- [
99
- title && createElement("title", { key: "svg-title" }, title),
100
- ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),
101
- ...Array.isArray(children) ? children : [children]
102
- ]
103
- )
104
- );
105
- Component.displayName = `${iconNamePascal}`;
106
- return Component;
76
+ var deckSlideKinds = {
77
+ TITLE: "TITLE",
78
+ AGENDA: "AGENDA",
79
+ SECTION: "SECTION",
80
+ CONTENT: "CONTENT",
81
+ CLOSING: "CLOSING"
82
+ };
83
+ var DEFAULT_DECK_ARTIFACT_LABELS = {
84
+ previous: "Previous slide",
85
+ next: "Next slide",
86
+ position: "Slide {current} of {total}",
87
+ download: "Download",
88
+ unavailable: "Deck content is unavailable.",
89
+ enterFullscreen: "Fullscreen",
90
+ exitFullscreen: "Exit fullscreen",
91
+ thankYou: "Thank you",
92
+ questions: "Questions?",
93
+ agenda: "Agenda",
94
+ chart: DEFAULT_CHART_ARTIFACT_LABELS,
95
+ table: DEFAULT_TABLE_ARTIFACT_LABELS
107
96
  };
108
-
109
- // node_modules/@tabler/icons-react/dist/esm/icons/IconAlertCircle.mjs
110
- 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" }]];
111
- var IconAlertCircle = createReactComponent("outline", "alert-circle", "AlertCircle", __iconNode);
112
-
113
- // node_modules/@tabler/icons-react/dist/esm/icons/IconCheck.mjs
114
- var __iconNode2 = [["path", { "d": "M5 12l5 5l10 -10", "key": "svg-0" }]];
115
- var IconCheck = createReactComponent("outline", "check", "Check", __iconNode2);
116
-
117
- // node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.mjs
118
- 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" }]];
119
- var IconCopy = createReactComponent("outline", "copy", "Copy", __iconNode3);
120
-
121
- // node_modules/@tabler/icons-react/dist/esm/icons/IconDownload.mjs
122
- 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" }]];
123
- var IconDownload = createReactComponent("outline", "download", "Download", __iconNode4);
124
-
125
- // node_modules/@tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs
126
- 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" }]];
127
- var IconFileSpreadsheet = createReactComponent("outline", "file-spreadsheet", "FileSpreadsheet", __iconNode5);
128
-
129
- // node_modules/@tabler/icons-react/dist/esm/icons/IconLoader2.mjs
130
- var __iconNode6 = [["path", { "d": "M12 3a9 9 0 1 0 9 9", "key": "svg-0" }]];
131
- var IconLoader2 = createReactComponent("outline", "loader-2", "Loader2", __iconNode6);
132
-
133
- // node_modules/@tabler/icons-react/dist/esm/icons/IconPhoto.mjs
134
- 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" }]];
135
- var IconPhoto = createReactComponent("outline", "photo", "Photo", __iconNode7);
136
-
137
- // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbDown.mjs
138
- var __iconNode8 = [["path", { "d": "M7 13v-8a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h3a4 4 0 0 1 4 4v1a2 2 0 0 0 4 0v-5h3a2 2 0 0 0 2 -2l-1 -5a2 3 0 0 0 -2 -2h-7a3 3 0 0 0 -3 3", "key": "svg-0" }]];
139
- var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode8);
140
-
141
- // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbUp.mjs
142
- var __iconNode9 = [["path", { "d": "M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3", "key": "svg-0" }]];
143
- var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode9);
144
97
 
145
98
  // src/components/artifacts/artifact-copy-as-image-button/artifact-copy-as-image-button.tsx
146
99
  import { useCallback as useCallback2 } from "react";
@@ -203,7 +156,7 @@ function useCopyAsImage(targetRef, options = {}) {
203
156
  setError(null);
204
157
  setStatus("working");
205
158
  try {
206
- const { copyNodeAsPng } = await import("./dom-to-image-NATF3446.js");
159
+ const { copyNodeAsPng } = await import("./dom-to-image-QB7KMTAE.js");
207
160
  await copyNodeAsPng(node, nodeOptions);
208
161
  setStatus("success");
209
162
  scheduleReset();
@@ -382,7 +335,7 @@ function ArtifactDownloadMenu({
382
335
  if (!node) return;
383
336
  const filename = `${png.filename ?? DEFAULT_PNG_BASENAME}.png`;
384
337
  try {
385
- const { downloadNodeAsPng } = await import("./dom-to-image-NATF3446.js");
338
+ const { downloadNodeAsPng } = await import("./dom-to-image-QB7KMTAE.js");
386
339
  await downloadNodeAsPng(node, filename);
387
340
  } catch (err) {
388
341
  console.warn("[clay] ArtifactDownloadMenu: PNG download failed", err);
@@ -417,9 +370,9 @@ function ArtifactDownloadMenu({
417
370
  import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2 } from "react";
418
371
 
419
372
  // src/components/ai-elements/artifact.tsx
420
- import { forwardRef as forwardRef4 } from "react";
373
+ import { forwardRef as forwardRef3 } from "react";
421
374
  import { jsx as jsx6 } from "react/jsx-runtime";
422
- var Artifact = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
375
+ var Artifact = forwardRef3(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
423
376
  "div",
424
377
  {
425
378
  ref,
@@ -434,9 +387,9 @@ var ArtifactActions = ({ className, ...props }) => /* @__PURE__ */ jsx6("div", {
434
387
  var ArtifactContent = ({ className, ...props }) => /* @__PURE__ */ jsx6("div", { className: cn("flex-1 overflow-auto p-4", className), ...props });
435
388
 
436
389
  // src/components/artifacts/status-message.tsx
437
- import { createElement as createElement2 } from "react";
390
+ import { createElement } from "react";
438
391
  function StatusMessage({ $tone, children }) {
439
- return createElement2(
392
+ return createElement(
440
393
  "div",
441
394
  {
442
395
  className: `py-6 px-2 text-center text-sm font-medium leading-5 ${$tone === "error" ? "text-red-600" : "text-brown-70"}`
@@ -762,8 +715,12 @@ function renderBody(validConfig, artifact, data, labels) {
762
715
  return /* @__PURE__ */ jsx11(ChartArtifactContent, { config: artifact.config, rows: data.rows, labels });
763
716
  }
764
717
 
765
- // src/components/artifacts/table-artifact/table-artifact.tsx
766
- import { useEffect as useEffect4, useMemo as useMemo3 } from "react";
718
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
719
+ import { useEffect as useEffect4, useMemo as useMemo3, useState as useState5 } from "react";
720
+ import { createPortal } from "react-dom";
721
+
722
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
723
+ import { useCallback as useCallback4, useLayoutEffect as useLayoutEffect2, useRef as useRef4, useState as useState4 } from "react";
767
724
 
768
725
  // src/components/artifacts/table-artifact/table-artifact-content.constants.ts
769
726
  var TABLE_STATUS = {
@@ -777,14 +734,10 @@ var TABLE_STATUS = {
777
734
  function formatCell(row, column) {
778
735
  return row[column.key] ?? "";
779
736
  }
780
- var HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
781
- var CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
782
- var ROW_CLASSES = "border-b-brown-30 bg-background/70 hover:bg-secondary";
783
- var DATA_ROW_CLASSES = `${ROW_CLASSES} animate-in fade-in duration-300`;
784
- var SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";
737
+ var DATA_ROW_CLASSES = `${DATA_TABLE_ROW_CLASS} animate-in fade-in duration-300`;
785
738
 
786
739
  // src/components/artifacts/table-artifact/table-artifact-content.tsx
787
- import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
740
+ import { jsx as jsx12 } from "react/jsx-runtime";
788
741
  function TableArtifactContent({
789
742
  columns,
790
743
  data,
@@ -809,33 +762,352 @@ function TableArtifactContent({
809
762
  return /* @__PURE__ */ jsx12(ArtifactTable, { columns, maxBodyHeight, children: data.rows.length === 0 ? renderEmptyRow(columns.length, labels.empty) : renderDataRows(columns, data.rows) });
810
763
  }
811
764
  function ArtifactTable({ columns, maxBodyHeight, children }) {
812
- const { targetRef, isScrolled } = useScrollShadow();
813
- return /* @__PURE__ */ jsx12("div", { ref: targetRef, className: "overscroll-none", style: { maxHeight: maxBodyHeight, overflowY: "auto" }, children: /* @__PURE__ */ jsxs5(Table, { containerClassName: "overflow-visible", children: [
814
- /* @__PURE__ */ jsx12(
815
- TableHeader,
816
- {
817
- "data-scrolled": isScrolled ? "true" : void 0,
818
- className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
819
- style: isScrolled ? { boxShadow: SCROLL_SHADOW } : void 0,
820
- children: /* @__PURE__ */ jsx12(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ jsx12(TableHead, { scope: "col", className: HEAD_CLASS, children: column.label }, column.key)) })
821
- }
822
- ),
823
- /* @__PURE__ */ jsx12(TableBody, { children })
824
- ] }) });
765
+ return /* @__PURE__ */ jsx12(
766
+ DataTable,
767
+ {
768
+ maxBodyHeight,
769
+ header: /* @__PURE__ */ jsx12(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ jsx12(TableHead, { scope: "col", className: DATA_TABLE_HEAD_CLASS, children: column.label }, column.key)) }),
770
+ children
771
+ }
772
+ );
825
773
  }
826
774
  function renderShimmerRows(columns, count) {
827
- return Array.from({ length: count }).map((_, index) => /* @__PURE__ */ jsx12(TableRow, { className: ROW_CLASSES, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ jsx12(TableCell, { className: CELL_CLASS, children: /* @__PURE__ */ jsx12("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index}`));
775
+ return Array.from({ length: count }).map((_, index) => /* @__PURE__ */ jsx12(TableRow, { className: DATA_TABLE_ROW_CLASS, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ jsx12(TableCell, { className: DATA_TABLE_CELL_CLASS, children: /* @__PURE__ */ jsx12("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index}`));
828
776
  }
829
777
  function renderDataRows(columns, rows) {
830
- return rows.map((row, index) => /* @__PURE__ */ jsx12(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ jsx12(TableCell, { className: CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index));
778
+ return rows.map((row, index) => /* @__PURE__ */ jsx12(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ jsx12(TableCell, { className: DATA_TABLE_CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index));
831
779
  }
832
780
  function renderEmptyRow(colSpan, emptyMessage) {
833
781
  return /* @__PURE__ */ jsx12(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ jsx12(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) });
834
782
  }
835
783
 
836
- // src/components/artifacts/table-artifact/use-table-artifact-data.ts
837
- function useTableArtifactData(presignedUrl, columns) {
838
- return useRowsArtifactData(presignedUrl, columns, parseCsv);
784
+ // src/components/artifacts/deck-artifact/deck-markdown.tsx
785
+ import ReactMarkdown from "react-markdown";
786
+ import remarkBreaks from "remark-breaks";
787
+ import remarkGfm from "remark-gfm";
788
+ import { jsx as jsx13 } from "react/jsx-runtime";
789
+ function sanitize(text) {
790
+ return text.split("\n").filter((line) => {
791
+ const t = line.trim();
792
+ return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
793
+ }).join("\n");
794
+ }
795
+ var MARKDOWN_COMPONENTS = {
796
+ h1: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("h1", { className: "text-[30px] font-semibold leading-tight text-foreground mb-3", ...props }),
797
+ h2: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("h2", { className: "text-[26px] font-semibold leading-tight text-foreground mb-2", ...props }),
798
+ h3: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("h3", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
799
+ h4: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("h4", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
800
+ h5: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("h5", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
801
+ h6: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("h6", { className: "text-[24px] font-semibold leading-tight text-foreground mb-2", ...props }),
802
+ p: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("p", { className: "text-[22px] leading-relaxed text-foreground my-2", ...props }),
803
+ ul: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("ul", { className: "list-disc pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
804
+ ol: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("ol", { className: "list-decimal pl-7 text-[22px] leading-relaxed text-foreground my-2", ...props }),
805
+ // react-markdown injects list metadata (`ordered` / `index` / `checked`) that must not leak to the DOM.
806
+ li: ({ node: _node, ordered: _ordered, index: _index, checked: _checked, ...props }) => /* @__PURE__ */ jsx13("li", { className: "my-1", ...props }),
807
+ strong: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("strong", { className: "font-semibold", ...props }),
808
+ em: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("em", { className: "italic", ...props }),
809
+ // Gate `<img src>` against an http(s) allowlist. react-markdown v8 percent-encodes the URL but
810
+ // does NOT protocol-filter image src (unlike link href), so an LLM-authored
811
+ // `![](javascript:…)` / `![](data:…)` or a tracking-pixel `![](http://…)` would otherwise render
812
+ // with the raw URL. Unsafe src → render nothing.
813
+ img: ({ node: _node, src, ...props }) => typeof src === "string" && isSafeDownloadUrl(src) ? /* @__PURE__ */ jsx13("img", { src, className: "max-w-full", ...props }) : null,
814
+ a: ({ node: _node, ...props }) => (
815
+ // `rel` is forced AFTER `{...props}` so it can't be overridden — if a consumer ever adds
816
+ // `linkTarget="_blank"`, LLM-authored links still can't reach `window.opener`.
817
+ /* @__PURE__ */ jsx13("a", { className: "underline underline-offset-2", ...props, rel: "noopener noreferrer" })
818
+ ),
819
+ // react-markdown passes `inline` to distinguish inline code from fenced blocks — strip it from the DOM.
820
+ code: ({ node: _node, inline: _inline, ...props }) => /* @__PURE__ */ jsx13("code", { className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[18px]", ...props }),
821
+ blockquote: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("blockquote", { className: "border-l-2 border-brown-alpha-12 pl-4 text-[22px] text-muted-foreground", ...props }),
822
+ hr: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("hr", { className: "my-4 border-brown-alpha-12", ...props }),
823
+ table: ({ node: _node, ...props }) => /* @__PURE__ */ jsx13("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsx13("table", { className: "w-full border-collapse text-[20px]", ...props }) }),
824
+ // react-markdown passes `isHeader` to cell renderers — strip it so it never reaches the DOM.
825
+ th: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ jsx13("th", { className: "border-b border-brown-alpha-12 px-3 py-1.5 text-left font-medium", ...props }),
826
+ td: ({ node: _node, isHeader: _isHeader, ...props }) => /* @__PURE__ */ jsx13("td", { className: "border-b border-brown-alpha-12 px-3 py-1.5", ...props })
827
+ };
828
+ function DeckMarkdown({ markdown }) {
829
+ return /* @__PURE__ */ jsx13(ReactMarkdown, { remarkPlugins: [remarkGfm, remarkBreaks], components: MARKDOWN_COMPONENTS, children: sanitize(markdown) });
830
+ }
831
+
832
+ // src/components/artifacts/deck-artifact/slide-renderers.tsx
833
+ import { useLayoutEffect, useRef as useRef3, useState as useState3 } from "react";
834
+ import { jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
835
+ function safeLogoUrl(meta) {
836
+ return meta?.logoUrl && isSafeDownloadUrl(meta.logoUrl) ? meta.logoUrl : null;
837
+ }
838
+ var DESIGN_W = 1280;
839
+ var DESIGN_H = 720;
840
+ var EYEBROW_H = 84;
841
+ var CANVAS_LOGO_MAX_H = 48;
842
+ var ACCENT_FONT = { fontFamily: `"${fontFamilies.CRIMSON_PRO}", serif`, fontStyle: "italic" };
843
+ function SlideFrame({ meta, children, accent = false, bare = false }) {
844
+ const frameRef = useRef3(null);
845
+ const [scale, setScale] = useState3(null);
846
+ useLayoutEffect(() => {
847
+ const el = frameRef.current;
848
+ if (!el) return;
849
+ const apply = (width) => {
850
+ if (width > 0) setScale(width / DESIGN_W);
851
+ };
852
+ apply(el.clientWidth);
853
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.width ?? 0));
854
+ ro.observe(el);
855
+ return () => ro.disconnect();
856
+ }, []);
857
+ const bg = accent ? "bg-indigo-600" : "bg-deck-canvas";
858
+ const eyebrowColor = accent ? "text-white/70" : "text-brown-60";
859
+ const borderColor = accent ? "border-white/20" : "border-brown-alpha-12";
860
+ const logoSrc = safeLogoUrl(meta);
861
+ return /* @__PURE__ */ jsx14("div", { ref: frameRef, className: `relative aspect-[16/9] w-full overflow-hidden rounded-lg ${bg}`, children: /* @__PURE__ */ jsxs5(
862
+ "div",
863
+ {
864
+ className: "absolute left-0 top-0 origin-top-left",
865
+ style: {
866
+ width: DESIGN_W,
867
+ height: DESIGN_H,
868
+ transform: `scale(${scale ?? 0})`,
869
+ visibility: scale === null ? "hidden" : "visible"
870
+ },
871
+ children: [
872
+ !bare ? /* @__PURE__ */ jsxs5(
873
+ "div",
874
+ {
875
+ className: `absolute inset-x-0 top-0 flex items-center justify-between border-b px-16 ${borderColor}`,
876
+ style: { height: EYEBROW_H },
877
+ children: [
878
+ meta?.eyebrow ? /* @__PURE__ */ jsx14("span", { className: eyebrowColor, style: { ...ACCENT_FONT, fontSize: 22 }, children: meta.eyebrow }) : /* @__PURE__ */ jsx14("span", {}),
879
+ logoSrc ? /* @__PURE__ */ jsx14("img", { src: logoSrc, alt: "", className: "object-contain", style: { maxHeight: CANVAS_LOGO_MAX_H } }) : null
880
+ ]
881
+ }
882
+ ) : null,
883
+ /* @__PURE__ */ jsx14("div", { className: "absolute inset-x-0 bottom-0 overflow-hidden", style: { top: bare ? 0 : EYEBROW_H }, children })
884
+ ]
885
+ }
886
+ ) });
887
+ }
888
+ function TitleSlide({ slide, meta }) {
889
+ const logoSrc = safeLogoUrl(meta);
890
+ return /* @__PURE__ */ jsx14(SlideFrame, { meta, bare: true, children: /* @__PURE__ */ jsxs5("div", { className: "flex h-full flex-col justify-center px-24 py-16", children: [
891
+ logoSrc ? /* @__PURE__ */ jsx14(
892
+ "img",
893
+ {
894
+ src: logoSrc,
895
+ alt: "",
896
+ className: "mb-16 object-contain object-left",
897
+ style: { maxHeight: 56, maxWidth: 380 }
898
+ }
899
+ ) : null,
900
+ /* @__PURE__ */ jsx14(
901
+ "h1",
902
+ {
903
+ className: "font-bold tracking-tight text-brown-100",
904
+ style: { fontSize: 92, lineHeight: 1.04, maxWidth: 1060 },
905
+ children: slide.title
906
+ }
907
+ ),
908
+ slide.subtitle ? /* @__PURE__ */ jsx14("p", { className: "mt-7 text-brown-70", style: { ...ACCENT_FONT, fontSize: 34 }, children: slide.subtitle }) : null,
909
+ slide.description ? /* @__PURE__ */ jsx14("p", { className: "mt-4 leading-relaxed text-brown-70", style: { fontSize: 24, maxWidth: 880 }, children: slide.description }) : null,
910
+ meta?.date ? /* @__PURE__ */ jsx14("p", { className: "mt-10 text-brown-70", style: { ...ACCENT_FONT, fontSize: 30 }, children: meta.date }) : null
911
+ ] }) });
912
+ }
913
+ function AgendaSlide({ slide, meta, labels }) {
914
+ const items = slide.items ?? [];
915
+ return /* @__PURE__ */ jsx14(SlideFrame, { meta, children: /* @__PURE__ */ jsxs5("div", { className: "h-full px-24 py-14", children: [
916
+ /* @__PURE__ */ jsx14("h2", { className: "mb-10 font-bold text-brown-90", style: { fontSize: 40 }, children: slide.title || labels.agenda }),
917
+ /* @__PURE__ */ jsx14("div", { className: "flex flex-col", children: items.map((item, i) => /* @__PURE__ */ jsxs5("div", { className: "flex items-baseline gap-6 border-b border-brown-alpha-12 py-5", children: [
918
+ /* @__PURE__ */ jsx14("span", { className: "shrink-0 text-indigo-600", style: { ...ACCENT_FONT, fontSize: 28, width: 64 }, children: String(i + 1).padStart(2, "0") }),
919
+ /* @__PURE__ */ jsx14("span", { className: "text-brown-90", style: { fontSize: 28 }, children: item })
920
+ ] }, i)) })
921
+ ] }) });
922
+ }
923
+ function SectionSlide({ slide, meta }) {
924
+ return /* @__PURE__ */ jsx14(SlideFrame, { meta, accent: true, children: /* @__PURE__ */ jsxs5("div", { className: "flex h-full flex-col justify-center gap-6 px-24", children: [
925
+ /* @__PURE__ */ jsx14("h2", { className: "font-bold text-white", style: { fontSize: 72, lineHeight: 1.05, maxWidth: 940 }, children: slide.title }),
926
+ /* @__PURE__ */ jsx14("div", { className: "mt-2 bg-white/50", style: { width: 96, height: 5 } })
927
+ ] }) });
928
+ }
929
+ function ClosingSlide({ meta, labels }) {
930
+ return /* @__PURE__ */ jsx14(SlideFrame, { meta, children: /* @__PURE__ */ jsxs5("div", { className: "flex h-full flex-col items-center justify-center gap-6 px-24 text-center", children: [
931
+ /* @__PURE__ */ jsx14("h1", { className: "font-bold text-brown-100", style: { fontSize: 72 }, children: labels.thankYou }),
932
+ /* @__PURE__ */ jsx14("p", { className: "text-indigo-600", style: { ...ACCENT_FONT, fontSize: 36 }, children: labels.questions })
933
+ ] }) });
934
+ }
935
+
936
+ // src/components/artifacts/deck-artifact/deck-artifact-content.tsx
937
+ import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
938
+ var TABLE_BLOCK_MAX_SHIMMER_ROWS = 10;
939
+ var TABLE_CHROME_RESERVE = 56;
940
+ var VISUAL_FALLBACK_HEIGHT = 360;
941
+ function DeckArtifactContent({
942
+ slides,
943
+ labels,
944
+ onNavigate,
945
+ meta,
946
+ onDark = false,
947
+ currentSlide,
948
+ onSlideChange
949
+ }) {
950
+ const navBtnClass = onDark ? "[&_svg]:!text-white hover:!bg-white/20 disabled:opacity-40" : void 0;
951
+ const navBtnSize = onDark ? "medium" : "small";
952
+ const isControlled = currentSlide !== void 0;
953
+ const [internalIndex, setInternalIndex] = useState4(0);
954
+ const index = isControlled ? currentSlide : internalIndex;
955
+ const current = Math.min(index, slides.length - 1);
956
+ const slide = slides[current];
957
+ const goTo = useCallback4(
958
+ (next) => {
959
+ const clamped = Math.max(0, Math.min(next, slides.length - 1));
960
+ if (isControlled) onSlideChange?.(clamped);
961
+ else setInternalIndex(clamped);
962
+ onNavigate?.(clamped);
963
+ },
964
+ [slides.length, onNavigate, isControlled, onSlideChange]
965
+ );
966
+ const position = labels.position.replace("{current}", String(current + 1)).replace("{total}", String(slides.length));
967
+ return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-3 p-4", children: [
968
+ /* @__PURE__ */ jsx15(SlideDispatch, { slide, labels, meta }),
969
+ /* @__PURE__ */ jsxs6(
970
+ "div",
971
+ {
972
+ className: `flex items-center justify-between border-t pt-2 ${onDark ? "border-white/20" : "border-brown-alpha-12"}`,
973
+ children: [
974
+ /* @__PURE__ */ jsx15(
975
+ IconButton,
976
+ {
977
+ icon: IconChevronLeft,
978
+ size: navBtnSize,
979
+ className: navBtnClass,
980
+ "aria-label": labels.previous,
981
+ disabled: current === 0,
982
+ onClick: () => goTo(current - 1)
983
+ }
984
+ ),
985
+ /* @__PURE__ */ jsx15("span", { className: `text-xs font-medium ${onDark ? "text-white/70" : "text-brown-70"}`, children: position }),
986
+ /* @__PURE__ */ jsx15(
987
+ IconButton,
988
+ {
989
+ icon: IconChevronRight,
990
+ size: navBtnSize,
991
+ className: navBtnClass,
992
+ "aria-label": labels.next,
993
+ disabled: current === slides.length - 1,
994
+ onClick: () => goTo(current + 1)
995
+ }
996
+ )
997
+ ]
998
+ }
999
+ )
1000
+ ] });
1001
+ }
1002
+ function SlideDispatch({ slide, labels, meta }) {
1003
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
1004
+ switch (kind) {
1005
+ case deckSlideKinds.TITLE:
1006
+ return /* @__PURE__ */ jsx15(TitleSlide, { slide, meta });
1007
+ case deckSlideKinds.AGENDA:
1008
+ return /* @__PURE__ */ jsx15(AgendaSlide, { slide, meta, labels });
1009
+ case deckSlideKinds.SECTION:
1010
+ return /* @__PURE__ */ jsx15(SectionSlide, { slide, meta });
1011
+ case deckSlideKinds.CLOSING:
1012
+ return /* @__PURE__ */ jsx15(ClosingSlide, { meta, labels });
1013
+ case deckSlideKinds.CONTENT:
1014
+ default:
1015
+ return /* @__PURE__ */ jsx15(ContentSlide, { slide, meta, labels });
1016
+ }
1017
+ }
1018
+ function isVisualBlock(block) {
1019
+ return block.type === deckBlockTypes.CHART || block.type === deckBlockTypes.TABLE;
1020
+ }
1021
+ function ContentSlide({ slide, meta, labels }) {
1022
+ const content = slide.content ?? [];
1023
+ const visuals = content.filter(isVisualBlock);
1024
+ const texts = content.filter(
1025
+ (b) => b.type === deckBlockTypes.TEXT
1026
+ );
1027
+ if (visuals.length === 1 && texts.length > 0) {
1028
+ return /* @__PURE__ */ jsx15(SlideFrame, { meta, children: /* @__PURE__ */ jsxs6("div", { className: "flex h-full items-stretch gap-12 px-16 py-12", children: [
1029
+ /* @__PURE__ */ jsx15("div", { className: "flex w-[42%] shrink-0 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs6(AutoFit, { children: [
1030
+ /* @__PURE__ */ jsx15("h3", { className: "mb-5 font-bold leading-tight text-foreground", style: { fontSize: 34 }, children: slide.title }),
1031
+ texts.map((block, i) => /* @__PURE__ */ jsx15(DeckMarkdown, { markdown: block.markdown }, i))
1032
+ ] }) }),
1033
+ /* @__PURE__ */ jsx15("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ jsx15(FillVisual, { block: visuals[0], labels }) })
1034
+ ] }) });
1035
+ }
1036
+ if (visuals.length > 0) {
1037
+ return /* @__PURE__ */ jsx15(SlideFrame, { meta, children: /* @__PURE__ */ jsxs6("div", { className: "flex h-full flex-col gap-5 px-16 py-10", children: [
1038
+ /* @__PURE__ */ jsx15("h3", { className: "shrink-0 font-bold leading-tight text-foreground", style: { fontSize: 32 }, children: slide.title }),
1039
+ content.map(
1040
+ (block, i) => isVisualBlock(block) ? /* @__PURE__ */ jsx15("div", { className: "min-h-0 min-w-0 flex-1", children: /* @__PURE__ */ jsx15(FillVisual, { block, labels }) }, i) : /* @__PURE__ */ jsx15("div", { className: "shrink-0 overflow-hidden", children: /* @__PURE__ */ jsx15(DeckMarkdown, { markdown: block.markdown }) }, i)
1041
+ )
1042
+ ] }) });
1043
+ }
1044
+ return /* @__PURE__ */ jsx15(SlideFrame, { meta, children: /* @__PURE__ */ jsx15("div", { className: "h-full px-24 py-12", children: /* @__PURE__ */ jsxs6(AutoFit, { children: [
1045
+ /* @__PURE__ */ jsx15("h3", { className: "mb-6 font-bold leading-tight text-foreground", style: { fontSize: 38 }, children: slide.title }),
1046
+ texts.map((block, i) => /* @__PURE__ */ jsx15(DeckMarkdown, { markdown: block.markdown }, i))
1047
+ ] }) }) });
1048
+ }
1049
+ function AutoFit({ children }) {
1050
+ const boxRef = useRef4(null);
1051
+ const contentRef = useRef4(null);
1052
+ const [fit, setFit] = useState4({ scale: 1, height: 0 });
1053
+ useLayoutEffect2(() => {
1054
+ const boxEl = boxRef.current;
1055
+ const contentEl = contentRef.current;
1056
+ if (!boxEl || !contentEl) return;
1057
+ const measure = () => {
1058
+ const avail = boxEl.clientHeight;
1059
+ const natural = contentEl.offsetHeight;
1060
+ const scale = avail > 0 && natural > avail ? avail / natural : 1;
1061
+ setFit({ scale, height: natural * scale });
1062
+ };
1063
+ measure();
1064
+ const ro = new ResizeObserver(measure);
1065
+ ro.observe(boxEl);
1066
+ ro.observe(contentEl);
1067
+ return () => ro.disconnect();
1068
+ }, []);
1069
+ const scaled = fit.scale < 1;
1070
+ return /* @__PURE__ */ jsx15("div", { ref: boxRef, className: "flex h-full min-h-0 w-full flex-col justify-center overflow-hidden", children: /* @__PURE__ */ jsx15("div", { style: scaled ? { height: fit.height } : void 0, children: /* @__PURE__ */ jsx15(
1071
+ "div",
1072
+ {
1073
+ ref: contentRef,
1074
+ className: "w-full origin-top-left",
1075
+ style: scaled ? { transform: `scale(${fit.scale})` } : void 0,
1076
+ children
1077
+ }
1078
+ ) }) });
1079
+ }
1080
+ function FillVisual({ block, labels }) {
1081
+ const ref = useRef4(null);
1082
+ const [height, setHeight] = useState4(VISUAL_FALLBACK_HEIGHT);
1083
+ useLayoutEffect2(() => {
1084
+ const el = ref.current;
1085
+ if (!el) return;
1086
+ const apply = (h) => {
1087
+ if (h > 0) setHeight(h);
1088
+ };
1089
+ apply(el.clientHeight);
1090
+ const ro = new ResizeObserver((entries) => apply(entries[0]?.contentRect.height ?? 0));
1091
+ ro.observe(el);
1092
+ return () => ro.disconnect();
1093
+ }, []);
1094
+ const chartLabels = labels.chart ?? DEFAULT_CHART_ARTIFACT_LABELS;
1095
+ return /* @__PURE__ */ jsx15("div", { ref, className: "h-full min-h-0 w-full overflow-hidden", children: block.type === deckBlockTypes.CHART ? (
1096
+ // ChartArtifactContent assumes a non-empty rowset (the standalone ChartArtifact guards
1097
+ // `rows.length > 0` upstream); mirror that guard here so an empty inline chart shows the
1098
+ // localized empty status instead of a blank chart area.
1099
+ block.rows.length === 0 ? /* @__PURE__ */ jsx15(StatusMessage, { $tone: "info", children: chartLabels.empty }) : /* @__PURE__ */ jsx15("div", { style: { height }, children: /* @__PURE__ */ jsx15(ChartArtifactContent, { config: block.config, rows: block.rows, labels: chartLabels }) })
1100
+ ) : /* @__PURE__ */ jsx15(
1101
+ TableArtifactContent,
1102
+ {
1103
+ columns: block.config.columns,
1104
+ data: { status: "ready", rows: block.rows, error: null },
1105
+ knownRowCount: block.config.stats?.rowCount ?? block.rows.length,
1106
+ maxShimmerRows: TABLE_BLOCK_MAX_SHIMMER_ROWS,
1107
+ maxBodyHeight: Math.max(0, height - TABLE_CHROME_RESERVE),
1108
+ labels: labels.table ?? DEFAULT_TABLE_ARTIFACT_LABELS
1109
+ }
1110
+ ) });
839
1111
  }
840
1112
 
841
1113
  // src/components/artifacts/table-artifact/validate.ts
@@ -854,19 +1126,206 @@ function isValidTableColumn(column) {
854
1126
  return true;
855
1127
  }
856
1128
 
857
- // src/components/artifacts/table-artifact/table-artifact.tsx
858
- import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
1129
+ // src/components/artifacts/deck-artifact/validate.ts
1130
+ function isValidDeckConfig(config) {
1131
+ if (!config || typeof config !== "object") return false;
1132
+ const candidate = config;
1133
+ if (!Array.isArray(candidate.slides)) return false;
1134
+ if (candidate.slides.length === 0) return false;
1135
+ return candidate.slides.every(isValidDeckSlide);
1136
+ }
1137
+ function isValidDeckSlide(slide) {
1138
+ if (!slide || typeof slide !== "object") return false;
1139
+ const candidate = slide;
1140
+ if (typeof candidate.title !== "string") return false;
1141
+ const kind = typeof candidate.kind === "string" ? candidate.kind : deckSlideKinds.CONTENT;
1142
+ if (kind === deckSlideKinds.CONTENT && !Array.isArray(candidate.content)) return false;
1143
+ const content = Array.isArray(candidate.content) ? candidate.content : [];
1144
+ if (candidate.items != null) {
1145
+ if (!Array.isArray(candidate.items)) return false;
1146
+ if (!candidate.items.every((item) => typeof item === "string")) return false;
1147
+ }
1148
+ return content.every(isValidDeckBlock);
1149
+ }
1150
+ function isValidDeckBlock(block) {
1151
+ if (!block || typeof block !== "object") return false;
1152
+ const candidate = block;
1153
+ switch (candidate.type) {
1154
+ case deckBlockTypes.TEXT:
1155
+ return typeof candidate.markdown === "string";
1156
+ case deckBlockTypes.CHART:
1157
+ return isValidChartConfig(candidate.config) && Array.isArray(candidate.rows);
1158
+ case deckBlockTypes.TABLE:
1159
+ return isValidTableConfig(candidate.config) && Array.isArray(candidate.rows);
1160
+ default:
1161
+ return false;
1162
+ }
1163
+ }
1164
+
1165
+ // src/components/artifacts/deck-artifact/deck-artifact.tsx
1166
+ import { Fragment, jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
859
1167
  var TITLE_CLASSES2 = "text-sm font-semibold text-foreground";
1168
+ function DeckArtifact({ artifact, labels, callbacks }) {
1169
+ const validConfig = isValidDeckConfig(artifact.config);
1170
+ const [isFullscreen, setIsFullscreen] = useState5(false);
1171
+ const [currentSlide, setCurrentSlide] = useState5(0);
1172
+ useEffect4(() => {
1173
+ if (validConfig) return;
1174
+ console.warn("[clay] DeckArtifact: malformed `config` \u2014 skipping render.");
1175
+ }, [validConfig]);
1176
+ useEffect4(() => {
1177
+ if (!isFullscreen) return;
1178
+ const handleKey = (e) => {
1179
+ if (e.key === "Escape") setIsFullscreen(false);
1180
+ };
1181
+ document.addEventListener("keydown", handleKey);
1182
+ const previousOverflow = document.documentElement.style.overflow;
1183
+ document.documentElement.style.overflow = "hidden";
1184
+ return () => {
1185
+ document.removeEventListener("keydown", handleKey);
1186
+ document.documentElement.style.overflow = previousOverflow;
1187
+ };
1188
+ }, [isFullscreen]);
1189
+ const resolvedLabels = useMemo3(
1190
+ () => ({
1191
+ ...DEFAULT_DECK_ARTIFACT_LABELS,
1192
+ ...labels ?? {},
1193
+ chart: { ...DEFAULT_CHART_ARTIFACT_LABELS, ...labels?.chart ?? {} },
1194
+ table: { ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels?.table ?? {} }
1195
+ }),
1196
+ [labels]
1197
+ );
1198
+ const onNavigate = callbacks?.onNavigate;
1199
+ const handleNavigate = onNavigate ? (slideIndex) => onNavigate(artifact, slideIndex) : void 0;
1200
+ const onDownload = callbacks?.onDownload;
1201
+ const handleDownload = onDownload ? () => onDownload(artifact) : void 0;
1202
+ const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
1203
+ const showDownload = presignedUrl !== null && isSafeDownloadUrl(presignedUrl);
1204
+ const meta = artifact.config?.meta;
1205
+ const handleOpenFullscreen = () => setIsFullscreen(true);
1206
+ const handleCloseFullscreen = () => setIsFullscreen(false);
1207
+ const actions = /* @__PURE__ */ jsxs7(ArtifactActions, { ...{ [CAPTURE_EXCLUDE_ATTRIBUTE]: "" }, children: [
1208
+ showDownload ? /* @__PURE__ */ jsx16(ArtifactDownloadButton, { href: presignedUrl ?? "", label: resolvedLabels.download, onClick: handleDownload }) : null,
1209
+ validConfig ? /* @__PURE__ */ jsx16(
1210
+ IconButton,
1211
+ {
1212
+ icon: IconArrowsMaximize,
1213
+ size: "small",
1214
+ "aria-label": resolvedLabels.enterFullscreen,
1215
+ onClick: handleOpenFullscreen
1216
+ }
1217
+ ) : null
1218
+ ] });
1219
+ if (!validConfig) {
1220
+ return /* @__PURE__ */ jsxs7(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1221
+ /* @__PURE__ */ jsxs7(ArtifactHeader, { className: "bg-background/70", children: [
1222
+ artifact.title ? /* @__PURE__ */ jsx16(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ jsx16("span", {}),
1223
+ actions
1224
+ ] }),
1225
+ /* @__PURE__ */ jsx16(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ jsx16(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
1226
+ ] });
1227
+ }
1228
+ return /* @__PURE__ */ jsxs7(Fragment, { children: [
1229
+ /* @__PURE__ */ jsxs7(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1230
+ /* @__PURE__ */ jsxs7(ArtifactHeader, { className: "bg-background/70", children: [
1231
+ artifact.title ? /* @__PURE__ */ jsx16(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ jsx16("span", {}),
1232
+ actions
1233
+ ] }),
1234
+ /* @__PURE__ */ jsx16(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ jsx16(
1235
+ DeckArtifactContent,
1236
+ {
1237
+ slides: artifact.config.slides,
1238
+ labels: resolvedLabels,
1239
+ onNavigate: handleNavigate,
1240
+ meta,
1241
+ currentSlide,
1242
+ onSlideChange: setCurrentSlide
1243
+ }
1244
+ ) })
1245
+ ] }),
1246
+ isFullscreen && createPortal(
1247
+ /* @__PURE__ */ jsx16(
1248
+ FullscreenOverlay,
1249
+ {
1250
+ artifact,
1251
+ resolvedLabels,
1252
+ onNavigate: handleNavigate,
1253
+ currentSlide,
1254
+ onSlideChange: setCurrentSlide,
1255
+ onClose: handleCloseFullscreen
1256
+ }
1257
+ ),
1258
+ document.body
1259
+ )
1260
+ ] });
1261
+ }
1262
+ function FullscreenOverlay({
1263
+ artifact,
1264
+ resolvedLabels,
1265
+ onNavigate,
1266
+ currentSlide,
1267
+ onSlideChange,
1268
+ onClose
1269
+ }) {
1270
+ const meta = artifact.config?.meta;
1271
+ return /* @__PURE__ */ jsx16(
1272
+ "div",
1273
+ {
1274
+ className: "fixed inset-0 z-[2147483647] flex items-center justify-center bg-black/80",
1275
+ role: "dialog",
1276
+ "aria-modal": "true",
1277
+ "aria-label": resolvedLabels.exitFullscreen,
1278
+ children: /* @__PURE__ */ jsxs7("div", { className: "relative", style: { width: "min(94vw, calc(82vh * 16 / 9))" }, children: [
1279
+ /* @__PURE__ */ jsx16(
1280
+ DeckArtifactContent,
1281
+ {
1282
+ slides: artifact.config.slides,
1283
+ labels: resolvedLabels,
1284
+ onNavigate,
1285
+ meta,
1286
+ currentSlide,
1287
+ onSlideChange,
1288
+ onDark: true
1289
+ }
1290
+ ),
1291
+ /* @__PURE__ */ jsxs7(
1292
+ "button",
1293
+ {
1294
+ className: "absolute -top-10 right-6 flex items-center gap-1.5 text-sm text-white/80 hover:text-white",
1295
+ "aria-label": resolvedLabels.exitFullscreen,
1296
+ onClick: onClose,
1297
+ children: [
1298
+ /* @__PURE__ */ jsx16(IconArrowsMinimize, { size: 16 }),
1299
+ /* @__PURE__ */ jsx16("span", { children: resolvedLabels.exitFullscreen })
1300
+ ]
1301
+ }
1302
+ )
1303
+ ] })
1304
+ }
1305
+ );
1306
+ }
1307
+
1308
+ // src/components/artifacts/table-artifact/table-artifact.tsx
1309
+ import { useEffect as useEffect5, useMemo as useMemo4 } from "react";
1310
+
1311
+ // src/components/artifacts/table-artifact/use-table-artifact-data.ts
1312
+ function useTableArtifactData(presignedUrl, columns) {
1313
+ return useRowsArtifactData(presignedUrl, columns, parseCsv);
1314
+ }
1315
+
1316
+ // src/components/artifacts/table-artifact/table-artifact.tsx
1317
+ import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
1318
+ var TITLE_CLASSES3 = "text-sm font-semibold text-foreground";
860
1319
  var TABLE_MAX_BODY_HEIGHT = 480;
861
1320
  var MAX_SHIMMER_ROWS = 10;
862
1321
  function TableArtifact({ artifact, labels, callbacks }) {
863
1322
  const validConfig = isValidTableConfig(artifact.config);
864
1323
  const validColumns = validConfig ? artifact.config.columns : null;
865
- useEffect4(() => {
1324
+ useEffect5(() => {
866
1325
  if (validConfig) return;
867
1326
  console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
868
1327
  }, [validConfig]);
869
- const resolvedLabels = useMemo3(
1328
+ const resolvedLabels = useMemo4(
870
1329
  () => ({ ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels ?? {} }),
871
1330
  [labels]
872
1331
  );
@@ -878,10 +1337,10 @@ function TableArtifact({ artifact, labels, callbacks }) {
878
1337
  const onDownload = callbacks?.onDownload;
879
1338
  const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
880
1339
  if (!validConfig || !validColumns) {
881
- return /* @__PURE__ */ jsxs6(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
882
- /* @__PURE__ */ jsxs6(ArtifactHeader, { className: "bg-background/70", children: [
883
- artifact.title ? /* @__PURE__ */ jsx13(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ jsx13("span", {}),
884
- presignedUrl ? /* @__PURE__ */ jsx13(ArtifactActions, { children: /* @__PURE__ */ jsx13(
1340
+ return /* @__PURE__ */ jsxs8(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1341
+ /* @__PURE__ */ jsxs8(ArtifactHeader, { className: "bg-background/70", children: [
1342
+ artifact.title ? /* @__PURE__ */ jsx17(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ jsx17("span", {}),
1343
+ presignedUrl ? /* @__PURE__ */ jsx17(ArtifactActions, { children: /* @__PURE__ */ jsx17(
885
1344
  ArtifactDownloadButton,
886
1345
  {
887
1346
  href: presignedUrl,
@@ -890,17 +1349,17 @@ function TableArtifact({ artifact, labels, callbacks }) {
890
1349
  }
891
1350
  ) }) : null
892
1351
  ] }),
893
- /* @__PURE__ */ jsx13(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ jsx13(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
1352
+ /* @__PURE__ */ jsx17(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ jsx17(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
894
1353
  ] });
895
1354
  }
896
1355
  return (
897
1356
  // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
898
1357
  // Disable the outer overflow container so only one scroll context exists — this prevents
899
1358
  // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
900
- /* @__PURE__ */ jsxs6(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
901
- /* @__PURE__ */ jsxs6(ArtifactHeader, { className: "bg-background/70", children: [
902
- artifact.title ? /* @__PURE__ */ jsx13(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ jsx13("span", {}),
903
- /* @__PURE__ */ jsx13(ArtifactActions, { children: /* @__PURE__ */ jsx13(
1359
+ /* @__PURE__ */ jsxs8(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1360
+ /* @__PURE__ */ jsxs8(ArtifactHeader, { className: "bg-background/70", children: [
1361
+ artifact.title ? /* @__PURE__ */ jsx17(ArtifactTitle, { className: TITLE_CLASSES3, children: artifact.title }) : /* @__PURE__ */ jsx17("span", {}),
1362
+ /* @__PURE__ */ jsx17(ArtifactActions, { children: /* @__PURE__ */ jsx17(
904
1363
  ArtifactDownloadButton,
905
1364
  {
906
1365
  href: presignedUrl ?? "",
@@ -909,7 +1368,7 @@ function TableArtifact({ artifact, labels, callbacks }) {
909
1368
  }
910
1369
  ) })
911
1370
  ] }),
912
- /* @__PURE__ */ jsx13(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ jsx13(
1371
+ /* @__PURE__ */ jsx17(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ jsx17(
913
1372
  TableArtifactContent,
914
1373
  {
915
1374
  columns: validColumns,
@@ -937,6 +1396,65 @@ var ChartArtifactService = {
937
1396
  toClipboardText: chartArtifactToClipboardText
938
1397
  };
939
1398
 
1399
+ // src/components/artifacts/deck-artifact/to-clipboard-text.ts
1400
+ function deckArtifactToClipboardText(artifact) {
1401
+ const header = artifact.title?.trim() || "Deck";
1402
+ const slides = artifact.config?.slides ?? [];
1403
+ const body = slides.map((slide, i) => slideToText(slide, i)).join("\n\n");
1404
+ return body ? `${header}
1405
+
1406
+ ${body}` : header;
1407
+ }
1408
+ function slideToText(slide, index) {
1409
+ const kind = slide.kind ?? deckSlideKinds.CONTENT;
1410
+ const prefix = `Slide ${index + 1}: `;
1411
+ switch (kind) {
1412
+ case deckSlideKinds.TITLE: {
1413
+ const parts = [slide.title];
1414
+ if (slide.subtitle) parts.push(slide.subtitle);
1415
+ if (slide.description) parts.push(slide.description);
1416
+ return `${prefix}${parts.join(" \u2014 ")}`.trim();
1417
+ }
1418
+ case deckSlideKinds.AGENDA: {
1419
+ const items = (slide.items ?? []).map((item, i) => ` ${String(i + 1).padStart(2, "0")}. ${item}`).join("\n");
1420
+ return `${prefix}${slide.title || "Agenda"}${items ? `
1421
+ ${items}` : ""}`.trim();
1422
+ }
1423
+ case deckSlideKinds.SECTION:
1424
+ return `${prefix}${slide.title}`.trim();
1425
+ case deckSlideKinds.CLOSING:
1426
+ return `${prefix}Thank you`.trim();
1427
+ case deckSlideKinds.CONTENT:
1428
+ default: {
1429
+ const blocks = (slide.content ?? []).map(blockToText).filter(Boolean).join("\n\n");
1430
+ return `${prefix}${slide.title}${blocks ? `
1431
+ ${blocks}` : ""}`.trim();
1432
+ }
1433
+ }
1434
+ }
1435
+ function blockToText(block) {
1436
+ switch (block.type) {
1437
+ case deckBlockTypes.TEXT:
1438
+ return block.markdown.trim();
1439
+ case deckBlockTypes.CHART:
1440
+ return `[Chart: ${block.config.variant}]`;
1441
+ case deckBlockTypes.TABLE: {
1442
+ const columnCount = block.config.columns.length;
1443
+ const rowCount = block.rows.length;
1444
+ return `[Table: ${columnCount} column${columnCount === 1 ? "" : "s"} \xD7 ${rowCount} row${rowCount === 1 ? "" : "s"}]`;
1445
+ }
1446
+ default:
1447
+ return "";
1448
+ }
1449
+ }
1450
+
1451
+ // src/components/artifacts/artifact-services/deck-artifact-service.ts
1452
+ var DeckArtifactService = {
1453
+ type: artifactTypes.DECK,
1454
+ Component: DeckArtifact,
1455
+ toClipboardText: deckArtifactToClipboardText
1456
+ };
1457
+
940
1458
  // src/components/artifacts/table-artifact/to-clipboard-text.ts
941
1459
  function tableArtifactToClipboardText(artifact) {
942
1460
  const trimmedTitle = artifact.title?.trim();
@@ -953,7 +1471,8 @@ var TableArtifactService = {
953
1471
  // src/components/artifacts/artifact-services/index.ts
954
1472
  var ArtifactServices = {
955
1473
  [artifactTypes.TABLE]: TableArtifactService,
956
- [artifactTypes.CHART]: ChartArtifactService
1474
+ [artifactTypes.CHART]: ChartArtifactService,
1475
+ [artifactTypes.DECK]: DeckArtifactService
957
1476
  };
958
1477
  function artifactToClipboardText(artifact) {
959
1478
  const entry = ArtifactServices[artifact.type];
@@ -967,38 +1486,17 @@ export {
967
1486
  artifactTypes,
968
1487
  DEFAULT_CHART_ARTIFACT_LABELS,
969
1488
  DEFAULT_TABLE_ARTIFACT_LABELS,
970
- IconCheck,
971
- IconCopy,
972
- IconThumbDown,
973
- IconThumbUp,
1489
+ deckBlockTypes,
1490
+ deckSlideKinds,
1491
+ DEFAULT_DECK_ARTIFACT_LABELS,
974
1492
  ArtifactCopyAsImageButton,
975
1493
  ArtifactDownloadButton,
976
1494
  isSafeDownloadUrl,
977
1495
  ArtifactDownloadMenu,
978
1496
  ChartArtifact,
1497
+ DeckArtifact,
979
1498
  TableArtifact,
980
1499
  ArtifactServices,
981
1500
  artifactToClipboardText
982
1501
  };
983
- /*! Bundled license information:
984
-
985
- @tabler/icons-react/dist/esm/defaultAttributes.mjs:
986
- @tabler/icons-react/dist/esm/createReactComponent.mjs:
987
- @tabler/icons-react/dist/esm/icons/IconAlertCircle.mjs:
988
- @tabler/icons-react/dist/esm/icons/IconCheck.mjs:
989
- @tabler/icons-react/dist/esm/icons/IconCopy.mjs:
990
- @tabler/icons-react/dist/esm/icons/IconDownload.mjs:
991
- @tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs:
992
- @tabler/icons-react/dist/esm/icons/IconLoader2.mjs:
993
- @tabler/icons-react/dist/esm/icons/IconPhoto.mjs:
994
- @tabler/icons-react/dist/esm/icons/IconThumbDown.mjs:
995
- @tabler/icons-react/dist/esm/icons/IconThumbUp.mjs:
996
- @tabler/icons-react/dist/esm/tabler-icons-react.mjs:
997
- (**
998
- * @license @tabler/icons-react v3.37.1 - MIT
999
- *
1000
- * This source code is licensed under the MIT license.
1001
- * See the LICENSE file in the root directory of this source tree.
1002
- *)
1003
- */
1004
- //# sourceMappingURL=chunk-6YZ65KPW.js.map
1502
+ //# sourceMappingURL=chunk-DC5KYT2G.js.map