@shapesos/clay 0.9.0 → 0.11.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 (74) hide show
  1. package/README.md +46 -1
  2. package/dist/artifacts.cjs +741 -0
  3. package/dist/artifacts.cjs.map +1 -0
  4. package/dist/artifacts.d.cts +56 -0
  5. package/dist/artifacts.d.ts +56 -0
  6. package/dist/artifacts.js +23 -0
  7. package/dist/artifacts.js.map +1 -0
  8. package/dist/blocks.cjs +1282 -0
  9. package/dist/blocks.cjs.map +1 -0
  10. package/dist/blocks.css +2 -0
  11. package/dist/blocks.d.cts +41 -0
  12. package/dist/blocks.d.ts +41 -0
  13. package/dist/blocks.js +31 -0
  14. package/dist/blocks.js.map +1 -0
  15. package/dist/button.d.cts +2 -2
  16. package/dist/button.d.ts +2 -2
  17. package/dist/chat.cjs +755 -281
  18. package/dist/chat.cjs.map +1 -1
  19. package/dist/chat.d.cts +31 -10
  20. package/dist/chat.d.ts +31 -10
  21. package/dist/chat.js +8 -3
  22. package/dist/chunk-BX5TCEPR.js +436 -0
  23. package/dist/chunk-BX5TCEPR.js.map +1 -0
  24. package/dist/chunk-JGMN6W72.js +12 -0
  25. package/dist/chunk-JGMN6W72.js.map +1 -0
  26. package/dist/{chunk-27GJUWVN.js → chunk-JJUIBBBU.js} +14 -8
  27. package/dist/chunk-JJUIBBBU.js.map +1 -0
  28. package/dist/chunk-L35M3OD5.js +99 -0
  29. package/dist/chunk-L35M3OD5.js.map +1 -0
  30. package/dist/chunk-MEJESPTZ.js +1 -0
  31. package/dist/chunk-MEJESPTZ.js.map +1 -0
  32. package/dist/chunk-MXOPG747.js +238 -0
  33. package/dist/chunk-MXOPG747.js.map +1 -0
  34. package/dist/{chunk-MLCRDVQ2.js → chunk-OBOXCBDL.js} +13 -5
  35. package/dist/chunk-OBOXCBDL.js.map +1 -0
  36. package/dist/chunk-OUW6PUEB.js +223 -0
  37. package/dist/chunk-OUW6PUEB.js.map +1 -0
  38. package/dist/{chunk-TDMJUF4A.js → chunk-WPQQVKWY.js} +4 -4
  39. package/dist/icon.cjs +12 -4
  40. package/dist/icon.cjs.map +1 -1
  41. package/dist/icon.d.cts +19 -6
  42. package/dist/icon.d.ts +19 -6
  43. package/dist/icon.js +1 -1
  44. package/dist/index.cjs +789 -273
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.d.cts +7 -3
  47. package/dist/index.d.ts +7 -3
  48. package/dist/index.js +61 -21
  49. package/dist/lottie.d.cts +2 -2
  50. package/dist/lottie.d.ts +2 -2
  51. package/dist/table.cjs +142 -0
  52. package/dist/table.cjs.map +1 -0
  53. package/dist/table.d.cts +44 -0
  54. package/dist/table.d.ts +44 -0
  55. package/dist/table.js +24 -0
  56. package/dist/table.js.map +1 -0
  57. package/dist/text-area.d.cts +2 -2
  58. package/dist/text-area.d.ts +2 -2
  59. package/dist/text-area.js +2 -2
  60. package/dist/types-3Gzk7cRt.d.cts +121 -0
  61. package/dist/types-3Gzk7cRt.d.ts +121 -0
  62. package/dist/types-C9XX-Uhk.d.ts +68 -0
  63. package/dist/types-DuuRI4ll.d.cts +68 -0
  64. package/dist/utils.cjs +14 -7
  65. package/dist/utils.cjs.map +1 -1
  66. package/dist/utils.d.cts +18 -1
  67. package/dist/utils.d.ts +18 -1
  68. package/dist/utils.js +6 -4
  69. package/package.json +34 -4
  70. package/dist/chunk-27GJUWVN.js.map +0 -1
  71. package/dist/chunk-A77BGJH4.js +0 -458
  72. package/dist/chunk-A77BGJH4.js.map +0 -1
  73. package/dist/chunk-MLCRDVQ2.js.map +0 -1
  74. /package/dist/{chunk-TDMJUF4A.js.map → chunk-WPQQVKWY.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -16342,9 +16342,16 @@ var require_lottie = __commonJS({
16342
16342
  // src/index.ts
16343
16343
  var src_exports = {};
16344
16344
  __export(src_exports, {
16345
+ ArtifactDownloadButton: () => ArtifactDownloadButton,
16346
+ ArtifactRefBlock: () => ArtifactRefBlock,
16347
+ ArtifactRefBlockService: () => ArtifactRefBlockService,
16348
+ ArtifactServices: () => ArtifactServices,
16345
16349
  BUTTON_INTENT: () => BUTTON_INTENT,
16346
16350
  BUTTON_SIZE: () => BUTTON_SIZE,
16347
16351
  BUTTON_VARIANT: () => BUTTON_VARIANT,
16352
+ Block: () => Block,
16353
+ BlockContext: () => BlockContext,
16354
+ BlockServices: () => BlockServices,
16348
16355
  Button: () => Button2,
16349
16356
  ChatContext: () => ChatContext,
16350
16357
  ChatMessage: () => ChatMessage,
@@ -16356,16 +16363,25 @@ __export(src_exports, {
16356
16363
  KeyboardShortcut: () => KeyboardShortcut,
16357
16364
  Lottie: () => Lottie,
16358
16365
  MESSAGE_ROLE: () => MESSAGE_ROLE,
16366
+ TableArtifact: () => TableArtifact,
16359
16367
  TextArea: () => TextArea,
16368
+ TextBlockService: () => TextBlockService,
16369
+ artifactToClipboardText: () => artifactToClipboardText,
16370
+ artifactTypes: () => artifactTypes,
16371
+ blockTypes: () => blockTypes,
16360
16372
  colors: () => colors,
16361
16373
  convertTableToCSV: () => convertTableToCSV,
16374
+ copyMessageText: () => copyMessageText,
16375
+ escapeCsvField: () => escapeCsvField,
16362
16376
  fontFamilies: () => fontFamilies,
16377
+ isSafeDownloadUrl: () => isSafeDownloadUrl,
16363
16378
  markdownToPlainText: () => markdownToPlainText,
16364
16379
  mergeRefs: () => mergeRefs,
16365
16380
  parseMarkdownTable: () => parseMarkdownTable,
16366
16381
  typographyMixin: () => typographyMixin,
16367
16382
  typographyStyles: () => typographyStyles,
16368
16383
  typographyTypes: () => typographyTypes,
16384
+ useBlockContext: () => useBlockContext,
16369
16385
  useChatContext: () => useChatContext,
16370
16386
  useCopyToClipboard: () => useCopyToClipboard
16371
16387
  });
@@ -16754,203 +16770,43 @@ function typographyMixin(type) {
16754
16770
  ].join(";\n ");
16755
16771
  }
16756
16772
 
16757
- // src/components/chat/chat-message-content/chat-message-content.tsx
16758
- var import_react_markdown = __toESM(require("react-markdown"), 1);
16759
- var import_remark_breaks = __toESM(require("remark-breaks"), 1);
16760
- var import_remark_gfm = __toESM(require("remark-gfm"), 1);
16761
-
16762
- // src/components/chat/scrollable-table/scrollable-table.tsx
16763
- var import_react2 = require("react");
16773
+ // src/components/blocks/types.ts
16774
+ var blockTypes = {
16775
+ TEXT: "TEXT",
16776
+ ARTIFACT_REF: "ARTIFACT_REF"
16777
+ };
16764
16778
 
16765
- // src/components/chat/chat-context/chat-context.ts
16766
- var import_react = require("react");
16767
- var ChatContext = (0, import_react.createContext)(null);
16768
- function useChatContext() {
16769
- const context = (0, import_react.useContext)(ChatContext);
16770
- if (!context) {
16771
- throw new Error("useChatContext must be used within a Chat.Root component");
16772
- }
16773
- return context;
16774
- }
16779
+ // src/components/artifacts/types.ts
16780
+ var artifactTypes = {
16781
+ TABLE: "TABLE"
16782
+ };
16775
16783
 
16776
- // src/components/chat/scrollable-table/scrollable-table-styles.ts
16777
- var import_styled_components = __toESM(require("styled-components"), 1);
16778
- var TableContainer = import_styled_components.default.div`
16779
- position: relative;
16780
- margin-block: 8px 16px;
16781
- `;
16782
- var TableScroll = import_styled_components.default.div`
16783
- width: 100%;
16784
- overflow-x: auto;
16785
- overflow-y: hidden;
16786
- `;
16787
- var TableActionsWrapper = import_styled_components.default.div`
16788
- display: flex;
16789
- justify-content: flex-start;
16790
- margin-block: 8px 0;
16791
- `;
16792
- var TableActionsDivider = import_styled_components.default.div`
16793
- height: 1px;
16794
- background: ${colors["brown-40"]};
16795
- margin-block: 8px 0;
16796
- `;
16784
+ // src/components/artifacts/table-artifact/table-artifact.tsx
16785
+ var import_react7 = require("react");
16797
16786
 
16798
- // src/components/chat/scrollable-table/scrollable-table.tsx
16799
- var import_jsx_runtime = require("react/jsx-runtime");
16800
- function ScrollableTable({ node: _node, messageId, counter, ...props }) {
16801
- const currentIndex = counter ? counter.value : 0;
16802
- if (counter) {
16803
- counter.value += 1;
16804
- }
16805
- const context = (0, import_react2.useContext)(ChatContext);
16806
- const TableActions = context?.TableActions;
16807
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableContainer, { children: [
16808
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableScroll, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("table", { ...props }) }),
16809
- TableActions && messageId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
16810
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableActionsWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableActions, { messageId, tableIndex: currentIndex }) }),
16811
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableActionsDivider, {})
16812
- ] })
16813
- ] });
16787
+ // src/lib/utils.ts
16788
+ var import_clsx = require("clsx");
16789
+ var import_tailwind_merge = require("tailwind-merge");
16790
+ function cn(...inputs) {
16791
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
16814
16792
  }
