@robr0/design-system 0.4.0 → 0.6.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 (70) hide show
  1. package/README.md +21 -10
  2. package/components/AgentStatus/AgentStatus.css +82 -22
  3. package/components/AgentStatus/AgentStatus.d.ts +6 -2
  4. package/components/AgentStatus/AgentStatus.js +38 -6
  5. package/components/AiButton/AiButton.css +163 -0
  6. package/components/AiButton/AiButton.d.ts +36 -0
  7. package/components/AiButton/AiButton.js +58 -0
  8. package/components/ChatHeader/ChatHeader.css +35 -0
  9. package/components/ChatHeader/ChatHeader.d.ts +30 -0
  10. package/components/ChatHeader/ChatHeader.js +17 -0
  11. package/components/ChatMarker/ChatMarker.css +52 -0
  12. package/components/ChatMarker/ChatMarker.d.ts +22 -0
  13. package/components/ChatMarker/ChatMarker.js +18 -0
  14. package/components/ChatMessage/ChatMessage.css +310 -0
  15. package/components/ChatMessage/ChatMessage.d.ts +74 -0
  16. package/components/ChatMessage/ChatMessage.js +71 -0
  17. package/components/ChatThread/ChatThread.css +171 -0
  18. package/components/ChatThread/ChatThread.d.ts +41 -0
  19. package/components/ChatThread/ChatThread.js +174 -0
  20. package/components/Chip/Chip.css +27 -0
  21. package/components/Chip/Chip.d.ts +2 -2
  22. package/components/CircularButton/CircularButton.d.ts +23 -8
  23. package/components/CircularButton/CircularButton.js +54 -52
  24. package/components/CodeBlock/CodeBlock.css +2 -2
  25. package/components/Composer/Composer.css +163 -0
  26. package/components/Composer/Composer.d.ts +67 -0
  27. package/components/Composer/Composer.js +120 -0
  28. package/components/DocumentChip/DocumentChip.css +181 -0
  29. package/components/DocumentChip/DocumentChip.d.ts +41 -0
  30. package/components/DocumentChip/DocumentChip.js +78 -0
  31. package/components/InterruptCard/InterruptCard.css +164 -0
  32. package/components/InterruptCard/InterruptCard.d.ts +55 -0
  33. package/components/InterruptCard/InterruptCard.js +57 -0
  34. package/components/MessageActions/MessageActions.css +76 -0
  35. package/components/MessageActions/MessageActions.d.ts +38 -0
  36. package/components/MessageActions/MessageActions.js +33 -0
  37. package/components/MessageCard/MessageCard.css +112 -0
  38. package/components/MessageCard/MessageCard.d.ts +35 -0
  39. package/components/MessageCard/MessageCard.js +28 -0
  40. package/components/NavList/NavList.css +155 -0
  41. package/components/NavList/NavList.d.ts +56 -0
  42. package/components/NavList/NavList.js +99 -0
  43. package/components/PromptSuggestions/PromptSuggestions.css +87 -0
  44. package/components/PromptSuggestions/PromptSuggestions.d.ts +51 -0
  45. package/components/PromptSuggestions/PromptSuggestions.js +34 -0
  46. package/components/Prose/Prose.css +252 -0
  47. package/components/Prose/Prose.d.ts +21 -0
  48. package/components/Prose/Prose.js +14 -0
  49. package/components/Reasoning/Reasoning.css +149 -25
  50. package/components/Reasoning/Reasoning.d.ts +19 -0
  51. package/components/Reasoning/Reasoning.js +32 -3
  52. package/components/SourceChip/SourceChip.css +102 -0
  53. package/components/SourceChip/SourceChip.d.ts +32 -0
  54. package/components/SourceChip/SourceChip.js +31 -0
  55. package/components/Stat/Stat.css +2 -2
  56. package/components/Timeline/Timeline.css +9 -1
  57. package/components/ToolCall/ToolCall.css +3 -3
  58. package/components/registry.json +113 -1
  59. package/components/registry.json.d.ts +113 -1
  60. package/components/registry.json.js +1 -1
  61. package/index.d.ts +14 -0
  62. package/index.js +28 -0
  63. package/package.json +1 -1
  64. package/tokens/registry.json +13 -0
  65. package/tokens/registry.json.d.ts +13 -0
  66. package/tokens/registry.json.js +1 -1
  67. package/tokens/tokens-dark.css +13 -0
  68. package/tokens/tokens-light.css +43 -0
  69. package/tokens/tokens-primitives.css +5 -0
  70. package/tokens/tokens-typography.css +24 -0
