@gravity-ui/aikit 0.6.0 → 1.0.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 (106) 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/__stories__/MessageList.stories.d.ts +25 -0
  62. package/dist/components/organisms/MessageList/__stories__/MessageList.stories.js +340 -0
  63. package/dist/components/organisms/PromptInput/__stories__/PromptInput.stories.d.ts +19 -0
  64. package/dist/components/organisms/PromptInput/__stories__/PromptInput.stories.js +304 -0
  65. package/dist/components/organisms/ThinkingMessage/__stories__/ThinkingMessage.stories.d.ts +12 -0
  66. package/dist/components/organisms/ThinkingMessage/__stories__/ThinkingMessage.stories.js +105 -0
  67. package/dist/components/organisms/ToolMessage/__stories__/ToolMessage.stories.d.ts +11 -0
  68. package/dist/components/organisms/ToolMessage/__stories__/ToolMessage.stories.js +70 -0
  69. package/dist/components/organisms/UserMessage/__stories__/UserMessage.stories.d.ts +9 -0
  70. package/dist/components/organisms/UserMessage/__stories__/UserMessage.stories.js +118 -0
  71. package/dist/components/pages/ChatContainer/__stories__/ChatContainer.stories.d.ts +79 -0
  72. package/dist/components/pages/ChatContainer/__stories__/ChatContainer.stories.js +1006 -0
  73. package/dist/components/templates/ChatContent/__stories__/ChatContent.stories.d.ts +14 -0
  74. package/dist/components/templates/ChatContent/__stories__/ChatContent.stories.js +315 -0
  75. package/dist/components/templates/EmptyContainer/__stories__/EmptyContainer.stories.d.ts +20 -0
  76. package/dist/components/templates/EmptyContainer/__stories__/EmptyContainer.stories.js +250 -0
  77. package/dist/components/templates/History/ChatItem.d.ts +2 -2
  78. package/dist/components/templates/History/ChatItem.js +2 -5
  79. package/dist/components/templates/History/History.scss +13 -9
  80. package/dist/components/templates/History/HistoryList.d.ts +3 -1
  81. package/dist/components/templates/History/HistoryList.js +9 -5
  82. package/dist/components/templates/History/__stories__/History.stories.d.ts +18 -0
  83. package/dist/components/templates/History/__stories__/History.stories.js +289 -0
  84. package/dist/demo/ContentWrapper/ContentWrapper.d.ts +4 -0
  85. package/dist/demo/ContentWrapper/ContentWrapper.js +9 -0
  86. package/dist/demo/ContentWrapper/index.d.ts +1 -0
  87. package/dist/demo/ContentWrapper/index.js +1 -0
  88. package/dist/demo/Showcase/Showcase.d.ts +9 -0
  89. package/dist/demo/Showcase/Showcase.js +7 -0
  90. package/dist/demo/Showcase/index.d.ts +1 -0
  91. package/dist/demo/Showcase/index.js +1 -0
  92. package/dist/demo/ShowcaseItem/ShowcaseItem.d.ts +8 -0
  93. package/dist/demo/ShowcaseItem/ShowcaseItem.js +7 -0
  94. package/dist/demo/ShowcaseItem/index.d.ts +1 -0
  95. package/dist/demo/ShowcaseItem/index.js +1 -0
  96. package/dist/demo/SwapArea/SwapArea.d.ts +2 -0
  97. package/dist/demo/SwapArea/SwapArea.js +7 -0
  98. package/dist/demo/SwapArea/index.d.ts +1 -0
  99. package/dist/demo/SwapArea/index.js +1 -0
  100. package/dist/types/common.d.ts +13 -5
  101. package/dist/types/messages.d.ts +9 -6
  102. package/dist/utils/actionUtils.d.ts +14 -0
  103. package/dist/utils/actionUtils.js +17 -0
  104. package/dist/utils/messageUtils.d.ts +7 -9
  105. package/dist/utils/messageUtils.js +7 -1
  106. package/package.json +12 -7
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { DOMProps, QAProps } from '@gravity-ui/uikit';
2
+ import { DOMProps, InputControlSize, QAProps } from '@gravity-ui/uikit';
3
3
  import { ChatType } from '../../../types';