16815
16793
 
16816
- // src/components/chat/chat-message-content/chat-message-content-styles.ts
16817
- var import_styled_components2 = __toESM(require("styled-components"), 1);
16818
- var ContentWrapper = import_styled_components2.default.div`
16819
- ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};
16820
- color: ${colors["brown-100"]};
16821
- word-break: break-word;
16822
-
16823
- & h1 {
16824
- ${typographyMixin(typographyTypes.GEIST_HEADING_S_BOLD)};
16825
- margin-block: 20px;
16826
- }
16827
-
16828
- & h2 {
16829
- ${typographyMixin(typographyTypes.GEIST_BODY_L_SEMI_BOLD)};
16830
- margin-block: 12px;
16831
- }
16832
-
16833
- & h3,
16834
- & h4,
16835
- & h5,
16836
- & h6 {
16837
- ${typographyMixin(typographyTypes.GEIST_BODY_M_SEMI_BOLD)};
16838
- margin-block: 8px;
16839
- }
16840
-
16841
- & strong {
16842
- ${typographyMixin(typographyTypes.GEIST_BODY_S_SEMI_BOLD)};
16843
- }
16844
-
16845
- & p {
16846
- margin-block: 0px;
16847
- }
16848
-
16849
- & p + p {
16850
- margin-block: 8px 0px;
16851
- }
16852
-
16853
- & ul,
16854
- & ol {
16855
- margin-block: 16px;
16856
- padding-left: 20px;
16857
- }
16858
-
16859
- & li + li {
16860
- margin-block: 4px;
16861
- }
16862
-
16863
- & ol {
16864
- list-style-type: decimal;
16865
- }
16866
-
16867
- & ol ol {
16868
- list-style-type: lower-alpha;
16869
- }
16870
-
16871
- & ol ol ol {
16872
- list-style-type: lower-roman;
16873
- }
16874
-
16875
- & a {
16876
- color: inherit;
16877
- text-decoration-line: underline;
16878
- text-decoration-style: dotted;
16879
- text-decoration-thickness: auto;
16880
- text-underline-offset: auto;
16881
- text-underline-position: from-font;
16882
- transition: color 75ms ease-in-out;
16883
-
16884
- &:hover {
16885
- color: ${colors["blue-600"]};
16886
- }
16887
- }
16888
-
16889
- & hr {
16890
- border: none;
16891
- border-top: 1px solid ${colors["brown-40"]};
16892
- margin-block: 20px;
16893
- }
16894
-
16895
- & table {
16896
- margin: 0;
16897
- width: 100%;
16898
- border-collapse: collapse;
16899
- }
16900
-
16901
- & th,
16902
- & td {
16903
- border: none;
16904
- border-bottom: 1px solid ${colors["brown-40"]};
16905
- text-align: left;
16906
- }
16907
-
16908
- & th {
16909
- ${typographyMixin(typographyTypes.GEIST_LABEL_CAPTION_MEDIUM)};
16910
- padding: 8px;
16911
- }
16912
-
16913
- & td {
16914
- ${typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM)};
16915
- padding: 16px 8px;
16916
- min-width: 150px;
16917
- width: 1%;
16918
- }
16919
-
16920
- & td strong {
16921
- font-weight: inherit;
16922
- font-size: inherit;
16923
- line-height: inherit;
16924
- }
16925
-
16926
- & blockquote {
16927
- margin-block: 4px;
16928
- margin-inline: 0px;
16929
- padding-left: 16px;
16930
- border-left: 4px solid ${colors["brown-40"]};
16931
- color: ${colors["brown-80"]};
16794
+ // src/components/ai-elements/artifact.tsx
16795
+ var import_jsx_runtime = require("react/jsx-runtime");
16796
+ var Artifact = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
16797
+ "div",
16798
+ {
16799
+ className: cn("flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm", className),
16800
+ ...props
16932
16801
  }
16933
- `;
16934
-
16935
- // src/components/chat/chat-message-content/chat-message-content.tsx
16936
- var import_jsx_runtime2 = require("react/jsx-runtime");
16937
- function ChatMessageContent({ content: content2, messageId }) {
16938
- const counter = { value: 0 };
16939
- const sanitizedContent = content2.split("\n").filter((line) => {
16940
- const t = line.trim();
16941
- return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
16942
- }).join("\n");
16943
- const markdownComponents = {
16944
- table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ScrollableTable, { ...tableProps, messageId, counter }))
16945
- };
16946
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ContentWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default, import_remark_breaks.default], components: markdownComponents, children: sanitizedContent }) });
16947
- }
16948
-
16949
- // src/components/chat/chat-message-actions/chat-message-actions.tsx
16950
- var import_react6 = require("react");
16802
+ );
16803
+ 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 });
16804
+ var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: cn("font-medium text-foreground text-sm", className), ...props });
16805
+ var ArtifactActions = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("flex items-center gap-1", className), ...props });
16806
+ var ArtifactContent = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("flex-1 overflow-auto p-4", className), ...props });
16951
16807
 
16952
16808
  // node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
16953
- var import_react3 = require("react");
16809
+ var import_react = require("react");
16954
16810
 
16955
16811
  // node_modules/@tabler/icons-react/dist/esm/defaultAttributes.mjs
16956
16812
  var defaultAttributes = {
@@ -16977,8 +16833,8 @@ var defaultAttributes = {
16977
16833
 
16978
16834
  // node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
16979
16835
  var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
16980
- const Component = (0, import_react3.forwardRef)(
16981
- ({ color = "currentColor", size = 24, stroke = 2, title, className, children, ...rest }, ref) => (0, import_react3.createElement)(
16836
+ const Component = (0, import_react.forwardRef)(
16837
+ ({ color = "currentColor", size = 24, stroke = 2, title, className, children, ...rest }, ref) => (0, import_react.createElement)(
16982
16838
  "svg",
16983
16839
  {
16984
16840
  ref,
@@ -16995,8 +16851,8 @@ var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
16995
16851
  ...rest
16996
16852
  },
16997
16853
  [
16998
- title && (0, import_react3.createElement)("title", { key: "svg-title" }, title),
16999
- ...iconNode.map(([tag, attrs]) => (0, import_react3.createElement)(tag, attrs)),
16854
+ title && (0, import_react.createElement)("title", { key: "svg-title" }, title),
16855
+ ...iconNode.map(([tag, attrs]) => (0, import_react.createElement)(tag, attrs)),
17000
16856
  ...Array.isArray(children) ? children : [children]
17001
16857
  ]
17002
16858
  )
@@ -17013,19 +16869,26 @@ var IconCheck = createReactComponent("outline", "check", "Check", __iconNode);
17013
16869
  var __iconNode2 = [["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" }]];
17014
16870
  var IconCopy = createReactComponent("outline", "copy", "Copy", __iconNode2);
17015
16871
 
16872
+ // node_modules/@tabler/icons-react/dist/esm/icons/IconDownload.mjs
16873
+ var __iconNode3 = [["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" }]];
16874
+ var IconDownload = createReactComponent("outline", "download", "Download", __iconNode3);
16875
+
17016
16876
  // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbDown.mjs
17017
- var __iconNode3 = [["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" }]];
17018
- var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode3);
16877
+ var __iconNode4 = [["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" }]];
16878
+ var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode4);
17019
16879
 
