@shapesos/clay 0.10.0 → 0.12.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 (85) hide show
  1. package/README.md +60 -0
  2. package/dist/artifacts.cjs +1467 -0
  3. package/dist/artifacts.cjs.map +1 -0
  4. package/dist/artifacts.d.cts +89 -0
  5. package/dist/artifacts.d.ts +89 -0
  6. package/dist/artifacts.js +33 -0
  7. package/dist/blocks.cjs +1418 -68
  8. package/dist/blocks.cjs.map +1 -1
  9. package/dist/blocks.css +2 -0
  10. package/dist/blocks.d.cts +36 -11
  11. package/dist/blocks.d.ts +36 -11
  12. package/dist/blocks.js +18 -5
  13. package/dist/button.d.cts +2 -2
  14. package/dist/button.d.ts +2 -2
  15. package/dist/chart.cjs +594 -0
  16. package/dist/chart.cjs.map +1 -0
  17. package/dist/chart.d.cts +439 -0
  18. package/dist/chart.d.ts +439 -0
  19. package/dist/chart.js +32 -0
  20. package/dist/chart.js.map +1 -0
  21. package/dist/chat.cjs +1462 -312
  22. package/dist/chat.cjs.map +1 -1
  23. package/dist/chat.d.cts +28 -10
  24. package/dist/chat.d.ts +28 -10
  25. package/dist/chat.js +10 -3
  26. package/dist/{chunk-R3BGPOAM.js → chunk-36CB624W.js} +53 -45
  27. package/dist/chunk-36CB624W.js.map +1 -0
  28. package/dist/chunk-4MZZH3WX.js +93 -0
  29. package/dist/chunk-4MZZH3WX.js.map +1 -0
  30. package/dist/chunk-AQEJRMRN.js +1 -0
  31. package/dist/chunk-AQEJRMRN.js.map +1 -0
  32. package/dist/{chunk-WS4IPADR.js → chunk-FFX3CAOX.js} +41 -109
  33. package/dist/chunk-FFX3CAOX.js.map +1 -0
  34. package/dist/chunk-JGMN6W72.js +12 -0
  35. package/dist/chunk-JGMN6W72.js.map +1 -0
  36. package/dist/{chunk-27GJUWVN.js → chunk-JJUIBBBU.js} +14 -8
  37. package/dist/chunk-JJUIBBBU.js.map +1 -0
  38. package/dist/{chunk-MLCRDVQ2.js → chunk-OBOXCBDL.js} +13 -5
  39. package/dist/chunk-OBOXCBDL.js.map +1 -0
  40. package/dist/chunk-P6GUNIAE.js +11 -0
  41. package/dist/chunk-P6GUNIAE.js.map +1 -0
  42. package/dist/chunk-QXGYMDIA.js +477 -0
  43. package/dist/chunk-QXGYMDIA.js.map +1 -0
  44. package/dist/chunk-Z5JWF24N.js +719 -0
  45. package/dist/chunk-Z5JWF24N.js.map +1 -0
  46. package/dist/icon.cjs +12 -4
  47. package/dist/icon.cjs.map +1 -1
  48. package/dist/icon.d.cts +19 -6
  49. package/dist/icon.d.ts +19 -6
  50. package/dist/icon.js +1 -1
  51. package/dist/index.cjs +1520 -332
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.cts +7 -4
  54. package/dist/index.d.ts +7 -4
  55. package/dist/index.js +58 -25
  56. package/dist/lottie.d.cts +2 -2
  57. package/dist/lottie.d.ts +2 -2
  58. package/dist/table.cjs +142 -0
  59. package/dist/table.cjs.map +1 -0
  60. package/dist/table.d.cts +44 -0
  61. package/dist/table.d.ts +44 -0
  62. package/dist/table.js +25 -0
  63. package/dist/table.js.map +1 -0
  64. package/dist/text-area.d.cts +2 -2
  65. package/dist/text-area.d.ts +2 -2
  66. package/dist/types-B2aYk82c.d.cts +29 -0
  67. package/dist/types-B2aYk82c.d.ts +29 -0
  68. package/dist/types-C0BvwliI.d.cts +332 -0
  69. package/dist/types-C5bFH4v3.d.ts +332 -0
  70. package/dist/types-DCutaXjZ.d.cts +83 -0
  71. package/dist/types-uPfn67Dc.d.ts +83 -0
  72. package/dist/utils.cjs +14 -7
  73. package/dist/utils.cjs.map +1 -1
  74. package/dist/utils.d.cts +18 -1
  75. package/dist/utils.d.ts +18 -1
  76. package/dist/utils.js +6 -4
  77. package/package.json +41 -4
  78. package/dist/chunk-27GJUWVN.js.map +0 -1
  79. package/dist/chunk-MLCRDVQ2.js.map +0 -1
  80. package/dist/chunk-OKPNST44.js +0 -1
  81. package/dist/chunk-R3BGPOAM.js.map +0 -1
  82. package/dist/chunk-WS4IPADR.js.map +0 -1
  83. package/dist/types-Q9aqd9nq.d.cts +0 -34
  84. package/dist/types-Q9aqd9nq.d.ts +0 -34
  85. /package/dist/{chunk-OKPNST44.js.map → artifacts.js.map} +0 -0
