@shapesos/clay 0.18.0 → 0.19.1

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 (60) hide show
  1. package/dist/artifacts.cjs +207 -139
  2. package/dist/artifacts.cjs.map +1 -1
  3. package/dist/artifacts.js +5 -2
  4. package/dist/badge.cjs +70 -0
  5. package/dist/badge.cjs.map +1 -0
  6. package/dist/badge.d.cts +28 -0
  7. package/dist/badge.d.ts +28 -0
  8. package/dist/badge.js +9 -0
  9. package/dist/badge.js.map +1 -0
  10. package/dist/blocks.cjs +452 -185
  11. package/dist/blocks.cjs.map +1 -1
  12. package/dist/blocks.css +1 -1
  13. package/dist/blocks.d.cts +14 -3
  14. package/dist/blocks.d.ts +14 -3
  15. package/dist/blocks.js +17 -5
  16. package/dist/chat.cjs +457 -240
  17. package/dist/chat.cjs.map +1 -1
  18. package/dist/chat.d.cts +1 -1
  19. package/dist/chat.d.ts +1 -1
  20. package/dist/chat.js +10 -5
  21. package/dist/{chunk-JGMN6W72.js → chunk-2X4KUXYP.js} +1 -1
  22. package/dist/{chunk-QR4VBGK4.js → chunk-63AGNGKG.js} +81 -200
  23. package/dist/chunk-63AGNGKG.js.map +1 -0
  24. package/dist/chunk-CSTCTO3B.js +161 -0
  25. package/dist/chunk-CSTCTO3B.js.map +1 -0
  26. package/dist/chunk-EIAWZXE4.js +69 -0
  27. package/dist/chunk-EIAWZXE4.js.map +1 -0
  28. package/dist/chunk-EXRNGIQ2.js +41 -0
  29. package/dist/chunk-EXRNGIQ2.js.map +1 -0
  30. package/dist/{chunk-4MZZH3WX.js → chunk-HU5W7CGE.js} +37 -2
  31. package/dist/chunk-HU5W7CGE.js.map +1 -0
  32. package/dist/chunk-PISZYS2H.js +406 -0
  33. package/dist/chunk-PISZYS2H.js.map +1 -0
  34. package/dist/{chunk-CATIRDZP.js → chunk-PWSEEUVL.js} +10 -44
  35. package/dist/chunk-PWSEEUVL.js.map +1 -0
  36. package/dist/copy-button.cjs +439 -0
  37. package/dist/copy-button.cjs.map +1 -0
  38. package/dist/copy-button.d.cts +20 -0
  39. package/dist/copy-button.d.ts +20 -0
  40. package/dist/copy-button.js +12 -0
  41. package/dist/copy-button.js.map +1 -0
  42. package/dist/index.cjs +533 -298
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.cts +4 -2
  45. package/dist/index.d.ts +4 -2
  46. package/dist/index.js +26 -9
  47. package/dist/table.cjs +40 -0
  48. package/dist/table.cjs.map +1 -1
  49. package/dist/table.d.cts +37 -2
  50. package/dist/table.d.ts +37 -2
  51. package/dist/table.js +11 -1
  52. package/dist/{types-BDYPVP2N.d.cts → types-Bhg0_ES8.d.cts} +74 -2
  53. package/dist/{types-BMwa4bPW.d.ts → types-orOQcI2z.d.ts} +74 -2
  54. package/package.json +11 -1
  55. package/dist/chunk-4MZZH3WX.js.map +0 -1
  56. package/dist/chunk-7MY4X4YL.js +0 -250
  57. package/dist/chunk-7MY4X4YL.js.map +0 -1
  58. package/dist/chunk-CATIRDZP.js.map +0 -1
  59. package/dist/chunk-QR4VBGK4.js.map +0 -1
  60. /package/dist/{chunk-JGMN6W72.js.map → chunk-2X4KUXYP.js.map} +0 -0