17020
16880
  // node_modules/@tabler/icons-react/dist/esm/icons/IconThumbUp.mjs
17021
- var __iconNode4 = [["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" }]];
17022
- var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode4);
16881
+ var __iconNode5 = [["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" }]];
16882
+ var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode5);
16883
+
16884
+ // src/components/icon-button/icon-button.tsx
16885
+ var import_react3 = require("react");
17023
16886
 
17024
16887
  // src/components/icon/icon.tsx
17025
- var import_react4 = require("react");
16888
+ var import_react2 = require("react");
17026
16889
 
17027
16890
  // src/components/icon/icon-styles.ts
17028
- var import_styled_components3 = __toESM(require("styled-components"), 1);
16891
+ var import_styled_components = __toESM(require("styled-components"), 1);
17029
16892
  var STROKE_WIDTH_BY_SIZE = {
17030
16893
  12: 1.4,
17031
16894
  14: 1.4,
@@ -17038,7 +16901,7 @@ var DEFAULT_STROKE_WIDTH = 1.8;
17038
16901
  function getStrokeWidth(size) {
17039
16902
  return STROKE_WIDTH_BY_SIZE[size] ?? DEFAULT_STROKE_WIDTH;
17040
16903
  }
17041
- var IconWrapper = import_styled_components3.default.span`
16904
+ var IconWrapper = import_styled_components.default.span`
17042
16905
  display: inline-flex;
17043
16906
  align-items: center;
17044
16907
  justify-content: center;
@@ -17047,10 +16910,10 @@ var IconWrapper = import_styled_components3.default.span`
17047
16910
  `;
17048
16911
 
17049
16912
  // src/components/icon/icon.tsx
17050
- var import_jsx_runtime3 = require("react/jsx-runtime");
16913
+ var import_jsx_runtime2 = require("react/jsx-runtime");
17051
16914
  var DEFAULT_SIZE = 16;
17052
- var Icon = (0, import_react4.forwardRef)(function Icon2({ icon: IconComponent, size = DEFAULT_SIZE, color, className, "aria-label": ariaLabel }, ref) {
17053
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
16915
+ var Icon = (0, import_react2.forwardRef)(function Icon2({ icon: IconComponent, size = DEFAULT_SIZE, color, className, "aria-label": ariaLabel }, ref) {
16916
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
17054
16917
  IconWrapper,
17055
16918
  {
17056
16919
  ref,
@@ -17058,13 +16921,13 @@ var Icon = (0, import_react4.forwardRef)(function Icon2({ icon: IconComponent, s
17058
16921
  $color: color,
17059
16922
  "aria-label": ariaLabel,
17060
16923
  role: ariaLabel ? "img" : void 0,
17061
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(IconComponent, { width: size, height: size, strokeWidth: getStrokeWidth(size) })
16924
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IconComponent, { width: size, height: size, strokeWidth: getStrokeWidth(size) })
17062
16925
  }
17063
16926
  );
17064
16927
  });
17065
16928
 
17066
16929
  // src/components/icon-button/icon-button-styles.ts
17067
- var import_styled_components4 = __toESM(require("styled-components"), 1);
16930
+ var import_styled_components2 = __toESM(require("styled-components"), 1);
17068
16931
  var PADDING = {
17069
16932
  short: {
17070
16933
  small: "4px",
@@ -17079,7 +16942,7 @@ var BORDER_RADIUS = {
17079
16942
  small: 6,
17080
16943
  medium: 10
17081
16944
  };
17082
- var Button = import_styled_components4.default.button`
16945
+ var Button = import_styled_components2.default.button`
17083
16946
  display: inline-flex;
17084
16947
  align-items: center;
17085
16948
  justify-content: center;
@@ -17107,12 +16970,12 @@ var Button = import_styled_components4.default.button`
17107
16970
  `;
17108
16971
 
17109
16972
  // src/components/icon-button/icon-button.tsx
17110
- var import_jsx_runtime4 = require("react/jsx-runtime");
16973
+ var import_jsx_runtime3 = require("react/jsx-runtime");
17111
16974
  var ICON_SIZE_BY_BUTTON_SIZE = {
17112
16975
  small: 16,
17113
16976
  medium: 20
17114
16977
  };
17115
- function IconButton({
16978
+ var IconButton = (0, import_react3.forwardRef)(function IconButton2({
17116
16979
  icon,
17117
16980
  size = "small",
17118
16981
  variant = "short",
@@ -17122,11 +16985,14 @@ function IconButton({
17122
16985
  className,
17123
16986
  id,
17124
16987
  as,
17125
- "aria-label": ariaLabel
17126
- }) {
17127
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
16988
+ "aria-label": ariaLabel,
16989
+ ...rest
16990
+ }, ref) {
16991
+ const isNativeButton = as === void 0 || as === "button";
16992
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
17128
16993
  Button,
17129
16994
  {
16995
+ ref,
17130
16996
  className,
17131
16997
  id,
17132
16998
  as,
@@ -17136,22 +17002,406 @@ function IconButton({
17136
17002
  disabled,
17137
17003
  onClick: disabled ? void 0 : onClick,
17138
17004
  "aria-label": ariaLabel,
17139
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { icon, size: ICON_SIZE_BY_BUTTON_SIZE[size] })
17005
+ ...isNativeButton ? { type: "button" } : {},
17006
+ ...rest,
17007
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { icon, size: ICON_SIZE_BY_BUTTON_SIZE[size] })
17140
17008
  }
17141
17009
  );
17010
+ });
17011
+
17012
+ // src/components/ui/tooltip.tsx
17013
+ var React = __toESM(require("react"), 1);
17014
+ var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
17015
+ var import_jsx_runtime4 = require("react/jsx-runtime");
17016
+ var TooltipProvider = TooltipPrimitive.Provider;
17017
+ var Tooltip = TooltipPrimitive.Root;
17018
+ var TooltipTrigger = TooltipPrimitive.Trigger;
17019
+ var TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
17020
+ TooltipPrimitive.Content,
17021
+ {
17022
+ ref,
17023
+ sideOffset,
17024
+ className: cn(
17025
+ "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]",
17026
+ className
17027
+ ),
17028
+ ...props
17029
+ }
17030
+ ));
17031
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
17032
+
17033
+ // src/components/artifacts/artifact-download-button/artifact-download-button.tsx
17034
+ var import_jsx_runtime5 = require("react/jsx-runtime");
17035
+ function ArtifactDownloadButton({ href }) {
17036
+ if (!isSafeDownloadUrl(href)) return null;
17037
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Tooltip, { children: [
17038
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
17039
+ IconButton,
17040
+ {
17041
+ as: "a",
17042
+ href,
17043
+ download: true,
17044
+ rel: "noopener noreferrer",
17045
+ icon: IconDownload,
17046
+ size: "small",
17047
+ "aria-label": "Download artifact"
17048
+ }
17049
+ ) }),
17050
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TooltipContent, { children: "Download" })
17051
+ ] }) });
17052
+ }
17053
+ function isSafeDownloadUrl(url) {
17054
+ try {
17055
+ const parsed = new URL(url);
17056
+ return parsed.protocol === "https:" || parsed.protocol === "http:";
17057
+ } catch {
17058
+ return false;
17059
+ }
17142
17060
  }
17143
17061
 
