@gravity-ui/aikit 0.6.0 → 1.0.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 (109) hide show
  1. package/dist/components/atoms/ActionButton/__stories__/ActionButton.stories.d.ts +8 -0
  2. package/dist/components/atoms/ActionButton/__stories__/ActionButton.stories.js +48 -0
  3. package/dist/components/atoms/Alert/__stories__/Alert.stories.d.ts +10 -0
  4. package/dist/components/atoms/Alert/__stories__/Alert.stories.js +72 -0
  5. package/dist/components/atoms/ChatDate/__stories__/ChatDate.stories.d.ts +16 -0
  6. package/dist/components/atoms/ChatDate/__stories__/ChatDate.stories.js +83 -0
  7. package/dist/components/atoms/ContextIndicator/__stories__/ContextIndicator.stories.d.ts +17 -0
  8. package/dist/components/atoms/ContextIndicator/__stories__/ContextIndicator.stories.js +72 -0
  9. package/dist/components/atoms/ContextItem/__stories__/ContextItem.stories.d.ts +8 -0
  10. package/dist/components/atoms/ContextItem/__stories__/ContextItem.stories.js +36 -0
  11. package/dist/components/atoms/DiffStat/__stories__/DiffStat.stories.d.ts +8 -0
  12. package/dist/components/atoms/DiffStat/__stories__/DiffStat.stories.js +45 -0
  13. package/dist/components/atoms/Disclaimer/__stories__/Disclaimer.stories.d.ts +12 -0
  14. package/dist/components/atoms/Disclaimer/__stories__/Disclaimer.stories.js +64 -0
  15. package/dist/components/atoms/Loader/__stories__/Loader.stories.d.ts +8 -0
  16. package/dist/components/atoms/Loader/__stories__/Loader.stories.js +47 -0
  17. package/dist/components/atoms/MarkdownRenderer/__stories__/MarkdownRenderer.stories.d.ts +6 -0
  18. package/dist/components/atoms/MarkdownRenderer/__stories__/MarkdownRenderer.stories.js +49 -0
  19. package/dist/components/atoms/MessageBalloon/__stories__/MessageBalloon.stories.d.ts +6 -0
  20. package/dist/components/atoms/MessageBalloon/__stories__/MessageBalloon.stories.js +32 -0
  21. package/dist/components/atoms/Shimmer/__stories__/Shimmer.stories.d.ts +5 -0
  22. package/dist/components/atoms/Shimmer/__stories__/Shimmer.stories.js +28 -0
  23. package/dist/components/atoms/SubmitButton/__stories__/SubmitButton.stories.d.ts +13 -0
  24. package/dist/components/atoms/SubmitButton/__stories__/SubmitButton.stories.js +98 -0
  25. package/dist/components/atoms/ToolIndicator/__stories__/ToolIndicator.stories.d.ts +9 -0
  26. package/dist/components/atoms/ToolIndicator/__stories__/ToolIndicator.stories.js +34 -0
  27. package/dist/components/molecules/BaseMessage/__stories__/BaseMessage.stories.d.ts +9 -0
  28. package/dist/components/molecules/BaseMessage/__stories__/BaseMessage.stories.js +77 -0
  29. package/dist/components/molecules/BaseMessage/index.d.ts +1 -1
  30. package/dist/components/molecules/BaseMessage/index.js +51 -20
  31. package/dist/components/molecules/ButtonGroup/__stories__/ButtonGroup.stories.d.ts +6 -0
  32. package/dist/components/molecules/ButtonGroup/__stories__/ButtonGroup.stories.js +44 -0
  33. package/dist/components/molecules/PromptInputBody/__stories__/PromptInputBody.stories.d.ts +11 -0
  34. package/dist/components/molecules/PromptInputBody/__stories__/PromptInputBody.stories.js +62 -0
  35. package/dist/components/molecules/PromptInputFooter/__stories__/PromptInputFooter.stories.d.ts +11 -0
  36. package/dist/components/molecules/PromptInputFooter/__stories__/PromptInputFooter.stories.js +96 -0
  37. package/dist/components/molecules/PromptInputHeader/__stories__/PromptInputHeader.stories.d.ts +15 -0
  38. package/dist/components/molecules/PromptInputHeader/__stories__/PromptInputHeader.stories.js +123 -0
  39. package/dist/components/molecules/PromptInputPanel/__stories__/PromptInputPanel.stories.d.ts +8 -0
  40. package/dist/components/molecules/PromptInputPanel/__stories__/PromptInputPanel.stories.js +38 -0
  41. package/dist/components/molecules/Suggestions/__stories__/Suggestions.stories.d.ts +22 -0
  42. package/dist/components/molecules/Suggestions/__stories__/Suggestions.stories.js +182 -0
  43. package/dist/components/molecules/Tabs/__stories__/Tabs.stories.d.ts +9 -0
  44. package/dist/components/molecules/Tabs/__stories__/Tabs.stories.js +103 -0
  45. package/dist/components/molecules/ToolFooter/__stories__/ToolFooter.stories.d.ts +7 -0
  46. package/dist/components/molecules/ToolFooter/__stories__/ToolFooter.stories.js +58 -0
  47. package/dist/components/molecules/ToolFooter/index.js +8 -1
  48. package/dist/components/molecules/ToolHeader/__stories__/ToolHeader.stories.d.ts +8 -0
  49. package/dist/components/molecules/ToolHeader/__stories__/ToolHeader.stories.js +59 -0
  50. package/dist/components/molecules/ToolHeader/index.js +10 -1
  51. package/dist/components/molecules/ToolStatus/__stories__/ToolStatus.stories.d.ts +9 -0
  52. package/dist/components/molecules/ToolStatus/__stories__/ToolStatus.stories.js +44 -0
  53. package/dist/components/organisms/AssistantMessage/__stories__/AssistantMessage.stories.d.ts +13 -0
  54. package/dist/components/organisms/AssistantMessage/__stories__/AssistantMessage.stories.js +151 -0
  55. package/dist/components/organisms/Header/Header.js +16 -17
  56. package/dist/components/organisms/Header/__stories__/Header.stories.d.ts +15 -0
  57. package/dist/components/organisms/Header/__stories__/Header.stories.js +159 -0
  58. package/dist/components/organisms/Header/types.d.ts +2 -3
  59. package/dist/components/organisms/Header/useHeader.d.ts +2 -4
  60. package/dist/components/organisms/Header/useHeader.js +2 -24
  61. package/dist/components/organisms/MessageList/MessageList.js +5 -6
  62. package/dist/components/organisms/MessageList/__stories__/MessageList.stories.d.ts +25 -0
  63. package/dist/components/organisms/MessageList/__stories__/MessageList.stories.js +340 -0
  64. package/dist/components/organisms/PromptInput/__stories__/PromptInput.stories.d.ts +19 -0
  65. package/dist/components/organisms/PromptInput/__stories__/PromptInput.stories.js +304 -0
  66. package/dist/components/organisms/ThinkingMessage/__stories__/ThinkingMessage.stories.d.ts +12 -0
  67. package/dist/components/organisms/ThinkingMessage/__stories__/ThinkingMessage.stories.js +105 -0
  68. package/dist/components/organisms/ToolMessage/__stories__/ToolMessage.stories.d.ts +11 -0
  69. package/dist/components/organisms/ToolMessage/__stories__/ToolMessage.stories.js +70 -0
  70. package/dist/components/organisms/UserMessage/__stories__/UserMessage.stories.d.ts +9 -0
  71. package/dist/components/organisms/UserMessage/__stories__/UserMessage.stories.js +118 -0
  72. package/dist/components/pages/ChatContainer/__stories__/ChatContainer.stories.d.ts +79 -0
  73. package/dist/components/pages/ChatContainer/__stories__/ChatContainer.stories.js +1006 -0
  74. package/dist/components/templates/ChatContent/__stories__/ChatContent.stories.d.ts +14 -0
  75. package/dist/components/templates/ChatContent/__stories__/ChatContent.stories.js +315 -0
  76. package/dist/components/templates/EmptyContainer/__stories__/EmptyContainer.stories.d.ts +20 -0
  77. package/dist/components/templates/EmptyContainer/__stories__/EmptyContainer.stories.js +250 -0
  78. package/dist/components/templates/History/ChatItem.d.ts +2 -2
  79. package/dist/components/templates/History/ChatItem.js +2 -5
  80. package/dist/components/templates/History/History.scss +13 -9
  81. package/dist/components/templates/History/HistoryList.d.ts +3 -1
  82. package/dist/components/templates/History/HistoryList.js +9 -5
  83. package/dist/components/templates/History/__stories__/History.stories.d.ts +18 -0
  84. package/dist/components/templates/History/__stories__/History.stories.js +289 -0
  85. package/dist/demo/ContentWrapper/ContentWrapper.d.ts +4 -0
  86. package/dist/demo/ContentWrapper/ContentWrapper.js +9 -0
  87. package/dist/demo/ContentWrapper/index.d.ts +1 -0
  88. package/dist/demo/ContentWrapper/index.js +1 -0
  89. package/dist/demo/Showcase/Showcase.d.ts +9 -0
  90. package/dist/demo/Showcase/Showcase.js +7 -0
  91. package/dist/demo/Showcase/index.d.ts +1 -0
  92. package/dist/demo/Showcase/index.js +1 -0
  93. package/dist/demo/ShowcaseItem/ShowcaseItem.d.ts +8 -0
  94. package/dist/demo/ShowcaseItem/ShowcaseItem.js +7 -0
  95. package/dist/demo/ShowcaseItem/index.d.ts +1 -0
  96. package/dist/demo/ShowcaseItem/index.js +1 -0
  97. package/dist/demo/SwapArea/SwapArea.d.ts +2 -0
  98. package/dist/demo/SwapArea/SwapArea.js +7 -0
  99. package/dist/demo/SwapArea/index.d.ts +1 -0
  100. package/dist/demo/SwapArea/index.js +1 -0
  101. package/dist/hooks/useSmartScroll.d.ts +7 -2
  102. package/dist/hooks/useSmartScroll.js +24 -22
  103. package/dist/types/common.d.ts +13 -5
  104. package/dist/types/messages.d.ts +9 -6
  105. package/dist/utils/actionUtils.d.ts +14 -0
  106. package/dist/utils/actionUtils.js +17 -0
  107. package/dist/utils/messageUtils.d.ts +7 -9
  108. package/dist/utils/messageUtils.js +7 -1
  109. package/package.json +12 -7
