@gravity-ui/aikit 0.4.2 → 0.4.3

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.
@@ -18,7 +18,7 @@ export function Suggestions(props) {
18
18
  onClick(item.title, item.id);
19
19
  };
20
20
  const renderButton = (item, index) => {
21
- return (_jsx(ActionButton, { tooltipTitle: item.title, size: "m", view: item.view || 'outlined', onClick: () => handleClick(item), className: b('button', { layout }), width: "auto", children: _jsxs("div", { className: b('button-content', {
21
+ return (_jsx(ActionButton, { tooltipTitle: wrapText ? undefined : item.title, size: "m", view: item.view || 'outlined', onClick: () => handleClick(item), className: b('button', { layout }), width: "auto", children: _jsxs("div", { className: b('button-content', {
22
22
  layout,
23
23
  'text-align': item.icon ? undefined : textAlign,
24
24
  }), children: [item.icon === 'left' && (_jsx("div", { className: b('button-icon'), children: _jsx(Icon, { data: ChevronLeft, size: 16 }) })), _jsx(Text, { as: "div", className: b(wrapText ? 'button-text-wrap' : 'button-text'), children: item.title }), item.icon === 'right' && (_jsx("div", { className: b('button-icon'), children: _jsx(Icon, { data: ChevronRight, size: 16 }) }))] }) }, item.id || index));
@@ -29,7 +29,7 @@ const FOLDING_ICONS = {
29
29
  * @returns Header component
30
30
  */
31
31
  export function Header(props) {
32
- const { title, preview, icon, baseActions, additionalActions, titlePosition, withIcon, className, historyButtonRef, } = useHeader(props);
32
+ const { title, preview, icon, baseActions, additionalActions, titlePosition, withIcon, showTitle = true, className, historyButtonRef, } = useHeader(props);
33
33
  // Render base action
34
34
  const renderBaseAction = (action) => {
35
35
  let IconComponent = ACTION_ICONS[action.id];
@@ -62,5 +62,5 @@ export function Header(props) {
62
62
  // Determine class for title positioning
63
63
  const titlePositionClass = b('title-container', { position: titlePosition });
64
64
  const iconElement = icon ? (_jsx("div", { className: b('icon'), children: icon })) : (_jsx(Icon, { data: Sparkles, size: 16 }));
65
- return (_jsxs("div", { className: b('', className), children: [withIcon && iconElement, _jsxs("div", { className: titlePositionClass, children: [title && (_jsx(Text, { as: "div", variant: "subheader-2", className: b('title'), children: title })), preview && _jsx("div", { className: b('preview'), children: preview })] }), _jsxs(ButtonGroup, { children: [additionalActions.map((action, index) => renderAdditionalAction(action, index)), baseActions.map((action) => renderBaseAction(action))] })] }));
65
+ return (_jsxs("div", { className: b('', className), children: [withIcon && iconElement, showTitle && (_jsxs("div", { className: titlePositionClass, children: [title && (_jsx(Text, { as: "div", variant: "subheader-2", className: b('title'), children: title })), preview && _jsx("div", { className: b('preview'), children: preview })] })), _jsxs(ButtonGroup, { children: [additionalActions.map((action, index) => renderAdditionalAction(action, index)), baseActions.map((action) => renderBaseAction(action))] })] }));
66
66
  }
@@ -20,5 +20,6 @@ export type HeaderProps = {
20
20
  foldingState?: 'collapsed' | 'opened';
21
21
  titlePosition?: 'left' | 'center';
22
22
  withIcon?: boolean;
23
+ showTitle?: boolean;
23
24
  className?: string;
24
25
  };
@@ -17,6 +17,7 @@ export declare function useHeader(props: HeaderProps): {
17
17
  additionalActions: ActionItem[];
18
18
  titlePosition: 'left' | 'center';
19
19
  withIcon: boolean;
20
+ showTitle: boolean;
20
21
  className?: string;
21
22
  historyButtonRef?: React.RefObject<HTMLElement>;
22
23
  };
@@ -1,7 +1,7 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { HeaderAction } from './types';
3
3
  export function useHeader(props) {
4
- const { icon, title, preview, baseActions = [], handleNewChat, handleHistoryToggle, handleClose, handleFolding, foldingState = 'opened', additionalActions = [], titlePosition = 'left', withIcon = true, className, historyButtonRef, } = props;
4
+ const { icon, title, preview, baseActions = [], handleNewChat, handleHistoryToggle, handleClose, handleFolding, foldingState = 'opened', additionalActions = [], titlePosition = 'left', withIcon = true, showTitle = true, className, historyButtonRef, } = props;
5
5
  // Build base actions
6
6
  const baseActionsList = useMemo(() => {
7
7
  const actions = [];
@@ -66,6 +66,7 @@ export function useHeader(props) {
66
66
  additionalActions: additionalActionsList,
67
67
  titlePosition,
68
68
  withIcon,
69
+ showTitle,
69
70
  className,
70
71
  historyButtonRef,
71
72
  };
@@ -19,7 +19,7 @@ const b = block('chat-container');
19
19
  */
20
20
  export function ChatContainer(props) {
21
21
  var _a, _b;
22
- const { chats = [], messages = [], onSendMessage, onDeleteChat, onCancel, onRetry, status = 'ready', error = null, showActionsOnHover = false, contextItems = [], transformOptions, messageListConfig, headerProps = {}, contentProps = {}, emptyContainerProps = {}, promptInputProps = {}, historyProps = {}, welcomeConfig, i18nConfig = {}, className, headerClassName, contentClassName, footerClassName, qa, } = props;
22
+ const { chats = [], messages = [], onSendMessage, onDeleteChat, onCancel, onRetry, status = 'ready', error = null, showActionsOnHover = false, contextItems = [], transformOptions, messageListConfig, headerProps = {}, contentProps = {}, emptyContainerProps = {}, promptInputProps = {}, disclaimerProps = {}, historyProps = {}, welcomeConfig, i18nConfig = {}, hideTitleOnEmptyChat = false, className, headerClassName, contentClassName, footerClassName, qa, } = props;
23
23
  const hookState = useChatContainer(props);
24
24
  // Collect i18n texts with overrides
25
25
  const headerTitle = useMemo(() => {
@@ -29,9 +29,24 @@ export function ChatContainer(props) {
29
29
  ((_b = hookState.activeChat) === null || _b === void 0 ? void 0 : _b.name) ||
30
30
  i18n('header-default-title');
31
31
  }, [(_a = i18nConfig.header) === null || _a === void 0 ? void 0 : _a.defaultTitle, headerProps.title, (_b = hookState.activeChat) === null || _b === void 0 ? void 0 : _b.name]);
32
+ // Determine if chat is empty
33
+ const isChatEmpty = hookState.chatContentView === 'empty';
34
+ // Calculate showTitle based on hideTitleOnEmptyChat option
35
+ const showTitle = useMemo(() => {
36
+ // If explicit showTitle is provided in headerProps, use it
37
+ if (headerProps.showTitle !== undefined) {
38
+ return headerProps.showTitle;
39
+ }
40
+ // If hideTitleOnEmptyChat is enabled, show title only when chat has messages
41
+ if (hideTitleOnEmptyChat && isChatEmpty) {
42
+ return false;
43
+ }
44
+ return true;
45
+ }, [hideTitleOnEmptyChat, isChatEmpty, headerProps.showTitle]);
32
46
  // Build props for Header
33
- const finalHeaderProps = useMemo(() => (Object.assign(Object.assign({}, headerProps), { title: headerTitle, baseActions: hookState.baseActions, handleNewChat: hookState.handleNewChat, handleHistoryToggle: hookState.handleHistoryToggle, handleClose: hookState.handleClose, historyButtonRef: hookState.historyButtonRef })), [
47
+ const finalHeaderProps = useMemo(() => (Object.assign(Object.assign({}, headerProps), { title: headerTitle, showTitle, baseActions: hookState.baseActions, handleNewChat: hookState.handleNewChat, handleHistoryToggle: hookState.handleHistoryToggle, handleClose: hookState.handleClose, historyButtonRef: hookState.historyButtonRef })), [
34
48
  headerTitle,
49
+ showTitle,
35
50
  hookState.baseActions,
36
51
  hookState.handleNewChat,
37
52
  hookState.handleHistoryToggle,
@@ -44,9 +59,7 @@ export function ChatContainer(props) {
44
59
  var _a, _b, _c, _d;
45
60
  return Object.assign(Object.assign({}, emptyContainerProps), { image: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.image, title: (welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.title) || ((_a = i18nConfig.emptyState) === null || _a === void 0 ? void 0 : _a.title) || i18n('empty-state-title'), description: (welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.description) ||
46
61
  ((_b = i18nConfig.emptyState) === null || _b === void 0 ? void 0 : _b.description) ||
47
- i18n('empty-state-description'), suggestionTitle: (welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.suggestionTitle) ||
48
- ((_c = i18nConfig.emptyState) === null || _c === void 0 ? void 0 : _c.suggestionsTitle) ||
49
- i18n('empty-state-suggestions-title'), suggestions: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.suggestions, alignment: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.alignment, layout: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.layout, wrapText: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.wrapText, showMore: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.showMore, showMoreText: (welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.showMoreText) ||
62
+ i18n('empty-state-description'), suggestionTitle: (welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.suggestionTitle) || ((_c = i18nConfig.emptyState) === null || _c === void 0 ? void 0 : _c.suggestionsTitle), suggestions: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.suggestions, alignment: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.alignment, layout: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.layout, wrapText: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.wrapText, showMore: welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.showMore, showMoreText: (welcomeConfig === null || welcomeConfig === void 0 ? void 0 : welcomeConfig.showMoreText) ||
50
63
  ((_d = i18nConfig.emptyState) === null || _d === void 0 ? void 0 : _d.showMoreText) ||
51
64
  i18n('empty-state-show-more'), onSuggestionClick: async (clickedTitle) => {
52
65
  await onSendMessage({ content: clickedTitle });
@@ -74,21 +87,21 @@ export function ChatContainer(props) {
74
87
  promptInputProps,
75
88
  ]);
76
89
  // Build props for Disclaimer
77
- const disclaimerProps = useMemo(() => {
90
+ const finalDisclaimerProps = useMemo(() => {
78
91
  var _a;
79
92
  const disclaimerText = ((_a = i18nConfig.disclaimer) === null || _a === void 0 ? void 0 : _a.text) || i18n('disclaimer-text');
80
- return {
81
- text: disclaimerText,
82
- };
83
- }, [i18nConfig.disclaimer]);
93
+ return Object.assign(Object.assign({}, disclaimerProps), { text: disclaimerProps.text || disclaimerText });
94
+ }, [i18nConfig.disclaimer, disclaimerProps]);
84
95
  // Build props for ChatContent
85
96
  const finalContentProps = useMemo(() => (Object.assign(Object.assign({}, contentProps), { view: hookState.chatContentView, emptyContainerProps: finalEmptyContainerProps, messageListProps })), [hookState.chatContentView, finalEmptyContainerProps, messageListProps, contentProps]);
86
97
  // Build props for History
87
98
  const finalHistoryProps = useMemo(() => {
88
- var _a;
99
+ var _a, _b;
89
100
  return (Object.assign(Object.assign({}, historyProps), { chats, selectedChat: hookState.activeChat, onSelectChat: hookState.handleSelectChat, onDeleteChat, open: hookState.isHistoryOpen, onOpenChange: hookState.handleHistoryOpenChange, anchorElement: hookState.historyButtonRef.current, emptyPlaceholder: ((_a = i18nConfig.history) === null || _a === void 0 ? void 0 : _a.emptyPlaceholder) ||
90
101
  historyProps.emptyPlaceholder ||
91
- i18n('history-empty') }));
102
+ i18n('history-empty'), emptyFilteredPlaceholder: ((_b = i18nConfig.history) === null || _b === void 0 ? void 0 : _b.emptyFilteredPlaceholder) ||
103
+ historyProps.emptyFilteredPlaceholder ||
104
+ i18n('history-empty-filtered') }));
92
105
  }, [
93
106
  chats,
94
107
  hookState.activeChat,
@@ -100,6 +113,6 @@ export function ChatContainer(props) {
100
113
  i18nConfig.history,
101
114
  historyProps,
102
115
  ]);
103
- const showFooter = finalPromptInputProps || disclaimerProps;
104
- return (_jsxs("div", { className: b(null, className), "data-qa": qa, children: [_jsx("div", { className: b('header', headerClassName), children: _jsx(Header, Object.assign({}, finalHeaderProps)) }), _jsx("div", { className: b('content', { view: hookState.chatContentView }, contentClassName), children: _jsx(ChatContent, Object.assign({}, finalContentProps)) }), showFooter && (_jsxs("div", { className: b('footer', { view: hookState.chatContentView }, footerClassName), children: [finalPromptInputProps && _jsx(PromptInput, Object.assign({}, finalPromptInputProps)), disclaimerProps && _jsx(Disclaimer, Object.assign({}, disclaimerProps))] })), _jsx(History, Object.assign({}, finalHistoryProps))] }));
116
+ const showFooter = finalPromptInputProps || finalDisclaimerProps;
117
+ return (_jsxs("div", { className: b(null, className), "data-qa": qa, children: [_jsx("div", { className: b('header', headerClassName), children: _jsx(Header, Object.assign({}, finalHeaderProps)) }), _jsx("div", { className: b('content', { view: hookState.chatContentView }, contentClassName), children: _jsx(ChatContent, Object.assign({}, finalContentProps)) }), showFooter && (_jsxs("div", { className: b('footer', { view: hookState.chatContentView }, footerClassName), children: [finalPromptInputProps && _jsx(PromptInput, Object.assign({}, finalPromptInputProps)), finalDisclaimerProps && _jsx(Disclaimer, Object.assign({}, finalDisclaimerProps))] })), _jsx(History, Object.assign({}, finalHistoryProps))] }));
105
118
  }
@@ -2,9 +2,9 @@
2
2
  "header-default-title": "AI Chat",
3
3
  "empty-state-title": "Welcome to AI Chat",
4
4
  "empty-state-description": "Start a conversation by typing a message below or selecting a suggestion.",
5
- "empty-state-suggestions-title": "Try asking:",
6
5
  "empty-state-show-more": "Show more examples",
7
6
  "prompt-placeholder": "Type your message...",
8
7
  "history-empty": "No chat history yet",
8
+ "history-empty-filtered": "No chats match your search",
9
9
  "disclaimer-text": "AI can make mistakes. Check important info."
10
10
  }
@@ -1,13 +1,13 @@
1
- export declare const i18n: ((key: "header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-suggestions-title" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "disclaimer-text", params?: import("@gravity-ui/i18n").Params) => string) & {
1
+ export declare const i18n: ((key: "header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "history-empty-filtered" | "disclaimer-text", params?: import("@gravity-ui/i18n").Params) => string) & {
2
2
  Translation: import("react").ComponentType<{
3
3
  children: (props: {
4
- t: (key: "header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-suggestions-title" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "disclaimer-text", params?: import("@gravity-ui/i18n").Params) => string;
4
+ t: (key: "header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "history-empty-filtered" | "disclaimer-text", params?: import("@gravity-ui/i18n").Params) => string;
5
5
  }) => React.ReactNode;
6
6
  }>;
7
7
  useTranslation: () => {
8
- t: (key: "header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-suggestions-title" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "disclaimer-text", params?: import("@gravity-ui/i18n").Params) => string;
8
+ t: (key: "header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "history-empty-filtered" | "disclaimer-text", params?: import("@gravity-ui/i18n").Params) => string;
9
9
  };
10
10
  keysetData: {
11
- "g-aikit-ChatContainer": Record<"header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-suggestions-title" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "disclaimer-text", import("@gravity-ui/i18n").KeyData>;
11
+ "g-aikit-ChatContainer": Record<"header-default-title" | "empty-state-title" | "empty-state-description" | "empty-state-show-more" | "prompt-placeholder" | "history-empty" | "history-empty-filtered" | "disclaimer-text", import("@gravity-ui/i18n").KeyData>;
12
12
  };
13
13
  };
@@ -2,9 +2,9 @@
2
2
  "header-default-title": "AI Чат",
3
3
  "empty-state-title": "Добро пожаловать в AI Чат",
4
4
  "empty-state-description": "Начните разговор, введя сообщение ниже или выбрав подсказку.",
5
- "empty-state-suggestions-title": "Попробуйте спросить:",
6
5
  "empty-state-show-more": "Показать больше примеров",
7
6
  "prompt-placeholder": "Введите ваше сообщение...",
8
7
  "history-empty": "История чатов пока пуста",
8
+ "history-empty-filtered": "Ничего не найдено по вашему запросу",
9
9
  "disclaimer-text": "ИИ может ошибаться. Проверяйте важную информацию."
10
10
  }
@@ -1,6 +1,7 @@
1
1
  import type { OptionsType } from '@diplodoc/transform/lib/typings';
2
2
  import { MessageListProps } from 'src/components/organisms/MessageList';
3
3
  import type { ChatStatus, ChatType, TChatMessage, TSubmitData } from '../../../types';
4
+ import type { DisclaimerProps } from '../../atoms/Disclaimer';
4
5
  import type { ContextItemConfig } from '../../molecules/PromptInputHeader';
5
6
  import type { SuggestionsItem } from '../../molecules/Suggestions';
6
7
  import type { HeaderProps } from '../../organisms/Header';
@@ -50,6 +51,8 @@ export interface ChatContainerI18nConfig {
50
51
  history?: {
51
52
  /** Empty state placeholder */
52
53
  emptyPlaceholder?: string;
54
+ /** Empty filtered state placeholder (when search returns no results) */
55
+ emptyFilteredPlaceholder?: string;
53
56
  /** Search placeholder */
54
57
  searchPlaceholder?: string;
55
58
  };
@@ -134,6 +137,8 @@ export interface ChatContainerProps {
134
137
  emptyContainerProps?: Partial<EmptyContainerProps>;
135
138
  /** Props override for PromptInput component */
136
139
  promptInputProps?: Partial<Omit<PromptInputProps, 'onSend' | 'onCancel'>>;
140
+ /** Props override for Disclaimer component */
141
+ disclaimerProps?: Partial<DisclaimerProps>;
137
142
  /** Props override for History component */
138
143
  historyProps?: Partial<Omit<HistoryProps, 'chats' | 'selectedChat' | 'onSelectChat' | 'onDeleteChat' | 'anchorElement'>>;
139
144
  /** Welcome screen configuration for empty state */
@@ -146,6 +151,8 @@ export interface ChatContainerProps {
146
151
  showNewChat?: boolean;
147
152
  /** Show close button */
148
153
  showClose?: boolean;
154
+ /** Hide header title when chat is empty */
155
+ hideTitleOnEmptyChat?: boolean;
149
156
  /** Additional CSS class */
150
157
  className?: string;
151
158
  /** Additional CSS class for header section */
@@ -26,6 +26,8 @@ export interface HistoryProps extends QAProps, DOMProps {
26
26
  showActions?: boolean;
27
27
  /** Empty state placeholder */
28
28
  emptyPlaceholder?: React.ReactNode;
29
+ /** Empty filtered state placeholder (when search returns no results) */
30
+ emptyFilteredPlaceholder?: React.ReactNode;
29
31
  /** Additional CSS class */
30
32
  className?: string;
31
33
  /** Custom filter function for search */
@@ -8,9 +8,9 @@ import { HistoryList } from './HistoryList';
8
8
  * @returns React component
9
9
  */
10
10
  export function History(props) {
11
- const { chats, selectedChat, onSelectChat, onDeleteChat, onLoadMore, hasMore = false, searchable = true, groupBy = 'date', showActions = true, emptyPlaceholder, className, qa, style, filterFunction, loading = false, open = false, onOpenChange, anchorElement, } = props;
11
+ const { chats, selectedChat, onSelectChat, onDeleteChat, onLoadMore, hasMore = false, searchable = true, groupBy = 'date', showActions = true, emptyPlaceholder, emptyFilteredPlaceholder, className, qa, style, filterFunction, loading = false, open = false, onOpenChange, anchorElement, } = props;
12
12
  const handleChatClick = () => {
13
13
  onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(false);
14
14
  };
15
- return (_jsx(Popup, { anchorElement: anchorElement, placement: "bottom-end", open: open, onOpenChange: onOpenChange, children: _jsx(HistoryList, { chats: chats, selectedChat: selectedChat, onSelectChat: onSelectChat, onDeleteChat: onDeleteChat, onLoadMore: onLoadMore, hasMore: hasMore, searchable: searchable, groupBy: groupBy, showActions: showActions, emptyPlaceholder: emptyPlaceholder, className: className, qa: qa, style: style, filterFunction: filterFunction, loading: loading, onChatClick: handleChatClick }) }));
15
+ return (_jsx(Popup, { anchorElement: anchorElement, placement: "bottom-end", open: open, onOpenChange: onOpenChange, children: _jsx(HistoryList, { chats: chats, selectedChat: selectedChat, onSelectChat: onSelectChat, onDeleteChat: onDeleteChat, onLoadMore: onLoadMore, hasMore: hasMore, searchable: searchable, groupBy: groupBy, showActions: showActions, emptyPlaceholder: emptyPlaceholder, emptyFilteredPlaceholder: emptyFilteredPlaceholder, className: className, qa: qa, style: style, filterFunction: filterFunction, loading: loading, onChatClick: handleChatClick }) }));
16
16
  }
@@ -27,7 +27,7 @@ $block: '.#{variables.$ns}history';
27
27
 
28
28
  &__filter {
29
29
  display: flex;
30
- padding: spacing(2);
30
+ padding: spacing(2) spacing(2) 0 spacing(2);
31
31
  align-items: center;
32
32
  gap: spacing(2);
33
33
  align-self: stretch;
@@ -44,6 +44,7 @@ $block: '.#{variables.$ns}history';
44
44
  }
45
45
 
46
46
  &__chat-item {
47
+ cursor: pointer;
47
48
  display: flex;
48
49
  padding: spacing(2) spacing(4);
49
50
  align-items: center;
@@ -27,6 +27,8 @@ export interface HistoryListProps extends QAProps, DOMProps {
27
27
  showActions?: boolean;
28
28
  /** Empty state placeholder */
29
29
  emptyPlaceholder?: React.ReactNode;
30
+ /** Empty filtered state placeholder (when search returns no results) */
31
+ emptyFilteredPlaceholder?: React.ReactNode;
30
32
  /** Additional CSS class */
31
33
  className?: string;
32
34
  /** Custom filter function for search */
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo } from 'react';
2
+ import { useMemo, useState } from 'react';
3
3
  import { Button, List } from '@gravity-ui/uikit';
4
4
  import { defaultChatFilter, groupChatsByDate } from '../../../utils/chatUtils';
5
5
  import { block } from '../../../utils/cn';
@@ -16,7 +16,8 @@ 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, 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, } = props;
20
+ const [filteredItemCount, setFilteredItemCount] = useState(null);
20
21
  // Group chats if needed
21
22
  const groupedChats = useMemo(() => {
22
23
  if (groupBy === 'none') {
@@ -84,5 +85,10 @@ export function HistoryList(props) {
84
85
  return (_jsx(ChatItem, { chat: item, showActions: showActions, onChatClick: handleChatClick, onDeleteClick: onDeleteChat ? handleDeleteClick : undefined }, item.id));
85
86
  };
86
87
  const emptyState = emptyPlaceholder || _jsx("div", { className: b('empty'), children: i18n('empty-state') });
87
- 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, { items: listItems, renderItem: renderItem, virtualized: false, filterable: searchable, filterItem: wrappedFilterFunction, filterPlaceholder: i18n('search-placeholder'), filterClassName: b('filter'), emptyPlaceholder: emptyState, selectedItemIndex: selectedItemIndex, itemsClassName: b('list'), itemClassName: b('list-item') })) }), hasMore && onLoadMore && (_jsx(Button, { view: "flat-action", size: "m", width: "max", onClick: onLoadMore, children: i18n('action-load-more') }))] }));
88
+ const emptyFilteredState = emptyFilteredPlaceholder || (_jsx("div", { className: b('empty'), children: i18n('empty-filtered-state') }));
89
+ // Determine which empty placeholder to show
90
+ const finalEmptyPlaceholder = filteredItemCount === null || filteredItemCount === listItems.length
91
+ ? emptyState
92
+ : 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') }))] }));
88
94
  }
@@ -2,6 +2,7 @@
2
2
  "action-load-more": "Load earlier conversations",
3
3
  "search-placeholder": "Search your chats",
4
4
  "empty-state": "No chats found",
5
+ "empty-filtered-state": "No chats match your search",
5
6
  "tooltip-history": "Chat history",
6
7
  "tooltip-delete": "Delete"
7
8
  }
@@ -1,13 +1,13 @@
1
- export declare const i18n: ((key: "action-load-more" | "search-placeholder" | "empty-state" | "tooltip-history" | "tooltip-delete", params?: import("@gravity-ui/i18n").Params) => string) & {
1
+ export declare const i18n: ((key: "action-load-more" | "search-placeholder" | "empty-state" | "empty-filtered-state" | "tooltip-history" | "tooltip-delete", params?: import("@gravity-ui/i18n").Params) => string) & {
2
2
  Translation: import("react").ComponentType<{
3
3
  children: (props: {
4
- t: (key: "action-load-more" | "search-placeholder" | "empty-state" | "tooltip-history" | "tooltip-delete", params?: import("@gravity-ui/i18n").Params) => string;
4
+ t: (key: "action-load-more" | "search-placeholder" | "empty-state" | "empty-filtered-state" | "tooltip-history" | "tooltip-delete", params?: import("@gravity-ui/i18n").Params) => string;
5
5
  }) => React.ReactNode;
6
6
  }>;
7
7
  useTranslation: () => {
8
- t: (key: "action-load-more" | "search-placeholder" | "empty-state" | "tooltip-history" | "tooltip-delete", params?: import("@gravity-ui/i18n").Params) => string;
8
+ t: (key: "action-load-more" | "search-placeholder" | "empty-state" | "empty-filtered-state" | "tooltip-history" | "tooltip-delete", params?: import("@gravity-ui/i18n").Params) => string;
9
9
  };
10
10
  keysetData: {
11
- "g-aikit-History": Record<"action-load-more" | "search-placeholder" | "empty-state" | "tooltip-history" | "tooltip-delete", import("@gravity-ui/i18n").KeyData>;
11
+ "g-aikit-History": Record<"action-load-more" | "search-placeholder" | "empty-state" | "empty-filtered-state" | "tooltip-history" | "tooltip-delete", import("@gravity-ui/i18n").KeyData>;
12
12
  };
13
13
  };
@@ -2,6 +2,7 @@
2
2
  "action-load-more": "Загрузить еще",
3
3
  "search-placeholder": "Поиск по чатам",
4
4
  "empty-state": "Чаты не найдены",
5
+ "empty-filtered-state": "Ничего не найдено по вашему запросу",
5
6
  "tooltip-history": "История чатов",
6
7
  "tooltip-delete": "Удалить"
7
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/aikit",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Gravity UI base kit for building ai assistant chats",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",