17144
- // src/components/chat/hooks/use-copy-to-clipboard.ts
17062
+ // src/components/ui/table.tsx
17063
+ var React2 = __toESM(require("react"), 1);
17064
+ var import_jsx_runtime6 = require("react/jsx-runtime");
17065
+ var Table = React2.forwardRef(({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("relative w-full overflow-auto", containerClassName), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props }) }));
17066
+ Table.displayName = "Table";
17067
+ var TableHeader = React2.forwardRef(
17068
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("thead", { ref, className: cn("[&_tr]:border-b", className), ...props })
17069
+ );
17070
+ TableHeader.displayName = "TableHeader";
17071
+ var TableBody = React2.forwardRef(
17072
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props })
17073
+ );
17074
+ TableBody.displayName = "TableBody";
17075
+ var TableFooter = React2.forwardRef(
17076
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tfoot", { ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props })
17077
+ );
17078
+ TableFooter.displayName = "TableFooter";
17079
+ var TableRow = React2.forwardRef(
17080
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
17081
+ "tr",
17082
+ {
17083
+ ref,
17084
+ className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className),
17085
+ ...props
17086
+ }
17087
+ )
17088
+ );
17089
+ TableRow.displayName = "TableRow";
17090
+ var TableHead = React2.forwardRef(
17091
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
17092
+ "th",
17093
+ {
17094
+ ref,
17095
+ className: cn(
17096
+ "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
17097
+ className
17098
+ ),
17099
+ ...props
17100
+ }
17101
+ )
17102
+ );
17103
+ TableHead.displayName = "TableHead";
17104
+ var TableCell = React2.forwardRef(
17105
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className), ...props })
17106
+ );
17107
+ TableCell.displayName = "TableCell";
17108
+ var TableCaption = React2.forwardRef(
17109
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })
17110
+ );
17111
+ TableCaption.displayName = "TableCaption";
17112
+
17113
+ // src/components/table/use-scroll-shadow.ts
17114
+ var import_react4 = require("react");
17115
+ function useScrollShadow() {
17116
+ const targetRef = (0, import_react4.useRef)(null);
17117
+ const [isScrolled, setIsScrolled] = (0, import_react4.useState)(false);
17118
+ (0, import_react4.useEffect)(() => {
17119
+ const target = targetRef.current;
17120
+ if (!target) return;
17121
+ let scrollContainer = target;
17122
+ while (scrollContainer) {
17123
+ const overflowY = getComputedStyle(scrollContainer).overflowY;
17124
+ if (overflowY === "auto" || overflowY === "scroll") break;
17125
+ scrollContainer = scrollContainer.parentElement;
17126
+ }
17127
+ if (!scrollContainer) return;
17128
+ setIsScrolled(scrollContainer.scrollTop > 0);
17129
+ const handleScroll = () => {
17130
+ if (!scrollContainer) return;
17131
+ setIsScrolled(scrollContainer.scrollTop > 0);
17132
+ };
17133
+ scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
17134
+ return () => scrollContainer.removeEventListener("scroll", handleScroll);
17135
+ }, []);
17136
+ return { targetRef, isScrolled };
17137
+ }
17138
+
17139
+ // src/components/artifacts/table-artifact/table-artifact-styles.ts
17145
17140
  var import_react5 = require("react");
17141
+ function StatusMessage({ $tone, children }) {
17142
+ return (0, import_react5.createElement)(
17143
+ "div",
17144
+ {
17145
+ className: `py-6 px-2 text-center text-sm font-medium leading-5 ${$tone === "error" ? "text-red-600" : "text-brown-70"}`
17146
+ },
17147
+ children
17148
+ );
17149
+ }
17146
17150
 