@@ -0,0 +1,1006 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable no-console */
3
+ import React, { useState } from 'react';
4
+ import { Gear, Sparkles, Star } from '@gravity-ui/icons';
5
+ import { Icon } from '@gravity-ui/uikit';
6
+ import { ChatContainer } from '..';
7
+ import { ContentWrapper } from '../../../../demo/ContentWrapper';
8
+ import MDXDocs from './Docs.mdx';
9
+ export default {
10
+ title: 'pages/ChatContainer',
11
+ component: ChatContainer,
12
+ parameters: {
13
+ docs: {
14
+ page: MDXDocs,
15
+ },
16
+ },
17
+ };
18
+ const defaultDecorators = [
19
+ (Story) => (_jsx(ContentWrapper, { height: "800px", width: "600px", children: _jsx(Story, {}) })),
20
+ ];
21
+ // Mock data
22
+ const mockSuggestions = [
23
+ {
24
+ id: '1',
25
+ title: 'Explain quantum computing in simple terms',
26
+ },
27
+ {
28
+ id: '2',
29
+ title: 'Write a poem about nature',
30
+ },
31
+ {
32
+ id: '3',
33
+ title: 'Help me debug my JavaScript code',
34
+ },
35
+ {
36
+ id: '4',
37
+ title: 'Summarize recent AI developments',
38
+ },
39
+ ];
40
+ const mockChats = [
41
+ {
42
+ id: '1',
43
+ name: 'Quantum Computing Discussion',
44
+ createTime: new Date(Date.now() - 1000 * 60 * 60).toISOString(),
45
+ lastMessage: 'Thanks for explaining quantum entanglement!',
46
+ },
47
+ {
48
+ id: '2',
49
+ name: 'Poetry Writing Session',
50
+ createTime: new Date(Date.now() - 1000 * 60 * 60 * 24).toISOString(),
51
+ lastMessage: 'That was a beautiful poem about autumn.',
52
+ },
53
+ {
54
+ id: '3',
55
+ name: 'Code Debugging Help',
56
+ createTime: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2).toISOString(),
57
+ lastMessage: 'The bug was in the async function.',
58
+ },
59
+ {
60
+ id: '4',
61
+ name: 'AI News Summary',
62
+ createTime: new Date(Date.now() - 1000 * 60 * 60 * 24 * 3).toISOString(),
63
+ lastMessage: 'Thanks for the comprehensive summary!',
64
+ },
65
+ ];
66
+ /**
67
+ * Mock messages for different chats
68
+ * Each chat has its own conversation history
69
+ * Keys correspond to chat IDs from mockChats
70
+ */
71
+ const mockChatMessages = {
72
+ '1': [
73
+ {
74
+ id: '1-1',
75
+ role: 'user',
76
+ content: 'What is quantum computing?',
77
+ timestamp: new Date(Date.now() - 1000 * 60 * 60).toISOString(),
78
+ },
79
+ {
80
+ id: '1-2',
81
+ role: 'assistant',
82
+ content: 'Quantum computing is a revolutionary approach to computation that leverages the principles of quantum mechanics. Unlike classical computers that use bits (0 or 1), quantum computers use quantum bits or "qubits" that can exist in multiple states simultaneously through a phenomenon called superposition.\n\nKey concepts include:\n1. **Superposition**: Qubits can be in multiple states at once\n2. **Entanglement**: Qubits can be correlated in ways that classical bits cannot\n3. **Quantum Interference**: Used to amplify correct answers and cancel out wrong ones',
83
+ timestamp: new Date(Date.now() - 1000 * 60 * 59).toISOString(),
84
+ },
85
+ {
86
+ id: '1-3',
87
+ role: 'user',
88
+ content: 'Can you explain quantum entanglement in simple terms?',
89
+ timestamp: new Date(Date.now() - 1000 * 60 * 58).toISOString(),
90
+ },
91
+ {
92
+ id: '1-4',
93
+ role: 'assistant',
94
+ content: 'Quantum entanglement is like having two magic coins that are mysteriously connected. When you flip one coin and it lands on heads, the other coin - no matter how far away - will instantly land on tails (or vice versa).\n\nIn quantum physics terms:\n- Two particles become "entangled" and share a quantum state\n- Measuring one particle instantly affects the other\n- This happens regardless of the distance between them\n- Einstein called it "spooky action at a distance"\n\nThis phenomenon is fundamental to quantum computing and quantum communication technologies.',
95
+ timestamp: new Date(Date.now() - 1000 * 60 * 57).toISOString(),
96
+ },
97
+ ],
98
+ '2': [
99
+ {
100
+ id: '2-1',
101
+ role: 'user',
102
+ content: 'Write a poem about autumn leaves',
103
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24).toISOString(),
104
+ },
105
+ {
106
+ id: '2-2',
107
+ role: 'assistant',
108
+ content: "Golden whispers fall from trees,\nDancing softly on the breeze,\nCrimsons, ambers, russet bright,\nPainting pathways with their light.\n\nNature's canvas, rich and warm,\nBefore the coming winter storm,\nEach leaf a story, each one told,\nOf seasons passing, growing old.",
109
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 + 60000).toISOString(),
110
+ },
111
+ {
112
+ id: '2-3',
113
+ role: 'user',
114
+ content: 'That was beautiful! Can you write one about winter snow?',
115
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 + 120000).toISOString(),
116
+ },
117
+ {
118
+ id: '2-4',
119
+ role: 'assistant',
120
+ content: "Snowflakes drift from silent skies,\nBlankets white before our eyes,\nCrystal diamonds, soft and pure,\nWinter's gentle signature.\n\nFrosted windows, frozen streams,\nLandscapes wrapped in silver dreams,\nQuiet peace in cold embrace,\nNature sleeps in gentle grace.",
121
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 + 180000).toISOString(),
122
+ },
123
+ ],
124
+ '3': [
125
+ {
126
+ id: '3-1',
127
+ role: 'user',
128
+ content: "I have a bug in my async function. It's not waiting for the promise to resolve.",
129
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2).toISOString(),
130
+ },
131
+ {
132
+ id: '3-2',
133
+ role: 'assistant',
134
+ content: "Let's debug this step by step. The most common issues with async/await are:\n\n1. **Missing await keyword**: Make sure you're using `await` before the promise\n2. **Function not marked as async**: The function must be declared with `async` keyword\n3. **Promise not being returned**: Ensure the function returns a promise\n\nCan you share your code? Here's a common pattern:\n\n```javascript\nasync function fetchData() {\n const result = await fetch('/api/data');\n const data = await result.json();\n return data;\n}\n```",
135
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2 + 60000).toISOString(),
136
+ },
137
+ {
138
+ id: '3-3',
139
+ role: 'user',
140
+ content: 'Oh! I forgot to mark the parent function as async. That was the issue. Thanks!',
141
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2 + 120000).toISOString(),
142
+ },
143
+ {
144
+ id: '3-4',
145
+ role: 'assistant',
146
+ content: "Great! That's a very common mistake. Remember: to use `await`, the containing function must be `async`. Also, if you're using `await` in a callback (like in `.map()` or `.forEach()`), make sure to make the callback function async too. Happy coding!",
147
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2 + 180000).toISOString(),
148
+ },
149
+ ],
150
+ '4': [
151
+ {
152
+ id: '4-1',
153
+ role: 'user',
154
+ content: 'What are the latest developments in AI?',
155
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 * 3).toISOString(),
156
+ },
157
+ {
158
+ id: '4-2',
159
+ role: 'assistant',
160
+ content: 'Recent AI developments include:\n\n**Large Language Models**\n- More efficient training methods\n- Better reasoning capabilities\n- Multimodal models (text, image, audio)\n\n**Computer Vision**\n- Improved object detection and segmentation\n- Real-time video analysis\n- 3D reconstruction from 2D images\n\n**AI Safety**\n- Constitutional AI and alignment research\n- Better interpretability tools\n- Red-teaming and safety testing\n\n**Edge AI**\n- Running models on mobile devices\n- Reduced latency for real-time applications\n- Privacy-preserving local inference',
161
+ timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24 * 3 + 60000).toISOString(),
162
+ },
163
+ ],
164
+ };
165
+ // Default messages for first chat
166
+ const mockMessages = mockChatMessages['1'];
167
+ /**
168
+ * Create message actions with handlers
169
+ * @param messageId - Message identifier
170
+ * @param role - Message role (user or assistant)
171
+ * @returns Array of message actions
172
+ */
173
+ const createMessageActions = (messageId, role) => {
174
+ const actions = [
175
+ {
176
+ actionType: 'copy',
177
+ onClick: () => console.log(`Copy message ${messageId}`),
178
+ },
179
+ ];
180
+ if (role === 'user') {
181
+ actions.push({
182
+ actionType: 'edit',
183
+ onClick: () => console.log(`Edit message ${messageId}`),
184
+ });
185
+ }
186
+ if (role === 'assistant') {
187
+ actions.push({
188
+ actionType: 'like',
189
+ onClick: () => console.log(`Like message ${messageId}`),
190
+ }, {
191
+ actionType: 'unlike',
192
+ onClick: () => console.log(`Unlike message ${messageId}`),
193
+ });
194
+ }
195
+ return actions;
196
+ };
197
+ /**
198
+ * Add actions to messages
199
+ * @param messages - Array of messages
200
+ * @returns Array of messages with actions added
201
+ */
202
+ const addActionsToMessages = (messages) => {
203
+ return messages.map((msg) => (Object.assign(Object.assign({}, msg), { actions: createMessageActions(msg.id || 'unknown', msg.role) })));
204
+ };
205
+ /**
206
+ * Playground story for interactive testing
207
+ */
208
+ export const Playground = {
209
+ args: {
210
+ messages: [],
211
+ chats: mockChats,
212
+ showHistory: true,
213
+ showNewChat: true,
214
+ showClose: false,
215
+ welcomeConfig: {
216
+ title: 'Welcome to AI Chat',
217
+ description: 'Start a conversation by typing a message or selecting a suggestion.',
218
+ suggestionTitle: 'Try asking:',
219
+ suggestions: mockSuggestions,
220
+ },
221
+ showActionsOnHover: true,
222
+ },
223
+ render: (args) => {
224
+ const initialChat = mockChats[0];
225
+ const [messages, setMessages] = useState(addActionsToMessages(mockChatMessages[initialChat.id] || []));
226
+ const [status, setStatus] = useState(args.status || 'ready');
227
+ const [activeChat, setActiveChat] = useState(initialChat);
228
+ const handleSendMessage = async (data) => {
229
+ const userMessage = {
230
+ id: Date.now().toString(),
231
+ role: 'user',
232
+ content: data.content,
233
+ timestamp: new Date().toISOString(),
234
+ actions: createMessageActions(Date.now().toString(), 'user'),
235
+ };
236
+ setMessages((prev) => [...prev, userMessage]);
237
+ // Simulate streaming
238
+ setStatus('streaming');
239
+ await new Promise((resolve) => setTimeout(resolve, 500));
240
+ const assistantMessageId = (Date.now() + 1).toString();
241
+ const assistantMessage = {
242
+ id: assistantMessageId,
243
+ role: 'assistant',
244
+ content: `This is a mock response to: "${data.content}". In a real application, this would be a streamed response from an AI model.`,
245
+ timestamp: new Date().toISOString(),
246
+ actions: createMessageActions(assistantMessageId, 'assistant'),
247
+ };
248
+ setMessages((prev) => [...prev, assistantMessage]);
249
+ setStatus('ready');
250
+ };
251
+ const handleSelectChat = (chat) => {
252
+ setActiveChat(chat);
253
+ // Load messages for selected chat
254
+ const chatMessages = mockChatMessages[chat.id] || [];
255
+ setMessages(addActionsToMessages(chatMessages));
256
+ };
257
+ const handleCreateChat = () => {
258
+ setActiveChat(null);
259
+ setMessages([]);
260
+ };
261
+ const handleCancel = async () => {
262
+ setStatus('ready');
263
+ };
264
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, activeChat: activeChat, onSendMessage: handleSendMessage, onCancel: handleCancel, onSelectChat: handleSelectChat, onCreateChat: handleCreateChat, status: status })));
265
+ },
266
+ decorators: defaultDecorators,
267
+ };
268
+ /**
269
+ * Empty state with welcome screen
270
+ */
271
+ export const EmptyState = {
272
+ args: {
273
+ messages: [],
274
+ welcomeConfig: {
275
+ image: _jsx(Icon, { data: Sparkles, size: 48 }),
276
+ title: 'Welcome to AI Chat',
277
+ description: 'Start a conversation by typing a message or selecting a suggestion.',
278
+ suggestionTitle: 'Try asking:',
279
+ suggestions: mockSuggestions,
280
+ },
281
+ },
282
+ render: (args) => {
283
+ const [messages, setMessages] = useState([]);
284
+ const handleSendMessage = async (data) => {
285
+ const userMessage = {
286
+ id: Date.now().toString(),
287
+ role: 'user',
288
+ content: data.content,
289
+ };
290
+ setMessages((prev) => [...prev, userMessage]);
291
+ };
292
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
293
+ },
294
+ decorators: defaultDecorators,
295
+ };
296
+ /**
297
+ * State with messages
298
+ */
299
+ export const WithMessages = {
300
+ args: {
301
+ messages: mockMessages,
302
+ chats: mockChats,
303
+ activeChat: mockChats[0],
304
+ showActionsOnHover: true,
305
+ },
306
+ render: (args) => {
307
+ const [messages, setMessages] = useState(addActionsToMessages(args.messages || []));
308
+ const handleSendMessage = async (data) => {
309
+ const userMessageId = Date.now().toString();
310
+ const userMessage = {
311
+ id: userMessageId,
312
+ role: 'user',
313
+ content: data.content,
314
+ actions: createMessageActions(userMessageId, 'user'),
315
+ };
316
+ setMessages((prev) => [...prev, userMessage]);
317
+ };
318
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
319
+ },
320
+ decorators: defaultDecorators,
321
+ };
322
+ /**
323
+ * With streaming
324
+ */
325
+ export const WithStreaming = {
326
+ args: {
327
+ messages: mockMessages,
328
+ showActionsOnHover: true,
329
+ },
330
+ render: (args) => {
331
+ const [messages, setMessages] = useState(addActionsToMessages(args.messages || []));
332
+ const [status, setStatus] = useState('ready');
333
+ const handleSendMessage = async (data) => {
334
+ const userMessageId = Date.now().toString();
335
+ const userMessage = {
336
+ id: userMessageId,
337
+ role: 'user',
338
+ content: data.content,
339
+ actions: createMessageActions(userMessageId, 'user'),
340
+ };
341
+ setMessages((prev) => [...prev, userMessage]);
342
+ // Simulate streaming
343
+ setStatus('streaming');
344
+ const assistantMessageId = (Date.now() + 1).toString();
345
+ const fullResponse = 'This is a simulated streaming response. In a real application, this text would appear word by word as it streams from the AI model. Streaming provides a better user experience for long responses.';
346
+ // Add empty message
347
+ setMessages((prev) => [
348
+ ...prev,
349
+ {
350
+ id: assistantMessageId,
351
+ role: 'assistant',
352
+ content: '',
353
+ actions: createMessageActions(assistantMessageId, 'assistant'),
354
+ },
355
+ ]);
356
+ // Simulate word-by-word streaming
357
+ const words = fullResponse.split(' ');
358
+ for (let i = 0; i < words.length; i++) {
359
+ await new Promise((resolve) => setTimeout(resolve, 100));
360
+ const currentText = words.slice(0, i + 1).join(' ');
361
+ setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId
362
+ ? Object.assign(Object.assign({}, msg), { content: currentText }) : msg));
363
+ }
364
+ setStatus('ready');
365
+ };
366
+ const handleCancel = async () => {
367
+ setStatus('ready');
368
+ };
369
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage, onCancel: handleCancel, status: status })));
370
+ },
371
+ decorators: defaultDecorators,
372
+ };
373
+ /**
374
+ * With history
375
+ */
376
+ export const WithHistory = {
377
+ args: {
378
+ messages: mockMessages,
379
+ chats: mockChats,
380
+ activeChat: mockChats[0],
381
+ showHistory: true,
382
+ showActionsOnHover: true,
383
+ },
384
+ render: (args) => {
385
+ const [messages, setMessages] = useState(addActionsToMessages(args.messages || []));
386
+ const [chats, setChats] = useState(args.chats || []);
387
+ const [activeChat, setActiveChat] = useState(args.activeChat || null);
388
+ const handleSendMessage = async (data) => {
389
+ const userMessageId = Date.now().toString();
390
+ const userMessage = {
391
+ id: userMessageId,
392
+ role: 'user',
393
+ content: data.content,
394
+ actions: createMessageActions(userMessageId, 'user'),
395
+ };
396
+ setMessages((prev) => [...prev, userMessage]);
397
+ };
398
+ const handleSelectChat = (chat) => {
399
+ setActiveChat(chat);
400
+ // Load messages for selected chat
401
+ const chatMessages = mockChatMessages[chat.id] || [];
402
+ setMessages(addActionsToMessages(chatMessages));
403
+ };
404
+ const handleCreateChat = () => {
405
+ const newChat = {
406
+ id: Date.now().toString(),
407
+ name: 'New Chat',
408
+ createTime: new Date().toISOString(),
409
+ };
410
+ setChats((prev) => [newChat, ...prev]);
411
+ setActiveChat(newChat);
412
+ setMessages([]);
413
+ };
414
+ const handleDeleteChat = (chat) => {
415
+ setChats((prev) => prev.filter((c) => c.id !== chat.id));
416
+ if ((activeChat === null || activeChat === void 0 ? void 0 : activeChat.id) === chat.id) {
417
+ setActiveChat(null);
418
+ setMessages([]);
419
+ }
420
+ };
421
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, chats: chats, activeChat: activeChat, onSendMessage: handleSendMessage, onSelectChat: handleSelectChat, onCreateChat: handleCreateChat, onDeleteChat: handleDeleteChat })));
422
+ },
423
+ decorators: defaultDecorators,
424
+ };
425
+ /**
426
+ * Empty state with text wrapping enabled
427
+ * Demonstrates usage of wrapText prop for long suggestion titles
428
+ */
429
+ export const EmptyStateWithTextWrap = {
430
+ args: {
431
+ messages: [],
432
+ welcomeConfig: {
433
+ image: _jsx(Icon, { data: Sparkles, size: 48 }),
434
+ title: 'Welcome to AI Chat',
435
+ description: 'Start a conversation by typing a message or selecting a suggestion.',
436
+ suggestionTitle: 'Try these longer prompts:',
437
+ suggestions: [
438
+ {
439
+ id: '1',
440
+ title: 'Can you explain quantum computing in simple terms with practical examples?',
441
+ },
442
+ {
443
+ id: '2',
444
+ title: 'Write a creative and emotional poem about the beauty of nature in different seasons',
445
+ },
446
+ {
447
+ id: '3',
448
+ title: 'Help me understand and debug complex asynchronous JavaScript code patterns',
449
+ },
450
+ ],
451
+ wrapText: true,
452
+ },
453
+ },
454
+ render: (args) => {
455
+ const [messages, setMessages] = useState([]);
456
+ const handleSendMessage = async (data) => {
457
+ const userMessage = {
458
+ id: Date.now().toString(),
459
+ role: 'user',
460
+ content: data.content,
461
+ };
462
+ setMessages((prev) => [...prev, userMessage]);
463
+ };
464
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
465
+ },
466
+ decorators: defaultDecorators,
467
+ };
468
+ /**
469
+ * Empty state with custom React elements
470
+ * Demonstrates usage of React elements for title and description
471
+ */
472
+ export const EmptyStateWithCustomElements = {
473
+ args: {
474
+ messages: [],
475
+ welcomeConfig: {
476
+ image: _jsx(Icon, { data: Sparkles, size: 48 }),
477
+ title: (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx(Icon, { data: Sparkles, size: 24 }), _jsx("span", { children: "Welcome to AI Chat" })] })),
478
+ description: (_jsxs("div", { children: [_jsx("p", { style: { margin: '0 0 8px 0' }, children: "Get started by selecting a suggestion below or typing your own message." }), _jsx("strong", { children: "Available 24/7 for your questions" })] })),
479
+ suggestionTitle: 'Try asking:',
480
+ suggestions: mockSuggestions,
481
+ },
482
+ },
483
+ render: (args) => {
484
+ const [messages, setMessages] = useState([]);
485
+ const handleSendMessage = async (data) => {
486
+ const userMessage = {
487
+ id: Date.now().toString(),
488
+ role: 'user',
489
+ content: data.content,
490
+ };
491
+ setMessages((prev) => [...prev, userMessage]);
492
+ };
493
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
494
+ },
495
+ decorators: defaultDecorators,
496
+ };
497
+ /**
498
+ * Empty state with centered alignment
499
+ * Demonstrates usage of alignment prop in welcomeConfig
500
+ */
501
+ export const EmptyStateWithCenteredAlignment = {
502
+ args: {
503
+ messages: [],
504
+ welcomeConfig: {
505
+ image: _jsx(Icon, { data: Sparkles, size: 48 }),
506
+ title: 'Welcome to AI Chat',
507
+ description: 'Start a conversation by typing a message or selecting a suggestion.',
508
+ suggestionTitle: 'Try asking:',
509
+ suggestions: mockSuggestions,
510
+ alignment: {
511
+ image: 'center',
512
+ title: 'center',
513
+ description: 'center',
514
+ },
515
+ },
516
+ },
517
+ render: (args) => {
518
+ const [messages, setMessages] = useState([]);
519
+ const handleSendMessage = async (data) => {
520
+ const userMessage = {
521
+ id: Date.now().toString(),
522
+ role: 'user',
523
+ content: data.content,
524
+ };
525
+ setMessages((prev) => [...prev, userMessage]);
526
+ };
527
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
528
+ },
529
+ decorators: defaultDecorators,
530
+ };
531
+ /**
532
+ * With custom i18n configuration
533
+ */
534
+ export const WithI18nConfig = {
535
+ args: {
536
+ messages: [],
537
+ i18nConfig: {
538
+ header: {
539
+ defaultTitle: 'My Custom AI Assistant',
540
+ },
541
+ emptyState: {
542
+ title: 'Hello!',
543
+ description: 'How can I help you today?',
544
+ suggestionsTitle: 'Quick actions:',
545
+ },
546
+ promptInput: {
547
+ placeholder: 'Ask me anything...',
548
+ },
549
+ disclaimer: {
550
+ text: 'Custom disclaimer text here.',
551
+ },
552
+ },
553
+ welcomeConfig: {
554
+ suggestions: mockSuggestions.slice(0, 2),
555
+ },
556
+ },
557
+ render: (args) => {
558
+ const [messages, setMessages] = useState([]);
559
+ const handleSendMessage = async (data) => {
560
+ const userMessage = {
561
+ id: Date.now().toString(),
562
+ role: 'user',
563
+ content: data.content,
564
+ };
565
+ setMessages((prev) => [...prev, userMessage]);
566
+ };
567
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
568
+ },
569
+ decorators: defaultDecorators,
570
+ };
571
+ /**
572
+ * With component props override
573
+ */
574
+ export const WithComponentPropsOverride = {
575
+ args: {
576
+ messages: mockMessages,
577
+ headerProps: {
578
+ titlePosition: 'center',
579
+ },
580
+ promptInputProps: {
581
+ view: 'full',
582
+ maxLength: 2000,
583
+ },
584
+ disclaimerProps: {
585
+ className: 'custom-disclaimer',
586
+ text: 'Custom disclaimer text with className and variant override',
587
+ variant: 'caption-2',
588
+ },
589
+ historyProps: {
590
+ groupBy: 'none',
591
+ },
592
+ },
593
+ render: (args) => {
594
+ const [messages, setMessages] = useState(args.messages || []);
595
+ const handleSendMessage = async (data) => {
596
+ const userMessage = {
597
+ id: Date.now().toString(),
598
+ role: 'user',
599
+ content: data.content,
600
+ };
601
+ setMessages((prev) => [...prev, userMessage]);
602
+ };
603
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
604
+ },
605
+ decorators: defaultDecorators,
606
+ };
607
+ /**
608
+ * With context items
609
+ */
610
+ export const WithContextItems = {
611
+ args: {
612
+ messages: mockMessages,
613
+ promptInputProps: {
614
+ view: 'full',
615
+ },
616
+ },
617
+ render: (args) => {
618
+ const [messages, setMessages] = useState(args.messages || []);
619
+ const [contextItems, setContextItems] = useState([
620
+ { id: '1', content: 'ChatContainer.tsx', onRemove: () => { } },
621
+ { id: '2', content: 'types.ts', onRemove: () => { } },
622
+ { id: '3', content: 'README.md', onRemove: () => { } },
623
+ ]);
624
+ const handleSendMessage = async (data) => {
625
+ const userMessage = {
626
+ id: Date.now().toString(),
627
+ role: 'user',
628
+ content: data.content,
629
+ };
630
+ setMessages((prev) => [...prev, userMessage]);
631
+ };
632
+ const handleRemoveContext = (id) => {
633
+ setContextItems((prev) => prev.filter((item) => item.id !== id));
634
+ };
635
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage, contextItems: contextItems.map((item) => (Object.assign(Object.assign({}, item), { onRemove: () => handleRemoveContext(item.id) }))) })));
636
+ },
637
+ decorators: defaultDecorators,
638
+ };
639
+ /**
640
+ * With context items and indicator
641
+ */
642
+ export const WithContextItemsAndIndicator = {
643
+ args: {
644
+ messages: mockMessages,
645
+ promptInputProps: {
646
+ view: 'full',
647
+ headerProps: {
648
+ showContextIndicator: true,
649
+ contextIndicatorProps: {
650
+ type: 'percent',
651
+ usedContext: 75,
652
+ },
653
+ },
654
+ },
655
+ },
656
+ render: (args) => {
657
+ const [messages, setMessages] = useState(args.messages || []);
658
+ const [contextItems, setContextItems] = useState([
659
+ { id: '1', content: 'file.tsx', onRemove: () => { } },
660
+ { id: '2', content: 'component.tsx', onRemove: () => { } },
661
+ ]);
662
+ const handleSendMessage = async (data) => {
663
+ const userMessage = {
664
+ id: Date.now().toString(),
665
+ role: 'user',
666
+ content: data.content,
667
+ };
668
+ setMessages((prev) => [...prev, userMessage]);
669
+ };
670
+ const handleRemoveContext = (id) => {
671
+ setContextItems((prev) => prev.filter((item) => item.id !== id));
672
+ };
673
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage, contextItems: contextItems.map((item) => (Object.assign(Object.assign({}, item), { onRemove: () => handleRemoveContext(item.id) }))) })));
674
+ },
675
+ decorators: defaultDecorators,
676
+ };
677
+ /**
678
+ * With loading state
679
+ */
680
+ export const LoadingState = {
681
+ args: {
682
+ messages: addActionsToMessages(mockMessages.slice(0, -1)),
683
+ status: 'submitted',
684
+ showActionsOnHover: true,
685
+ },
686
+ render: (args) => {
687
+ return _jsx(ChatContainer, Object.assign({}, args, { onSendMessage: async () => { } }));
688
+ },
689
+ decorators: defaultDecorators,
690
+ };
691
+ /**
692
+ * With error
693
+ */
694
+ export const ErrorState = {
695
+ args: {
696
+ messages: addActionsToMessages(mockMessages.slice(0, -1)),
697
+ status: 'error',
698
+ error: new Error('Failed to send message. Please try again.'),
699
+ showActionsOnHover: true,
700
+ },
701
+ render: (args) => {
702
+ const [messages, setMessages] = useState(args.messages || []);
703
+ const handleSendMessage = async (data) => {
704
+ const userMessageId = Date.now().toString();
705
+ const userMessage = {
706
+ id: userMessageId,
707
+ role: 'user',
708
+ content: data.content,
709
+ actions: createMessageActions(userMessageId, 'user'),
710
+ };
711
+ setMessages((prev) => [...prev, userMessage]);
712
+ };
713
+ return _jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage }));
714
+ },
715
+ decorators: defaultDecorators,
716
+ };
717
+ /**
718
+ * Full example with realistic streaming via fetch API
719
+ */
720
+ export const FullStreamingExample = {
721
+ args: {
722
+ messages: [],
723
+ chats: mockChats,
724
+ activeChat: mockChats[0],
725
+ showHistory: true,
726
+ showNewChat: true,
727
+ welcomeConfig: {
728
+ image: _jsx(Icon, { data: Sparkles, size: 48 }),
729
+ title: 'AI Streaming Chat',
730
+ description: 'Experience real-time streaming responses',
731
+ suggestionTitle: 'Try these prompts:',
732
+ suggestions: mockSuggestions,
733
+ },
734
+ showActionsOnHover: true,
735
+ },
736
+ render: (args) => {
737
+ const initialChat = mockChats[0];
738
+ const [messages, setMessages] = useState(addActionsToMessages(mockChatMessages[initialChat.id] || []));
739
+ const [activeChat, setActiveChat] = useState(initialChat);
740
+ const [status, setStatus] = useState('ready');
741
+ const [controller, setController] = useState(null);
742
+ const isProcessingRef = React.useRef(false);
743
+ const handleSendMessage = async (data) => {
744
+ if (isProcessingRef.current || status === 'streaming' || status === 'submitted') {
745
+ return;
746
+ }
747
+ isProcessingRef.current = true;
748
+ // Add user message
749
+ const timestamp = Date.now();
750
+ const userMessageId = `user-${timestamp}-${Math.random().toString(36).substr(2, 9)}`;
751
+ const userMessage = {
752
+ id: userMessageId,
753
+ role: 'user',
754
+ content: data.content,
755
+ timestamp: new Date().toISOString(),
756
+ actions: createMessageActions(userMessageId, 'user'),
757
+ };
758
+ setMessages((prev) => [...prev, userMessage]);
759
+ // Show submitted state first
760
+ setStatus('submitted');
761
+ const abortController = new AbortController();
762
+ setController(abortController);
763
+ try {
764
+ // In real app, this would be a fetch to API
765
+ // const response = await fetch('/api/chat/stream', {
766
+ // method: 'POST',
767
+ // headers: {'Content-Type': 'application/json'},
768
+ // body: JSON.stringify({message: data.content}),
769
+ // signal: abortController.signal,
770
+ // });
771
+ // Simulate streaming for demo
772
+ const assistantMessageId = `assistant-${timestamp + 1}-${Math.random().toString(36).substr(2, 9)}`;
773
+ const fullResponse = `This is a detailed response to your question: "${data.content}"\n\nIn a production environment, this text would be streamed from an AI model in real-time. The streaming provides several benefits:\n\n1. **Better User Experience**: Users see the response as it's being generated\n2. **Lower Perceived Latency**: The wait feels shorter when content appears incrementally\n3. **Ability to Cancel**: Users can stop generation if they have enough information\n4. **Resource Efficiency**: Responses can be processed as they arrive\n\nThe implementation would use Server-Sent Events (SSE) or streaming fetch API to receive chunks of text from the backend, updating the message content in real-time.`;
774
+ // Wait a bit before starting streaming
775
+ await new Promise((resolve) => setTimeout(resolve, 500));
776
+ // Start streaming
777
+ setStatus('streaming');
778
+ // Create empty assistant message
779
+ setMessages((prev) => [
780
+ ...prev,
781
+ {
782
+ id: assistantMessageId,
783
+ role: 'assistant',
784
+ content: ' ',
785
+ timestamp: new Date().toISOString(),
786
+ actions: createMessageActions(assistantMessageId, 'assistant'),
787
+ },
788
+ ]);
789
+ // Simulate word-by-word streaming
790
+ const words = fullResponse.split(' ');
791
+ for (let i = 0; i < words.length; i++) {
792
+ if (abortController.signal.aborted) {
793
+ break;
794
+ }
795
+ await new Promise((resolve) => setTimeout(resolve, 50));
796
+ const currentText = words.slice(0, i + 1).join(' ');
797
+ setMessages((prev) => {
798
+ const assistantMessageExists = prev.some((msg) => msg.id === assistantMessageId);
799
+ if (!assistantMessageExists) {
800
+ return prev;
801
+ }
802
+ return prev.map((msg) => msg.id === assistantMessageId
803
+ ? Object.assign(Object.assign({}, msg), { content: currentText }) : msg);
804
+ });
805
+ }
806
+ }
807
+ catch (error) {
808
+ if (error.name !== 'AbortError') {
809
+ // In real app, error handling would be here
810
+ // console.error('Streaming error:', error);
811
+ }
812
+ }
813
+ finally {
814
+ setStatus('ready');
815
+ setController(null);
816
+ isProcessingRef.current = false;
817
+ }
818
+ };
819
+ const handleCancel = async () => {
820
+ controller === null || controller === void 0 ? void 0 : controller.abort();
821
+ setStatus('ready');
822
+ };
823
+ const handleSelectChat = (chat) => {
824
+ setActiveChat(chat);
825
+ // Load messages for selected chat
826
+ const chatMessages = mockChatMessages[chat.id] || [];
827
+ setMessages(addActionsToMessages(chatMessages));
828
+ };
829
+ const handleCreateChat = () => {
830
+ setActiveChat(null);
831
+ setMessages([]);
832
+ };
833
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, activeChat: activeChat, onSendMessage: handleSendMessage, onCancel: handleCancel, onSelectChat: handleSelectChat, onCreateChat: handleCreateChat, status: status })));
834
+ },
835
+ decorators: defaultDecorators,
836
+ };
837
+ /**
838
+ * Hidden Title on Empty Chat
839
+ * Demonstrates the hideTitleOnEmptyChat prop which hides the header title
840
+ * and preview when the chat is empty (no messages)
841
+ */
842
+ export const HiddenTitleOnEmpty = {
843
+ render: (args) => {
844
+ const [messages, setMessages] = useState([]);
845
+ const [status, setStatus] = useState('ready');
846
+ const handleSendMessage = async (data) => {
847
+ const timestamp = Date.now();
848
+ const userMessage = {
849
+ id: `user-${timestamp}`,
850
+ role: 'user',
851
+ content: data.content,
852
+ timestamp: new Date().toISOString(),
853
+ };
854
+ setMessages((prev) => [...prev, userMessage]);
855
+ setStatus('submitted');
856
+ // Simulate response after a short delay
857
+ await new Promise((resolve) => setTimeout(resolve, 1000));
858
+ const assistantMessage = {
859
+ id: `assistant-${timestamp + 1}`,
860
+ role: 'assistant',
861
+ content: `This is a response to: "${data.content}"`,
862
+ timestamp: new Date().toISOString(),
863
+ };
864
+ setMessages((prev) => [...prev, assistantMessage]);
865
+ setStatus('ready');
866
+ };
867
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, onSendMessage: handleSendMessage, status: status, hideTitleOnEmptyChat: true, headerProps: {
868
+ title: 'AI Chat Assistant',
869
+ preview: _jsx("span", { children: "Beta" }),
870
+ }, welcomeConfig: {
871
+ title: 'Welcome to AI Assistant',
872
+ description: 'Ask me anything to get started. The title will appear after you send your first message.',
873
+ suggestions: mockSuggestions,
874
+ } })));
875
+ },
876
+ decorators: defaultDecorators,
877
+ };
878
+ /**
879
+ * Static additional actions for Header - extracted outside component
880
+ * to prevent creating new array on each render
881
+ */
882
+ const headerAdditionalActionsConfig = [
883
+ {
884
+ icon: _jsx(Icon, { data: Gear, size: 16 }),
885
+ label: 'Settings',
886
+ onClick: () => console.log('Settings clicked'),
887
+ view: 'flat',
888
+ },
889
+ {
890
+ icon: _jsx(Icon, { data: Star, size: 16 }),
891
+ label: 'Favorites',
892
+ onClick: () => console.log('Favorites clicked'),
893
+ view: 'flat',
894
+ },
895
+ ];
896
+ /**
897
+ * Static actions for user messages with custom "Add to favorites" action
898
+ */
899
+ const customUserActions = [
900
+ {
901
+ actionType: 'copy',
902
+ onClick: () => console.log('Copy user message'),
903
+ },
904
+ {
905
+ actionType: 'edit',
906
+ onClick: () => console.log('Edit user message'),
907
+ },
908
+ {
909
+ actionType: 'custom',
910
+ icon: _jsx(Icon, { data: Star, size: 16 }),
911
+ label: 'Add to favorites',
912
+ onClick: () => console.log('Add user message to favorites'),
913
+ },
914
+ ];
915
+ /**
916
+ * Static actions for assistant messages with custom "Add to favorites" action
917
+ */
918
+ const customAssistantActions = [
919
+ {
920
+ actionType: 'copy',
921
+ onClick: () => console.log('Copy assistant message'),
922
+ },
923
+ {
924
+ actionType: 'like',
925
+ onClick: () => console.log('Like assistant message'),
926
+ },
927
+ {
928
+ actionType: 'unlike',
929
+ onClick: () => console.log('Unlike assistant message'),
930
+ },
931
+ {
932
+ actionType: 'custom',
933
+ icon: _jsx(Icon, { data: Star, size: 16 }),
934
+ label: 'Add to favorites',
935
+ onClick: () => console.log('Add assistant message to favorites'),
936
+ },
937
+ ];
938
+ /**
939
+ * Add custom actions to messages based on role
940
+ * @param messages - Array of messages
941
+ * @returns Array of messages with custom actions added
942
+ */
943
+ const addCustomActionsToMessages = (messages) => {
944
+ return messages.map((msg) => (Object.assign(Object.assign({}, msg), { actions: msg.role === 'user' ? customUserActions : customAssistantActions })));
945
+ };
946
+ /**
947
+ * With Additional Actions
948
+ * Demonstrates passing additional actions to Header and custom actions to BaseMessage
949
+ */
950
+ export const WithAdditionalActions = {
951
+ args: {
952
+ messages: mockMessages,
953
+ chats: mockChats,
954
+ activeChat: mockChats[0],
955
+ showHistory: true,
956
+ showNewChat: true,
957
+ showActionsOnHover: true,
958
+ },
959
+ render: (args) => {
960
+ const initialChat = mockChats[0];
961
+ const [messages, setMessages] = useState(() => addCustomActionsToMessages(mockChatMessages[initialChat.id] || []));
962
+ const [status, setStatus] = useState('ready');
963
+ const [activeChat, setActiveChat] = useState(initialChat);
964
+ const handleSendMessage = async (data) => {
965
+ const timestamp = Date.now();
966
+ const userMessageId = `user-${timestamp}`;
967
+ const userMessage = {
968
+ id: userMessageId,
969
+ role: 'user',
970
+ content: data.content,
971
+ timestamp: new Date().toISOString(),
972
+ actions: customUserActions,
973
+ };
974
+ setMessages((prev) => [...prev, userMessage]);
975
+ setStatus('streaming');
976
+ // Simulate response
977
+ await new Promise((resolve) => setTimeout(resolve, 500));
978
+ const assistantMessageId = `assistant-${timestamp + 1}`;
979
+ const assistantMessage = {
980
+ id: assistantMessageId,
981
+ role: 'assistant',
982
+ content: `Response to: "${data.content}". This message demonstrates custom actions including a "Add to favorites" button with a star icon.`,
983
+ timestamp: new Date().toISOString(),
984
+ actions: customAssistantActions,
985
+ };
986
+ setMessages((prev) => [...prev, assistantMessage]);
987
+ setStatus('ready');
988
+ };
989
+ const handleSelectChat = (chat) => {
990
+ setActiveChat(chat);
991
+ const chatMessages = mockChatMessages[chat.id] || [];
992
+ setMessages(addCustomActionsToMessages(chatMessages));
993
+ };
994
+ const handleCreateChat = () => {
995
+ setActiveChat(null);
996
+ setMessages([]);
997
+ };
998
+ const handleCancel = async () => {
999
+ setStatus('ready');
1000
+ };
1001
+ return (_jsx(ChatContainer, Object.assign({}, args, { messages: messages, activeChat: activeChat, onSendMessage: handleSendMessage, onCancel: handleCancel, onSelectChat: handleSelectChat, onCreateChat: handleCreateChat, status: status, headerProps: {
1002
+ additionalActions: headerAdditionalActionsConfig,
1003
+ } })));
1004
+ },
1005
+ decorators: defaultDecorators,
1006
+ };