@@ -1,250 +0,0 @@
1
- import {
2
- markdownToPlainText
3
- } from "./chunk-NMKKU2UG.js";
4
- import {
5
- ArtifactServices,
6
- artifactToClipboardText
7
- } from "./chunk-QR4VBGK4.js";
8
- import {
9
- typographyMixin,
10
- typographyTypes
11
- } from "./chunk-UXT2H3FM.js";
12
- import {
13
- colors
14
- } from "./chunk-SN3ORQSJ.js";
15
-
16
- // src/components/blocks/types.ts
17
- var blockTypes = {
18
- TEXT: "TEXT",
19
- ARTIFACT_REF: "ARTIFACT_REF"
20
- };
21
-
22
- // src/components/blocks/artifact-ref-block/artifact-ref-block.tsx
23
- import { jsx } from "react/jsx-runtime";
24
- function ArtifactRefBlock({ block }) {
25
- const { artifact, labels, callbacks } = block.payload;
26
- const entry = ArtifactServices[artifact.type];
27
- if (!entry) return null;
28
- const Component = entry.Component;
29
- return /* @__PURE__ */ jsx(Component, { artifact, labels, callbacks });
30
- }
31
-
32
- // src/components/blocks/block-services/artifact-ref-block-service.ts
33
- var ArtifactRefBlockService = {
34
- type: blockTypes.ARTIFACT_REF,
35
- Component: ArtifactRefBlock,
36
- /**
37
- * Delegates to the registered artifact component's `toClipboardText`. Falls back to
38
- * `[Artifact: <title>]` via `artifactToClipboardText`'s own fallback when the artifact type
39
- * has no registered component, so copy never silently produces an empty string.
40
- */
41
- toClipboardText: (block) => artifactToClipboardText(block.payload.artifact)
42
- };
43
-
44
- // src/components/blocks/text-block/text-block.tsx
45
- import ReactMarkdown from "react-markdown";
46
- import remarkBreaks from "remark-breaks";
47
- import remarkGfm from "remark-gfm";
48
-
49
- // src/components/blocks/scrollable-table/scrollable-table-styles.ts
50
- import styled from "styled-components";
51
- var TableContainer = styled.div`
52
- position: relative;
53
- margin-block: 8px 16px;
54
- `;
55
- var TableScroll = styled.div`
56
- width: 100%;
57
- overflow-x: auto;
58
- overflow-y: hidden;
59
- `;
60
-
61
- // src/components/blocks/scrollable-table/scrollable-table.tsx
62
- import { jsx as jsx2 } from "react/jsx-runtime";
63
- function ScrollableTable({ node: _node, ...props }) {
64
- return /* @__PURE__ */ jsx2(TableContainer, { children: /* @__PURE__ */ jsx2(TableScroll, { children: /* @__PURE__ */ jsx2("table", { ...props }) }) });
65
- }
66
-
67
- // src/components/blocks/text-block/sanitize.ts
68
- function sanitize(text) {
69
- return text.split("\n").filter((line) => {
70
- const t = line.trim();
71
- return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
72
- }).join("\n");
73
- }
74
-
75
- // src/components/blocks/text-block/text-block-styles.ts
76
- import styled2 from "styled-components";
77
- var TextBlockWrapper = styled2.div`
78
- ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};
79
- color: ${colors["brown-100"]};
80
- word-break: break-word;
81
-
82
- & h1 {
83
- ${typographyMixin(typographyTypes.GEIST_HEADING_S_BOLD)};
84
- margin-block: 20px;
85
- }
86
-
87
- & h2 {
88
- ${typographyMixin(typographyTypes.GEIST_BODY_L_SEMI_BOLD)};
89
- margin-block: 12px;
90
- }
91
-
92
- & h3,
93
- & h4,
94
- & h5,
95
- & h6 {
96
- ${typographyMixin(typographyTypes.GEIST_BODY_M_SEMI_BOLD)};
97
- margin-block: 8px;
98
- }
99
-
100
- & strong {
101
- ${typographyMixin(typographyTypes.GEIST_BODY_S_SEMI_BOLD)};
102
- }
103
-
104
- & p {
105
- margin-block: 0px;
106
- }
107
-
108
- & p + p {
109
- margin-block: 8px 0px;
110
- }
111
-
112
- & ul,
113
- & ol {
114
- margin-block: 16px;
115
- padding-left: 20px;
116
- }
117
-
118
- & li + li {
119
- margin-block: 4px;
120
- }
121
-
122
- & ul {
123
- list-style-type: disc;
124
- }
125
-
126
- & ul ul {
127
- list-style-type: circle;
128
- }
129
-
130
- & ul ul ul {
131
- list-style-type: square;
132
- }
133
-
134
- & ol {
135
- list-style-type: decimal;
136
- }
137
-
138
- & ol ol {
139
- list-style-type: lower-alpha;
140
- }
141
-
142
- & ol ol ol {
143
- list-style-type: lower-roman;
144
- }
145
-
146
- & a {
147
- color: inherit;
148
- text-decoration-line: underline;
149
- text-decoration-style: dotted;
150
- text-decoration-thickness: auto;
151
- text-underline-offset: auto;
152
- text-underline-position: from-font;
153
- transition: color 75ms ease-in-out;
154
-
155
- &:hover {
156
- color: ${colors["blue-600"]};
157
- }
158
- }
159
-
160
- & hr {
161
- border: none;
162
- border-top: 1px solid ${colors["brown-40"]};
163
- margin-block: 20px;
164
- }
165
-
166
- & table {
167
- margin: 0;
168
- width: 100%;
169
- border-collapse: collapse;
170
- }
171
-
172
- & th,
173
- & td {
174
- border: none;
175
- border-bottom: 1px solid ${colors["brown-40"]};
176
- text-align: left;
177
- }
178
-
179
- & th {
180
- ${typographyMixin(typographyTypes.GEIST_LABEL_CAPTION_MEDIUM)};
181
- padding: 8px;
182
- }
183
-
184
- & td {
185
- ${typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM)};
186
- padding: 16px 8px;
187
- min-width: 150px;
188
- width: 1%;
189
- }
190
-
191
- & td strong {
192
- font-weight: inherit;
193
- font-size: inherit;
194
- line-height: inherit;
195
- }
196
-
197
- & blockquote {
198
- margin-block: 4px;
199
- margin-inline: 0px;
200
- padding-left: 16px;
201
- border-left: 4px solid ${colors["brown-40"]};
202
- color: ${colors["brown-80"]};
203
- }
204
- `;
205
-
206
- // src/components/blocks/text-block/text-block.tsx
207
- import { jsx as jsx3 } from "react/jsx-runtime";
208
- var markdownComponents = {
209
- table: ((tableProps) => /* @__PURE__ */ jsx3(ScrollableTable, { ...tableProps }))
210
- };
211
- function TextBlock({ block }) {
212
- return /* @__PURE__ */ jsx3(TextBlockWrapper, { children: /* @__PURE__ */ jsx3(ReactMarkdown, { remarkPlugins: [remarkGfm, remarkBreaks], components: markdownComponents, children: sanitize(block.payload.text) }) });
213
- }
214
-
215
- // src/components/blocks/block-services/text-block-service.ts
216
- var TextBlockService = {
217
- type: blockTypes.TEXT,
218
- Component: TextBlock,
219
- /**
220
- * Converts the block's markdown source to plain text so the final clipboard value is clean
221
- * when pasted into tools that don't render markdown. Each block type owns its own clipboard
222
- * conversion so `useCopyToClipboard` can write text verbatim without a second pass.
223
- */
224
- toClipboardText: (block) => markdownToPlainText(block.payload.text)
225
- };
226
-
227
- // src/components/blocks/block-services/index.ts
228
- var BlockServices = {
229
- [blockTypes.TEXT]: TextBlockService,
230
- [blockTypes.ARTIFACT_REF]: ArtifactRefBlockService
231
- };
232
-
233
- // src/components/blocks/block/block.tsx
234
- import { jsx as jsx4 } from "react/jsx-runtime";
235
- function Block({ block }) {
236
- const service = BlockServices[block.type];
237
- if (!service) return null;
238
- const { Component } = service;
239
- return /* @__PURE__ */ jsx4(Component, { block });
240
- }
241
-
242
- export {
243
- blockTypes,
244
- ArtifactRefBlock,
245
- ArtifactRefBlockService,
246
- TextBlockService,
247
- BlockServices,
248
- Block
249
- };
250
- //# sourceMappingURL=chunk-7MY4X4YL.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/blocks/types.ts","../src/components/blocks/artifact-ref-block/artifact-ref-block.tsx","../src/components/blocks/block-services/artifact-ref-block-service.ts","../src/components/blocks/text-block/text-block.tsx","../src/components/blocks/scrollable-table/scrollable-table-styles.ts","../src/components/blocks/scrollable-table/scrollable-table.tsx","../src/components/blocks/text-block/sanitize.ts","../src/components/blocks/text-block/text-block-styles.ts","../src/components/blocks/block-services/text-block-service.ts","../src/components/blocks/block-services/index.ts","../src/components/blocks/block/block.tsx"],"sourcesContent":["import type { ComponentType } from \"react\";\n\nimport type { ArtifactCallbacksOf, ArtifactLabelsOf, ArtifactRecord } from \"@/components/artifacts/types\";\n\n/** Block-type discriminator constants. Mirrors the wire shape from io-server / shapes-agent. */\nexport const blockTypes = {\n TEXT: \"TEXT\",\n ARTIFACT_REF: \"ARTIFACT_REF\",\n} as const;\n\n/** Discriminator for content blocks. */\nexport type BlockType = (typeof blockTypes)[keyof typeof blockTypes];\n\n/** Plain-text content block — rendered as Markdown. */\nexport interface TextBlockRecord {\n /** Block-type discriminator. */\n type: typeof blockTypes.TEXT;\n /** Type-specific data; kept as `payload` to match the wire shape 1:1. */\n payload: {\n /** The Markdown source for this text segment. */\n text: string;\n };\n}\n\n/**\n * Reference-to-an-artifact content block — dispatched to the per-type artifact component.\n *\n * The artifact-domain types (`ArtifactRecord`, `TableArtifactRecord`, etc.) live in\n * `@/components/artifacts/types` so the artifact layer can be consumed independently of the\n * block layer (e.g. by a future surface that renders an artifact outside chat). The block layer\n * imports them here to wrap an artifact in an `ARTIFACT_REF` block.\n *\n * `ArtifactRefBlockRecord` is a *distributed* union over `ArtifactRecord` branches — TS narrows\n * `labels` and `callbacks` to the slice matching `artifact.type` via `ArtifactLabelsOf<T>` /\n * `ArtifactCallbacksOf<T>`. Without this distribution, `Partial<ChartLabels | TableLabels>`\n * collapses to `Partial<ChartLabels> | Partial<TableLabels>` and TS accepts chart-only keys on\n * a TABLE block's payload (the discriminator becomes load-bearing only at runtime, not in the\n * type system).\n */\nexport type ArtifactRefBlockRecord = ArtifactRecord extends infer TArtifact\n ? TArtifact extends ArtifactRecord\n ? {\n /** Block-type discriminator. */\n type: typeof blockTypes.ARTIFACT_REF;\n /** Type-specific data; kept as `payload` to match the wire shape 1:1. */\n payload: {\n /** The artifact's stable identifier, used for keying / future cross-message reuse. */\n artifactId: string;\n /** Inlined artifact metadata — clients fetch the underlying data via `artifact.protectedAsset.presignedUrl`. */\n artifact: TArtifact;\n /**\n * Optional consumer-supplied labels for the rendered artifact's action buttons + status\n * messages — a flat slice narrowed by `artifact.type`. NOT a wire field; the consumer\n * constructs this from their i18n layer when materialising the block-record from the\n * server payload, then passes the augmented block to `<Block>`. The dispatcher forwards\n * the slice directly to the matching renderer — no per-type key wrapping (the block\n * already carries the discriminator).\n *\n * TS catches cross-type assignments here: `block.payload.labels = { downloadCsv: 'X' }`\n * on a `TableArtifactRecord`-typed block is a type error because `downloadCsv` isn't a\n * `TableArtifactLabels` key.\n */\n labels?: Partial<ArtifactLabelsOf<TArtifact>>;\n /**\n * Optional side-effect callbacks for actions on the rendered artifact (e.g. `onDownload`).\n * Flat slice narrowed by `artifact.type` via `ArtifactCallbacksOf<T>`. NOT a wire field\n * — the consumer wires this once to bridge artifact actions to their analytics /\n * observability layer.\n */\n callbacks?: Partial<ArtifactCallbacksOf<TArtifact>>;\n };\n }\n : never\n : never;\n\n/** Discriminated union of all supported content blocks. Additive — new types extend this union. */\nexport type BlockRecord = TextBlockRecord | ArtifactRefBlockRecord;\n\n/** Props every concrete block component receives from the dispatcher. */\nexport interface BlockComponentProps<TBlock extends BlockRecord = BlockRecord> {\n /** The block to render. */\n block: TBlock;\n}\n\n/** Per-block-type service — registry entry that pairs a discriminator with its concrete component. */\nexport interface BlockService<TBlock extends BlockRecord = BlockRecord> {\n /** Discriminator value this service handles. */\n type: BlockType;\n /** React component that renders a block of this type. */\n Component: ComponentType<BlockComponentProps<TBlock>>;\n /**\n * Returns a plain-text or markdown string representation of this block suitable for clipboard\n * copy. Called by `copyMessageText` when the user clicks \"copy message\".\n *\n * - `TextBlockService`: returns `block.payload.text` verbatim (markdown preserved).\n * - `ArtifactRefBlockService`: delegates to `ArtifactServices[artifact.type].toClipboardText`.\n * Falls back to `[Artifact: <title>]` when the artifact type has no registered component.\n *\n * Optional so external `BlockService` implementors don't break on upgrade — when omitted, the\n * aggregator treats the block as contributing the empty string (silently skipped). Implementations\n * must be pure, synchronous functions — no async, no hooks, no side effects.\n */\n toClipboardText?: (block: TBlock) => string;\n}\n","import type { ComponentType, ReactNode } from \"react\";\n\nimport { ArtifactServices } from \"@/components/artifacts/artifact-services\";\nimport type { ArtifactRefBlockRecord, BlockComponentProps } from \"../types\";\n\n/**\n * Renders an `ARTIFACT_REF` block by dispatching the inlined artifact to its per-type component.\n *\n * The cast at the seam is necessary because the registry-based dispatch can't statically prove\n * type-T narrowing — but it's not hiding a bug. `ArtifactRefBlockRecord` is a distributed union\n * over `ArtifactRecord` branches (see `blocks/types.ts`), so TS catches wrong-shape labels at the\n * consumer's construction site: a chart-labels bag assigned to a TABLE block's payload is a type\n * error there, not silently forwarded to the wrong renderer here.\n *\n * Unknown artifact types render as `null` — the map only contains types we know how to render,\n * so an older clay client receiving a future artifact type degrades silently rather than\n * crashing the chat.\n */\nexport function ArtifactRefBlock({ block }: BlockComponentProps<ArtifactRefBlockRecord>): ReactNode {\n const { artifact, labels, callbacks } = block.payload;\n const entry = ArtifactServices[artifact.type];\n if (!entry) return null;\n // The registry stores `ArtifactService<ArtifactRecord>` (the union), so `entry.Component` is\n // `ComponentType<ArtifactServiceProps<ArtifactRecord>>`. The labels/callbacks props in the\n // narrower per-type `ArtifactServiceProps<TArtifact>` are `Partial<ArtifactLabelsOf<TArtifact>>`\n // which the union doesn't satisfy positionally. Cast forwards the values verbatim — the\n // runtime invariant is provably correct because the distributed `ArtifactRefBlockRecord` type\n // enforces it at construction.\n const Component = entry.Component as ComponentType<{\n artifact: typeof artifact;\n labels?: typeof labels;\n callbacks?: typeof callbacks;\n }>;\n return <Component artifact={artifact} labels={labels} callbacks={callbacks} />;\n}\n","import { artifactToClipboardText } from \"@/components/artifacts/artifact-services\";\nimport { ArtifactRefBlock } from \"../artifact-ref-block/artifact-ref-block\";\nimport { blockTypes } from \"../types\";\nimport type { ArtifactRefBlockRecord, BlockService } from \"../types\";\n\nexport const ArtifactRefBlockService: BlockService<ArtifactRefBlockRecord> = {\n type: blockTypes.ARTIFACT_REF,\n Component: ArtifactRefBlock,\n /**\n * Delegates to the registered artifact component's `toClipboardText`. Falls back to\n * `[Artifact: <title>]` via `artifactToClipboardText`'s own fallback when the artifact type\n * has no registered component, so copy never silently produces an empty string.\n */\n toClipboardText: (block) => artifactToClipboardText(block.payload.artifact),\n};\n","import type { ReactNode } from \"react\";\nimport ReactMarkdown from \"react-markdown\";\nimport remarkBreaks from \"remark-breaks\";\nimport remarkGfm from \"remark-gfm\";\n\nimport { ScrollableTable } from \"../scrollable-table/scrollable-table\";\nimport type { BlockComponentProps, TextBlockRecord } from \"../types\";\nimport { sanitize } from \"./sanitize\";\nimport { TextBlockWrapper } from \"./text-block-styles\";\n\nconst markdownComponents = {\n table: ((tableProps: { node?: unknown; children?: ReactNode }) => (\n <ScrollableTable {...tableProps} />\n )) as React.ComponentType<unknown>,\n};\n\n/** Renders a TEXT block as Markdown with GFM (tables, strikethrough) and line breaks. */\nexport function TextBlock({ block }: BlockComponentProps<TextBlockRecord>): ReactNode {\n return (\n <TextBlockWrapper>\n <ReactMarkdown remarkPlugins={[remarkGfm, remarkBreaks]} components={markdownComponents}>\n {sanitize(block.payload.text)}\n </ReactMarkdown>\n </TextBlockWrapper>\n );\n}\n","import styled from \"styled-components\";\n\nexport const TableContainer = styled.div`\n position: relative;\n margin-block: 8px 16px;\n`;\n\nexport const TableScroll = styled.div`\n width: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n`;\n","import { type ReactNode } from \"react\";\n\nimport { TableContainer, TableScroll } from \"./scrollable-table-styles\";\n\n/** Props for the ScrollableTable component. */\ninterface ScrollableTableProps {\n /** Unused node prop from react-markdown. */\n node?: unknown;\n /** Table children elements. */\n children?: ReactNode;\n}\n\n/** Renders a markdown table inside a horizontally scrollable wrapper. Read-only — actions live on artifact-tables. */\nexport function ScrollableTable({ node: _node, ...props }: ScrollableTableProps): ReactNode {\n return (\n <TableContainer>\n <TableScroll>\n <table {...props} />\n </TableScroll>\n </TableContainer>\n );\n}\n","// Strips io-server's `<!-- table-title: ... -->` HTML-comment metadata before rendering.\n// The marker is emitted by the server's CSV-export pipeline so the export button can label\n// the file; it has no place in the visual output. If the server-side format changes\n// (prefix, spacing, closing-tag style), this filter silently stops matching and the\n// raw HTML comment leaks into rendered Markdown — keep this contract aligned with io-server.\nexport function sanitize(text: string): string {\n return text\n .split(\"\\n\")\n .filter((line) => {\n const t = line.trim();\n return !(t.startsWith(\"<!-- table-title:\") && t.endsWith(\"-->\"));\n })\n .join(\"\\n\");\n}\n","import styled from \"styled-components\";\n\nimport { colors } from \"@/tokens/colors\";\nimport { typographyMixin, typographyTypes } from \"@/tokens/typography\";\n\nexport const TextBlockWrapper = styled.div`\n ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};\n color: ${colors[\"brown-100\"]};\n word-break: break-word;\n\n & h1 {\n ${typographyMixin(typographyTypes.GEIST_HEADING_S_BOLD)};\n margin-block: 20px;\n }\n\n & h2 {\n ${typographyMixin(typographyTypes.GEIST_BODY_L_SEMI_BOLD)};\n margin-block: 12px;\n }\n\n & h3,\n & h4,\n & h5,\n & h6 {\n ${typographyMixin(typographyTypes.GEIST_BODY_M_SEMI_BOLD)};\n margin-block: 8px;\n }\n\n & strong {\n ${typographyMixin(typographyTypes.GEIST_BODY_S_SEMI_BOLD)};\n }\n\n & p {\n margin-block: 0px;\n }\n\n & p + p {\n margin-block: 8px 0px;\n }\n\n & ul,\n & ol {\n margin-block: 16px;\n padding-left: 20px;\n }\n\n & li + li {\n margin-block: 4px;\n }\n\n & ul {\n list-style-type: disc;\n }\n\n & ul ul {\n list-style-type: circle;\n }\n\n & ul ul ul {\n list-style-type: square;\n }\n\n & ol {\n list-style-type: decimal;\n }\n\n & ol ol {\n list-style-type: lower-alpha;\n }\n\n & ol ol ol {\n list-style-type: lower-roman;\n }\n\n & a {\n color: inherit;\n text-decoration-line: underline;\n text-decoration-style: dotted;\n text-decoration-thickness: auto;\n text-underline-offset: auto;\n text-underline-position: from-font;\n transition: color 75ms ease-in-out;\n\n &:hover {\n color: ${colors[\"blue-600\"]};\n }\n }\n\n & hr {\n border: none;\n border-top: 1px solid ${colors[\"brown-40\"]};\n margin-block: 20px;\n }\n\n & table {\n margin: 0;\n width: 100%;\n border-collapse: collapse;\n }\n\n & th,\n & td {\n border: none;\n border-bottom: 1px solid ${colors[\"brown-40\"]};\n text-align: left;\n }\n\n & th {\n ${typographyMixin(typographyTypes.GEIST_LABEL_CAPTION_MEDIUM)};\n padding: 8px;\n }\n\n & td {\n ${typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM)};\n padding: 16px 8px;\n min-width: 150px;\n width: 1%;\n }\n\n & td strong {\n font-weight: inherit;\n font-size: inherit;\n line-height: inherit;\n }\n\n & blockquote {\n margin-block: 4px;\n margin-inline: 0px;\n padding-left: 16px;\n border-left: 4px solid ${colors[\"brown-40\"]};\n color: ${colors[\"brown-80\"]};\n }\n`;\n","import { markdownToPlainText } from \"@/utils/markdown-to-plain-text\";\nimport { TextBlock } from \"../text-block/text-block\";\nimport { blockTypes } from \"../types\";\nimport type { BlockService, TextBlockRecord } from \"../types\";\n\nexport const TextBlockService: BlockService<TextBlockRecord> = {\n type: blockTypes.TEXT,\n Component: TextBlock,\n /**\n * Converts the block's markdown source to plain text so the final clipboard value is clean\n * when pasted into tools that don't render markdown. Each block type owns its own clipboard\n * conversion so `useCopyToClipboard` can write text verbatim without a second pass.\n */\n toClipboardText: (block) => markdownToPlainText(block.payload.text),\n};\n","import { blockTypes, type BlockService, type BlockType } from \"../types\";\nimport { ArtifactRefBlockService } from \"./artifact-ref-block-service\";\nimport { TextBlockService } from \"./text-block-service\";\n\n// `BlockService<TBlock>` is invariant on `TBlock` via React's `ComponentType` (props are\n// contravariant). The concrete services overlap structurally with the base `BlockService` type\n// enough for a direct `as BlockService` cast. The registry dispatches by runtime discriminator —\n// `BlockServices[block.type]` always resolves to the matching concrete service — so the cast is sound.\nexport const BlockServices: Record<BlockType, BlockService> = {\n [blockTypes.TEXT]: TextBlockService as BlockService,\n [blockTypes.ARTIFACT_REF]: ArtifactRefBlockService as BlockService,\n};\n","import type { ReactNode } from \"react\";\n\nimport { BlockServices } from \"../block-services\";\nimport type { BlockRecord } from \"../types\";\n\n/** Props for the Block dispatcher. */\ninterface BlockProps {\n /** The block to render. Dispatched to the registered concrete component for its `type`. */\n block: BlockRecord;\n}\n\n/**\n * Dispatches a single block to its registered concrete component. Unknown types render as a no-op.\n *\n * Generic by design: per-block-type extras (e.g. localized artifact labels for `ARTIFACT_REF`)\n * live on the block's `payload`, not as sibling props here. That keeps the dispatcher's contract\n * shallow — third-party `BlockService` implementors only need to handle `{ block }` — and lets\n * the consumer materialise a fully-decorated block once (from the server payload + their i18n\n * layer) instead of threading sibling props through every dispatch site.\n */\nexport function Block({ block }: BlockProps): ReactNode {\n const service = BlockServices[block.type];\n if (!service) return null;\n const { Component } = service;\n return <Component block={block} />;\n}\n"],"mappings":"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","names":["jsx","styled","styled","jsx","jsx"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/chat/chat-message/chat-message.tsx","../src/components/chat/hooks/copy-message-text.ts","../src/components/chat/chat-message-actions/chat-message-actions.tsx","../src/components/chat/chat-context/chat-context.ts","../src/components/chat/hooks/use-copy-to-clipboard.ts","../src/utils/clipboard.ts","../src/components/chat/constants.ts","../src/components/chat/chat-message-actions/chat-message-actions-styles.ts","../src/components/chat/chat-message/chat-message-styles.ts"],"sourcesContent":["import { useMemo } from \"react\";\n\nimport { Block } from \"@/components/blocks/block\";\nimport { copyMessageText } from \"../hooks/copy-message-text\";\nimport type { ChatMessage as ChatMessageType } from \"../types\";\nimport { ChatMessageActions } from \"../chat-message-actions/chat-message-actions\";\nimport { MessageRow, MessageBubble, MessageContainer } from \"./chat-message-styles\";\n\ninterface ChatMessageProps {\n message: ChatMessageType;\n}\n\nexport function ChatMessage({ message }: ChatMessageProps) {\n // Aggregate per-block clipboard text so the copy button produces richer output than the\n // server-supplied `fallbackText` (which is typically \"[table: Title]\" for artifact blocks).\n // `useMemo` keeps the string stable across re-renders that don't change the blocks array.\n const clipboardText = useMemo(() => copyMessageText(message), [message]);\n\n return (\n <MessageRow $role={message.role} role=\"article\" aria-label={`${message.role} message`}>\n <MessageContainer $role={message.role}>\n <MessageBubble $role={message.role} data-testid=\"message-bubble\">\n {message.blocks.map((block, index) => (\n <Block key={index} block={block} />\n ))}\n </MessageBubble>\n <ChatMessageActions\n messageId={message.id}\n content={clipboardText}\n role={message.role}\n isHelpful={message.isHelpful}\n />\n </MessageContainer>\n </MessageRow>\n );\n}\n","import { BlockServices } from \"@/components/blocks/block-services\";\nimport type { ChatMessage } from \"../types\";\n\n/**\n * Aggregates the clipboard text for all blocks in a message.\n *\n * Iterates `message.blocks` in order, calls `BlockServices[block.type].toClipboardText(block)`\n * for each, and joins the results with `\"\\n\\n\"` so multi-block messages have a blank line between\n * each section (matching the visual gap rendered between blocks in the chat UI).\n *\n * Block-type-specific behaviour:\n * - `TEXT` blocks: markdown stripped to plain text via `markdownToPlainText`.\n * - `ARTIFACT_REF` blocks: delegates to the registered artifact component's `toClipboardText`\n * (e.g. the artifact title as plain text for table artifacts).\n * - Unknown block types: silently skipped (no registered service → no contribution to output).\n *\n * Falls back to `message.fallbackText` only when every block produces an empty string — this\n * guards against edge cases (empty message, all-unknown block types) while still preferring\n * the richer per-block text in the normal case.\n *\n * @param message The chat message whose blocks should be aggregated.\n * @returns A string suitable for writing to the system clipboard.\n */\nexport function copyMessageText(message: ChatMessage): string {\n const parts: string[] = [];\n\n for (const block of message.blocks) {\n const service = BlockServices[block.type];\n if (!service) continue;\n // `toClipboardText` is optional on the BlockService interface — external implementors may\n // omit it. Skip silently when absent (contributes \"\" to the aggregated output).\n if (!service.toClipboardText) continue;\n // The registry is keyed by BlockType and each service's toClipboardText is typed to its\n // concrete TBlock. The cast is safe because BlockServices[block.type] is always the matching\n // service for block.type — same soundness argument as the registry's own type erasure.\n const text = (service as { toClipboardText: (b: typeof block) => string }).toClipboardText(block);\n if (text) parts.push(text);\n }\n\n if (parts.length === 0) return message.fallbackText;\n return parts.join(\"\\n\\n\");\n}\n","import { useCallback } from \"react\";\nimport { IconCopy, IconCheck, IconThumbUp, IconThumbDown } from \"@tabler/icons-react\";\n\nimport { IconButton } from \"../../icon-button/icon-button\";\nimport { useChatContext } from \"../chat-context/chat-context\";\nimport { useCopyToClipboard } from \"../hooks/use-copy-to-clipboard\";\nimport { MESSAGE_ROLE } from \"../constants\";\nimport type { MessageRole } from \"../types\";\nimport { ActionsContainer, AnimatedAction } from \"./chat-message-actions-styles\";\n\ninterface ChatMessageActionsProps {\n className?: string;\n messageId: string;\n content: string;\n role: MessageRole;\n isHelpful?: boolean | null;\n}\n\nexport function ChatMessageActions({ className, messageId, content, role, isHelpful }: ChatMessageActionsProps) {\n const { onCopyMessage, onThumbUpClick, onThumbDownClick } = useChatContext();\n const { isCopied, copy } = useCopyToClipboard();\n\n const handleCopy = useCallback(() => {\n copy(content);\n onCopyMessage?.(messageId);\n }, [content, messageId, copy, onCopyMessage]);\n\n const handleThumbUp = useCallback(() => {\n onThumbUpClick?.(messageId, isHelpful === true ? null : true);\n }, [messageId, isHelpful, onThumbUpClick]);\n\n const handleThumbDown = useCallback(() => {\n onThumbDownClick?.(messageId, isHelpful === false ? null : false);\n }, [messageId, isHelpful, onThumbDownClick]);\n\n const isAssistant = role === MESSAGE_ROLE.ASSISTANT;\n const hasFeedback = isAssistant && (onThumbUpClick || onThumbDownClick);\n\n return (\n <ActionsContainer $role={role} className={className}>\n <IconButton\n icon={isCopied ? IconCheck : IconCopy}\n onClick={handleCopy}\n aria-label={isCopied ? \"Copied\" : \"Copy message\"}\n />\n\n {hasFeedback && (\n <AnimatedAction $visible={isHelpful !== false}>\n <IconButton\n icon={IconThumbUp}\n onClick={handleThumbUp}\n isSelected={isHelpful === true}\n aria-label=\"Good response\"\n />\n </AnimatedAction>\n )}\n\n {hasFeedback && (\n <AnimatedAction $visible={isHelpful !== true}>\n <IconButton\n icon={IconThumbDown}\n onClick={handleThumbDown}\n isSelected={isHelpful === false}\n aria-label=\"Bad response\"\n />\n </AnimatedAction>\n )}\n </ActionsContainer>\n );\n}\n","import { createContext, useContext } from \"react\";\nimport type { ChatContextValue } from \"../types\";\n\nexport const ChatContext = createContext<ChatContextValue | null>(null);\n\nexport function useChatContext(): ChatContextValue {\n const context = useContext(ChatContext);\n if (!context) {\n throw new Error(\"useChatContext must be used within a Chat.Root component\");\n }\n return context;\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\n\nimport { copyToClipboard } from \"@/utils/clipboard\";\n\nconst RESET_DELAY_MS = 2000;\n\ninterface UseCopyToClipboardResult {\n isCopied: boolean;\n copy: (text: string) => void;\n}\n\nexport function useCopyToClipboard(): UseCopyToClipboardResult {\n const [isCopied, setIsCopied] = useState(false);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n // Write text verbatim — callers (copyMessageText + each BlockService.toClipboardText) are\n // responsible for converting their own format to clipboard-ready plain text.\n const copy = useCallback((text: string) => {\n copyToClipboard(text, {\n onSuccess: () => {\n setIsCopied(true);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => {\n setIsCopied(false);\n timeoutRef.current = null;\n }, RESET_DELAY_MS);\n },\n });\n }, []);\n\n return { isCopied, copy };\n}\n","/** Options for the {@link copyToClipboard} function. */\ninterface CopyToClipboardOptions {\n /** Called after the text has been successfully written to the clipboard. */\n onSuccess?: () => void;\n /** Called if the clipboard write fails (e.g., permission denied). */\n onFailure?: (error: unknown) => void;\n}\n\n/**\n * Copies text to the system clipboard using the Clipboard API.\n * @param text - The string to copy.\n * @param options - Optional success/failure callbacks.\n */\nexport function copyToClipboard(text: string, options?: CopyToClipboardOptions): void {\n navigator.clipboard.writeText(text).then(\n () => options?.onSuccess?.(),\n (error) => options?.onFailure?.(error)\n );\n}\n","export const MESSAGE_ROLE = {\n USER: \"user\",\n ASSISTANT: \"assistant\",\n} as const;\n","import styled from \"styled-components\";\n\nimport { MESSAGE_ROLE } from \"../constants\";\nimport type { MessageRole } from \"../types\";\n\nconst FADE_DURATION_MS = 150;\nconst ANIMATE_DURATION_MS = 200;\n\nexport const ActionsContainer = styled.div<{ $role: MessageRole }>`\n display: flex;\n opacity: ${({ $role }) => ($role === MESSAGE_ROLE.ASSISTANT ? 1 : 0)};\n pointer-events: ${({ $role }) => ($role === MESSAGE_ROLE.ASSISTANT ? \"auto\" : \"none\")};\n transition: opacity ${FADE_DURATION_MS}ms ease;\n`;\n\nexport const AnimatedAction = styled.div<{ $visible: boolean }>`\n display: flex;\n overflow: hidden;\n max-width: ${({ $visible }) => ($visible ? \"40px\" : \"0\")};\n opacity: ${({ $visible }) => ($visible ? 1 : 0)};\n transition: max-width ${ANIMATE_DURATION_MS}ms ease, opacity ${ANIMATE_DURATION_MS}ms ease;\n`;\n","import styled from \"styled-components\";\n\nimport { colors } from \"../../../tokens/colors\";\nimport { typographyMixin, typographyTypes } from \"../../../tokens/typography\";\nimport { ActionsContainer } from \"../chat-message-actions/chat-message-actions-styles\";\nimport { MESSAGE_ROLE } from \"../constants\";\nimport type { MessageRole } from \"../types\";\n\nexport const MessageRow = styled.div<{ $role: MessageRole }>`\n display: flex;\n justify-content: ${({ $role }) => ($role === MESSAGE_ROLE.USER ? \"flex-end\" : \"flex-start\")};\n\n &:hover ${ActionsContainer} {\n opacity: 1;\n pointer-events: auto;\n }\n`;\n\nexport const MessageContainer = styled.div<{ $role: MessageRole }>`\n display: flex;\n flex-direction: column;\n align-items: ${({ $role }) => ($role === MESSAGE_ROLE.USER ? \"flex-end\" : \"flex-start\")};\n max-width: 90%;\n width: ${({ $role }) => ($role === MESSAGE_ROLE.USER ? \"auto\" : \"100%\")};\n gap: 12px;\n`;\n\nexport const MessageBubble = styled.div<{ $role: MessageRole }>`\n ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};\n color: ${colors[\"brown-100\"]};\n background: ${({ $role }) => ($role === MESSAGE_ROLE.USER ? colors.white : \"transparent\")};\n padding: ${({ $role }) => ($role === MESSAGE_ROLE.USER ? \"12px 16px\" : \"0\")};\n border-radius: ${({ $role }) => ($role === MESSAGE_ROLE.USER ? \"16px\" : \"0\")};\n max-width: 100%;\n width: 100%;\n min-width: 0;\n /* Vertical rhythm between consecutive blocks — renderer-owned, not agent-emitted.\n * Industry standard (Claude, ChatGPT, Vercel AI Elements): the chat renderer applies\n * spacing via CSS; agents emit semantic blocks only. Value matches the MessageContainer\n * gap. TODO: replace 12px with a clay spacing token when a spacing scale is added. */\n display: flex;\n flex-direction: column;\n gap: 12px;\n`;\n"],"mappings":"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","names":["useCallback","useCallback","styled","styled","jsx","jsxs"]}