17147
- // src/utils/clipboard.ts
17148
- function copyToClipboard(text2, options) {
17149
- navigator.clipboard.writeText(text2).then(
17150
- () => options?.onSuccess?.(),
17151
- (error) => options?.onFailure?.(error)
17151
+ // src/components/artifacts/table-artifact/table-artifact-content.constants.ts
17152
+ var TABLE_STATUS = {
17153
+ LOADING: "loading",
17154
+ READY: "ready",
17155
+ ERROR: "error",
17156
+ UNAVAILABLE: "unavailable"
17157
+ };
17158
+
17159
+ // src/components/artifacts/table-artifact/table-artifact-content.utils.ts
17160
+ function formatCell(row, column) {
17161
+ return row[column.key] ?? "";
17162
+ }
17163
+ var HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
17164
+ var CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
17165
+ var ROW_CLASSES = "border-b-brown-30 bg-background/70 hover:bg-secondary";
17166
+ var DATA_ROW_CLASSES = `${ROW_CLASSES} animate-in fade-in duration-300`;
17167
+ var SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";
17168
+
17169
+ // src/components/artifacts/table-artifact/table-artifact-content.tsx
17170
+ var import_jsx_runtime7 = require("react/jsx-runtime");
17171
+ function TableArtifactContent({
17172
+ columns,
17173
+ data: data2,
17174
+ knownRowCount,
17175
+ maxShimmerRows,
17176
+ maxBodyHeight,
17177
+ unavailableMessage
17178
+ }) {
17179
+ if (data2.status === TABLE_STATUS.ERROR) {
17180
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StatusMessage, { $tone: "error", children: "Couldn't load table data." });
17181
+ }
17182
+ if (data2.status === TABLE_STATUS.UNAVAILABLE) {
17183
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StatusMessage, { $tone: "info", children: unavailableMessage });
17184
+ }
17185
+ if (data2.status === TABLE_STATUS.LOADING) {
17186
+ if (typeof knownRowCount === "number" && knownRowCount > 0) {
17187
+ const shimmerCount = Math.min(knownRowCount, maxShimmerRows);
17188
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ArtifactTable, { columns, maxBodyHeight, children: renderShimmerRows(columns, shimmerCount) });
17189
+ }
17190
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StatusMessage, { $tone: "info", children: "Loading table\u2026" });
17191
+ }
17192
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ArtifactTable, { columns, maxBodyHeight, children: data2.rows.length === 0 ? renderEmptyRow(columns.length) : renderDataRows(columns, data2.rows) });
17193
+ }
17194
+ function ArtifactTable({ columns, maxBodyHeight, children }) {
17195
+ const { targetRef, isScrolled } = useScrollShadow();
17196
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: targetRef, className: "overscroll-none", style: { maxHeight: maxBodyHeight, overflowY: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Table, { containerClassName: "overflow-visible", children: [
17197
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
17198
+ TableHeader,
17199
+ {
17200
+ "data-scrolled": isScrolled ? "true" : void 0,
17201
+ className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
17202
+ style: isScrolled ? { boxShadow: SCROLL_SHADOW } : void 0,
17203
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableHead, { scope: "col", className: HEAD_CLASS, children: column.label }, column.key)) })
17204
+ }
17205
+ ),
17206
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableBody, { children })
17207
+ ] }) });
17208
+ }
17209
+ function renderShimmerRows(columns, count) {
17210
+ return Array.from({ length: count }).map((_, index2) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableRow, { className: ROW_CLASSES, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableCell, { className: CELL_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index2}`));
17211
+ }
17212
+ function renderDataRows(columns, rows) {
17213
+ return rows.map((row, index2) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableCell, { className: CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index2));
17214
+ }
17215
+ function renderEmptyRow(colSpan) {
17216
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: "No rows to display." }) });
17217
+ }
17218
+
17219
+ // src/components/artifacts/table-artifact/use-table-artifact-data.ts
17220
+ var import_react6 = require("react");
17221
+
17222
+ // src/components/artifacts/table-artifact/parse-csv.ts
17223
+ var import_papaparse = __toESM(require("papaparse"), 1);
17224
+ function parseCsv(text2, columns) {
17225
+ const result = import_papaparse.default.parse(text2, {
17226
+ header: true,
17227
+ skipEmptyLines: true,
17228
+ dynamicTyping: false
17229
+ });
17230
+ const csvHeaders = new Set(result.meta?.fields ?? []);
17231
+ const presentColumns = columns.filter((col) => csvHeaders.has(col.key));
17232
+ return result.data.map((rawRow) => {
17233
+ const row = {};
17234
+ for (const column of presentColumns) {
17235
+ const value2 = rawRow[column.key];
17236
+ row[column.key] = value2 === void 0 || value2 === "" ? null : value2;
17237
+ }
17238
+ return row;
17239
+ });
17240
+ }
17241
+
17242
+ // src/components/artifacts/table-artifact/use-table-artifact-data.ts
17243
+ var LOADING = { status: "loading", rows: null, error: null };
17244
+ var UNAVAILABLE = { status: "unavailable", rows: null, error: null };
17245
+ var INITIAL_INTERNAL = { cacheKey: null, data: LOADING };
17246
+ function columnsFingerprint(columns) {
17247
+ return columns.map((c) => `${c.key}:${c.type ?? "string"}`).join("|");
17248
+ }
17249
+ function useTableArtifactData(presignedUrl, columns) {
17250
+ const colsKey = (0, import_react6.useMemo)(() => columnsFingerprint(columns), [columns]);
17251
+ const cacheKey = presignedUrl ? `${presignedUrl}::${colsKey}` : null;
17252
+ const [state, setState] = (0, import_react6.useState)(INITIAL_INTERNAL);
17253
+ (0, import_react6.useEffect)(() => {
17254
+ if (!presignedUrl) return;
17255
+ const controller = new AbortController();
17256
+ fetch(presignedUrl, {
17257
+ signal: controller.signal,
17258
+ headers: { Accept: "text/csv" },
17259
+ // Presigned URLs are cross-origin S3 in production and don't need credentials. Explicit
17260
+ // omit so a same-origin URL (compromised payload, local dev) can't accidentally receive
17261
+ // session cookies or auth headers.
17262
+ credentials: "omit"
17263
+ }).then(async (response) => {
17264
+ if (!response.ok) throw new Error(`Failed to load table data (${response.status})`);
17265
+ return response.text();
17266
+ }).then((text2) => {
17267
+ if (controller.signal.aborted) return;
17268
+ try {
17269
+ const rows = parseCsv(text2, columns);
17270
+ setState({ cacheKey: `${presignedUrl}::${colsKey}`, data: { status: "ready", rows, error: null } });
17271
+ } catch (parseError) {
17272
+ console.error("[TableArtifact] CSV parse failed", parseError);
17273
+ const err = parseError instanceof Error ? parseError : new Error(String(parseError));
17274
+ setState({ cacheKey: `${presignedUrl}::${colsKey}`, data: { status: "error", rows: null, error: err } });
17275
+ }
17276
+ }).catch((error) => {
17277
+ if (controller.signal.aborted) return;
17278
+ console.error("[TableArtifact] Fetch failed", error);
17279
+ const err = error instanceof Error ? error : new Error(String(error));
17280
+ setState({ cacheKey: `${presignedUrl}::${colsKey}`, data: { status: "error", rows: null, error: err } });
17281
+ });
17282
+ return () => {
17283
+ controller.abort();
17284
+ };
17285
+ }, [presignedUrl, colsKey]);
17286
+ if (!presignedUrl) return UNAVAILABLE;
17287
+ if (state.cacheKey !== cacheKey) return LOADING;
17288
+ return state.data;
17289
+ }
17290
+
17291
+ // src/components/artifacts/table-artifact/validate.ts
17292
+ function isValidTableConfig(config) {
17293
+ if (!config || typeof config !== "object") return false;
17294
+ const candidate = config;
17295
+ if (!Array.isArray(candidate.columns)) return false;
17296
+ if (candidate.columns.length === 0) return false;
17297
+ return candidate.columns.every(isValidTableColumn);
17298
+ }
17299
+ function isValidTableColumn(column) {
17300
+ if (!column || typeof column !== "object") return false;
17301
+ const candidate = column;
17302
+ if (typeof candidate.key !== "string" || candidate.key.length === 0) return false;
17303
+ if (typeof candidate.label !== "string") return false;
17304
+ return true;
17305
+ }
17306
+
17307
+ // src/components/artifacts/table-artifact/table-artifact.tsx
17308
+ var import_jsx_runtime8 = require("react/jsx-runtime");
17309
+ var TITLE_CLASSES = "text-sm font-semibold text-foreground";
17310
+ var TABLE_MAX_BODY_HEIGHT = 480;
17311
+ var MAX_SHIMMER_ROWS = 10;
17312
+ var MSG_UNAVAILABLE = "Table data is unavailable.";
17313
+ function TableArtifact({ artifact }) {
17314
+ const validConfig = isValidTableConfig(artifact.config);
17315
+ const validColumns = validConfig ? artifact.config.columns : null;
17316
+ (0, import_react7.useEffect)(() => {
17317
+ if (validConfig) return;
17318
+ console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
17319
+ }, [validConfig]);
17320
+ const data2 = useTableArtifactData(
17321
+ validConfig ? artifact.protectedAsset?.presignedUrl ?? null : null,
17322
+ validColumns ?? []
17152
17323
  );
17324
+ const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
17325
+ if (!validConfig || !validColumns) {
17326
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
17327
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
17328
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactTitle, { className: TITLE_CLASSES, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", {}),
17329
+ presignedUrl ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactDownloadButton, { href: presignedUrl }) }) : null
17330
+ ] }),
17331
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusMessage, { $tone: "info", children: MSG_UNAVAILABLE }) })
17332
+ ] });
17333
+ }
17334
+ return (
17335
+ // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
17336
+ // Disable the outer overflow container so only one scroll context exists — this prevents
17337
+ // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
17338
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
17339
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ArtifactHeader, { className: "bg-background/70", children: [
17340
+ artifact.title ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactTitle, { className: TITLE_CLASSES, children: artifact.title }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", {}),
17341
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactActions, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactDownloadButton, { href: presignedUrl ?? "" }) })
17342
+ ] }),
17343
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
17344
+ TableArtifactContent,
17345
+ {
17346
+ columns: validColumns,
17347
+ data: data2,
17348
+ knownRowCount: artifact.config.stats?.rowCount,
17349
+ maxShimmerRows: MAX_SHIMMER_ROWS,
17350
+ maxBodyHeight: TABLE_MAX_BODY_HEIGHT,
17351
+ unavailableMessage: MSG_UNAVAILABLE
17352
+ }
17353
+ ) })
17354
+ ] })
17355
+ );
17356
+ }
17357
+
17358
+ // src/components/artifacts/table-artifact/to-clipboard-text.ts
17359
+ function tableArtifactToClipboardText(artifact) {
17360
+ const trimmedTitle = artifact.title?.trim();
17361
+ return trimmedTitle || "Table";
17362
+ }
17363
+
17364
+ // src/components/artifacts/artifact-services/table-artifact-service.ts
17365
+ var TableArtifactService = {
17366
+ type: artifactTypes.TABLE,
17367
+ Component: TableArtifact,
17368
+ toClipboardText: tableArtifactToClipboardText
17369
+ };
17370
+
17371
+ // src/components/artifacts/artifact-services/index.ts
17372
+ var ArtifactServices = {
17373
+ [artifactTypes.TABLE]: TableArtifactService
17374
+ };
17375
+ function artifactToClipboardText(artifact) {
17376
+ const entry = ArtifactServices[artifact.type];
17377
+ if (!entry) {
17378
+ return `[Artifact: ${artifact.title ?? artifact.type}]`;
17379
+ }
17380
+ return entry.toClipboardText(artifact);
17381
+ }
17382
+
17383
+ // src/components/blocks/artifact-ref-block/artifact-ref-block.tsx
17384
+ var import_jsx_runtime9 = require("react/jsx-runtime");
17385
+ function ArtifactRefBlock({ block }) {
17386
+ const { artifact } = block.payload;
17387
+ const entry = ArtifactServices[artifact.type];
17388
+ if (!entry) return null;
17389
+ const { Component } = entry;
17390
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Component, { artifact });
17153
17391
  }
17154
17392
 
17393
+ // src/components/blocks/block-services/artifact-ref-block-service.ts
17394
+ var ArtifactRefBlockService = {
17395
+ type: blockTypes.ARTIFACT_REF,
17396
+ Component: ArtifactRefBlock,
17397
+ /**
17398
+ * Delegates to the registered artifact component's `toClipboardText`. Falls back to
17399
+ * `[Artifact: <title>]` via `artifactToClipboardText`'s own fallback when the artifact type
17400
+ * has no registered component, so copy never silently produces an empty string.
17401
+ */
17402
+ toClipboardText: (block) => artifactToClipboardText(block.payload.artifact)
17403
+ };
17404
+
17155
17405
  // src/utils/markdown-to-plain-text.ts
17156
17406
  var PLACEHOLDER_PREFIX = "\u200B\u200BIC";
17157
17407
  var PLACEHOLDER_SUFFIX = "\u200B\u200B";
@@ -17171,18 +17421,253 @@ function markdownToPlainText(markdown) {
17171
17421
  return result;
17172
17422
  }
17173
17423
 
17424
+ // src/components/blocks/text-block/text-block.tsx
17425
+ var import_react_markdown = __toESM(require("react-markdown"), 1);
17426
+ var import_remark_breaks = __toESM(require("remark-breaks"), 1);
17427
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
17428
+
17429
+ // src/components/blocks/scrollable-table/scrollable-table-styles.ts
17430
+ var import_styled_components3 = __toESM(require("styled-components"), 1);
17431
+ var TableContainer = import_styled_components3.default.div`
17432
+ position: relative;
17433
+ margin-block: 8px 16px;
17434
+ `;
17435
+ var TableScroll = import_styled_components3.default.div`
17436
+ width: 100%;
17437
+ overflow-x: auto;
17438
+ overflow-y: hidden;
17439
+ `;
17440
+
17441
+ // src/components/blocks/scrollable-table/scrollable-table.tsx
17442
+ var import_jsx_runtime10 = require("react/jsx-runtime");
17443
+ function ScrollableTable({ node: _node, ...props }) {
17444
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TableContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TableScroll, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("table", { ...props }) }) });
17445
+ }
17446
+
17447
+ // src/components/blocks/text-block/sanitize.ts
17448
+ function sanitize(text2) {
17449
+ return text2.split("\n").filter((line) => {
17450
+ const t = line.trim();
17451
+ return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
17452
+ }).join("\n");
17453
+ }
17454
+
17455
+ // src/components/blocks/text-block/text-block-styles.ts
17456
+ var import_styled_components4 = __toESM(require("styled-components"), 1);
17457
+ var TextBlockWrapper = import_styled_components4.default.div`
17458
+ ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};
17459
+ color: ${colors["brown-100"]};
17460
+ word-break: break-word;
17461
+
17462
+ & h1 {
17463
+ ${typographyMixin(typographyTypes.GEIST_HEADING_S_BOLD)};
17464
+ margin-block: 20px;
17465
+ }
17466
+
17467
+ & h2 {
17468
+ ${typographyMixin(typographyTypes.GEIST_BODY_L_SEMI_BOLD)};
17469
+ margin-block: 12px;
17470
+ }
17471
+
17472
+ & h3,
17473
+ & h4,
17474
+ & h5,
17475
+ & h6 {
17476
+ ${typographyMixin(typographyTypes.GEIST_BODY_M_SEMI_BOLD)};
17477
+ margin-block: 8px;
17478
+ }
17479
+
17480
+ & strong {
17481
+ ${typographyMixin(typographyTypes.GEIST_BODY_S_SEMI_BOLD)};
17482
+ }
17483
+
17484
+ & p {
17485
+ margin-block: 0px;
17486
+ }
17487
+
17488
+ & p + p {
17489
+ margin-block: 8px 0px;
17490
+ }
17491
+
17492
+ & ul,
17493
+ & ol {
17494
+ margin-block: 16px;
17495
+ padding-left: 20px;
17496
+ }
17497
+
17498
+ & li + li {
17499
+ margin-block: 4px;
17500
+ }
17501
+
17502
+ & ol {
17503
+ list-style-type: decimal;
17504
+ }
17505
+
17506
+ & ol ol {
17507
+ list-style-type: lower-alpha;
17508
+ }
17509
+
17510
+ & ol ol ol {
17511
+ list-style-type: lower-roman;
17512
+ }
17513
+
17514
+ & a {
17515
+ color: inherit;
17516
+ text-decoration-line: underline;
17517
+ text-decoration-style: dotted;
17518
+ text-decoration-thickness: auto;
17519
+ text-underline-offset: auto;
17520
+ text-underline-position: from-font;
17521
+ transition: color 75ms ease-in-out;
17522
+
17523
+ &:hover {
17524
+ color: ${colors["blue-600"]};
17525
+ }
17526
+ }
17527
+
17528
+ & hr {
17529
+ border: none;
17530
+ border-top: 1px solid ${colors["brown-40"]};
17531
+ margin-block: 20px;
17532
+ }
17533
+
17534
+ & table {
17535
+ margin: 0;
17536
+ width: 100%;
17537
+ border-collapse: collapse;
17538
+ }
17539
+
17540
+ & th,
17541
+ & td {
17542
+ border: none;
17543
+ border-bottom: 1px solid ${colors["brown-40"]};
17544
+ text-align: left;
17545
+ }
17546
+
17547
+ & th {
17548
+ ${typographyMixin(typographyTypes.GEIST_LABEL_CAPTION_MEDIUM)};
17549
+ padding: 8px;
17550
+ }
17551
+
17552
+ & td {
17553
+ ${typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM)};
17554
+ padding: 16px 8px;
17555
+ min-width: 150px;
17556
+ width: 1%;
17557
+ }
17558
+
17559
+ & td strong {
17560
+ font-weight: inherit;
17561
+ font-size: inherit;
17562
+ line-height: inherit;
17563
+ }
17564
+
17565
+ & blockquote {
17566
+ margin-block: 4px;
17567
+ margin-inline: 0px;
17568
+ padding-left: 16px;
17569
+ border-left: 4px solid ${colors["brown-40"]};
17570
+ color: ${colors["brown-80"]};
17571
+ }
17572
+ `;
17573
+
17574
+ // src/components/blocks/text-block/text-block.tsx
17575
+ var import_jsx_runtime11 = require("react/jsx-runtime");
17576
+ var markdownComponents = {
17577
+ table: ((tableProps) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScrollableTable, { ...tableProps }))
17578
+ };
17579
+ function TextBlock({ block }) {
17580
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TextBlockWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default, import_remark_breaks.default], components: markdownComponents, children: sanitize(block.payload.text) }) });
17581
+ }
17582
+
17583
+ // src/components/blocks/block-services/text-block-service.ts
17584
+ var TextBlockService = {
17585
+ type: blockTypes.TEXT,
17586
+ Component: TextBlock,
17587
+ /**
17588
+ * Converts the block's markdown source to plain text so the final clipboard value is clean
17589
+ * when pasted into tools that don't render markdown. Each block type owns its own clipboard
17590
+ * conversion so `useCopyToClipboard` can write text verbatim without a second pass.
17591
+ */
17592
+ toClipboardText: (block) => markdownToPlainText(block.payload.text)
17593
+ };
17594
+
17595
+ // src/components/blocks/block-services/index.ts
17596
+ var BlockServices = {
17597
+ [blockTypes.TEXT]: TextBlockService,
17598
+ [blockTypes.ARTIFACT_REF]: ArtifactRefBlockService
17599
+ };
17600
+
17601
+ // src/components/blocks/block/block.tsx
17602
+ var import_jsx_runtime12 = require("react/jsx-runtime");
17603
+ function Block({ block }) {
17604
+ const service = BlockServices[block.type];
17605
+ if (!service) return null;
17606
+ const { Component } = service;
17607
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Component, { block });
17608
+ }
17609
+
17610
+ // src/components/blocks/block-context/block-context.tsx
17611
+ var import_react8 = require("react");
17612
+ var BlockContext = (0, import_react8.createContext)(null);
17613
+ function useBlockContext() {
17614
+ return (0, import_react8.useContext)(BlockContext) ?? {};
17615
+ }
17616
+
17617
+ // src/components/chat/chat-message/chat-message.tsx
17618
+ var import_react12 = require("react");
17619
+
17620
+ // src/components/chat/hooks/copy-message-text.ts
17621
+ function copyMessageText(message) {
17622
+ const parts = [];
17623
+ for (const block of message.blocks) {
17624
+ const service = BlockServices[block.type];
17625
+ if (!service) continue;
17626
+ if (!service.toClipboardText) continue;
17627
+ const text2 = service.toClipboardText(block);
17628
+ if (text2) parts.push(text2);
17629
+ }
17630
+ if (parts.length === 0) return message.fallbackText;
17631
+ return parts.join("\n\n");
17632
+ }
17633
+
17634
+ // src/components/chat/chat-message-actions/chat-message-actions.tsx
17635
+ var import_react11 = require("react");
17636
+
17637
+ // src/components/chat/chat-context/chat-context.ts
17638
+ var import_react9 = require("react");
17639
+ var ChatContext = (0, import_react9.createContext)(null);
17640
+ function useChatContext() {
17641
+ const context = (0, import_react9.useContext)(ChatContext);
17642
+ if (!context) {
17643
+ throw new Error("useChatContext must be used within a Chat.Root component");
17644
+ }
17645
+ return context;
17646
+ }
17647
+
17648
+ // src/components/chat/hooks/use-copy-to-clipboard.ts
17649
+ var import_react10 = require("react");
17650
+
17651
+ // src/utils/clipboard.ts
17652
+ function copyToClipboard(text2, options) {
17653
+ navigator.clipboard.writeText(text2).then(
17654
+ () => options?.onSuccess?.(),
17655
+ (error) => options?.onFailure?.(error)
17656
+ );
17657
+ }
17658
+
17174
17659
  // src/components/chat/hooks/use-copy-to-clipboard.ts
17175
17660
  var RESET_DELAY_MS = 2e3;
17176
17661
  function useCopyToClipboard() {
17177
- const [isCopied, setIsCopied] = (0, import_react5.useState)(false);
17178
- const timeoutRef = (0, import_react5.useRef)(null);
17179
- (0, import_react5.useEffect)(() => {
17662
+ const [isCopied, setIsCopied] = (0, import_react10.useState)(false);
17663
+ const timeoutRef = (0, import_react10.useRef)(null);
17664
+ (0, import_react10.useEffect)(() => {
17180
17665
  return () => {
17181
17666
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
17182
17667
  };
17183
17668
  }, []);
17184
- const copy = (0, import_react5.useCallback)((text2) => {
17185
- copyToClipboard(markdownToPlainText(text2), {
17669
+ const copy = (0, import_react10.useCallback)((text2) => {
17670
+ copyToClipboard(text2, {
17186
17671
  onSuccess: () => {
17187
17672
  setIsCopied(true);
17188
17673
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
@@ -17221,24 +17706,24 @@ var AnimatedAction = import_styled_components5.default.div`
17221
17706
  `;
17222
17707
 
17223
17708
  // src/components/chat/chat-message-actions/chat-message-actions.tsx
17224
- var import_jsx_runtime5 = require("react/jsx-runtime");
17709
+ var import_jsx_runtime13 = require("react/jsx-runtime");
17225
17710
  function ChatMessageActions({ className, messageId, content: content2, role, isHelpful }) {
17226
17711
  const { onCopyMessage, onThumbUpClick, onThumbDownClick } = useChatContext();
17227
17712
  const { isCopied, copy } = useCopyToClipboard();
17228
- const handleCopy = (0, import_react6.useCallback)(() => {
17713
+ const handleCopy = (0, import_react11.useCallback)(() => {
17229
17714
  copy(content2);
17230
17715
  onCopyMessage?.(messageId);
17231
17716
  }, [content2, messageId, copy, onCopyMessage]);
17232
- const handleThumbUp = (0, import_react6.useCallback)(() => {
17717
+ const handleThumbUp = (0, import_react11.useCallback)(() => {
17233
17718
  onThumbUpClick?.(messageId, isHelpful === true ? null : true);
17234
17719
  }, [messageId, isHelpful, onThumbUpClick]);
17235
- const handleThumbDown = (0, import_react6.useCallback)(() => {
17720
+ const handleThumbDown = (0, import_react11.useCallback)(() => {
17236
17721
  onThumbDownClick?.(messageId, isHelpful === false ? null : false);
17237
17722
  }, [messageId, isHelpful, onThumbDownClick]);
17238
17723
  const isAssistant = role === MESSAGE_ROLE.ASSISTANT;
17239
17724
  const hasFeedback = isAssistant && (onThumbUpClick || onThumbDownClick);
17240
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ActionsContainer, { $role: role, className, children: [
17241
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
17725
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ActionsContainer, { $role: role, className, children: [
17726
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
17242
17727
  IconButton,
17243
17728
  {
17244
17729
  icon: isCopied ? IconCheck : IconCopy,
@@ -17246,7 +17731,7 @@ function ChatMessageActions({ className, messageId, content: content2, role, isH
17246
17731
  "aria-label": isCopied ? "Copied" : "Copy message"
17247
17732
  }
17248
17733
  ),
17249
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
17734
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
17250
17735
  IconButton,
17251
17736
  {
17252
17737
  icon: IconThumbUp,
@@ -17255,7 +17740,7 @@ function ChatMessageActions({ className, messageId, content: content2, role, isH
17255
17740
  "aria-label": "Good response"
17256
17741
  }
17257
17742
  ) }),
17258
- hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
17743
+ hasFeedback && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
17259
17744
  IconButton,
17260
17745
  {
17261
17746
  icon: IconThumbDown,
@@ -17293,19 +17778,28 @@ var MessageBubble = import_styled_components6.default.div`
17293
17778
  padding: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "12px 16px" : "0"};