@@ -0,0 +1,17 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import "./ChatHeader.css";
4
+ const ChatHeader = React.forwardRef(
5
+ ({ title, actions, className = "", ...rest }, ref) => {
6
+ const baseClass = "ds-chat-header";
7
+ const classes = [baseClass, className].filter(Boolean).join(" ");
8
+ return /* @__PURE__ */ jsxs("header", { ...rest, ref, className: classes, children: [
9
+ typeof title === "string" ? /* @__PURE__ */ jsx("span", { className: `${baseClass}__title`, children: title }) : title,
10
+ actions && /* @__PURE__ */ jsx("div", { className: `${baseClass}__actions`, children: actions })
11
+ ] });
12
+ }
13
+ );
14
+ ChatHeader.displayName = "ChatHeader";
15
+ export {
16
+ ChatHeader
17
+ };
@@ -0,0 +1,52 @@
1
+ /* ============================================
2
+ CHAT MARKER COMPONENT
3
+ Inline conversation separator for dates and system notes
4
+ ============================================ */
5
+
6
+ .ds-chat-marker {
7
+ display: flex;
8
+ align-items: center;
9
+ gap: var(--gap-sm-md);
10
+ width: 100%;
11
+ }
12
+
13
+ /* Flanking lines — kept as flex spacers when bare, so the label
14
+ stays centred either way */
15
+ .ds-chat-marker::before,
16
+ .ds-chat-marker::after {
17
+ content: '';
18
+ flex: 1;
19
+ height: var(--border-xs);
20
+ background-color: var(--color-divider);
21
+ }
22
+
23
+ .ds-chat-marker--bare::before,
24
+ .ds-chat-marker--bare::after {
25
+ background-color: transparent;
26
+ }
27
+
28
+ /* ============================================
29
+ LABEL
30
+ ============================================ */
31
+
32
+ .ds-chat-marker__label {
33
+ flex-shrink: 0;
34
+ display: inline-flex;
35
+ align-items: center;
36
+ gap: var(--gap-xs);
37
+ font-family: var(--font-paragraph-sm-family);
38
+ font-size: var(--font-paragraph-sm-size);
39
+ font-weight: var(--font-paragraph-sm-weight);
40
+ line-height: var(--font-paragraph-sm-line-height);
41
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
42
+ color: var(--color-text-tertiary);
43
+ }
44
+
45
+ .ds-chat-marker__icon {
46
+ display: inline-flex;
47
+ align-items: center;
48
+ }
49
+
50
+ .ds-chat-marker__icon .material-symbols-rounded {
51
+ --icon-size: var(--icon-size-sm);
52
+ }
@@ -0,0 +1,22 @@
1
+ import { default as React } from 'react';
2
+ /** Props owned by ChatMarker itself — everything else falls through to the root element. */
3
+ type ChatMarkerOwnProps = {
4
+ /** Leading icon — a Material Symbol name, or any custom element. */
5
+ icon?: string | React.ReactNode;
6
+ /** Draw the flanking divider lines. Turn off for a bare centred note. */
7
+ line?: boolean;
8
+ /** Additional CSS classes */
9
+ className?: string;
10
+ /** The marker text, e.g. "Today" or "Chat renamed". */
11
+ children?: React.ReactNode;
12
+ };
13
+ export interface ChatMarkerProps extends ChatMarkerOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ChatMarkerOwnProps> {
14
+ }
15
+ /**
16
+ * ChatMarker is the inline separator a conversation uses for anything that
17
+ * is not a turn: date breaks, joins, mode changes, system notes. It reads
18
+ * as furniture rather than as a message — quiet tertiary text between two
19
+ * divider lines, so the eye skips it while scanning turns.
20
+ */
21
+ export declare const ChatMarker: React.ForwardRefExoticComponent<ChatMarkerProps & React.RefAttributes<HTMLDivElement>>;
22
+ export {};
@@ -0,0 +1,18 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import "./ChatMarker.css";
4
+ import "../../fonts/material-symbols.css";
5
+ const ChatMarker = React.forwardRef(
6
+ ({ icon, line = true, className = "", children, ...rest }, ref) => {
7
+ const baseClass = "ds-chat-marker";
8
+ const classes = [baseClass, line ? "" : `${baseClass}--bare`, className].filter(Boolean).join(" ");
9
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes, role: "separator", children: /* @__PURE__ */ jsxs("span", { className: `${baseClass}__label`, children: [
10
+ icon && /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon`, "aria-hidden": "true", children: typeof icon === "string" ? /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", children: icon }) : icon }),
11
+ children
12
+ ] }) });
13
+ }
14
+ );
15
+ ChatMarker.displayName = "ChatMarker";
16
+ export {
17
+ ChatMarker
18
+ };
@@ -0,0 +1,310 @@
1
+ /* ============================================
2
+ CHAT MESSAGE COMPONENT
3
+ A single chat turn: avatar, author, timestamp,
4
+ and bubble or plain content aligned by role.
5
+
6
+ Bubble surfaces come only from the four
7
+ --color-chat-bubble-* tokens — never the
8
+ container ramp directly — so re-theming a chat
9
+ means repointing those four and nothing else.
10
+ ============================================ */
11
+
12
+ .ds-chat-message {
13
+ /* Gutter width matches the Avatar sm footprint, so a run of turns keeps
14
+ its left edge whether or not each row shows its avatar. Consumers can
15
+ repoint it for a larger avatar. */
16
+ --ds-chat-message-gutter: var(--icon-size-lg);
17
+
18
+ display: flex;
19
+ align-items: flex-start;
20
+ gap: var(--gap-sm-md);
21
+ width: 100%;
22
+ }
23
+
24
+ .ds-chat-message--user {
25
+ flex-direction: row-reverse;
26
+ }
27
+
28
+ /* ============================================
29
+ GUTTER
30
+ ============================================ */
31
+
32
+ .ds-chat-message__gutter {
33
+ flex: none;
34
+ display: flex;
35
+ justify-content: center;
36
+ width: var(--ds-chat-message-gutter);
37
+ }
38
+
39
+ /* Hidden, not removed — the reserved width is what keeps a run aligned */
40
+ .ds-chat-message__gutter--hidden {
41
+ visibility: hidden;
42
+ }
43
+
44
+ /* ============================================
45
+ BODY
46
+ ============================================ */
47
+
48
+ .ds-chat-message__body {
49
+ flex: 1;
50
+ min-width: 0;
51
+ display: flex;
52
+ flex-direction: column;
53
+ align-items: flex-start;
54
+ gap: var(--gap-xs);
55
+ }
56
+
57
+ .ds-chat-message--user .ds-chat-message__body {
58
+ align-items: flex-end;
59
+ }
60
+
61
+ /* ============================================
62
+ META ROW
63
+ ============================================ */
64
+
65
+ .ds-chat-message__meta {
66
+ display: flex;
67
+ align-items: baseline;
68
+ gap: var(--gap-sm);
69
+ }
70
+
71
+ .ds-chat-message__author {
72
+ font-family: var(--font-paragraph-sm-em-family);
73
+ font-size: var(--font-paragraph-sm-em-size);
74
+ font-weight: var(--font-paragraph-sm-em-weight);
75
+ line-height: var(--font-paragraph-sm-em-line-height);
76
+ letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
77
+ color: var(--color-text-secondary);
78
+ }
79
+
80
+ .ds-chat-message__timestamp {
81
+ font-family: var(--font-paragraph-sm-family);
82
+ font-size: var(--font-paragraph-sm-size);
83
+ font-weight: var(--font-paragraph-sm-weight);
84
+ line-height: var(--font-paragraph-sm-line-height);
85
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
86
+ font-variant-numeric: tabular-nums;
87
+ color: var(--color-text-tertiary);
88
+ }
89
+
90
+ /* ============================================
91
+ CONTENT
92
+ ============================================ */
93
+
94
+ .ds-chat-message__content {
95
+ font-family: var(--font-paragraph-family);
96
+ font-size: var(--font-paragraph-size);
97
+ font-weight: var(--font-paragraph-weight);
98
+ line-height: var(--font-paragraph-line-height);
99
+ letter-spacing: var(--font-paragraph-letter-spacing);
100
+ /* Content never pushes the turn wider than its container — an unbroken
101
+ run (a URL, a token) wraps inside the bubble or column instead. */
102
+ min-width: 0;
103
+ max-width: 100%;
104
+ overflow-wrap: anywhere;
105
+ }
106
+
107
+ /* Plain — the assistant default: no surface, full width, primary text */
108
+ .ds-chat-message--plain .ds-chat-message__content {
109
+ width: 100%;
110
+ color: var(--color-text-primary);
111
+ }
112
+
113
+ /* Bubble — capped width so a short line never drags a surface across the
114
+ whole row; the fallback is the sanctioned consumer-override hook */
115
+ .ds-chat-message--bubble .ds-chat-message__content {
116
+ max-width: var(--ds-chat-message-max-width, 75%);
117
+ padding: var(--padding-sm-md) var(--padding-lg);
118
+ border-radius: var(--radius-xl);
119
+ }
120
+
121
+ /* Sent — the user's own turns */
122
+ .ds-chat-message--bubble.ds-chat-message--user .ds-chat-message__content {
123
+ background-color: var(--color-chat-bubble-sent-bg);
124
+ color: var(--color-chat-bubble-sent-text);
125
+ }
126
+
127
+ /* Received — an assistant turn opted into a bubble */
128
+ .ds-chat-message--bubble.ds-chat-message--assistant .ds-chat-message__content {
129
+ background-color: var(--color-chat-bubble-received-bg);
130
+ color: var(--color-chat-bubble-received-text);
131
+ }
132
+
133
+ /* Tail — the speaker-side bottom corner squares off to point at them */
134
+ .ds-chat-message--tail.ds-chat-message--bubble.ds-chat-message--user
135
+ .ds-chat-message__content {
136
+ border-bottom-right-radius: var(--radius-xs);
137
+ }
138
+
139
+ .ds-chat-message--tail.ds-chat-message--bubble.ds-chat-message--assistant
140
+ .ds-chat-message__content {
141
+ border-bottom-left-radius: var(--radius-xs);
142
+ }
143
+
144
+ /* ============================================
145
+ GROUPED
146
+ A follow-on row in the same speaker's run:
147
+ no meta, avatar hidden but gutter kept, and
148
+ the row pulls up towards the one above so the
149
+ run reads as one utterance. The negative
150
+ margin offsets part of the container's gap.
151
+ ============================================ */
152
+
153
+ .ds-chat-message--grouped {
154
+ margin-top: calc(-1 * var(--gap-sm));
155
+ }
156
+
157
+ /* ============================================
158
+ COMPACT
159
+ ============================================ */
160
+
161
+ .ds-chat-message--compact .ds-chat-message__content {
162
+ font-family: var(--font-paragraph-sm-family);
163
+ font-size: var(--font-paragraph-sm-size);
164
+ font-weight: var(--font-paragraph-sm-weight);
165
+ line-height: var(--font-paragraph-sm-line-height);
166
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
167
+ }
168
+
169
+ .ds-chat-message--compact.ds-chat-message--bubble .ds-chat-message__content {
170
+ padding: var(--padding-xs) var(--padding-sm-md);
171
+ }
172
+
173
+ /* ============================================
174
+ PENDING
175
+ Three dots pulsing in sequence while the
176
+ first content is still on its way.
177
+ ============================================ */
178
+
179
+ .ds-chat-message__pending {
180
+ --ds-chat-message-pending-cycle: var(--motion-duration-loop-matrix);
181
+
182
+ display: inline-flex;
183
+ align-items: center;
184
+ }
185
+
186
+ .ds-chat-message__dots {
187
+ display: inline-flex;
188
+ align-items: center;
189
+ gap: var(--gap-xs);
190
+ }
191
+
192
+ .ds-chat-message__dot {
193
+ width: var(--gap-sm);
194
+ height: var(--gap-sm);
195
+ border-radius: var(--radius-full);
196
+ background-color: var(--color-text-tertiary);
197
+ opacity: 0.25;
198
+ animation: ds-chat-message-dot var(--ds-chat-message-pending-cycle)
199
+ var(--motion-ease-linear) infinite;
200
+ }
201
+
202
+ .ds-chat-message__dot:nth-child(2) {
203
+ animation-delay: calc(var(--ds-chat-message-pending-cycle) / 6);
204
+ }
205
+
206
+ .ds-chat-message__dot:nth-child(3) {
207
+ animation-delay: calc(var(--ds-chat-message-pending-cycle) / 3);
208
+ }
209
+
210
+ /* Each dot brightens and falls back within the first half of the cycle, so
211
+ the stagger reads as a wave rather than three independent blinkers */
212
+ @keyframes ds-chat-message-dot {
213
+ 0%,
214
+ 60%,
215
+ 100% {
216
+ opacity: 0.25;
217
+ }
218
+
219
+ 30% {
220
+ opacity: 1;
221
+ }
222
+ }
223
+
224
+ /* ============================================
225
+ ACTIONS
226
+ Hidden until the row is hovered or holds
227
+ keyboard focus; touch has no hover, so there
228
+ they stay visible.
229
+
230
+ Opacity only, never visibility: hidden would
231
+ drop the buttons from the tab order, so a
232
+ message with no other focusable child could
233
+ never match :focus-within and keyboard users
234
+ could never reach the actions. Invisible-but-
235
+ tabbable is the point — the first Tab into a
236
+ button reveals the row.
237
+ ============================================ */
238
+
239
+ .ds-chat-message__actions {
240
+ display: flex;
241
+ align-items: center;
242
+ gap: var(--gap-xs);
243
+ /* The row hides with opacity, not display, so this offset is always
244
+ reserved — the body's own gap plus this margin sets the row a full
245
+ --gap-md off the content without loosening the meta stack above. */
246
+ margin-top: var(--gap-sm-md);
247
+ opacity: 0;
248
+ transition: opacity var(--motion-duration-fast) var(--motion-ease-standard);
249
+ }
250
+
251
+ .ds-chat-message:hover .ds-chat-message__actions,
252
+ .ds-chat-message:focus-within .ds-chat-message__actions {
253
+ opacity: 1;
254
+ }
255
+
256
+ /* showActions pins the row on: the actions are part of the response, not a
257
+ secondary affordance to discover. */
258
+ .ds-chat-message--show-actions .ds-chat-message__actions {
259
+ opacity: 1;
260
+ }
261
+
262
+ @media (hover: none) {
263
+ .ds-chat-message__actions {
264
+ opacity: 1;
265
+ }
266
+ }
267
+
268
+ /* ============================================
269
+ FOOTER
270
+ ============================================ */
271
+
272
+ .ds-chat-message__footer {
273
+ display: flex;
274
+ align-items: center;
275
+ flex-wrap: wrap;
276
+ gap: var(--gap-xs);
277
+ }
278
+
279
+ /* ============================================
280
+ VISUALLY HIDDEN
281
+ The pending label is for screen readers only.
282
+ ============================================ */
283
+
284
+ .ds-chat-message__sr-only {
285
+ position: absolute;
286
+ width: 1px;
287
+ height: 1px;
288
+ padding: 0;
289
+ margin: -1px;
290
+ overflow: hidden;
291
+ clip: rect(0, 0, 0, 0);
292
+ white-space: nowrap;
293
+ border: 0;
294
+ }
295
+
296
+ /* ============================================
297
+ REDUCED MOTION
298
+ The global guard collapses the loop to its
299
+ final frame, which is the dim phase — three
300
+ near-invisible dots. Park them at a legible
301
+ static opacity instead; the visually hidden
302
+ label still says what is happening.
303
+ ============================================ */
304
+
305
+ @media (prefers-reduced-motion: reduce) {
306
+ .ds-chat-message__dot {
307
+ animation: none;
308
+ opacity: 0.55;
309
+ }
310
+ }
@@ -0,0 +1,74 @@
1
+ import { default as React } from 'react';
2
+ /** Props owned by ChatMessage itself — everything else falls through to the root element. */
3
+ type ChatMessageOwnProps = {
4
+ /**
5
+ * Which side of the conversation this turn belongs to. Drives alignment
6
+ * and the default surface: user turns are right-aligned bubbles,
7
+ * assistant turns are surface-less full-width text. Shadows the ARIA
8
+ * role attribute; the root renders no ARIA role.
9
+ */
10
+ role?: 'user' | 'assistant';
11
+ /** Avatar slot, e.g. an `<Avatar>`. Omit for no gutter at all. */
12
+ avatar?: React.ReactNode;
13
+ /**
14
+ * Show the passed avatar. When false the avatar is hidden but its gutter
15
+ * space is kept, so consecutive rows in a run stay aligned.
16
+ */
17
+ showAvatar?: boolean;
18
+ /** Display name shown above the content. */
19
+ author?: string;
20
+ /** Time shown beside the author, e.g. "2:41 PM". Free text, so callers keep their own formatting. */
21
+ timestamp?: string;
22
+ /**
23
+ * Consecutive-message mode: hides the avatar (keeping its gutter), drops
24
+ * the author and timestamp, and tightens the spacing to the row above.
25
+ */
26
+ grouped?: boolean;
27
+ /**
28
+ * Override the role's default surface. Explicit true on an assistant turn
29
+ * renders a received bubble; explicit false on a user turn renders plain text.
30
+ */
31
+ bubble?: boolean;
32
+ /**
33
+ * Square the speaker-side bottom corner of the bubble — bottom-right on a
34
+ * sent bubble, bottom-left on a received one. Only meaningful when a
35
+ * bubble renders.
36
+ */
37
+ tail?: boolean;
38
+ /** Compact drops the type one size step and tightens the bubble padding. */
39
+ size?: 'default' | 'compact';
40
+ /** Waiting for the first content: renders a three-dot pulse in place of children. */
41
+ pending?: boolean;
42
+ /** Accessible text announced for the pending state. */
43
+ pendingLabel?: string;
44
+ /** Action row under the content, revealed on hover and keyboard focus (always visible on touch) — `showActions` pins it on. */
45
+ actions?: React.ReactNode;
46
+ /**
47
+ * Always show the action row instead of revealing it on hover and focus.
48
+ * For surfaces where the actions are part of the response — a copy or
49
+ * feedback row — rather than a secondary affordance.
50
+ */
51
+ showActions?: boolean;
52
+ /** Footer slot under the content — a sources row, an edited note. */
53
+ footer?: React.ReactNode;
54
+ /** Additional CSS classes */
55
+ className?: string;
56
+ /**
57
+ * The message content. The package ships no markdown renderer; render
58
+ * markdown yourself, ideally wrapped in Prose, and pass the result.
59
+ */
60
+ children?: React.ReactNode;
61
+ };
62
+ export interface ChatMessageProps extends ChatMessageOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ChatMessageOwnProps> {
63
+ }
64
+ /**
65
+ * ChatMessage is a single chat turn: avatar, author, timestamp, and the
66
+ * content itself, aligned by role. User turns read as right-aligned bubbles;
67
+ * assistant turns read as plain full-width text, so a transcript keeps the
68
+ * question-and-answer rhythm without every row wearing a surface.
69
+ *
70
+ * The bubble colours come exclusively from the four `--color-chat-bubble-*`
71
+ * tokens, so re-theming a chat means repointing those and nothing else.
72
+ */
73
+ export declare const ChatMessage: React.ForwardRefExoticComponent<ChatMessageProps & React.RefAttributes<HTMLDivElement>>;
74
+ export {};
@@ -0,0 +1,71 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import "./ChatMessage.css";
4
+ const ChatMessage = React.forwardRef(
5
+ ({
6
+ role = "assistant",
7
+ avatar,
8
+ showAvatar = true,
9
+ author,
10
+ timestamp,
11
+ grouped = false,
12
+ bubble,
13
+ tail = false,
14
+ size = "default",
15
+ pending = false,
16
+ pendingLabel = "Waiting for a reply",
17
+ actions,
18
+ showActions = false,
19
+ footer,
20
+ className = "",
21
+ children,
22
+ ...rest
23
+ }, ref) => {
24
+ const baseClass = "ds-chat-message";
25
+ const hasBubble = bubble ?? role === "user";
26
+ const hideAvatar = grouped || !showAvatar;
27
+ const classes = [
28
+ baseClass,
29
+ `${baseClass}--${role}`,
30
+ hasBubble ? `${baseClass}--bubble` : `${baseClass}--plain`,
31
+ tail ? `${baseClass}--tail` : "",
32
+ grouped ? `${baseClass}--grouped` : "",
33
+ size === "compact" ? `${baseClass}--compact` : "",
34
+ pending ? `${baseClass}--pending` : "",
35
+ showActions ? `${baseClass}--show-actions` : "",
36
+ className
37
+ ].filter(Boolean).join(" ");
38
+ return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, children: [
39
+ avatar !== void 0 && /* @__PURE__ */ jsx(
40
+ "span",
41
+ {
42
+ className: [
43
+ `${baseClass}__gutter`,
44
+ hideAvatar ? `${baseClass}__gutter--hidden` : ""
45
+ ].filter(Boolean).join(" "),
46
+ children: avatar
47
+ }
48
+ ),
49
+ /* @__PURE__ */ jsxs("div", { className: `${baseClass}__body`, children: [
50
+ !grouped && (author || timestamp) && /* @__PURE__ */ jsxs("div", { className: `${baseClass}__meta`, children: [
51
+ author && /* @__PURE__ */ jsx("span", { className: `${baseClass}__author`, children: author }),
52
+ timestamp && /* @__PURE__ */ jsx("span", { className: `${baseClass}__timestamp`, children: timestamp })
53
+ ] }),
54
+ /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children: pending ? /* @__PURE__ */ jsxs("span", { className: `${baseClass}__pending`, role: "status", children: [
55
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr-only`, children: pendingLabel }),
56
+ /* @__PURE__ */ jsxs("span", { className: `${baseClass}__dots`, "aria-hidden": "true", children: [
57
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__dot` }),
58
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__dot` }),
59
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__dot` })
60
+ ] })
61
+ ] }) : children }),
62
+ actions && /* @__PURE__ */ jsx("div", { className: `${baseClass}__actions`, children: actions }),
63
+ footer && /* @__PURE__ */ jsx("div", { className: `${baseClass}__footer`, children: footer })
64
+ ] })
65
+ ] });
66
+ }
67
+ );
68
+ ChatMessage.displayName = "ChatMessage";
69
+ export {
70
+ ChatMessage
71
+ };