@shapesos/clay 0.8.2 → 0.10.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.
- package/README.md +46 -1
- package/dist/blocks.cjs +650 -0
- package/dist/blocks.cjs.map +1 -0
- package/dist/blocks.d.cts +29 -0
- package/dist/blocks.d.ts +29 -0
- package/dist/blocks.js +21 -0
- package/dist/blocks.js.map +1 -0
- package/dist/button.cjs +98 -71
- package/dist/button.cjs.map +1 -1
- package/dist/button.d.cts +10 -1
- package/dist/button.d.ts +10 -1
- package/dist/button.js +3 -1
- package/dist/chat.cjs +89 -47
- package/dist/chat.cjs.map +1 -1
- package/dist/chat.d.cts +7 -3
- package/dist/chat.d.ts +7 -3
- package/dist/chat.js +3 -2
- package/dist/chunk-EDICS62G.js +177 -0
- package/dist/chunk-EDICS62G.js.map +1 -0
- package/dist/chunk-OKPNST44.js +1 -0
- package/dist/chunk-OKPNST44.js.map +1 -0
- package/dist/chunk-R3BGPOAM.js +230 -0
- package/dist/chunk-R3BGPOAM.js.map +1 -0
- package/dist/{chunk-TDMJUF4A.js → chunk-WPQQVKWY.js} +4 -4
- package/dist/{chunk-A77BGJH4.js → chunk-WS4IPADR.js} +34 -201
- package/dist/chunk-WS4IPADR.js.map +1 -0
- package/dist/index.cjs +228 -145
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +30 -13
- package/dist/text-area.js +2 -2
- package/dist/types-Q9aqd9nq.d.cts +34 -0
- package/dist/types-Q9aqd9nq.d.ts +34 -0
- package/package.json +6 -1
- package/dist/chunk-A77BGJH4.js.map +0 -1
- package/dist/chunk-FFABDVB3.js +0 -149
- package/dist/chunk-FFABDVB3.js.map +0 -1
- /package/dist/{chunk-TDMJUF4A.js.map → chunk-WPQQVKWY.js.map} +0 -0
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
markdownToPlainText
|
|
3
|
+
} from "./chunk-NMKKU2UG.js";
|
|
4
|
+
import {
|
|
5
|
+
Block,
|
|
6
|
+
BlockContext
|
|
7
|
+
} from "./chunk-R3BGPOAM.js";
|
|
1
8
|
import {
|
|
2
9
|
IconButton
|
|
3
10
|
} from "./chunk-MLCRDVQ2.js";
|
|
@@ -8,17 +15,9 @@ import {
|
|
|
8
15
|
import {
|
|
9
16
|
colors
|
|
10
17
|
} from "./chunk-JF3P66JF.js";
|
|
11
|
-
import {
|
|
12
|
-
markdownToPlainText
|
|
13
|
-
} from "./chunk-NMKKU2UG.js";
|
|
14
18
|
|
|
15
|
-
// src/components/chat/chat-message
|
|
16
|
-
import
|
|
17
|
-
import remarkBreaks from "remark-breaks";
|
|
18
|
-
import remarkGfm from "remark-gfm";
|
|
19
|
-
|
|
20
|
-
// src/components/chat/scrollable-table/scrollable-table.tsx
|
|
21
|
-
import { useContext as useContext2 } from "react";
|
|
19
|
+
// src/components/chat/chat-message/chat-message.tsx
|
|
20
|
+
import { useMemo } from "react";
|
|
22
21
|
|
|
23
22
|
// src/components/chat/chat-context/chat-context.ts
|
|
24
23
|
import { createContext, useContext } from "react";
|
|
@@ -31,179 +30,6 @@ function useChatContext() {
|
|
|
31
30
|
return context;
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
// src/components/chat/scrollable-table/scrollable-table-styles.ts
|
|
35
|
-
import styled from "styled-components";
|
|
36
|
-
var TableContainer = styled.div`
|
|
37
|
-
position: relative;
|
|
38
|
-
margin-block: 8px 16px;
|
|
39
|
-
`;
|
|
40
|
-
var TableScroll = styled.div`
|
|
41
|
-
width: 100%;
|
|
42
|
-
overflow-x: auto;
|
|
43
|
-
overflow-y: hidden;
|
|
44
|
-
`;
|
|
45
|
-
var TableActionsWrapper = styled.div`
|
|
46
|
-
display: flex;
|
|
47
|
-
justify-content: flex-start;
|
|
48
|
-
margin-block: 8px 0;
|
|
49
|
-
`;
|
|
50
|
-
var TableActionsDivider = styled.div`
|
|
51
|
-
height: 1px;
|
|
52
|
-
background: ${colors["brown-40"]};
|
|
53
|
-
margin-block: 8px 0;
|
|
54
|
-
`;
|
|
55
|
-
|
|
56
|
-
// src/components/chat/scrollable-table/scrollable-table.tsx
|
|
57
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
58
|
-
function ScrollableTable({ node: _node, messageId, counter, ...props }) {
|
|
59
|
-
const currentIndex = counter ? counter.value : 0;
|
|
60
|
-
if (counter) {
|
|
61
|
-
counter.value += 1;
|
|
62
|
-
}
|
|
63
|
-
const context = useContext2(ChatContext);
|
|
64
|
-
const TableActions = context?.TableActions;
|
|
65
|
-
return /* @__PURE__ */ jsxs(TableContainer, { children: [
|
|
66
|
-
/* @__PURE__ */ jsx(TableScroll, { children: /* @__PURE__ */ jsx("table", { ...props }) }),
|
|
67
|
-
TableActions && messageId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
68
|
-
/* @__PURE__ */ jsx(TableActionsWrapper, { children: /* @__PURE__ */ jsx(TableActions, { messageId, tableIndex: currentIndex }) }),
|
|
69
|
-
/* @__PURE__ */ jsx(TableActionsDivider, {})
|
|
70
|
-
] })
|
|
71
|
-
] });
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// src/components/chat/chat-message-content/chat-message-content-styles.ts
|
|
75
|
-
import styled2 from "styled-components";
|
|
76
|
-
var ContentWrapper = styled2.div`
|
|
77
|
-
${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};
|
|
78
|
-
color: ${colors["brown-100"]};
|
|
79
|
-
word-break: break-word;
|
|
80
|
-
|
|
81
|
-
& h1 {
|
|
82
|
-
${typographyMixin(typographyTypes.GEIST_HEADING_S_BOLD)};
|
|
83
|
-
margin-block: 20px;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
& h2 {
|
|
87
|
-
${typographyMixin(typographyTypes.GEIST_BODY_L_SEMI_BOLD)};
|
|
88
|
-
margin-block: 12px;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
& h3,
|
|
92
|
-
& h4,
|
|
93
|
-
& h5,
|
|
94
|
-
& h6 {
|
|
95
|
-
${typographyMixin(typographyTypes.GEIST_BODY_M_SEMI_BOLD)};
|
|
96
|
-
margin-block: 8px;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
& strong {
|
|
100
|
-
${typographyMixin(typographyTypes.GEIST_BODY_S_SEMI_BOLD)};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
& p {
|
|
104
|
-
margin-block: 0px;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
& p + p {
|
|
108
|
-
margin-block: 8px 0px;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
& ul,
|
|
112
|
-
& ol {
|
|
113
|
-
margin-block: 16px;
|
|
114
|
-
padding-left: 20px;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
& li + li {
|
|
118
|
-
margin-block: 4px;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
& ol {
|
|
122
|
-
list-style-type: decimal;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
& ol ol {
|
|
126
|
-
list-style-type: lower-alpha;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
& ol ol ol {
|
|
130
|
-
list-style-type: lower-roman;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
& a {
|
|
134
|
-
color: inherit;
|
|
135
|
-
text-decoration-line: underline;
|
|
136
|
-
text-decoration-style: dotted;
|
|
137
|
-
text-decoration-thickness: auto;
|
|
138
|
-
text-underline-offset: auto;
|
|
139
|
-
text-underline-position: from-font;
|
|
140
|
-
transition: color 75ms ease-in-out;
|
|
141
|
-
|
|
142
|
-
&:hover {
|
|
143
|
-
color: ${colors["blue-600"]};
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
& hr {
|
|
148
|
-
border: none;
|
|
149
|
-
border-top: 1px solid ${colors["brown-40"]};
|
|
150
|
-
margin-block: 20px;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
& table {
|
|
154
|
-
margin: 0;
|
|
155
|
-
width: 100%;
|
|
156
|
-
border-collapse: collapse;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
& th,
|
|
160
|
-
& td {
|
|
161
|
-
border: none;
|
|
162
|
-
border-bottom: 1px solid ${colors["brown-40"]};
|
|
163
|
-
text-align: left;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
& th {
|
|
167
|
-
${typographyMixin(typographyTypes.GEIST_LABEL_CAPTION_MEDIUM)};
|
|
168
|
-
padding: 8px;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
& td {
|
|
172
|
-
${typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM)};
|
|
173
|
-
padding: 16px 8px;
|
|
174
|
-
min-width: 150px;
|
|
175
|
-
width: 1%;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
& td strong {
|
|
179
|
-
font-weight: inherit;
|
|
180
|
-
font-size: inherit;
|
|
181
|
-
line-height: inherit;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
& blockquote {
|
|
185
|
-
margin-block: 4px;
|
|
186
|
-
margin-inline: 0px;
|
|
187
|
-
padding-left: 16px;
|
|
188
|
-
border-left: 4px solid ${colors["brown-40"]};
|
|
189
|
-
color: ${colors["brown-80"]};
|
|
190
|
-
}
|
|
191
|
-
`;
|
|
192
|
-
|
|
193
|
-
// src/components/chat/chat-message-content/chat-message-content.tsx
|
|
194
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
195
|
-
function ChatMessageContent({ content, messageId }) {
|
|
196
|
-
const counter = { value: 0 };
|
|
197
|
-
const sanitizedContent = content.split("\n").filter((line) => {
|
|
198
|
-
const t = line.trim();
|
|
199
|
-
return !(t.startsWith("<!-- table-title:") && t.endsWith("-->"));
|
|
200
|
-
}).join("\n");
|
|
201
|
-
const markdownComponents = {
|
|
202
|
-
table: ((tableProps) => /* @__PURE__ */ jsx2(ScrollableTable, { ...tableProps, messageId, counter }))
|
|
203
|
-
};
|
|
204
|
-
return /* @__PURE__ */ jsx2(ContentWrapper, { children: /* @__PURE__ */ jsx2(ReactMarkdown, { remarkPlugins: [remarkGfm, remarkBreaks], components: markdownComponents, children: sanitizedContent }) });
|
|
205
|
-
}
|
|
206
|
-
|
|
207
33
|
// src/components/chat/chat-message-actions/chat-message-actions.tsx
|
|
208
34
|
import { useCallback as useCallback2 } from "react";
|
|
209
35
|
|
|
@@ -322,16 +148,16 @@ var MESSAGE_ROLE = {
|
|
|
322
148
|
};
|
|
323
149
|
|
|
324
150
|
// src/components/chat/chat-message-actions/chat-message-actions-styles.ts
|
|
325
|
-
import
|
|
151
|
+
import styled from "styled-components";
|
|
326
152
|
var FADE_DURATION_MS = 150;
|
|
327
153
|
var ANIMATE_DURATION_MS = 200;
|
|
328
|
-
var ActionsContainer =
|
|
154
|
+
var ActionsContainer = styled.div`
|
|
329
155
|
display: flex;
|
|
330
156
|
opacity: ${({ $role }) => $role === MESSAGE_ROLE.ASSISTANT ? 1 : 0};
|
|
331
157
|
pointer-events: ${({ $role }) => $role === MESSAGE_ROLE.ASSISTANT ? "auto" : "none"};
|
|
332
158
|
transition: opacity ${FADE_DURATION_MS}ms ease;
|
|
333
159
|
`;
|
|
334
|
-
var AnimatedAction =
|
|
160
|
+
var AnimatedAction = styled.div`
|
|
335
161
|
display: flex;
|
|
336
162
|
overflow: hidden;
|
|
337
163
|
max-width: ${({ $visible }) => $visible ? "40px" : "0"};
|
|
@@ -340,7 +166,7 @@ var AnimatedAction = styled3.div`
|
|
|
340
166
|
`;
|
|
341
167
|
|
|
342
168
|
// src/components/chat/chat-message-actions/chat-message-actions.tsx
|
|
343
|
-
import { jsx
|
|
169
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
344
170
|
function ChatMessageActions({ className, messageId, content, role, isHelpful }) {
|
|
345
171
|
const { onCopyMessage, onThumbUpClick, onThumbDownClick } = useChatContext();
|
|
346
172
|
const { isCopied, copy } = useCopyToClipboard();
|
|
@@ -356,8 +182,8 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
|
|
|
356
182
|
}, [messageId, isHelpful, onThumbDownClick]);
|
|
357
183
|
const isAssistant = role === MESSAGE_ROLE.ASSISTANT;
|
|
358
184
|
const hasFeedback = isAssistant && (onThumbUpClick || onThumbDownClick);
|
|
359
|
-
return /* @__PURE__ */
|
|
360
|
-
/* @__PURE__ */
|
|
185
|
+
return /* @__PURE__ */ jsxs(ActionsContainer, { $role: role, className, children: [
|
|
186
|
+
/* @__PURE__ */ jsx(
|
|
361
187
|
IconButton,
|
|
362
188
|
{
|
|
363
189
|
icon: isCopied ? IconCheck : IconCopy,
|
|
@@ -365,7 +191,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
|
|
|
365
191
|
"aria-label": isCopied ? "Copied" : "Copy message"
|
|
366
192
|
}
|
|
367
193
|
),
|
|
368
|
-
hasFeedback && /* @__PURE__ */
|
|
194
|
+
hasFeedback && /* @__PURE__ */ jsx(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ jsx(
|
|
369
195
|
IconButton,
|
|
370
196
|
{
|
|
371
197
|
icon: IconThumbUp,
|
|
@@ -374,7 +200,7 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
|
|
|
374
200
|
"aria-label": "Good response"
|
|
375
201
|
}
|
|
376
202
|
) }),
|
|
377
|
-
hasFeedback && /* @__PURE__ */
|
|
203
|
+
hasFeedback && /* @__PURE__ */ jsx(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ jsx(
|
|
378
204
|
IconButton,
|
|
379
205
|
{
|
|
380
206
|
icon: IconThumbDown,
|
|
@@ -387,8 +213,8 @@ function ChatMessageActions({ className, messageId, content, role, isHelpful })
|
|
|
387
213
|
}
|
|
388
214
|
|
|
389
215
|
// src/components/chat/chat-message/chat-message-styles.ts
|
|
390
|
-
import
|
|
391
|
-
var MessageRow =
|
|
216
|
+
import styled2 from "styled-components";
|
|
217
|
+
var MessageRow = styled2.div`
|
|
392
218
|
display: flex;
|
|
393
219
|
justify-content: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "flex-end" : "flex-start"};
|
|
394
220
|
|
|
@@ -397,7 +223,7 @@ var MessageRow = styled4.div`
|
|
|
397
223
|
pointer-events: auto;
|
|
398
224
|
}
|
|
399
225
|
`;
|
|
400
|
-
var MessageContainer =
|
|
226
|
+
var MessageContainer = styled2.div`
|
|
401
227
|
display: flex;
|
|
402
228
|
flex-direction: column;
|
|
403
229
|
align-items: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "flex-end" : "flex-start"};
|
|
@@ -405,7 +231,7 @@ var MessageContainer = styled4.div`
|
|
|
405
231
|
width: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "auto" : "100%"};
|
|
406
232
|
gap: 12px;
|
|
407
233
|
`;
|
|
408
|
-
var MessageBubble =
|
|
234
|
+
var MessageBubble = styled2.div`
|
|
409
235
|
${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};
|
|
410
236
|
color: ${colors["brown-100"]};
|
|
411
237
|
background: ${({ $role }) => $role === MESSAGE_ROLE.USER ? colors.white : "transparent"};
|
|
@@ -416,15 +242,22 @@ var MessageBubble = styled4.div`
|
|
|
416
242
|
`;
|
|
417
243
|
|
|
418
244
|
// src/components/chat/chat-message/chat-message.tsx
|
|
419
|
-
import { jsx as
|
|
245
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
420
246
|
function ChatMessage({ message }) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
247
|
+
const { TableActions: ChatTableActions } = useChatContext();
|
|
248
|
+
const blockContextValue = useMemo(
|
|
249
|
+
() => ({
|
|
250
|
+
TableActions: ChatTableActions ? ({ tableIndex }) => /* @__PURE__ */ jsx2(ChatTableActions, { messageId: message.id, tableIndex }) : void 0
|
|
251
|
+
}),
|
|
252
|
+
[ChatTableActions, message.id]
|
|
253
|
+
);
|
|
254
|
+
return /* @__PURE__ */ jsx2(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ jsxs2(MessageContainer, { $role: message.role, children: [
|
|
255
|
+
/* @__PURE__ */ jsx2(MessageBubble, { $role: message.role, children: /* @__PURE__ */ jsx2(BlockContext.Provider, { value: blockContextValue, children: message.blocks.map((block, index) => /* @__PURE__ */ jsx2(Block, { block }, index)) }) }),
|
|
256
|
+
/* @__PURE__ */ jsx2(
|
|
424
257
|
ChatMessageActions,
|
|
425
258
|
{
|
|
426
259
|
messageId: message.id,
|
|
427
|
-
content: message.
|
|
260
|
+
content: message.fallbackText,
|
|
428
261
|
role: message.role,
|
|
429
262
|
isHelpful: message.isHelpful
|
|
430
263
|
}
|
|
@@ -455,4 +288,4 @@ export {
|
|
|
455
288
|
* See the LICENSE file in the root directory of this source tree.
|
|
456
289
|
*)
|
|
457
290
|
*/
|
|
458
|
-
//# sourceMappingURL=chunk-
|
|
291
|
+
//# sourceMappingURL=chunk-WS4IPADR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat/chat-message/chat-message.tsx","../src/components/chat/chat-context/chat-context.ts","../src/components/chat/chat-message-actions/chat-message-actions.tsx","../node_modules/@tabler/icons-react/src/defaultAttributes.ts","../node_modules/@tabler/icons-react/src/createReactComponent.ts","../node_modules/@tabler/icons-react/src/icons/IconCheck.ts","../node_modules/@tabler/icons-react/src/icons/IconCopy.ts","../node_modules/@tabler/icons-react/src/icons/IconThumbDown.ts","../node_modules/@tabler/icons-react/src/icons/IconThumbUp.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 { BlockContext, type BlockContextValue } from \"@/components/blocks/block-context\";\nimport { useChatContext } from \"../chat-context/chat-context\";\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 const { TableActions: ChatTableActions } = useChatContext();\n\n // Adapt the chat-shaped TableActions ({ messageId, tableIndex }) into the generic block-shaped\n // signature ({ tableIndex }) by binding this message's id. The blocks namespace stays\n // chat-agnostic; chat owns the messageId-to-action correlation.\n const blockContextValue = useMemo<BlockContextValue>(\n () => ({\n TableActions: ChatTableActions\n ? ({ tableIndex }) => <ChatTableActions messageId={message.id} tableIndex={tableIndex} />\n : undefined,\n }),\n [ChatTableActions, message.id]\n );\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}>\n <BlockContext.Provider value={blockContextValue}>\n {message.blocks.map((block, index) => (\n <Block key={index} block={block} />\n ))}\n </BlockContext.Provider>\n </MessageBubble>\n <ChatMessageActions\n messageId={message.id}\n content={message.fallbackText}\n role={message.role}\n isHelpful={message.isHelpful}\n />\n </MessageContainer>\n </MessageRow>\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 { 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","export default {\n outline: {\n xmlns: 'http://www.w3.org/2000/svg',\n width: 24,\n height: 24,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n },\n filled: {\n xmlns: 'http://www.w3.org/2000/svg',\n width: 24,\n height: 24,\n viewBox: '0 0 24 24',\n fill: 'currentColor',\n stroke: 'none',\n },\n};\n","import { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes';\nimport type { IconNode, IconProps, Icon } from './types';\n\nconst createReactComponent = (\n type: 'outline' | 'filled',\n iconName: string,\n iconNamePascal: string,\n iconNode: IconNode,\n) => {\n const Component = forwardRef<SVGSVGElement, IconProps>(\n (\n { color = 'currentColor', size = 24, stroke = 2, title, className, children, ...rest }: IconProps,\n ref,\n ) =>\n createElement(\n 'svg',\n {\n ref,\n ...defaultAttributes[type],\n width: size,\n height: size,\n className: [`tabler-icon`, `tabler-icon-${iconName}`, className].join(' '),\n ...(type === 'filled'\n ? {\n fill: color,\n }\n : {\n strokeWidth: stroke,\n stroke: color,\n }),\n ...rest,\n },\n [\n title && createElement('title', { key: 'svg-title' }, title),\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...(Array.isArray(children) ? children : [children]),\n ],\n ),\n );\n\n Component.displayName = `${iconNamePascal}`;\n\n return Component;\n};\n\nexport default createReactComponent;\n","import createReactComponent from '../createReactComponent';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [[\"path\",{\"d\":\"M5 12l5 5l10 -10\",\"key\":\"svg-0\"}]]\n\nconst IconCheck = createReactComponent('outline', 'check', 'Check', __iconNode);\n\nexport default IconCheck;","import createReactComponent from '../createReactComponent';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [[\"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\"}]]\n\nconst IconCopy = createReactComponent('outline', 'copy', 'Copy', __iconNode);\n\nexport default IconCopy;","import createReactComponent from '../createReactComponent';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [[\"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\"}]]\n\nconst IconThumbDown = createReactComponent('outline', 'thumb-down', 'ThumbDown', __iconNode);\n\nexport default IconThumbDown;","import createReactComponent from '../createReactComponent';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [[\"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\"}]]\n\nconst IconThumbUp = createReactComponent('outline', 'thumb-up', 'ThumbUp', __iconNode);\n\nexport default IconThumbUp;","import { useState, useCallback, useRef, useEffect } from \"react\";\n\nimport { copyToClipboard } from \"@/utils/clipboard\";\nimport { markdownToPlainText } from \"@/utils/markdown-to-plain-text\";\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 const copy = useCallback((text: string) => {\n copyToClipboard(markdownToPlainText(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 min-width: 0;\n`;\n"],"mappings":"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","names":["useCallback","__iconNode","__iconNode","__iconNode","useCallback","styled","styled","jsx","jsxs"]}
|