17294
17779
  border-radius: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "16px" : "0"};
17295
17780
  max-width: 100%;
17781
+ width: 100%;
17296
17782
  min-width: 0;
17783
+ /* Vertical rhythm between consecutive blocks — renderer-owned, not agent-emitted.
17784
+ * Industry standard (Claude, ChatGPT, Vercel AI Elements): the chat renderer applies
17785
+ * spacing via CSS; agents emit semantic blocks only. Value matches the MessageContainer
17786
+ * gap. TODO: replace 12px with a clay spacing token when a spacing scale is added. */
17787
+ display: flex;
17788
+ flex-direction: column;
17789
+ gap: 12px;
17297
17790
  `;
17298
17791
 
17299
17792
  // src/components/chat/chat-message/chat-message.tsx
17300
- var import_jsx_runtime6 = require("react/jsx-runtime");
17793
+ var import_jsx_runtime14 = require("react/jsx-runtime");
17301
17794
  function ChatMessage({ message }) {
17302
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(MessageContainer, { $role: message.role, children: [
17303
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { $role: message.role, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChatMessageContent, { content: message.content, messageId: message.id }) }),
17304
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
17795
+ const clipboardText = (0, import_react12.useMemo)(() => copyMessageText(message), [message]);
17796
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(MessageContainer, { $role: message.role, children: [
17797
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageBubble, { $role: message.role, "data-testid": "message-bubble", children: message.blocks.map((block, index2) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Block, { block }, index2)) }),
17798
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
17305
17799
  ChatMessageActions,
17306
17800
  {
17307
17801
  messageId: message.id,
17308
- content: message.content,
17802
+ content: clipboardText,
17309
17803
  role: message.role,
17310
17804
  isHelpful: message.isHelpful
17311
17805
  }
@@ -17350,20 +17844,20 @@ var Key = import_styled_components7.default.kbd`
17350
17844
  `;
17351
17845
 
17352
17846
  // src/components/keyboard-shortcut/keyboard-shortcut.tsx
17353
- var import_jsx_runtime7 = require("react/jsx-runtime");
17847
+ var import_jsx_runtime15 = require("react/jsx-runtime");
17354
17848
  function KeyboardShortcut({
17355
17849
  keys,
17356
17850
  variant = KEYBOARD_SHORTCUT_VARIANTS.OUTLINED,
17357
17851
  className
17358
17852
  }) {
17359
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Wrapper, { className, children: keys.map((KeyComponent, index2) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Key, { $variant: variant, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { icon: KeyComponent, size: 12 }) }, index2)) });
17853
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Wrapper, { className, children: keys.map((KeyComponent, index2) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Key, { $variant: variant, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { icon: KeyComponent, size: 12 }) }, index2)) });
17360
17854
  }
17361
17855
 
17362
17856
  // src/components/keyboard-shortcut/icons/icon-ctrl.tsx
17363
- var import_jsx_runtime8 = require("react/jsx-runtime");
17857
+ var import_jsx_runtime16 = require("react/jsx-runtime");
17364
17858
  function IconCtrl(props) {
17365
17859
  const { width: width2 = 24, height: height2 = 24, ...rest } = props;
17366
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: width2, height: height2, fill: "none", ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
17860
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: width2, height: height2, fill: "none", ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
17367
17861
  "text",
17368
17862
  {
17369
17863
  x: "50%",
@@ -17380,7 +17874,7 @@ function IconCtrl(props) {
17380
17874
  }
17381
17875
 
17382
17876
  // src/components/lottie/lottie.tsx
17383
- var import_react8 = require("react");
17877
+ var import_react14 = require("react");
17384
17878
 
17385
17879
  // src/components/lottie/lottie-styles.ts
17386
17880
  var import_styled_components8 = __toESM(require("styled-components"), 1);
@@ -17396,7 +17890,7 @@ var LottieContainer = import_styled_components8.default.div`
17396
17890
  `;
17397
17891
 
17398
17892
  // src/components/lottie/use-lottie.ts
17399
- var import_react7 = require("react");
17893
+ var import_react13 = require("react");
17400
17894
  var import_lottie_web = __toESM(require_lottie(), 1);
17401
17895
  function useLottie({
17402
17896
  animationData: animationData2,
@@ -17411,17 +17905,17 @@ function useLottie({
17411
17905
  onLoopComplete,
17412
17906
  onEnterFrame
17413
17907
  }) {
17414
- const containerRef = (0, import_react7.useRef)(null);
17415
- const animationRef = (0, import_react7.useRef)(null);
17416
- const onAnimationLoadedRef = (0, import_react7.useRef)(onAnimationLoaded);
17417
- const onCompleteRef = (0, import_react7.useRef)(onComplete);
17418
- const onLoopCompleteRef = (0, import_react7.useRef)(onLoopComplete);
17419
- const onEnterFrameRef = (0, import_react7.useRef)(onEnterFrame);
17908
+ const containerRef = (0, import_react13.useRef)(null);
17909
+ const animationRef = (0, import_react13.useRef)(null);
17910
+ const onAnimationLoadedRef = (0, import_react13.useRef)(onAnimationLoaded);
17911
+ const onCompleteRef = (0, import_react13.useRef)(onComplete);
17912
+ const onLoopCompleteRef = (0, import_react13.useRef)(onLoopComplete);
17913
+ const onEnterFrameRef = (0, import_react13.useRef)(onEnterFrame);
17420
17914
  onAnimationLoadedRef.current = onAnimationLoaded;
17421
17915
  onCompleteRef.current = onComplete;
17422
17916
  onLoopCompleteRef.current = onLoopComplete;
17423
17917
  onEnterFrameRef.current = onEnterFrame;
17424
- (0, import_react7.useEffect)(() => {
17918
+ (0, import_react13.useEffect)(() => {
17425
17919
  if (!containerRef.current) return;
17426
17920
  const anim = import_lottie_web.default.loadAnimation({
17427
17921
  container: containerRef.current,
@@ -17513,8 +18007,8 @@ function createLottieRef(animationRef) {
17513
18007
  }
17514
18008
 
17515
18009
  // src/components/lottie/lottie.tsx
17516
- var import_jsx_runtime9 = require("react/jsx-runtime");
17517
- var Lottie = (0, import_react8.forwardRef)(function Lottie2({
18010
+ var import_jsx_runtime17 = require("react/jsx-runtime");
18011
+ var Lottie = (0, import_react14.forwardRef)(function Lottie2({
17518
18012
  animationData: animationData2,
17519
18013
  autoplay,
17520
18014
  loop,
@@ -17544,8 +18038,8 @@ var Lottie = (0, import_react8.forwardRef)(function Lottie2({
17544
18038
  onLoopComplete,
17545
18039
  onEnterFrame
17546
18040
  });
17547
- (0, import_react8.useImperativeHandle)(ref, () => createLottieRef(animationRef), [animationRef]);
17548
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
18041
+ (0, import_react14.useImperativeHandle)(ref, () => createLottieRef(animationRef), [animationRef]);
18042
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
17549
18043
  LottieContainer,
17550
18044
  {
17551
18045
  ref: containerRef,
@@ -17559,7 +18053,7 @@ var Lottie = (0, import_react8.forwardRef)(function Lottie2({
17559
18053
  });
17560
18054
 
17561
18055
  // src/components/text-area/text-area.tsx
17562
- var import_react9 = require("react");
18056
+ var import_react15 = require("react");
17563
18057
 
17564
18058
  // src/utils/merge-refs.ts
17565
18059
  function mergeRefs(...refs) {
@@ -17599,23 +18093,23 @@ var StyledTextArea = import_styled_components9.default.textarea`
17599
18093
  `;
17600
18094
 
17601
18095
  // src/components/text-area/text-area.tsx
17602
- var import_jsx_runtime10 = require("react/jsx-runtime");
17603
- var TextArea = (0, import_react9.forwardRef)(function TextArea2({ value: value2, onChange, placeholder, maxHeight, rows = 1, autoFocus, onKeyDown, disabled, className }, externalRef) {
17604
- const internalRef = (0, import_react9.useRef)(null);
17605
- (0, import_react9.useLayoutEffect)(() => {
18096
+ var import_jsx_runtime18 = require("react/jsx-runtime");
18097
+ var TextArea = (0, import_react15.forwardRef)(function TextArea2({ value: value2, onChange, placeholder, maxHeight, rows = 1, autoFocus, onKeyDown, disabled, className }, externalRef) {
18098
+ const internalRef = (0, import_react15.useRef)(null);
18099
+ (0, import_react15.useLayoutEffect)(() => {
17606
18100
  const el = internalRef.current;
17607
18101
  if (el) {
17608
18102
  el.style.height = "auto";
17609
18103
  el.style.height = `${el.scrollHeight}px`;
17610
18104
  }
17611
18105
  }, [value2]);
17612
- const handleChange = (0, import_react9.useCallback)(
18106
+ const handleChange = (0, import_react15.useCallback)(
17613
18107
  (e) => {
17614
18108
  onChange(e.target.value);
17615
18109
  },
17616
18110
  [onChange]
17617
18111
  );
17618
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
18112
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
17619
18113
  StyledTextArea,
17620
18114
  {
17621
18115
  ref: mergeRefs(internalRef, externalRef),
@@ -17685,21 +18179,26 @@ function parseMarkdownTable(markdown, tableIndex = 0) {
17685
18179
  return null;
17686
18180
  }
17687
18181
 
17688
- // src/utils/convert-table-to-csv.ts
17689
- function escapeField(field) {
17690
- if (field.includes(",") || field.includes('"') || field.includes("\n") || field.includes("\r")) {
17691
- return `"${field.replace(/"/g, '""')}"`;
18182
+ // src/utils/escape-csv-field.ts
18183
+ var FORMULA_TRIGGERS = /* @__PURE__ */ new Set(["=", "+", "@", " ", "\r"]);
18184
+ function escapeCsvField(field) {
18185
+ const needsNeutralise = field.length > 0 && FORMULA_TRIGGERS.has(field[0]);
18186
+ const safeField = needsNeutralise ? ` ${field}` : field;
18187
+ if (needsNeutralise || safeField.includes(",") || safeField.includes('"') || safeField.includes("\n") || safeField.includes("\r")) {
18188
+ return `"${safeField.replace(/"/g, '""')}"`;
17692
18189
  }
17693
- return field;
18190
+ return safeField;
17694
18191
  }