@@ -0,0 +1,1467 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/components/artifacts/index.ts
31
+ var artifacts_exports = {};
32
+ __export(artifacts_exports, {
33
+ ArtifactDownloadButton: () => ArtifactDownloadButton,
34
+ ArtifactServices: () => ArtifactServices,
35
+ ChartArtifact: () => ChartArtifact,
36
+ DEFAULT_CHART_ARTIFACT_LABELS: () => DEFAULT_CHART_ARTIFACT_LABELS,
37
+ DEFAULT_TABLE_ARTIFACT_LABELS: () => DEFAULT_TABLE_ARTIFACT_LABELS,
38
+ TableArtifact: () => TableArtifact,
39
+ artifactToClipboardText: () => artifactToClipboardText,
40
+ artifactTypes: () => artifactTypes,
41
+ isSafeDownloadUrl: () => isSafeDownloadUrl
42
+ });
43
+ module.exports = __toCommonJS(artifacts_exports);
44
+
45
+ // src/components/artifacts/artifact-base.ts
46
+ var artifactTypes = {
47
+ TABLE: "TABLE",
48
+ CHART: "CHART"
49
+ };
50
+
51
+ // src/components/artifacts/chart-artifact/types.ts
52
+ var DEFAULT_CHART_ARTIFACT_LABELS = {
53
+ download: "Download CSV",
54
+ unavailable: "Chart data is unavailable.",
55
+ loadError: "Couldn't load chart data.",
56
+ loading: "Loading chart\u2026",
57
+ empty: "No data to chart.",
58
+ othersCategoryLabels: ["Others", "Other"]
59
+ };
60
+
61
+ // src/components/artifacts/table-artifact/types.ts
62
+ var DEFAULT_TABLE_ARTIFACT_LABELS = {
63
+ download: "Download CSV",
64
+ unavailable: "Table data is unavailable.",
65
+ loadError: "Couldn't load table data.",
66
+ loading: "Loading table\u2026",
67
+ empty: "No rows to display."
68
+ };
69
+
70
+ // src/components/artifacts/chart-artifact/chart-artifact.tsx
71
+ var import_react9 = require("react");
72
+
73
+ // src/lib/utils.ts
74
+ var import_clsx = require("clsx");
75
+ var import_tailwind_merge = require("tailwind-merge");
76
+ function cn(...inputs) {
77
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
78
+ }
79
+
80
+ // src/components/ai-elements/artifact.tsx
81
+ var import_jsx_runtime = require("react/jsx-runtime");
82
+ var Artifact = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
83
+ "div",
84
+ {
85
+ className: cn("flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm", className),
86
+ ...props
87
+ }
88
+ );
89
+ var ArtifactHeader = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("flex items-center justify-between border-b bg-muted/50 px-4 py-3", className), ...props });
90
+ var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: cn("font-medium text-foreground text-sm", className), ...props });
91
+ var ArtifactActions = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("flex items-center gap-1", className), ...props });
92
+ var ArtifactContent = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("flex-1 overflow-auto p-4", className), ...props });
93
+
94
+ // node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
95
+ var import_react = require("react");
96
+
97
+ // node_modules/@tabler/icons-react/dist/esm/defaultAttributes.mjs
98
+ var defaultAttributes = {
99
+ outline: {
100
+ xmlns: "http://www.w3.org/2000/svg",
101
+ width: 24,
102
+ height: 24,
103
+ viewBox: "0 0 24 24",
104
+ fill: "none",
105
+ stroke: "currentColor",
106
+ strokeWidth: 2,
107
+ strokeLinecap: "round",
108
+ strokeLinejoin: "round"
109
+ },
110
+ filled: {
111
+ xmlns: "http://www.w3.org/2000/svg",
112
+ width: 24,
113
+ height: 24,
114
+ viewBox: "0 0 24 24",
115
+ fill: "currentColor",
116
+ stroke: "none"
117
+ }
118
+ };
119
+
120
+ // node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
121
+ var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
122
+ const Component = (0, import_react.forwardRef)(
123
+ ({ color = "currentColor", size = 24, stroke = 2, title, className, children, ...rest }, ref) => (0, import_react.createElement)(
124
+ "svg",
125
+ {
126
+ ref,
127
+ ...defaultAttributes[type],
128
+ width: size,
129
+ height: size,
130
+ className: [`tabler-icon`, `tabler-icon-${iconName}`, className].join(" "),
131
+ ...type === "filled" ? {
132
+ fill: color
133
+ } : {
134
+ strokeWidth: stroke,
135
+ stroke: color
136
+ },
137
+ ...rest
138
+ },
139
+ [
140
+ title && (0, import_react.createElement)("title", { key: "svg-title" }, title),
141
+ ...iconNode.map(([tag, attrs]) => (0, import_react.createElement)(tag, attrs)),
142
+ ...Array.isArray(children) ? children : [children]
143
+ ]
144
+ )
145
+ );
146
+ Component.displayName = `${iconNamePascal}`;
147
+ return Component;
148
+ };
149
+
150
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconDownload.mjs
151
+ var __iconNode = [["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" }]];
152
+ var IconDownload = createReactComponent("outline", "download", "Download", __iconNode);
153
+
154
+ // src/components/icon-button/icon-button.tsx
155
+ var import_react3 = require("react");
156
+
157
+ // src/components/icon/icon.tsx
158
+ var import_react2 = require("react");
159
+
160
+ // src/components/icon/icon-styles.ts
161
+ var import_styled_components = __toESM(require("styled-components"), 1);
162
+ var STROKE_WIDTH_BY_SIZE = {
163
+ 12: 1.4,
164
+ 14: 1.4,
165
+ 16: 1.8,
166
+ 18: 1.8,
167
+ 20: 1.8,
168
+ 24: 1.8
169
+ };
170
+ var DEFAULT_STROKE_WIDTH = 1.8;
171
+ function getStrokeWidth(size) {
172
+ return STROKE_WIDTH_BY_SIZE[size] ?? DEFAULT_STROKE_WIDTH;
173
+ }
174
+ var IconWrapper = import_styled_components.default.span`
175
+ display: inline-flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ color: ${({ $color }) => $color ?? "currentColor"};
179
+ flex-shrink: 0;
180
+ `;
181
+
182
+ // src/components/icon/icon.tsx
183
+ var import_jsx_runtime2 = require("react/jsx-runtime");
184
+ var DEFAULT_SIZE = 16;
185
+ var Icon = (0, import_react2.forwardRef)(function Icon2({ icon: IconComponent, size = DEFAULT_SIZE, color, className, "aria-label": ariaLabel }, ref) {
186
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
187
+ IconWrapper,
188
+ {
189
+ ref,
190
+ className,
191
+ $color: color,
192
+ "aria-label": ariaLabel,
193
+ role: ariaLabel ? "img" : void 0,
194
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IconComponent, { width: size, height: size, strokeWidth: getStrokeWidth(size) })
195
+ }
196
+ );
197
+ });
198
+
199
+ // src/components/icon-button/icon-button-styles.ts
200
+ var import_styled_components2 = __toESM(require("styled-components"), 1);
201
+
202
+ // src/tokens/colors.ts
203
+ var colors = {
204
+ // White
205
+ white: "#FFFFFF",
206
+ "white-alpha-85": "rgba(255, 255, 255, 0.85)",
207
+ "white-alpha-40": "rgba(255, 255, 255, 0.40)",
208
+ // Brown
209
+ "brown-10": "#FAF9F8",
210
+ "brown-20": "#F5F3F0",
211
+ "brown-30": "#EEEBE5",
212
+ "brown-40": "#E6E2DA",
213
+ "brown-50": "#CFCBC4",
214
+ "brown-60": "#A19E99",
215
+ "brown-70": "#73716D",
216
+ "brown-80": "#5C5A57",
217
+ "brown-90": "#2E2D2C",
218
+ "brown-100": "#171716",
219
+ "brown-alpha-12": "rgba(23, 23, 22, 0.12)",
220
+ "brown-alpha-20": "rgba(23, 23, 22, 0.20)",
221
+ "brown-alpha-55": "rgba(23, 23, 22, 0.55)",
222
+ "brown-alpha-70": "rgba(23, 23, 22, 0.70)",
223
+ "brown-alpha-80": "rgba(23, 23, 22, 0.80)",
224
+ "brown-alpha-90": "rgba(23, 23, 22, 0.90)",
225
+ // Fuchsia
226
+ "fuchsia-50": "#FAF5FF",
227
+ "fuchsia-300": "#F0ABFC",
228
+ "fuchsia-500": "#D946EF",
229
+ "fuchsia-600": "#C026D3",
230
+ "fuchsia-800": "#86198F",
231
+ // Pink
232
+ "pink-50": "#FDF2F8",
233
+ "pink-400": "#F472B6",
234
+ "pink-600": "#DB2777",
235
+ "pink-800": "#9D174D",
236
+ // Violet
237
+ "violet-50": "#F5F3FF",
238
+ "violet-400": "#A78BFA",
239
+ "violet-600": "#7C3AED",
240
+ "violet-800": "#5B21B6",
241
+ // Indigo
242
+ "indigo-50": "#EEF2FF",
243
+ "indigo-400": "#818CF8",
244
+ "indigo-500": "#6366F1",
245
+ "indigo-600": "#4F46E5",
246
+ "indigo-800": "#3730A3",
247
+ // Cyan
248
+ "cyan-50": "#E7FEFF",
249
+ "cyan-300": "#67E8F9",
250
+ "cyan-600": "#0891B2",
251
+ "cyan-900": "#164E63",
252
+ // Teal
253
+ "teal-50": "#EBFDF9",
254
+ "teal-300": "#5EEAD4",
255
+ "teal-600": "#0D9488",
256
+ // Rose
257
+ "rose-400": "#FB7185",
258
+ // Purple
259
+ "purple-400": "#C084FC",
260
+ // Blue
261
+ "blue-50": "#EFF6FF",
262
+ "blue-100": "#DBEAFE",
263
+ "blue-300": "#93C5FD",
264
+ "blue-400": "#60A5FA",
265
+ "blue-600": "#2563EB",
266
+ "blue-800": "#1E40AF",
267
+ // Sky
268
+ "sky-300": "#7DD3FC",
269
+ // Green
270
+ "green-50": "#ECF9F0",
271
+ "green-100": "#D4F1D9",
272
+ "green-400": "#3DC269",
273
+ "green-700": "#277C43",
274
+ "green-800": "#1C5930",
275
+ // Orange
276
+ "orange-50": "#FFF7ED",
277
+ "orange-100": "#FFEDD5",
278
+ "orange-200": "#FED7AA",
279
+ "orange-500": "#F97316",
280
+ "orange-600": "#EA580C",
281
+ // Red
282
+ "red-50": "#FEF2F2",
283
+ "red-100": "#FEE2E2",
284
+ "red-200": "#FECACA",
285
+ "red-400": "#F7776C",
286
+ "red-500": "#EF4444",
287
+ "red-600": "#DC2626"
288
+ };
289
+
290
+ // src/components/icon-button/icon-button-styles.ts
291
+ var PADDING = {
292
+ short: {
293
+ small: "4px",
294
+ medium: "6px"
295
+ },
296
+ long: {
297
+ small: "4px 6px",
298
+ medium: "6px 10px"
299
+ }
300
+ };
301
+ var BORDER_RADIUS = {
302
+ small: 6,
303
+ medium: 10
304
+ };
305
+ var Button = import_styled_components2.default.button`
306
+ display: inline-flex;
307
+ align-items: center;
308
+ justify-content: center;
309
+ padding: ${({ $size, $variant }) => PADDING[$variant][$size]};
310
+ border: none;
311
+ border-radius: ${({ $size }) => BORDER_RADIUS[$size]}px;
312
+ background: ${({ $isSelected }) => $isSelected ? colors["brown-40"] : "transparent"};
313
+ color: ${colors["brown-100"]};
314
+ cursor: pointer;
315
+ transition: background-color 100ms ease;
316
+
317
+ &:hover {
318
+ background: ${({ $isSelected }) => $isSelected ? colors["brown-40"] : colors["brown-20"]};
319
+ }
320
+
321
+ &:active {
322
+ background: ${colors["brown-40"]};
323
+ }
324
+
325
+ &:disabled {
326
+ color: ${colors["brown-50"]};
327
+ background: transparent;
328
+ cursor: not-allowed;
329
+ }
330
+ `;
331
+
332
+ // src/components/icon-button/icon-button.tsx
333
+ var import_jsx_runtime3 = require("react/jsx-runtime");
334
+ var ICON_SIZE_BY_BUTTON_SIZE = {
335
+ small: 16,
336
+ medium: 20
337
+ };
338
+ var IconButton = (0, import_react3.forwardRef)(function IconButton2({
339
+ icon,
340
+ size = "small",
341
+ variant = "short",
342
+ isSelected = false,
343
+ disabled = false,
344
+ onClick,
345
+ className,
346
+ id,
347
+ as,
348
+ "aria-label": ariaLabel,
349
+ ...rest
350
+ }, ref) {
351
+ const isNativeButton = as === void 0 || as === "button";
352
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
353
+ Button,
354
+ {
355
+ ref,
356
+ className,
357
+ id,
358
+ as,
359
+ $size: size,
360
+ $variant: variant,
361
+ $isSelected: isSelected,
362
+ disabled,
363
+ onClick: disabled ? void 0 : onClick,
364
+ "aria-label": ariaLabel,
365
+ ...isNativeButton ? { type: "button" } : {},
366
+ ...rest,
367
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { icon, size: ICON_SIZE_BY_BUTTON_SIZE[size] })
368
+ }
369
+ );
370
+ });
371
+
372
+ // src/components/ui/tooltip.tsx
373
+ var React = __toESM(require("react"), 1);
374
+ var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
375
+ var import_jsx_runtime4 = require("react/jsx-runtime");
376
+ var TooltipProvider = TooltipPrimitive.Provider;
377
+ var Tooltip = TooltipPrimitive.Root;
378
+ var TooltipTrigger = TooltipPrimitive.Trigger;
379
+ var TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
380
+ TooltipPrimitive.Content,
381
+ {
382
+ ref,
383
+ sideOffset,
384
+ className: cn(
385
+ "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
386
+ className
387
+ ),
388
+ ...props
389
+ }
390
+ ));
391
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
392
+
393
+ // src/components/artifacts/artifact-download-button/artifact-download-button.tsx
394
+ var import_jsx_runtime5 = require("react/jsx-runtime");
395
+ var DEFAULT_LABEL = "Download CSV";
396
+ function ArtifactDownloadButton({
397
+ href,
398
+ label = DEFAULT_LABEL,
399
+ onClick
400
+ }) {
401
+ if (!isSafeDownloadUrl(href)) return null;
402
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Tooltip, { children: [
403
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
404
+ IconButton,
405
+ {
406
+ as: "a",
407
+ href,
408
+ download: true,
409
+ rel: "noopener noreferrer",
410
+ onClick,
411
+ icon: IconDownload,
412
+ size: "small",
413
+ "aria-label": label
414
+ }
415
+ ) }),
416
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TooltipContent, { children: label })
417
+ ] }) });
418
+ }
419
+ function isSafeDownloadUrl(url) {
420
+ try {
421
+ const parsed = new URL(url);
422
+ return parsed.protocol === "https:" || parsed.protocol === "http:";
423
+ } catch {
424
+ return false;
425
+ }
426
+ }
427
+
428
+ // src/components/artifacts/status-message.tsx
429
+ var import_react4 = require("react");
430
+ function StatusMessage({ $tone, children }) {
431
+ return (0, import_react4.createElement)(
432
+ "div",
433
+ {
434
+ className: `py-6 px-2 text-center text-sm font-medium leading-5 ${$tone === "error" ? "text-red-600" : "text-brown-70"}`
435
+ },
436
+ children
437
+ );
438
+ }
439
+
440
+ // src/components/chart/bar-chart/bar-chart.tsx
441
+ var import_react5 = require("react");
442
+ var import_recharts2 = require("recharts");
443
+
444
+ // src/components/chart/chart-container.tsx
445
+ var import_recharts = require("recharts");
446
+ var import_jsx_runtime6 = require("react/jsx-runtime");
447
+ function ChartContainer({
448
+ children,
449
+ height = 320,
450
+ width = "100%",
451
+ className,
452
+ style
453
+ }) {
454
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("text-xs text-foreground", className), style: { width, height, ...style }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children }) });
455
+ }
456
+
457
+ // src/components/chart/chart-legend-content.tsx
458
+ var import_jsx_runtime7 = require("react/jsx-runtime");
459
+ function ChartLegendContent({ payload, className, iconType = "square" }) {
460
+ if (!payload || payload.length === 0) return null;
461
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
462
+ "ul",
463
+ {
464
+ className: cn("flex flex-wrap items-center justify-center gap-x-4 gap-y-2 text-xs text-brown-80", className),
465
+ children: payload.map((entry, i) => {
466
+ const swatchColor = typeof entry.color === "string" ? entry.color : "transparent";
467
+ const label = entry.value !== void 0 ? String(entry.value) : "";
468
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { className: "flex items-center gap-1.5", children: [
469
+ iconType === "square" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-2.5 w-2.5 shrink-0 rounded-sm", style: { background: swatchColor } }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-[3px] w-4 shrink-0 rounded-full", style: { background: swatchColor } }),
470
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: label })
471
+ ] }, `${label}-${i}`);
472
+ })
473
+ }
474
+ );
475
+ }
476
+
477
+ // src/components/chart/chart-tooltip-content.tsx
478
+ var import_jsx_runtime8 = require("react/jsx-runtime");
479
+ function ChartTooltipContent({
480
+ active,
481
+ payload,
482
+ label,
483
+ className,
484
+ showLabel = true,
485
+ formatValue
486
+ }) {
487
+ if (!active || !payload || payload.length === 0) return null;
488
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
489
+ "div",
490
+ {
491
+ className: cn(
492
+ "rounded-lg border border-brown-40 bg-brown-10 px-3 py-2 text-xs shadow-sm",
493
+ "min-w-32 text-foreground",
494
+ className
495
+ ),
496
+ children: [
497
+ showLabel && label !== void 0 && label !== null ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mb-1.5 font-medium text-brown-90", children: String(label) }) : null,
498
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "space-y-1", children: payload.map((entry, i) => {
499
+ const name = entry.name !== void 0 ? String(entry.name) : "";
500
+ const rawValue = entry.value;
501
+ const display = formatValue ? formatValue(rawValue, name) : rawValue === void 0 ? "" : String(rawValue);
502
+ const swatch = typeof entry.color === "string" ? entry.color : "transparent";
503
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { className: "flex items-center gap-2", children: [
504
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-block h-2.5 w-2.5 shrink-0 rounded-sm", style: { background: swatch } }),
505
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-brown-70", children: name }),
506
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "ml-auto font-semibold tabular-nums text-brown-90", children: display })
507
+ ] }, `${name}-${i}`);
508
+ }) })
509
+ ]
510
+ }
511
+ );
512
+ }
513
+
514
+ // src/components/chart/chart-palette.ts
515
+ var CHART_PALETTE = [
516
+ colors["blue-600"],
517
+ // #2563EB — primary
518
+ colors["blue-400"],
519
+ // #60A5FA — mid
520
+ colors["blue-300"],
521
+ // #93C5FD — light
522
+ colors["blue-100"],
523
+ // #DBEAFE — very light
524
+ colors["indigo-400"],
525
+ // #818CF8
526
+ colors["indigo-500"],
527
+ // #6366F1
528
+ colors["indigo-600"],
529
+ // #4F46E5
530
+ colors["indigo-800"],
531
+ // #3730A3
532
+ colors["blue-800"]
533
+ // #1E40AF — deepest
534
+ ];
535
+ var OTHERS_SLICE_COLOR = colors["brown-60"];
536
+ var DEFAULT_OTHERS_CATEGORY_LABELS = ["others", "other"];
537
+ function isOthersCategory(value, labels) {
538
+ if (value === null || value === void 0) return false;
539
+ if (labels.length === 0) return false;
540
+ const normalized = String(value).trim().toLowerCase();
541
+ for (const label of labels) {
542
+ if (normalized === label.toLowerCase()) return true;
543
+ }
544
+ return false;
545
+ }
546
+ function colorForSeriesIndex(index, palette = CHART_PALETTE) {
547
+ return palette[index % palette.length] ?? CHART_PALETTE[0];
548
+ }
549
+
550
+ // src/components/chart/chart-styles.ts
551
+ var GRID_STROKE = colors["brown-40"];
552
+ var AXIS_STROKE = colors["brown-50"];
553
+ var AXIS_TICK_STYLE = {
554
+ fill: colors["brown-70"],
555
+ fontSize: 12,
556
+ fontWeight: 500
557
+ };
558
+ var CHART_VALUE_LABEL_STYLE = {
559
+ fill: colors["brown-70"],
560
+ fontSize: 12,
561
+ fontWeight: 500
562
+ };
563
+ var BAR_TOOLTIP_CURSOR_FILL = colors["brown-alpha-12"];
564
+ var LINE_ACTIVE_DOT_STROKE = colors["brown-10"];
565
+ var CHART_MARGIN = { top: 8, right: 16, left: 0, bottom: 4 };
566
+ var PIE_CHART_MARGIN = { top: 0, right: 24, left: 24, bottom: 4 };
567
+ var CHART_AXIS_PROPS = {
568
+ stroke: AXIS_STROKE,
569
+ tick: AXIS_TICK_STYLE,
570
+ tickLine: false,
571
+ axisLine: false
572
+ };
573
+ var CHART_GRID_PROPS = {
574
+ stroke: GRID_STROKE,
575
+ strokeDasharray: "3 3",
576
+ vertical: false
577
+ };
578
+
579
+ // src/components/chart/chart-tick-utils.ts
580
+ function maxTickCharsByCategoryCount(n) {
581
+ if (n <= 5) return 24;
582
+ if (n <= 8) return 14;
583
+ if (n <= 12) return 10;
584
+ if (n <= 16) return 7;
585
+ return 5;
586
+ }
587
+ function truncateLabel(value, maxChars) {
588
+ const s = String(value ?? "");
589
+ if (s.length <= maxChars) return s;
590
+ return s.slice(0, Math.max(1, maxChars - 1)).trimEnd() + "\u2026";
591
+ }
592
+ function evenlyDistributedVisibleIndices(n, target) {
593
+ if (n <= target) {
594
+ return new Set(Array.from({ length: n }, (_, i) => i));
595
+ }
596
+ const set = /* @__PURE__ */ new Set();
597
+ const step = (n - 1) / (target - 1);
598
+ for (let i = 0; i < target; i++) {
599
+ set.add(Math.round(i * step));
600
+ }
601
+ return set;
602
+ }
603
+ function defaultBarTickFormatter(categoryCount) {
604
+ const max = maxTickCharsByCategoryCount(categoryCount);
605
+ return (value) => truncateLabel(value, max);
606
+ }
607
+ function defaultLineChartTickFormatter(categoryCount, visibleIndices) {
608
+ const max = maxTickCharsByCategoryCount(visibleIndices.size || categoryCount);
609
+ return (value, index) => {
610
+ if (!visibleIndices.has(index)) return "";
611
+ return truncateLabel(value, max);
612
+ };
613
+ }
614
+
615
+ // src/components/chart/coerce-numeric.ts
616
+ function coerceNumericColumns(rows, numericKeys) {
617
+ return rows.map((row) => {
618
+ const out = { ...row };
619
+ for (const k of numericKeys) {
620
+ const v = out[k];
621
+ if (v == null) continue;
622
+ const n = Number(v);
623
+ out[k] = Number.isFinite(n) ? n : NaN;
624
+ }
625
+ return out;
626
+ });
627
+ }
628
+
629
+ // src/components/chart/bar-chart/bar-chart.tsx
630
+ var import_jsx_runtime9 = require("react/jsx-runtime");
631
+ function BarChart({
632
+ data,
633
+ xKey,
634
+ series,
635
+ stacked = false,
636
+ height = 320,
637
+ width = "100%",
638
+ className,
639
+ palette = CHART_PALETTE,
640
+ showTooltip = true,
641
+ showLegend,
642
+ showGrid = true,
643
+ showXAxis = true,
644
+ showYAxis = true,
645
+ showValueLabels,
646
+ xAxisInterval = 0,
647
+ xAxisAngle,
648
+ xAxisTickFormatter
649
+ }) {
650
+ const seriesKeys = (0, import_react5.useMemo)(() => series.map((s) => s.key), [series]);
651
+ const coercedData = (0, import_react5.useMemo)(
652
+ () => coerceNumericColumns(data, seriesKeys),
653
+ [data, seriesKeys]
654
+ );
655
+ const resolvedShowLegend = showLegend ?? series.length > 1;
656
+ const resolvedShowValueLabels = showValueLabels ?? (!stacked && series.length === 1);
657
+ const resolvedAngle = xAxisAngle ?? (coercedData.length >= 8 ? -30 : 0);
658
+ const resolvedTickFormatter = (0, import_react5.useMemo)(
659
+ () => xAxisTickFormatter ?? defaultBarTickFormatter(coercedData.length),
660
+ [xAxisTickFormatter, coercedData.length]
661
+ );
662
+ const angledLabelPad = resolvedAngle === 0 ? 0 : Math.min(Math.abs(resolvedAngle) * 0.7, 40);
663
+ const chartMargin = { ...CHART_MARGIN, bottom: CHART_MARGIN.bottom + angledLabelPad };
664
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChartContainer, { height, width, className, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_recharts2.BarChart, { data: coercedData, margin: chartMargin, barCategoryGap: "22%", children: [
665
+ showGrid ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_recharts2.CartesianGrid, { ...CHART_GRID_PROPS }) : null,
666
+ showXAxis ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
667
+ import_recharts2.XAxis,
668
+ {
669
+ dataKey: xKey,
670
+ ...CHART_AXIS_PROPS,
671
+ interval: xAxisInterval,
672
+ angle: resolvedAngle,
673
+ textAnchor: resolvedAngle !== 0 ? "end" : "middle",
674
+ tickMargin: resolvedAngle === 0 ? 8 : 12,
675
+ height: resolvedAngle !== 0 ? 60 : void 0,
676
+ tickFormatter: resolvedTickFormatter
677
+ }
678
+ ) : null,
679
+ showYAxis ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_recharts2.YAxis, { ...CHART_AXIS_PROPS, width: 40 }) : null,
680
+ showTooltip ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_recharts2.Tooltip, { cursor: { fill: BAR_TOOLTIP_CURSOR_FILL }, content: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChartTooltipContent, {}) }) : null,
681
+ resolvedShowLegend ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
682
+ import_recharts2.Legend,
683
+ {
684
+ verticalAlign: "top",
685
+ align: "center",
686
+ wrapperStyle: { top: 0 },
687
+ itemSorter: null,
688
+ content: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChartLegendContent, { iconType: "square" })
689
+ }
690
+ ) : null,
691
+ series.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
692
+ import_recharts2.Bar,
693
+ {
694
+ dataKey: s.key,
695
+ name: s.label,
696
+ fill: colorForSeriesIndex(i, palette),
697
+ stackId: stacked ? "default" : s.key,
698
+ radius: barRadius(stacked, i, series.length),
699
+ children: resolvedShowValueLabels ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_recharts2.LabelList, { dataKey: s.key, position: "top", style: CHART_VALUE_LABEL_STYLE }) : null
700
+ },
701
+ s.key
702
+ ))
703
+ ] }) });
704
+ }
705
+ function barRadius(stacked, seriesIndex, seriesCount) {
706
+ if (!stacked) return [6, 6, 0, 0];
707
+ const isTopSegment = seriesIndex === seriesCount - 1;
708
+ return isTopSegment ? [6, 6, 0, 0] : [0, 0, 0, 0];
709
+ }
710
+
711
+ // src/components/artifacts/chart-artifact/chart-variant-services/constants.ts
712
+ var VARIANT_CHART_HEIGHT = "100%";
713
+
714
+ // src/components/artifacts/chart-artifact/chart-variant-services/bar-chart-variant-component.tsx
715
+ var import_jsx_runtime10 = require("react/jsx-runtime");
716
+ function BarChartVariantComponent({ config, rows }) {
717
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
718
+ BarChart,
719
+ {
720
+ data: rows,
721
+ xKey: config.xKey,
722
+ series: config.series,
723
+ stacked: config.stacked,
724
+ height: VARIANT_CHART_HEIGHT
725
+ }
726
+ );
727
+ }
728
+
729
+ // src/components/artifacts/chart-artifact/chart-variant-services/shared-column-keys.ts
730
+ function seriesBasedColumnKeys(config) {
731
+ return [config.xKey, ...config.series.map((s) => s.key)];
732
+ }
733
+ function pieColumnKeys(config) {
734
+ return [config.categoryKey, config.valueKey];
735
+ }
736
+
737
+ // src/components/artifacts/chart-artifact/chart-variant-services/shared-validators.ts
738
+ function isValidChartSeries(series) {
739
+ if (!series || typeof series !== "object") return false;
740
+ const candidate = series;
741
+ if (typeof candidate.key !== "string" || candidate.key.length === 0) return false;
742
+ if (typeof candidate.label !== "string") return false;
743
+ return true;
744
+ }
745
+
746
+ // src/components/artifacts/chart-artifact/chart-variant-services/bar-chart-variant-service.tsx
747
+ function isValidBarChartConfig(config) {
748
+ if (!config || typeof config !== "object") return false;
749
+ const candidate = config;
750
+ if (candidate.variant !== "BAR") return false;
751
+ if (typeof candidate.xKey !== "string" || candidate.xKey.length === 0) return false;
752
+ if (!Array.isArray(candidate.series) || candidate.series.length === 0) return false;
753
+ if (!candidate.series.every(isValidChartSeries)) return false;
754
+ return true;
755
+ }
756
+ var BarChartVariantService = {
757
+ variant: "BAR",
758
+ isValidConfig: isValidBarChartConfig,
759
+ columnKeys: seriesBasedColumnKeys,
760
+ Component: BarChartVariantComponent
761
+ };
762
+
763
+ // src/components/chart/line-chart/line-chart.tsx
764
+ var import_react6 = require("react");
765
+ var import_recharts3 = require("recharts");
766
+ var import_jsx_runtime11 = require("react/jsx-runtime");
767
+ var TARGET_VISIBLE_LABELS = 5;
768
+ function LineChart({
769
+ data,
770
+ xKey,
771
+ series,
772
+ smooth = true,
773
+ showDots = true,
774
+ strokeWidth = 2,
775
+ height = 320,
776
+ width = "100%",
777
+ className,
778
+ palette = CHART_PALETTE,
779
+ showTooltip = true,
780
+ showLegend,
781
+ showGrid = true,
782
+ showXAxis = true,
783
+ showYAxis = true,
784
+ showValueLabels = false,
785
+ xAxisInterval = 0,
786
+ xAxisAngle = 0,
787
+ xAxisTickFormatter
788
+ }) {
789
+ const seriesKeys = (0, import_react6.useMemo)(() => series.map((s) => s.key), [series]);
790
+ const coercedData = (0, import_react6.useMemo)(
791
+ () => coerceNumericColumns(data, seriesKeys),
792
+ [data, seriesKeys]
793
+ );
794
+ const lineType = smooth ? "monotone" : "linear";
795
+ const resolvedShowLegend = showLegend ?? series.length > 1;
796
+ const resolvedTickFormatter = (0, import_react6.useMemo)(() => {
797
+ if (xAxisTickFormatter) return xAxisTickFormatter;
798
+ const visible = evenlyDistributedVisibleIndices(coercedData.length, TARGET_VISIBLE_LABELS);
799
+ return defaultLineChartTickFormatter(coercedData.length, visible);
800
+ }, [xAxisTickFormatter, coercedData.length]);
801
+ const angledLabelPad = xAxisAngle === 0 ? 0 : Math.min(Math.abs(xAxisAngle) * 0.7, 40);
802
+ const chartMargin = { ...CHART_MARGIN, right: CHART_MARGIN.right + 16, bottom: CHART_MARGIN.bottom + angledLabelPad };
803
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ChartContainer, { height, width, className, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_recharts3.LineChart, { data: coercedData, margin: chartMargin, children: [
804
+ showGrid ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_recharts3.CartesianGrid, { ...CHART_GRID_PROPS }) : null,
805
+ showXAxis ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
806
+ import_recharts3.XAxis,
807
+ {
808
+ dataKey: xKey,
809
+ ...CHART_AXIS_PROPS,
810
+ interval: xAxisInterval,
811
+ angle: xAxisAngle,
812
+ textAnchor: xAxisAngle !== 0 ? "end" : "middle",
813
+ tickMargin: xAxisAngle === 0 ? 8 : 12,
814
+ height: xAxisAngle !== 0 ? 60 : void 0,
815
+ tickFormatter: resolvedTickFormatter
816
+ }
817
+ ) : null,
818
+ showYAxis ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_recharts3.YAxis, { ...CHART_AXIS_PROPS, width: 40 }) : null,
819
+ showTooltip ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_recharts3.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ChartTooltipContent, {}) }) : null,
820
+ resolvedShowLegend ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
821
+ import_recharts3.Legend,
822
+ {
823
+ verticalAlign: "top",
824
+ align: "center",
825
+ wrapperStyle: { top: 0 },
826
+ itemSorter: null,
827
+ content: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ChartLegendContent, { iconType: "line" })
828
+ }
829
+ ) : null,
830
+ series.map((s, i) => {
831
+ const color = colorForSeriesIndex(i, palette);
832
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
833
+ import_recharts3.Line,
834
+ {
835
+ type: lineType,
836
+ dataKey: s.key,
837
+ name: s.label,
838
+ stroke: color,
839
+ strokeWidth,
840
+ dot: showDots ? { r: 3, fill: color, stroke: color, strokeWidth: 0 } : false,
841
+ activeDot: { r: 5, fill: color, stroke: LINE_ACTIVE_DOT_STROKE, strokeWidth: 2 },
842
+ children: showValueLabels ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_recharts3.LabelList, { dataKey: s.key, position: "top", style: CHART_VALUE_LABEL_STYLE }) : null
843
+ },
844
+ s.key
845
+ );
846
+ })
847
+ ] }) });
848
+ }
849
+
850
+ // src/components/artifacts/chart-artifact/chart-variant-services/line-chart-variant-component.tsx
851
+ var import_jsx_runtime12 = require("react/jsx-runtime");
852
+ function LineChartVariantComponent({ config, rows }) {
853
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LineChart, { data: rows, xKey: config.xKey, series: config.series, height: VARIANT_CHART_HEIGHT });
854
+ }
855
+
856
+ // src/components/artifacts/chart-artifact/chart-variant-services/line-chart-variant-service.tsx
857
+ function isValidLineChartConfig(config) {
858
+ if (!config || typeof config !== "object") return false;
859
+ const candidate = config;
860
+ if (candidate.variant !== "LINE") return false;
861
+ if (typeof candidate.xKey !== "string" || candidate.xKey.length === 0) return false;
862
+ if (!Array.isArray(candidate.series) || candidate.series.length === 0) return false;
863
+ if (!candidate.series.every(isValidChartSeries)) return false;
864
+ return true;
865
+ }
866
+ var LineChartVariantService = {
867
+ variant: "LINE",
868
+ isValidConfig: isValidLineChartConfig,
869
+ columnKeys: seriesBasedColumnKeys,
870
+ Component: LineChartVariantComponent
871
+ };
872
+
873
+ // src/components/chart/pie-chart/pie-chart.tsx
874
+ var import_react7 = require("react");
875
+ var import_recharts4 = require("recharts");
876
+ var import_jsx_runtime13 = require("react/jsx-runtime");
877
+ function PieChart({
878
+ data,
879
+ categoryKey,
880
+ valueKey,
881
+ height = 320,
882
+ width = "100%",
883
+ className,
884
+ palette = CHART_PALETTE,
885
+ showLabels = true,
886
+ showTooltip = true,
887
+ showLegend = true,
888
+ innerRadius = 0,
889
+ outerRadius = "68%",
890
+ othersCategoryLabels = DEFAULT_OTHERS_CATEGORY_LABELS
891
+ }) {
892
+ const { orderedData, sliceColors } = (0, import_react7.useMemo)(() => {
893
+ const coerced = coerceNumericColumns(data, [valueKey]);
894
+ const namedRows = [];
895
+ const namedColors = [];
896
+ const othersRows = [];
897
+ const othersColors = [];
898
+ for (const row of coerced) {
899
+ if (isOthersCategory(row[categoryKey], othersCategoryLabels)) {
900
+ othersRows.push(row);
901
+ othersColors.push(OTHERS_SLICE_COLOR);
902
+ } else {
903
+ namedRows.push(row);
904
+ namedColors.push(colorForSeriesIndex(namedRows.length - 1, palette));
905
+ }
906
+ }
907
+ return {
908
+ orderedData: [...namedRows, ...othersRows],
909
+ sliceColors: [...namedColors, ...othersColors]
910
+ };
911
+ }, [data, valueKey, categoryKey, othersCategoryLabels, palette]);
912
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChartContainer, { height, width, className, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_recharts4.PieChart, { margin: PIE_CHART_MARGIN, children: [
913
+ showTooltip ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_recharts4.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChartTooltipContent, {}) }) : null,
914
+ showLegend ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
915
+ import_recharts4.Legend,
916
+ {
917
+ verticalAlign: "top",
918
+ align: "center",
919
+ wrapperStyle: { top: 0 },
920
+ itemSorter: null,
921
+ content: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChartLegendContent, { iconType: "square" })
922
+ }
923
+ ) : null,
924
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
925
+ import_recharts4.Pie,
926
+ {
927
+ data: orderedData,
928
+ dataKey: valueKey,
929
+ nameKey: categoryKey,
930
+ cx: "50%",
931
+ cy: "52%",
932
+ startAngle: 90,
933
+ endAngle: -270,
934
+ innerRadius,
935
+ outerRadius,
936
+ label: showLabels ? (entry) => {
937
+ const v = entry.value;
938
+ if (v === void 0 || v === null) return null;
939
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
940
+ "text",
941
+ {
942
+ x: entry.x,
943
+ y: entry.y,
944
+ fill: CHART_VALUE_LABEL_STYLE.fill,
945
+ fontSize: CHART_VALUE_LABEL_STYLE.fontSize,
946
+ fontWeight: CHART_VALUE_LABEL_STYLE.fontWeight,
947
+ textAnchor: entry.textAnchor,
948
+ dominantBaseline: "central",
949
+ children: String(v)
950
+ }
951
+ );
952
+ } : false,
953
+ labelLine: false,
954
+ stroke: "none",
955
+ strokeWidth: 0,
956
+ children: orderedData.map((_row, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_recharts4.Cell, { fill: sliceColors[i] }, i))
957
+ }
958
+ )
959
+ ] }) });
960
+ }
961
+
962
+ // src/components/artifacts/chart-artifact/chart-variant-services/pie-chart-variant-component.tsx
963
+ var import_jsx_runtime14 = require("react/jsx-runtime");
964
+ function PieChartVariantComponent({
965
+ config,
966
+ rows,
967
+ labels
968
+ }) {
969
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
970
+ PieChart,
971
+ {
972
+ data: rows,
973
+ categoryKey: config.categoryKey,
974
+ valueKey: config.valueKey,
975
+ othersCategoryLabels: labels.othersCategoryLabels,
976
+ height: VARIANT_CHART_HEIGHT
977
+ }
978
+ );
979
+ }
980
+
981
+ // src/components/artifacts/chart-artifact/chart-variant-services/pie-chart-variant-service.tsx
982
+ function isValidPieChartConfig(config) {
983
+ if (!config || typeof config !== "object") return false;
984
+ const candidate = config;
985
+ if (candidate.variant !== "PIE") return false;
986
+ if (typeof candidate.categoryKey !== "string" || candidate.categoryKey.length === 0) return false;
987
+ if (typeof candidate.valueKey !== "string" || candidate.valueKey.length === 0) return false;
988
+ if (!Array.isArray(candidate.series)) return false;
989
+ return true;
990
+ }
991
+ var PieChartVariantService = {
992
+ variant: "PIE",
993
+ isValidConfig: isValidPieChartConfig,
994
+ columnKeys: pieColumnKeys,
995
+ Component: PieChartVariantComponent
996
+ };
997
+
998
+ // src/components/artifacts/chart-artifact/chart-variant-services/index.ts
999
+ var ChartVariantServices = {
1000
+ LINE: LineChartVariantService,
1001
+ BAR: BarChartVariantService,
1002
+ PIE: PieChartVariantService
1003
+ };
1004
+
1005
+ // src/components/artifacts/chart-artifact/chart-artifact-content.tsx
1006
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1007
+ function ChartArtifactContent({ config, rows, labels }) {
1008
+ const service = ChartVariantServices[config.variant];
1009
+ if (!service) {
1010
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
1011
+ }
1012
+ const Component = service.Component;
1013
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Component, { config, rows, labels });
1014
+ }
1015
+
1016
+ // src/components/artifacts/parse-csv.ts
1017
+ var import_papaparse = __toESM(require("papaparse"), 1);
1018
+ function parseCsv(text, columns) {
1019
+ const result = import_papaparse.default.parse(text, {
1020
+ header: true,
1021
+ skipEmptyLines: true,
1022
+ dynamicTyping: false
1023
+ });
1024
+ const csvHeaders = new Set(result.meta?.fields ?? []);
1025
+ const presentColumns = columns.filter((col) => csvHeaders.has(col.key));
1026
+ if (presentColumns.length === 0) return [];
1027
+ return result.data.map((rawRow) => {
1028
+ const row = {};
1029
+ for (const column of presentColumns) {
1030
+ const value = rawRow[column.key];
1031
+ row[column.key] = value === void 0 || value === "" ? null : value;
1032
+ }
1033
+ return row;
1034
+ });
1035
+ }
1036
+
1037
+ // src/components/artifacts/use-rows-artifact-data.ts
1038
+ var import_react8 = require("react");
1039
+ var LOADING = { status: "loading", rows: null, error: null };
1040
+ var UNAVAILABLE = { status: "unavailable", rows: null, error: null };
1041
+ var INITIAL_INTERNAL = { cacheKey: null, data: LOADING };
1042
+ function columnsFingerprint(columns) {
1043
+ return columns.map((c) => c.key).join("|");
1044
+ }
1045
+ function scrubUrl(url) {
1046
+ const q = url.indexOf("?");
1047
+ return q === -1 ? url : `${url.slice(0, q)}?<redacted>`;
1048
+ }
1049
+ function useRowsArtifactData(presignedUrl, columns, parse) {
1050
+ const colsKey = (0, import_react8.useMemo)(() => columnsFingerprint(columns), [columns]);
1051
+ const safeUrl = presignedUrl && isSafeDownloadUrl(presignedUrl) ? presignedUrl : null;
1052
+ const cacheKey = safeUrl ? `${safeUrl}::${colsKey}` : null;
1053
+ const [state, setState] = (0, import_react8.useState)(INITIAL_INTERNAL);
1054
+ (0, import_react8.useEffect)(() => {
1055
+ if (!safeUrl) return;
1056
+ const controller = new AbortController();
1057
+ fetch(safeUrl, {
1058
+ signal: controller.signal,
1059
+ headers: { Accept: "text/csv" },
1060
+ // Presigned URLs are cross-origin S3 in production and don't need credentials. Explicit
1061
+ // omit so a same-origin URL (compromised payload, local dev) can't accidentally receive
1062
+ // session cookies or auth headers.
1063
+ credentials: "omit"
1064
+ }).then(async (response) => {
1065
+ if (!response.ok) throw new Error(`Failed to load artifact data (${response.status})`);
1066
+ return response.text();
1067
+ }).then((text) => {
1068
+ if (controller.signal.aborted) return;
1069
+ try {
1070
+ const rows = parse(text, columns);
1071
+ setState({ cacheKey: `${safeUrl}::${colsKey}`, data: { status: "ready", rows, error: null } });
1072
+ } catch (parseError) {
1073
+ const err = parseError instanceof Error ? parseError : new Error(String(parseError));
1074
+ console.error("[ArtifactData] CSV parse failed:", err.message);
1075
+ setState({ cacheKey: `${safeUrl}::${colsKey}`, data: { status: "error", rows: null, error: err } });
1076
+ }
1077
+ }).catch((error) => {
1078
+ if (controller.signal.aborted) return;
1079
+ const err = error instanceof Error ? error : new Error(String(error));
1080
+ console.error(`[ArtifactData] Fetch failed [${scrubUrl(safeUrl)}]:`, err.message);
1081
+ setState({ cacheKey: `${safeUrl}::${colsKey}`, data: { status: "error", rows: null, error: err } });
1082
+ });
1083
+ return () => {
1084
+ controller.abort();
1085
+ };
1086
+ }, [safeUrl, colsKey]);
1087
+ if (!safeUrl) return UNAVAILABLE;
1088
+ if (state.cacheKey !== cacheKey) return LOADING;
1089
+ return state.data;
1090
+ }
1091
+
1092
+ // src/components/artifacts/chart-artifact/use-chart-artifact-data.ts
1093
+ function useChartArtifactData(presignedUrl, config) {
1094
+ const service = ChartVariantServices[config.variant];
1095
+ const keys = service ? service.columnKeys(config) : [];
1096
+ const columns = keys.map((key) => ({ key }));
1097
+ return useRowsArtifactData(presignedUrl, columns, parseCsv);
1098
+ }
1099
+
1100
+ // src/components/artifacts/chart-artifact/validate.ts
1101
+ function isValidChartConfig(config) {
1102
+ if (!config || typeof config !== "object") return false;
1103
+ const variant = config.variant;
1104
+ if (typeof variant !== "string") return false;
1105
+ const service = ChartVariantServices[variant];
1106
+ if (!service) return false;
1107
+ return service.isValidConfig(config);
1108
+ }
1109
+
1110
+ // src/components/artifacts/chart-artifact/chart-artifact.tsx
1111
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1112
+ var TITLE_CLASSES = "text-sm font-semibold text-foreground";
1113
+ var CHART_HEIGHT = 320;
1114
+ function ChartArtifact({ artifact, labels, callbacks }) {
1115
+ const validConfig = isValidChartConfig(artifact.config);
1116
+ (0, import_react9.useEffect)(() => {
1117
+ if (validConfig) return;
1118
+ console.warn("[clay] ChartArtifact: malformed `config` \u2014 skipping render.");
1119
+ }, [validConfig]);
1120
+ const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
1121
+ const resolvedLabels = (0, import_react9.useMemo)(
1122
+ () => ({ ...DEFAULT_CHART_ARTIFACT_LABELS, ...labels?.[artifactTypes.CHART] ?? {} }),
1123
+ [labels]
1124
+ );
1125
+ const data = useChartArtifactData(
1126
+ validConfig ? presignedUrl : null,
1127
+ validConfig ? artifact.config : { variant: "LINE", series: [], xKey: "x" }
1128
+ );
1129
+ const onDownload = callbacks?.[artifactTypes.CHART]?.onDownload;
1130
+ const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
1131
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1132
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
1133
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArtifactTitle, { className: TITLE_CLASSES, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", {}),
1134
+ presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArtifactDownloadButton, { href: presignedUrl, label: resolvedLabels.download, onClick: handleDownloadClick }) }) : null
1135
+ ] }),
1136
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1137
+ ArtifactContent,
1138
+ {
1139
+ className: "p-4 overflow-visible flex flex-none items-center justify-center",
1140
+ style: { height: CHART_HEIGHT },
1141
+ children: renderBody(validConfig, artifact, data, resolvedLabels)
1142
+ }
1143
+ )
1144
+ ] });
1145
+ }
1146
+ function renderBody(validConfig, artifact, data, labels) {
1147
+ if (!validConfig) {
1148
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
1149
+ }
1150
+ if (data.status === "error") {
1151
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatusMessage, { $tone: "error", children: labels.loadError });
1152
+ }
1153
+ if (data.status === "unavailable") {
1154
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
1155
+ }
1156
+ if (data.status === "loading") {
1157
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatusMessage, { $tone: "info", children: labels.loading });
1158
+ }
1159
+ if (data.rows.length === 0) {
1160
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatusMessage, { $tone: "info", children: labels.empty });
1161
+ }
1162
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChartArtifactContent, { config: artifact.config, rows: data.rows, labels });
1163
+ }
1164
+
1165
+ // src/components/artifacts/chart-artifact/to-clipboard-text.ts
1166
+ function chartArtifactToClipboardText(artifact) {
1167
+ const trimmedTitle = artifact.title?.trim();
1168
+ return trimmedTitle || "Chart";
1169
+ }
1170
+
1171
+ // src/components/artifacts/artifact-services/chart-artifact-service.ts
1172
+ var ChartArtifactService = {
1173
+ type: artifactTypes.CHART,
1174
+ Component: ChartArtifact,
1175
+ toClipboardText: chartArtifactToClipboardText
1176
+ };
1177
+
1178
+ // src/components/artifacts/table-artifact/table-artifact.tsx
1179
+ var import_react11 = require("react");
1180
+
1181
+ // src/components/ui/table.tsx
1182
+ var React2 = __toESM(require("react"), 1);
1183
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1184
+ var Table = React2.forwardRef(({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: cn("relative w-full overflow-auto", containerClassName), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props }) }));
1185
+ Table.displayName = "Table";
1186
+ var TableHeader = React2.forwardRef(
1187
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("thead", { ref, className: cn("[&_tr]:border-b", className), ...props })
1188
+ );
1189
+ TableHeader.displayName = "TableHeader";
1190
+ var TableBody = React2.forwardRef(
1191
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props })
1192
+ );
1193
+ TableBody.displayName = "TableBody";
1194
+ var TableFooter = React2.forwardRef(
1195
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tfoot", { ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props })
1196
+ );
1197
+ TableFooter.displayName = "TableFooter";
1198
+ var TableRow = React2.forwardRef(
1199
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1200
+ "tr",
1201
+ {
1202
+ ref,
1203
+ className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className),
1204
+ ...props
1205
+ }
1206
+ )
1207
+ );
1208
+ TableRow.displayName = "TableRow";
1209
+ var TableHead = React2.forwardRef(
1210
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1211
+ "th",
1212
+ {
1213
+ ref,
1214
+ className: cn(
1215
+ "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
1216
+ className
1217
+ ),
1218
+ ...props
1219
+ }
1220
+ )
1221
+ );
1222
+ TableHead.displayName = "TableHead";
1223
+ var TableCell = React2.forwardRef(
1224
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className), ...props })
1225
+ );
1226
+ TableCell.displayName = "TableCell";
1227
+ var TableCaption = React2.forwardRef(
1228
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })
1229
+ );
1230
+ TableCaption.displayName = "TableCaption";
1231
+
1232
+ // src/components/table/use-scroll-shadow.ts
1233
+ var import_react10 = require("react");
1234
+ function useScrollShadow() {
1235
+ const targetRef = (0, import_react10.useRef)(null);
1236
+ const [isScrolled, setIsScrolled] = (0, import_react10.useState)(false);
1237
+ (0, import_react10.useEffect)(() => {
1238
+ const target = targetRef.current;
1239
+ if (!target) return;
1240
+ let scrollContainer = target;
1241
+ while (scrollContainer) {
1242
+ const overflowY = getComputedStyle(scrollContainer).overflowY;
1243
+ if (overflowY === "auto" || overflowY === "scroll") break;
1244
+ scrollContainer = scrollContainer.parentElement;
1245
+ }
1246
+ if (!scrollContainer) return;
1247
+ setIsScrolled(scrollContainer.scrollTop > 0);
1248
+ const handleScroll = () => {
1249
+ if (!scrollContainer) return;
1250
+ setIsScrolled(scrollContainer.scrollTop > 0);
1251
+ };
1252
+ scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
1253
+ return () => scrollContainer.removeEventListener("scroll", handleScroll);
1254
+ }, []);
1255
+ return { targetRef, isScrolled };
1256
+ }
1257
+
1258
+ // src/components/artifacts/table-artifact/table-artifact-content.constants.ts
1259
+ var TABLE_STATUS = {
1260
+ LOADING: "loading",
1261
+ READY: "ready",
1262
+ ERROR: "error",
1263
+ UNAVAILABLE: "unavailable"
1264
+ };
1265
+
1266
+ // src/components/artifacts/table-artifact/table-artifact-content.utils.ts
1267
+ function formatCell(row, column) {
1268
+ return row[column.key] ?? "";
1269
+ }
1270
+ var HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
1271
+ var CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
1272
+ var ROW_CLASSES = "border-b-brown-30 bg-background/70 hover:bg-secondary";
1273
+ var DATA_ROW_CLASSES = `${ROW_CLASSES} animate-in fade-in duration-300`;
1274
+ var SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";
1275
+
1276
+ // src/components/artifacts/table-artifact/table-artifact-content.tsx
1277
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1278
+ function TableArtifactContent({
1279
+ columns,
1280
+ data,
1281
+ knownRowCount,
1282
+ maxShimmerRows,
1283
+ maxBodyHeight,
1284
+ labels
1285
+ }) {
1286
+ if (data.status === TABLE_STATUS.ERROR) {
1287
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusMessage, { $tone: "error", children: labels.loadError });
1288
+ }
1289
+ if (data.status === TABLE_STATUS.UNAVAILABLE) {
1290
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusMessage, { $tone: "info", children: labels.unavailable });
1291
+ }
1292
+ if (data.status === TABLE_STATUS.LOADING) {
1293
+ if (typeof knownRowCount === "number" && knownRowCount > 0) {
1294
+ const shimmerCount = Math.min(knownRowCount, maxShimmerRows);
1295
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactTable, { columns, maxBodyHeight, children: renderShimmerRows(columns, shimmerCount) });
1296
+ }
1297
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusMessage, { $tone: "info", children: labels.loading });
1298
+ }
1299
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactTable, { columns, maxBodyHeight, children: data.rows.length === 0 ? renderEmptyRow(columns.length, labels.empty) : renderDataRows(columns, data.rows) });
1300
+ }
1301
+ function ArtifactTable({ columns, maxBodyHeight, children }) {
1302
+ const { targetRef, isScrolled } = useScrollShadow();
1303
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: targetRef, className: "overscroll-none", style: { maxHeight: maxBodyHeight, overflowY: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Table, { containerClassName: "overflow-visible", children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1305
+ TableHeader,
1306
+ {
1307
+ "data-scrolled": isScrolled ? "true" : void 0,
1308
+ className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
1309
+ style: isScrolled ? { boxShadow: SCROLL_SHADOW } : void 0,
1310
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableHead, { scope: "col", className: HEAD_CLASS, children: column.label }, column.key)) })
1311
+ }
1312
+ ),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableBody, { children })
1314
+ ] }) });
1315
+ }
1316
+ function renderShimmerRows(columns, count) {
1317
+ return Array.from({ length: count }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableRow, { className: ROW_CLASSES, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableCell, { className: CELL_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index}`));
1318
+ }
1319
+ function renderDataRows(columns, rows) {
1320
+ return rows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableCell, { className: CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index));
1321
+ }
1322
+ function renderEmptyRow(colSpan, emptyMessage) {
1323
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) });
1324
+ }
1325
+
1326
+ // src/components/artifacts/table-artifact/use-table-artifact-data.ts
1327
+ function useTableArtifactData(presignedUrl, columns) {
1328
+ return useRowsArtifactData(presignedUrl, columns, parseCsv);
1329
+ }
1330
+
1331
+ // src/components/artifacts/table-artifact/validate.ts
1332
+ function isValidTableConfig(config) {
1333
+ if (!config || typeof config !== "object") return false;
1334
+ const candidate = config;
1335
+ if (!Array.isArray(candidate.columns)) return false;
1336
+ if (candidate.columns.length === 0) return false;
1337
+ return candidate.columns.every(isValidTableColumn);
1338
+ }
1339
+ function isValidTableColumn(column) {
1340
+ if (!column || typeof column !== "object") return false;
1341
+ const candidate = column;
1342
+ if (typeof candidate.key !== "string" || candidate.key.length === 0) return false;
1343
+ if (typeof candidate.label !== "string") return false;
1344
+ return true;
1345
+ }
1346
+
1347
+ // src/components/artifacts/table-artifact/table-artifact.tsx
1348
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1349
+ var TITLE_CLASSES2 = "text-sm font-semibold text-foreground";
1350
+ var TABLE_MAX_BODY_HEIGHT = 480;
1351
+ var MAX_SHIMMER_ROWS = 10;
1352
+ function TableArtifact({ artifact, labels, callbacks }) {
1353
+ const validConfig = isValidTableConfig(artifact.config);
1354
+ const validColumns = validConfig ? artifact.config.columns : null;
1355
+ (0, import_react11.useEffect)(() => {
1356
+ if (validConfig) return;
1357
+ console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
1358
+ }, [validConfig]);
1359
+ const resolvedLabels = (0, import_react11.useMemo)(
1360
+ () => ({ ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels?.[artifactTypes.TABLE] ?? {} }),
1361
+ [labels]
1362
+ );
1363
+ const data = useTableArtifactData(
1364
+ validConfig ? artifact.protectedAsset?.presignedUrl ?? null : null,
1365
+ validColumns ?? []
1366
+ );
1367
+ const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
1368
+ const onDownload = callbacks?.[artifactTypes.TABLE]?.onDownload;
1369
+ const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
1370
+ if (!validConfig || !validColumns) {
1371
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1372
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
1373
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", {}),
1374
+ presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1375
+ ArtifactDownloadButton,
1376
+ {
1377
+ href: presignedUrl,
1378
+ label: resolvedLabels.download,
1379
+ onClick: handleDownloadClick
1380
+ }
1381
+ ) }) : null
1382
+ ] }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
1384
+ ] });
1385
+ }
1386
+ return (
1387
+ // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
1388
+ // Disable the outer overflow container so only one scroll context exists — this prevents
1389
+ // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
1390
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
1391
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
1392
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", {}),
1393
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1394
+ ArtifactDownloadButton,
1395
+ {
1396
+ href: presignedUrl ?? "",
1397
+ label: resolvedLabels.download,
1398
+ onClick: handleDownloadClick
1399
+ }
1400
+ ) })
1401
+ ] }),
1402
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1403
+ TableArtifactContent,
1404
+ {
1405
+ columns: validColumns,
1406
+ data,
1407
+ knownRowCount: artifact.config.stats?.rowCount,
1408
+ maxShimmerRows: MAX_SHIMMER_ROWS,
1409
+ maxBodyHeight: TABLE_MAX_BODY_HEIGHT,
1410
+ labels: resolvedLabels
1411
+ }
1412
+ ) })
1413
+ ] })
1414
+ );
1415
+ }
1416
+
1417
+ // src/components/artifacts/table-artifact/to-clipboard-text.ts
1418
+ function tableArtifactToClipboardText(artifact) {
1419
+ const trimmedTitle = artifact.title?.trim();
1420
+ return trimmedTitle || "Table";
1421
+ }
1422
+
1423
+ // src/components/artifacts/artifact-services/table-artifact-service.ts
1424
+ var TableArtifactService = {
1425
+ type: artifactTypes.TABLE,
1426
+ Component: TableArtifact,
1427
+ toClipboardText: tableArtifactToClipboardText
1428
+ };
1429
+
1430
+ // src/components/artifacts/artifact-services/index.ts
1431
+ var ArtifactServices = {
1432
+ [artifactTypes.TABLE]: TableArtifactService,
1433
+ [artifactTypes.CHART]: ChartArtifactService
1434
+ };
1435
+ function artifactToClipboardText(artifact) {
1436
+ const entry = ArtifactServices[artifact.type];
1437
+ if (!entry) {
1438
+ return `[Artifact: ${artifact.title ?? artifact.type}]`;
1439
+ }
1440
+ return entry.toClipboardText(artifact);
1441
+ }
1442
+ // Annotate the CommonJS export names for ESM import in node:
1443
+ 0 && (module.exports = {
1444
+ ArtifactDownloadButton,
1445
+ ArtifactServices,
1446
+ ChartArtifact,
1447
+ DEFAULT_CHART_ARTIFACT_LABELS,
1448
+ DEFAULT_TABLE_ARTIFACT_LABELS,
1449
+ TableArtifact,
1450
+ artifactToClipboardText,
1451
+ artifactTypes,
1452
+ isSafeDownloadUrl
1453
+ });
1454
+ /*! Bundled license information:
1455
+
1456
+ @tabler/icons-react/dist/esm/defaultAttributes.mjs:
1457
+ @tabler/icons-react/dist/esm/createReactComponent.mjs:
1458
+ @tabler/icons-react/dist/esm/icons/IconDownload.mjs:
1459
+ @tabler/icons-react/dist/esm/tabler-icons-react.mjs:
1460
+ (**
1461
+ * @license @tabler/icons-react v3.37.1 - MIT
1462
+ *
1463
+ * This source code is licensed under the MIT license.
1464
+ * See the LICENSE file in the root directory of this source tree.
1465
+ *)
1466
+ */
1467
+ //# sourceMappingURL=artifacts.cjs.map