4
4
  import { ChatFilterFunction } from '../../../utils/chatUtils';
5
5
  import './History.scss';
@@ -37,6 +37,8 @@ export interface HistoryListProps extends QAProps, DOMProps {
37
37
  loading?: boolean;
38
38
  /** Callback when chat is clicked (for closing popup in parent) */
39
39
  onChatClick?: (chat: ChatType) => void;
40
+ /** Size of the list */
41
+ size?: InputControlSize;
40
42
  }
41
43
  /**
42
44
  * HistoryList component - displays a list of chats with search, grouping, and actions
@@ -16,7 +16,7 @@ const b = block('history');
16
16
  * @returns React component
17
17
  */
18
18
  export function HistoryList(props) {
19
- const { chats, selectedChat, onSelectChat, onDeleteChat, onLoadMore, hasMore = false, searchable = true, groupBy = 'date', showActions = true, emptyPlaceholder, emptyFilteredPlaceholder, className, qa, style, filterFunction = defaultChatFilter, loading = false, onChatClick, } = props;
19
+ const { chats, selectedChat, onSelectChat, onDeleteChat, onLoadMore, hasMore = false, searchable = true, groupBy = 'date', showActions = true, emptyPlaceholder, emptyFilteredPlaceholder, className, qa, style, filterFunction = defaultChatFilter, loading = false, onChatClick, size = 'm', } = props;
20
20
  const [filteredItemCount, setFilteredItemCount] = useState(null);
21
21
  // Group chats if needed
22
22
  const groupedChats = useMemo(() => {
@@ -57,7 +57,11 @@ export function HistoryList(props) {
57
57
  const selectedItemIndex = useMemo(() => {
58
58
  return listItems.findIndex((item) => item.type === 'chat' && item.id === (selectedChat === null || selectedChat === void 0 ? void 0 : selectedChat.id));
59
59
  }, [listItems, selectedChat]);
60
- const handleChatClick = (chat) => {
60
+ const handleChatClick = (chat, _, fromKeyboard, event) => {
61
+ var _a;
62
+ if (fromKeyboard && ((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.type) === 'button') {
63
+ return;
64
+ }
61
65
  onSelectChat === null || onSelectChat === void 0 ? void 0 : onSelectChat(chat);
62
66
  onChatClick === null || onChatClick === void 0 ? void 0 : onChatClick(chat);
63
67
  };
@@ -78,11 +82,11 @@ export function HistoryList(props) {
78
82
  };
79
83
  };
80
84
  }, [filterFunction]);
81
- const renderItem = (item) => {
85
+ const renderItem = (item, isActive) => {
82
86
  if (item.type === 'date-header') {
83
87
  return _jsx(DateHeaderItem, { date: item.date }, `date-${item.date}`);
84
88
  }
85
- return (_jsx(ChatItem, { chat: item, showActions: showActions, onChatClick: handleChatClick, onDeleteClick: onDeleteChat ? handleDeleteClick : undefined }, item.id));
89
+ return (_jsx(ChatItem, { chat: item, showActions: showActions, onDeleteClick: onDeleteChat ? handleDeleteClick : undefined, isActive: isActive }, item.id));
86
90
  };
87
91
  const emptyState = emptyPlaceholder || _jsx("div", { className: b('empty'), children: i18n('empty-state') });
88
92
  const emptyFilteredState = emptyFilteredPlaceholder || (_jsx("div", { className: b('empty'), children: i18n('empty-filtered-state') }));
@@ -90,5 +94,5 @@ export function HistoryList(props) {
90
94
  const finalEmptyPlaceholder = filteredItemCount === null || filteredItemCount === listItems.length
91
95
  ? emptyState
92
96
  : emptyFilteredState;
93
- return (_jsxs("div", { className: b('container', className), "data-qa": qa, style: style, children: [_jsx("div", { className: b('list-wrapper'), children: loading ? (_jsx("div", { className: b('loader-wrapper'), children: _jsx(Loader, { view: "loading" }) })) : (_jsx(List, { size: "m", items: listItems, renderItem: renderItem, virtualized: false, filterable: searchable, filterItem: wrappedFilterFunction, filterPlaceholder: i18n('search-placeholder'), filterClassName: b('filter'), emptyPlaceholder: finalEmptyPlaceholder, selectedItemIndex: selectedItemIndex, itemsClassName: b('list'), itemClassName: b('list-item'), onFilterEnd: (data) => setFilteredItemCount(data.items.length) })) }), hasMore && onLoadMore && (_jsx(Button, { view: "flat-action", size: "m", width: "max", onClick: onLoadMore, children: i18n('action-load-more') }))] }));
97
+ return (_jsxs("div", { className: b('container', className), "data-qa": qa, style: style, children: [_jsx("div", { className: b('list-wrapper'), children: loading ? (_jsx("div", { className: b('loader-wrapper'), children: _jsx(Loader, { view: "loading" }) })) : (_jsx(List, { size: size, items: listItems, renderItem: renderItem, virtualized: false, filterable: searchable, filterItem: wrappedFilterFunction, filterPlaceholder: i18n('search-placeholder'), filterClassName: b('filter'), emptyPlaceholder: finalEmptyPlaceholder, selectedItemIndex: selectedItemIndex, itemsClassName: b('list'), itemClassName: b('list-item'), onFilterEnd: (data) => setFilteredItemCount(data.items.length), onItemClick: handleChatClick })) }), hasMore && onLoadMore && (_jsx(Button, { view: "flat-action", size: "m", width: "max", onClick: onLoadMore, children: i18n('action-load-more') }))] }));
94
98
  }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { History } from '..';
3
+ declare const _default: Meta;
4
+ export default _default;
5
+ type Story = StoryObj<typeof History>;
6
+ export declare const Playground: Story;
7
+ export declare const WithSelectedChat: Story;
8
+ export declare const WithLoadMore: Story;
9
+ export declare const WithoutSearch: Story;
10
+ export declare const WithoutGrouping: Story;
11
+ export declare const WithoutActions: Story;
12
+ export declare const EmptyState: Story;
13
+ export declare const WithLoadMoreAndDelete: Story;
14
+ export declare const Interactive: Story;
15
+ export declare const WithCustomEmptyPlaceholder: Story;
16
+ export declare const WithCustomFilter: Story;
17
+ export declare const NotForceOpen: Story;
18
+ export declare const Loading: Story;
@@ -0,0 +1,289 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { ClockArrowRotateLeft } from '@gravity-ui/icons';
5
+ import { Icon } from '@gravity-ui/uikit';
6
+ import { History } from '..';
7
+ import { ContentWrapper } from '../../../../demo/ContentWrapper';
8
+ import { ActionButton } from '../../../atoms/ActionButton';
9
+ import MDXDocs from './Docs.mdx';
10
+ export default {
11
+ title: 'templates/History',
12
+ component: History,
13
+ parameters: {
14
+ docs: {
15
+ page: MDXDocs,
16
+ },
17
+ },
18
+ };
19
+ // Generate mock chats
20
+ const generateMockChats = (count) => {
21
+ const now = new Date();
22
+ const chats = [];
23
+ for (let i = 0; i < count; i++) {
24
+ const daysAgo = Math.floor(i / 3); // Group 3 chats per day
25
+ const date = new Date(now);
26
+ date.setDate(date.getDate() - daysAgo);
27
+ chats.push({
28
+ id: `chat-${i}`,
29
+ name: `Chat ${i + 1}`,
30
+ createTime: date.toISOString(),
31
+ lastMessage: i % 3 === 0
32
+ ? `Looooooooong last message for example ellipsis from chat ${i + 1}`
33
+ : `Last message from chat ${i + 1}`,
34
+ metadata: {},
35
+ });
36
+ }
37
+ return chats;
38
+ };
39
+ const mockChats = generateMockChats(15);
40
+ function HistoryWithTrigger(_a) {
41
+ var { initialOpen = true } = _a, props = __rest(_a, ["initialOpen"]);
42
+ const [open, setOpen] = useState(false);
43
+ const anchorRef = useRef(null);
44
+ const setInitialOpen = useRef(false);
45
+ useEffect(() => {
46
+ if (initialOpen && !open && anchorRef.current && !setInitialOpen.current) {
47
+ setOpen(true);
48
+ setInitialOpen.current = true;
49
+ }
50
+ }, [initialOpen, open, anchorRef.current, setInitialOpen.current]);
51
+ return (_jsxs("div", { style: { paddingLeft: '400px' }, children: [_jsx(ActionButton, { ref: anchorRef, view: "flat", size: "m", onClick: () => setOpen(!open), tooltipTitle: "Chat History", children: _jsx(Icon, { data: ClockArrowRotateLeft, size: 16 }) }), _jsx(History, Object.assign({}, props, { open: open, onOpenChange: setOpen, anchorElement: anchorRef.current }))] }));
52
+ }
53
+ const defaultDecorators = [
54
+ (Story) => (_jsx(ContentWrapper, { width: "600px", height: "800px", children: _jsx(Story, {}) })),
55
+ ];
56
+ export const Playground = {
57
+ args: {
58
+ chats: mockChats,
59
+ searchable: true,
60
+ groupBy: 'date',
61
+ showActions: true,
62
+ onSelectChat: (chat) => {
63
+ // eslint-disable-next-line no-console
64
+ console.log('Selected chat:', chat);
65
+ },
66
+ onDeleteChat: (chat) => {
67
+ // eslint-disable-next-line no-console
68
+ console.log('Delete chat:', chat);
69
+ },
70
+ },
71
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
72
+ decorators: defaultDecorators,
73
+ };
74
+ export const WithSelectedChat = {
75
+ args: {
76
+ chats: mockChats,
77
+ selectedChat: mockChats[2],
78
+ searchable: true,
79
+ groupBy: 'date',
80
+ showActions: true,
81
+ onSelectChat: (chat) => {
82
+ // eslint-disable-next-line no-console
83
+ console.log('Selected chat:', chat);
84
+ },
85
+ },
86
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
87
+ decorators: defaultDecorators,
88
+ };
89
+ export const WithLoadMore = {
90
+ args: {
91
+ searchable: true,
92
+ groupBy: 'date',
93
+ showActions: true,
94
+ onSelectChat: (chat) => {
95
+ // eslint-disable-next-line no-console
96
+ console.log('Selected chat:', chat);
97
+ },
98
+ },
99
+ render: (args) => {
100
+ const [chats, setChats] = useState(mockChats.slice(0, 6));
101
+ const [hasMore, setHasMore] = useState(true);
102
+ const handleLoadMore = () => {
103
+ // eslint-disable-next-line no-console
104
+ console.log('Loading more chats...');
105
+ const currentLength = chats.length;
106
+ const nextChats = mockChats.slice(0, currentLength + 6);
107
+ setChats(nextChats);
108
+ if (nextChats.length >= mockChats.length) {
109
+ setHasMore(false);
110
+ }
111
+ };
112
+ return (_jsx(HistoryWithTrigger, Object.assign({}, args, { chats: chats, hasMore: hasMore, onLoadMore: handleLoadMore })));
113
+ },
114
+ decorators: defaultDecorators,
115
+ };
116
+ export const WithoutSearch = {
117
+ args: {
118
+ chats: mockChats,
119
+ searchable: false,
120
+ groupBy: 'date',
121
+ showActions: true,
122
+ onSelectChat: (chat) => {
123
+ // eslint-disable-next-line no-console
124
+ console.log('Selected chat:', chat);
125
+ },
126
+ },
127
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
128
+ decorators: defaultDecorators,
129
+ };
130
+ export const WithoutGrouping = {
131
+ args: {
132
+ chats: mockChats,
133
+ searchable: true,
134
+ groupBy: 'none',
135
+ showActions: true,
136
+ onSelectChat: (chat) => {
137
+ // eslint-disable-next-line no-console
138
+ console.log('Selected chat:', chat);
139
+ },
140
+ },
141
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
142
+ decorators: defaultDecorators,
143
+ };
144
+ export const WithoutActions = {
145
+ args: {
146
+ chats: mockChats,
147
+ searchable: true,
148
+ groupBy: 'date',
149
+ showActions: false,
150
+ onSelectChat: (chat) => {
151
+ // eslint-disable-next-line no-console
152
+ console.log('Selected chat:', chat);
153
+ },
154
+ },
155
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
156
+ decorators: defaultDecorators,
157
+ };
158
+ export const EmptyState = {
159
+ args: {
160
+ chats: [],
161
+ searchable: true,
162
+ groupBy: 'date',
163
+ showActions: true,
164
+ },
165
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
166
+ decorators: defaultDecorators,
167
+ };
168
+ export const WithLoadMoreAndDelete = {
169
+ args: {
170
+ chats: mockChats,
171
+ searchable: true,
172
+ groupBy: 'date',
173
+ showActions: true,
174
+ hasMore: true,
175
+ onSelectChat: (chat) => {
176
+ // eslint-disable-next-line no-console
177
+ console.log('Selected chat:', chat);
178
+ },
179
+ onDeleteChat: (chat) => {
180
+ // eslint-disable-next-line no-console
181
+ console.log('Delete chat:', chat);
182
+ },
183
+ onLoadMore: () => {
184
+ // eslint-disable-next-line no-console
185
+ console.log('Load more chats');
186
+ },
187
+ },
188
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
189
+ decorators: defaultDecorators,
190
+ };
191
+ export const Interactive = {
192
+ args: {
193
+ searchable: true,
194
+ groupBy: 'date',
195
+ showActions: true,
196
+ },
197
+ render: (args) => {
198
+ const [chats, setChats] = useState(mockChats);
199
+ const [selectedChat, setSelectedChat] = useState(null);
200
+ const handleDeleteChat = (chat) => {
201
+ setChats((prev) => prev.filter((c) => c.id !== chat.id));
202
+ if ((selectedChat === null || selectedChat === void 0 ? void 0 : selectedChat.id) === chat.id) {
203
+ setSelectedChat(null);
204
+ }
205
+ };
206
+ return (_jsx(HistoryWithTrigger, Object.assign({}, args, { chats: chats, selectedChat: selectedChat, onSelectChat: setSelectedChat, onDeleteChat: handleDeleteChat })));
207
+ },
208
+ decorators: defaultDecorators,
209
+ };
210
+ export const WithCustomEmptyPlaceholder = {
211
+ args: {
212
+ chats: [],
213
+ searchable: true,
214
+ groupBy: 'date',
215
+ showActions: true,
216
+ emptyPlaceholder: (_jsxs("div", { style: {
217
+ padding: '40px',
218
+ color: '#999',
219
+ width: '100%',
220
+ display: 'flex',
221
+ flexDirection: 'column',
222
+ alignItems: 'center',
223
+ justifyContent: 'center',
224
+ }, children: [_jsx("div", { style: {
225
+ fontSize: '48px',
226
+ height: '48px',
227
+ display: 'flex',
228
+ alignItems: 'center',
229
+ justifyContent: 'center',
230
+ marginBottom: '16px',
231
+ }, children: "\uD83D\uDCAC" }), _jsx("div", { style: {
232
+ fontSize: '16px',
233
+ fontWeight: 'bold',
234
+ marginBottom: '8px',
235
+ }, children: "No conversations yet" }), _jsx("div", { style: { fontSize: '14px' }, children: "Start a new chat to begin" })] })),
236
+ },
237
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
238
+ decorators: defaultDecorators,
239
+ };
240
+ export const WithCustomFilter = {
241
+ args: {
242
+ chats: mockChats,
243
+ searchable: true,
244
+ groupBy: 'date',
245
+ showActions: true,
246
+ onSelectChat: (chat) => {
247
+ // eslint-disable-next-line no-console
248
+ console.log('Selected chat:', chat);
249
+ },
250
+ // Custom filter that searches only in chat names (not in messages)
251
+ filterFunction: (filter) => (item) => {
252
+ if (item.type === 'date-header') {
253
+ return true;
254
+ }
255
+ return item.name.toLowerCase().includes(filter.toLowerCase());
256
+ },
257
+ },
258
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
259
+ decorators: defaultDecorators,
260
+ };
261
+ export const NotForceOpen = {
262
+ args: {
263
+ chats: mockChats,
264
+ searchable: true,
265
+ groupBy: 'date',
266
+ showActions: true,
267
+ onSelectChat: (chat) => {
268
+ // eslint-disable-next-line no-console
269
+ console.log('Selected chat:', chat);
270
+ },
271
+ onDeleteChat: (chat) => {
272
+ // eslint-disable-next-line no-console
273
+ console.log('Delete chat:', chat);
274
+ },
275
+ },
276
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({ initialOpen: false }, args)),
277
+ decorators: defaultDecorators,
278
+ };
279
+ export const Loading = {
280
+ args: {
281
+ chats: [],
282
+ loading: true,
283
+ searchable: true,
284
+ groupBy: 'date',
285
+ showActions: true,
286
+ },
287
+ render: (args) => _jsx(HistoryWithTrigger, Object.assign({}, args)),
288
+ decorators: defaultDecorators,
289
+ };
@@ -0,0 +1,4 @@
1
+ import './ContentWrapper.scss';
2
+ type Props = React.PropsWithChildren<React.CSSProperties>;
3
+ export declare function ContentWrapper(props: Props): import("react/jsx-runtime").JSX.Element;
4
+ export {};
@@ -0,0 +1,9 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { cn } from '../../utils/cn';
4
+ import './ContentWrapper.scss';
5
+ const b = cn('content-wrapper');
6
+ export function ContentWrapper(props) {
7
+ const { children } = props, style = __rest(props, ["children"]);
8
+ return (_jsx("div", { className: b(), style: style, children: children }));
9
+ }
@@ -0,0 +1 @@
1
+ export { ContentWrapper } from './ContentWrapper';
@@ -0,0 +1 @@
1
+ export { ContentWrapper } from './ContentWrapper';
@@ -0,0 +1,9 @@
1
+ import './Showcase.scss';
2
+ type Props = React.PropsWithChildren<{
3
+ title?: string;
4
+ description?: React.ReactNode;
5
+ direction?: 'row' | 'column';
6
+ className?: string;
7
+ }>;
8
+ export declare function Showcase({ title, description, direction, className, children }: Props): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../utils/cn';
3
+ import './Showcase.scss';
4
+ const b = cn('showcase');
5
+ export function Showcase({ title, description, direction = 'row', className, children }) {
6
+ return (_jsxs("div", { className: b({ direction }, className), children: [title && _jsx("div", { className: b('title'), children: title }), description && _jsx("div", { className: b('description'), children: description }), _jsx("div", { className: b('content'), children: children })] }));
7
+ }
@@ -0,0 +1 @@
1
+ export { Showcase } from './Showcase';
@@ -0,0 +1 @@
1
+ export { Showcase } from './Showcase';
@@ -0,0 +1,8 @@
1
+ import './ShowcaseItem.scss';
2
+ interface ShowcaseItemProps {
3
+ title: string;
4
+ children: React.ReactNode;
5
+ width?: string | number;
6
+ }
7
+ export declare function ShowcaseItem({ title, children, width }: ShowcaseItemProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../utils/cn';
3
+ import './ShowcaseItem.scss';
4
+ const b = cn('showcase-item');
5
+ export function ShowcaseItem({ title, children, width }) {
6
+ return (_jsxs("div", { className: b(), style: { width }, children: [_jsx("div", { className: b('title'), children: title }), _jsx("div", { className: b('content'), children: children })] }));
7
+ }
@@ -0,0 +1 @@
1
+ export { ShowcaseItem } from './ShowcaseItem';
@@ -0,0 +1 @@
1
+ export { ShowcaseItem } from './ShowcaseItem';
@@ -0,0 +1,2 @@
1
+ import './SwapArea.scss';
2
+ export declare const SwapArea: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { block } from '../../utils/cn';
3
+ import './SwapArea.scss';
4
+ const b = block('swap-area');
5
+ export const SwapArea = () => {
6
+ return _jsx("div", { className: b(), children: "Swap Area" });
7
+ };
@@ -0,0 +1 @@
1
+ export { SwapArea } from './SwapArea';
@@ -0,0 +1 @@
1
+ export { SwapArea } from './SwapArea';
@@ -1,7 +1,15 @@
1
- import { ButtonView } from '@gravity-ui/uikit';
2
- export type Action = {
1
+ import { ButtonButtonProps } from '@gravity-ui/uikit';
2
+ /**
3
+ * Action configuration object with properties
4
+ */
5
+ export type ActionConfig = {
6
+ actionType?: string;
3
7
  label?: string;
4
- onClick?: () => void;
5
- view?: ButtonView;
6
8
  icon?: React.ReactNode;
7
- };
9
+ } & ButtonButtonProps;
10
+ /**
11
+ * Action can be either:
12
+ * - ActionConfig object with properties (label, icon, onClick, view)
13
+ * - React.ReactNode for fully custom content
14
+ */
15
+ export type Action = ActionConfig | React.ReactNode;
@@ -1,14 +1,17 @@
1
1
  import type React from 'react';
2
- import type { IconData } from '@gravity-ui/uikit';
2
+ import { ActionConfig } from './common';
3
3
  import { ToolMessageProps } from './tool';
4
+ export type BaseMessageActionConfig = ActionConfig;
5
+ /**
6
+ * BaseMessage action can be either:
7
+ * - BaseMessageActionConfig object with properties (including type for default icons)
8
+ * - React.ReactNode for fully custom content
9
+ */
10
+ export type BaseMessageAction = BaseMessageActionConfig | React.ReactNode;
4
11
  export type BaseMessageProps = {
5
12
  children: React.ReactNode;
6
13
  role: TMessageRole;
7
- actions?: Array<{
8
- type: string;
9
- onClick: () => void;
10
- icon?: IconData;
11
- }>;
14
+ actions?: BaseMessageAction[];
12
15
  timestamp?: string;
13
16
  showTimestamp?: boolean;
14
17
  showActionsOnHover?: boolean;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { Action, ActionConfig } from '../types/common';
3
+ /**
4
+ * Type guard для проверки, является ли action React элементом
5
+ * @param action - Проверяемое значение
6
+ * @returns true если action является React.ReactNode, false если это ActionConfig
7
+ */
8
+ export declare function isReactNodeAction(action: Action): action is React.ReactNode;
9
+ /**
10
+ * Type guard для проверки, является ли action объектом конфигурации
11
+ * @param action - Проверяемое значение
12
+ * @returns true если action является ActionConfig, false если это React.ReactNode
13
+ */
14
+ export declare function isActionConfig(action: Action): action is ActionConfig;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ /**
3
+ * Type guard для проверки, является ли action React элементом
4
+ * @param action - Проверяемое значение
5
+ * @returns true если action является React.ReactNode, false если это ActionConfig
6
+ */
7
+ export function isReactNodeAction(action) {
8
+ return React.isValidElement(action);
9
+ }
10
+ /**
11
+ * Type guard для проверки, является ли action объектом конфигурации
12
+ * @param action - Проверяемое значение
13
+ * @returns true если action является ActionConfig, false если это React.ReactNode
14
+ */
15
+ export function isActionConfig(action) {
16
+ return !React.isValidElement(action);
17
+ }
@@ -1,15 +1,13 @@
1
- import type { IconData } from '@gravity-ui/uikit';
2
- import type { TAssistantMessage, TChatMessage, TMessageContent, TMessageContentUnion, TMessageMetadata, TUserMessage } from '../types';
1
+ import type { ButtonView } from '@gravity-ui/uikit';
2
+ import type { BaseMessageAction, TAssistantMessage, TChatMessage, TMessageContent, TMessageContentUnion, TMessageMetadata, TUserMessage } from '../types';
3
3
  export declare function isUserMessage<Metadata = TMessageMetadata, TCustomMessageContent extends TMessageContent = never>(message: TChatMessage<TCustomMessageContent, Metadata>): message is TUserMessage<Metadata>;
4
4
  export declare function isAssistantMessage<Metadata = TMessageMetadata, TCustomMessageContent extends TMessageContent = never>(message: TChatMessage<TCustomMessageContent, Metadata>): message is TAssistantMessage<TCustomMessageContent, Metadata>;
5
5
  export declare function normalizeContent<TCustomMessageContent extends TMessageContent = never>(content: TAssistantMessage<TCustomMessageContent, TMessageMetadata>['content']): TMessageContentUnion<TCustomMessageContent>[];
6
6
  export type DefaultMessageAction<TMessage> = {
7
- type: string;
7
+ type?: string;
8
8
  onClick: (message: TMessage) => void;
9
- icon?: IconData;
9
+ icon?: React.ReactNode;
10
+ label?: string;
11
+ view?: ButtonView;
10
12
  };
11
- export declare function resolveMessageActions<TMessage extends TChatMessage<TMessageContent, TMessageMetadata>>(message: TMessage, defaultActions?: DefaultMessageAction<TMessage>[]): Array<{
12
- type: string;
13
- onClick: () => void;
14
- icon?: IconData;
15
- }> | undefined;
13
+ export declare function resolveMessageActions<TMessage extends TChatMessage<TMessageContent, TMessageMetadata>>(message: TMessage, defaultActions?: DefaultMessageAction<TMessage>[]): BaseMessageAction[] | undefined;
@@ -28,7 +28,13 @@ export function resolveMessageActions(message, defaultActions) {
28
28
  return message.actions;
29
29
  }
30
30
  if (defaultActions) {
31
- return defaultActions.map((action) => (Object.assign(Object.assign({}, action), { onClick: () => action.onClick(message) })));
31
+ return defaultActions.map((action) => ({
32
+ actionType: action.type,
33
+ icon: action.icon,
34
+ label: action.label,
35
+ view: action.view,
36
+ onClick: () => action.onClick(message),
37
+ }));
32
38
  }
33
39
  return undefined;
34
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/aikit",
3
- "version": "0.6.0",
3
+ "version": "1.0.0",
4
4
  "description": "Gravity UI base kit for building ai assistant chats",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -77,6 +77,10 @@
77
77
  "@gravity-ui/prettier-config": "^1.1.0",
78
78
  "@gravity-ui/stylelint-config": "^4.0.1",
79
79
  "@gravity-ui/tsconfig": "^1.0.0",
80
+ "@diplodoc/transform": "^4.63.3",
81
+ "@gravity-ui/i18n": "^1.8.0",
82
+ "@gravity-ui/icons": "^2.16.0",
83
+ "@gravity-ui/uikit": "^7.25.0",
80
84
  "@playwright/experimental-ct-react": "^1.56.1",
81
85
  "@playwright/test": "^1.56.1",
82
86
  "@storybook/addon-docs": "^9.0.5",
@@ -94,6 +98,7 @@
94
98
  "copyfiles": "^2.4.1",
95
99
  "eslint": "^8.57.0",
96
100
  "eslint-plugin-storybook": "^9.0.5",
101
+ "highlight.js": "^11.11.1",
97
102
  "husky": "^9.0.11",
98
103
  "jest": "^29.7.0",
99
104
  "jest-environment-jsdom": "^30.2.0",
@@ -114,7 +119,12 @@
114
119
  },
115
120
  "peerDependencies": {
116
121
  "react": "^18.2.0",
117
- "react-dom": "^18.2.0"
122
+ "react-dom": "^18.2.0",
123
+ "@diplodoc/transform": "^4.63.3",
124
+ "@gravity-ui/i18n": "^1.8.0",
125
+ "@gravity-ui/icons": "^2.16.0",
126
+ "@gravity-ui/uikit": "^7.25.0",
127
+ "highlight.js": "^11.11.1"
118
128
  },
119
129
  "nano-staged": {
120
130
  "*.{scss}": [
@@ -129,12 +139,7 @@
129
139
  },
130
140
  "dependencies": {
131
141
  "@bem-react/classname": "^1.7.0",
132
- "@diplodoc/transform": "^4.63.3",
133
- "@gravity-ui/i18n": "^1.8.0",
134
- "@gravity-ui/icons": "^2.16.0",
135
- "@gravity-ui/uikit": "^7.25.0",
136
142
  "dayjs": "^1.11.19",
137
- "highlight.js": "^11.11.1",
138
143
  "react-window": "^2.2.1",
139
144
  "uuid": "^13.0.0"
140
145
  }