18192
+
18193
+ // src/utils/convert-table-to-csv.ts
17695
18194
  function convertTableToCSV(table) {
17696
- const headerRow = table.columns.map(escapeField).join(",");
17697
- const dataRows = table.rows.map((row) => row.map(escapeField).join(","));
18195
+ const headerRow = table.columns.map(escapeCsvField).join(",");
18196
+ const dataRows = table.rows.map((row) => row.map(escapeCsvField).join(","));
17698
18197
  return [headerRow, ...dataRows].join("\r\n");
17699
18198
  }
17700
18199
 
17701
18200
  // src/components/button/button.tsx
17702
- var import_react10 = require("react");
18201
+ var import_react16 = require("react");
17703
18202
 
17704
18203
  // src/components/button/button-styles.ts
17705
18204
  var import_styled_components10 = __toESM(require("styled-components"), 1);
@@ -17821,8 +18320,8 @@ var StyledButton = import_styled_components10.default.button`
17821
18320
  `;
17822
18321
 
17823
18322
  // src/components/button/button.tsx
17824
- var import_jsx_runtime11 = require("react/jsx-runtime");
17825
- var Button2 = (0, import_react10.forwardRef)(function Button3({
18323
+ var import_jsx_runtime19 = require("react/jsx-runtime");
18324
+ var Button2 = (0, import_react16.forwardRef)(function Button3({
17826
18325
  children,
17827
18326
  variant = BUTTON_VARIANT.SOLID,
17828
18327
  intent = BUTTON_INTENT.PRIMARY,
@@ -17834,8 +18333,8 @@ var Button2 = (0, import_react10.forwardRef)(function Button3({
17834
18333
  className,
17835
18334
  "aria-label": ariaLabel
17836
18335
  }, ref) {
17837
- const iconElement = icon ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { icon, size: 16 }) : null;
17838
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
18336
+ const iconElement = icon ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Icon, { icon, size: 16 }) : null;
18337
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
17839
18338
  StyledButton,
17840
18339
  {
17841
18340
  ref,
@@ -17849,7 +18348,7 @@ var Button2 = (0, import_react10.forwardRef)(function Button3({
17849
18348
  "aria-label": ariaLabel,
17850
18349
  children: [
17851
18350
  iconPosition === ICON_POSITION.LEADING && iconElement,
17852
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children }),
18351
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children }),
17853
18352
  iconPosition === ICON_POSITION.TRAILING && iconElement
17854
18353
  ]
17855
18354
  }
@@ -17857,9 +18356,16 @@ var Button2 = (0, import_react10.forwardRef)(function Button3({
17857
18356
  });
17858
18357
  // Annotate the CommonJS export names for ESM import in node:
17859
18358
  0 && (module.exports = {
18359
+ ArtifactDownloadButton,
18360
+ ArtifactRefBlock,
18361
+ ArtifactRefBlockService,
18362
+ ArtifactServices,
17860
18363
  BUTTON_INTENT,
17861
18364
  BUTTON_SIZE,
17862
18365
  BUTTON_VARIANT,
18366
+ Block,
18367
+ BlockContext,
18368
+ BlockServices,
17863
18369
  Button,
17864
18370
  ChatContext,
17865
18371
  ChatMessage,
@@ -17871,16 +18377,25 @@ var Button2 = (0, import_react10.forwardRef)(function Button3({
17871
18377
  KeyboardShortcut,
17872
18378
  Lottie,
17873
18379
  MESSAGE_ROLE,
18380
+ TableArtifact,
17874
18381
  TextArea,
18382
+ TextBlockService,
18383
+ artifactToClipboardText,
18384
+ artifactTypes,
18385
+ blockTypes,
17875
18386
  colors,
17876
18387
  convertTableToCSV,
18388
+ copyMessageText,
18389
+ escapeCsvField,
17877
18390
  fontFamilies,
18391
+ isSafeDownloadUrl,
17878
18392
  markdownToPlainText,
17879
18393
  mergeRefs,
17880
18394
  parseMarkdownTable,
17881
18395
  typographyMixin,
17882
18396
  typographyStyles,
17883
18397
  typographyTypes,
18398
+ useBlockContext,
17884
18399
  useChatContext,
17885
18400
  useCopyToClipboard
17886
18401
  });
@@ -17900,6 +18415,7 @@ lottie-web/build/player/lottie.js:
17900
18415
  @tabler/icons-react/dist/esm/createReactComponent.mjs:
17901
18416
  @tabler/icons-react/dist/esm/icons/IconCheck.mjs:
17902
18417
  @tabler/icons-react/dist/esm/icons/IconCopy.mjs:
18418
+ @tabler/icons-react/dist/esm/icons/IconDownload.mjs:
17903
18419
  @tabler/icons-react/dist/esm/icons/IconThumbDown.mjs:
17904
18420
  @tabler/icons-react/dist/esm/icons/IconThumbUp.mjs:
17905
18421
  @tabler/icons-react/dist/esm/tabler-icons-react.mjs: