@gravity-ui/aikit 0.3.1 → 0.4.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 (37) hide show
  1. package/dist/components/atoms/Alert/Alert.scss +11 -1
  2. package/dist/components/atoms/Alert/index.d.ts +3 -1
  3. package/dist/components/atoms/Alert/index.js +8 -4
  4. package/dist/components/atoms/SubmitButton/SubmitButton.d.ts +9 -1
  5. package/dist/components/atoms/SubmitButton/SubmitButton.js +16 -2
  6. package/dist/components/atoms/SubmitButton/i18n/en.json +2 -1
  7. package/dist/components/atoms/SubmitButton/i18n/index.d.ts +4 -4
  8. package/dist/components/atoms/SubmitButton/i18n/ru.json +2 -1
  9. package/dist/components/molecules/Suggestions/Suggestions.d.ts +3 -2
  10. package/dist/components/molecules/Suggestions/Suggestions.js +1 -1
  11. package/dist/components/molecules/ToolHeader/index.js +3 -9
  12. package/dist/components/molecules/ToolStatus/ToolStatus.scss +6 -0
  13. package/dist/components/molecules/ToolStatus/i18n/en.json +3 -0
  14. package/dist/components/molecules/ToolStatus/i18n/index.d.ts +13 -0
  15. package/dist/components/molecules/ToolStatus/i18n/index.js +5 -0
  16. package/dist/components/molecules/ToolStatus/i18n/ru.json +3 -0
  17. package/dist/components/molecules/ToolStatus/index.d.ts +8 -0
  18. package/dist/components/molecules/ToolStatus/index.js +24 -0
  19. package/dist/components/molecules/index.d.ts +1 -0
  20. package/dist/components/molecules/index.js +1 -0
  21. package/dist/components/organisms/PromptInput/PromptInputFull.js +3 -1
  22. package/dist/components/organisms/PromptInput/PromptInputSimple.js +3 -1
  23. package/dist/components/organisms/PromptInput/types.d.ts +6 -2
  24. package/dist/components/organisms/UserMessage/index.d.ts +1 -1
  25. package/dist/components/pages/ChatContainer/ChatContainer.js +12 -4
  26. package/dist/components/pages/ChatContainer/types.d.ts +10 -7
  27. package/dist/components/templates/EmptyContainer/EmptyContainer.d.ts +4 -4
  28. package/dist/components/templates/EmptyContainer/EmptyContainer.js +1 -1
  29. package/dist/hooks/index.d.ts +2 -0
  30. package/dist/hooks/index.js +2 -0
  31. package/dist/hooks/useAutoCollapseOnCancelled.d.ts +6 -0
  32. package/dist/hooks/useAutoCollapseOnCancelled.js +10 -0
  33. package/dist/hooks/useAutoCollapseOnSuccess.d.ts +6 -0
  34. package/dist/hooks/useAutoCollapseOnSuccess.js +10 -0
  35. package/dist/hooks/useToolMessage.js +5 -1
  36. package/dist/types/tool.d.ts +5 -3
  37. package/package.json +1 -1
@@ -4,9 +4,19 @@ $block: '.#{variables.$ns}alert';
4
4
 
5
5
  #{$block} {
6
6
  display: flex;
7
- align-items: center;
7
+ flex-direction: column;
8
8
  gap: var(--g-spacing-2);
9
9
 
10
+ &__header {
11
+ display: flex;
12
+ align-items: center;
13
+ gap: var(--g-spacing-2);
14
+ }
15
+
16
+ &__text {
17
+ flex: 1;
18
+ }
19
+
10
20
  &__icon {
11
21
  flex-shrink: 0;
12
22
 
@@ -7,7 +7,9 @@ export interface AlertProps {
7
7
  content: React.ReactNode;
8
8
  onClick: () => void;
9
9
  };
10
+ content?: React.ReactNode;
11
+ initialExpanded?: boolean;
10
12
  className?: string;
11
13
  qa?: string;
12
14
  }
13
- export declare function Alert({ text, icon, button, variant, className, qa }: AlertProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function Alert({ text, icon, button, content, initialExpanded, variant, className, qa, }: AlertProps): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo } from 'react';
3
- import { CircleExclamationFill, CircleInfoFill, TriangleExclamationFill } from '@gravity-ui/icons';
2
+ import { useMemo, useState } from 'react';
3
+ import { ChevronDown, ChevronUp, CircleExclamationFill, CircleInfoFill, TriangleExclamationFill, } from '@gravity-ui/icons';
4
4
  import { Button, Icon, Text } from '@gravity-ui/uikit';
5
5
  import { block } from '../../../utils/cn';
6
6
  import './Alert.scss';
@@ -10,7 +10,8 @@ const statusIcons = {
10
10
  warning: TriangleExclamationFill,
11
11
  error: CircleExclamationFill,
12
12
  };
13
- export function Alert({ text, icon, button, variant = 'default', className, qa }) {
13
+ export function Alert({ text, icon, button, content, initialExpanded = false, variant = 'default', className, qa, }) {
14
+ const [isExpanded, setIsExpanded] = useState(initialExpanded);
14
15
  const statusIcon = useMemo(() => {
15
16
  if (icon) {
16
17
  return _jsx("div", { className: b('icon'), children: icon });
@@ -21,5 +22,8 @@ export function Alert({ text, icon, button, variant = 'default', className, qa }
21
22
  }
22
23
  return null;
23
24
  }, [icon, variant]);
24
- return (_jsxs("div", { className: b(null, className), "data-qa": qa, children: [statusIcon, _jsx(Text, { variant: "body-1", children: text }), button ? (_jsx(Button, { onClick: button.onClick, size: "s", view: "outlined", className: b('action'), children: button.content })) : null] }));
25
+ const toggleExpanded = () => {
26
+ setIsExpanded((prev) => !prev);
27
+ };
28
+ return (_jsxs("div", { className: b(null, className), "data-qa": qa, children: [_jsxs("div", { className: b('header'), children: [statusIcon, _jsx(Text, { variant: "body-1", className: b('text'), children: text }), content && (_jsx(Button, { onClick: toggleExpanded, size: "s", view: "flat", className: b('collapse-button'), children: _jsx(Icon, { data: isExpanded ? ChevronUp : ChevronDown, size: 16 }) })), button ? (_jsx(Button, { onClick: button.onClick, size: "s", view: "outlined", className: b('action'), children: button.content })) : null] }), content && isExpanded && _jsx("div", { className: b('content'), children: content })] }));
25
29
  }
@@ -18,6 +18,14 @@ export interface SubmitButtonProps {
18
18
  * Button size
19
19
  */
20
20
  size?: ButtonButtonProps['size'];
21
+ /**
22
+ * Custom tooltip for enabled state
23
+ */
24
+ tooltipSend?: string;
25
+ /**
26
+ * Custom tooltip for cancelable state
27
+ */
28
+ tooltipCancel?: string;
21
29
  /**
22
30
  * QA/test identifier
23
31
  */
@@ -34,4 +42,4 @@ export interface SubmitButtonProps {
34
42
  *
35
43
  * @returns Submit button component
36
44
  */
37
- export declare function SubmitButton({ onClick, state, className, size, qa }: SubmitButtonProps): import("react/jsx-runtime").JSX.Element;
45
+ export declare function SubmitButton({ onClick, state, className, size, tooltipSend, tooltipCancel, qa, }: SubmitButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -18,7 +18,7 @@ const b = block('submit-button');
18
18
  *
19
19
  * @returns Submit button component
20
20
  */
21
- export function SubmitButton({ onClick, state, className, size = 'm', qa }) {
21
+ export function SubmitButton({ onClick, state, className, size = 'm', tooltipSend, tooltipCancel, qa, }) {
22
22
  const isCancelable = state === 'cancelable';
23
23
  const isLoading = state === 'loading';
24
24
  const isDisabled = state === 'disabled';
@@ -29,5 +29,19 @@ export function SubmitButton({ onClick, state, className, size = 'm', qa }) {
29
29
  }
30
30
  return Promise.resolve();
31
31
  }, [state, onClick]);
32
- return (_jsx(ActionButton, { view: "action", size: size, color: "brand", disabled: isDisabled, onClick: handleClick, className: b({ size, loading: isLoading, cancelable: isCancelable }, className), qa: qa, tooltipTitle: i18n('tooltip-send'), children: isLoading ? (_jsx("div", { className: b('loader'), children: _jsx(Spin, { className: b('spinner'), size: "xs" }) })) : (_jsx(Icon, { size: 16, data: iconData })) }));
32
+ // Get tooltip based on state
33
+ const getTooltipTitle = () => {
34
+ switch (state) {
35
+ case 'enabled':
36
+ return tooltipSend || i18n('tooltip-send');
37
+ case 'cancelable':
38
+ return tooltipCancel || i18n('tooltip-cancel');
39
+ case 'disabled':
40
+ case 'loading':
41
+ return undefined;
42
+ default:
43
+ return undefined;
44
+ }
45
+ };
46
+ return (_jsx(ActionButton, { view: "action", size: size, color: "brand", disabled: isDisabled, onClick: handleClick, className: b({ size, loading: isLoading, cancelable: isCancelable }, className), qa: qa, tooltipTitle: getTooltipTitle(), children: isLoading ? (_jsx("div", { className: b('loader'), children: _jsx(Spin, { className: b('spinner'), size: "xs" }) })) : (_jsx(Icon, { size: 16, data: iconData })) }));
33
47
  }
@@ -1,3 +1,4 @@
1
1
  {
2
- "tooltip-send": "Send"
2
+ "tooltip-send": "Send",
3
+ "tooltip-cancel": "Cancel"
3
4
  }
@@ -1,13 +1,13 @@
1
- export declare const i18n: ((key: "tooltip-send", params?: import("@gravity-ui/i18n").Params) => string) & {
1
+ export declare const i18n: ((key: "tooltip-send" | "tooltip-cancel", params?: import("@gravity-ui/i18n").Params) => string) & {
2
2
  Translation: import("react").ComponentType<{
3
3
  children: (props: {
4
- t: (key: "tooltip-send", params?: import("@gravity-ui/i18n").Params) => string;
4
+ t: (key: "tooltip-send" | "tooltip-cancel", params?: import("@gravity-ui/i18n").Params) => string;
5
5
  }) => React.ReactNode;
6
6
  }>;
7
7
  useTranslation: () => {
8
- t: (key: "tooltip-send", params?: import("@gravity-ui/i18n").Params) => string;
8
+ t: (key: "tooltip-send" | "tooltip-cancel", params?: import("@gravity-ui/i18n").Params) => string;
9
9
  };
10
10
  keysetData: {
11
- "g-aikit-SubmitButton": Record<"tooltip-send", import("@gravity-ui/i18n").KeyData>;
11
+ "g-aikit-SubmitButton": Record<"tooltip-send" | "tooltip-cancel", import("@gravity-ui/i18n").KeyData>;
12
12
  };
13
13
  };
@@ -1,3 +1,4 @@
1
1
  {
2
- "tooltip-send": "Отправить"
2
+ "tooltip-send": "Отправить",
3
+ "tooltip-cancel": "Отменить"
3
4
  }
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import { ButtonButtonProps } from '@gravity-ui/uikit';
2
3
  import './Suggestions.scss';
3
4
  export type SuggestionsItem = {
@@ -18,8 +19,8 @@ export type SuggestionsProps = {
18
19
  items: SuggestionsItem[];
19
20
  /** Callback function called when a suggestion is clicked */
20
21
  onClick: (content: string, id?: string) => void | Promise<void>;
21
- /** Title to display above suggestions */
22
- title?: string;
22
+ /** Title to display above suggestions - can be string or custom React element */
23
+ title?: React.ReactNode;
23
24
  /** Layout orientation: 'grid' for horizontal, 'list' for vertical */
24
25
  layout?: 'grid' | 'list';
25
26
  /** Text alignment inside buttons: 'left', 'center', or 'right' */
@@ -23,5 +23,5 @@ export function Suggestions(props) {
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));
25
25
  };
26
- return (_jsxs("div", { className: b('container', className), "data-qa": qa, children: [title && (_jsx("div", { className: b('title'), children: _jsx(Text, { variant: "body-1", color: "primary", children: title }) })), _jsx("div", { className: b({ layout }), children: items.map((item, index) => renderButton(item, index)) })] }));
26
+ return (_jsxs("div", { className: b('container', className), "data-qa": qa, children: [title && (_jsx("div", { className: b('title'), children: typeof title === 'string' ? (_jsx(Text, { variant: "body-1", color: "primary", children: title })) : (title) })), _jsx("div", { className: b({ layout }), children: items.map((item, index) => renderButton(item, index)) })] }));
27
27
  }
@@ -1,19 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Text } from '@gravity-ui/uikit';
3
3
  import { block } from '../../../utils/cn';
4
- import { ActionButton, ToolIndicator } from '../../atoms';
4
+ import { ActionButton } from '../../atoms';
5
5
  import { ButtonGroup } from '../ButtonGroup';
6
+ import { ToolStatus } from '../ToolStatus';
6
7
  import './ToolHeader.scss';
7
8
  const b = block('tool-header');
8
- function getIndicatorStatus(status) {
9
- if (status === 'success' || status === 'error' || status === 'loading') {
10
- return status;
11
- }
12
- return undefined;
13
- }
14
9
  export function ToolHeader(props) {
15
10
  const { toolIcon, toolName, content, actions, status, className, qa } = props;
16
11
  const hasActions = actions && actions.length > 0;
17
- const indicatorStatus = getIndicatorStatus(status);
18
- return (_jsxs("div", { className: b('', className), "data-qa": qa, children: [_jsxs("div", { className: b('left'), children: [toolIcon, _jsx(Text, { children: toolName }), content] }), _jsxs("div", { className: b('right'), children: [hasActions && (_jsx(ButtonGroup, { children: actions.map((action, index) => (_jsx(ActionButton, Object.assign({ tooltipTitle: action.label, view: "flat-secondary", size: "s" }, action, { children: action.icon }), index))) })), indicatorStatus && _jsx(ToolIndicator, { status: indicatorStatus })] })] }));
12
+ return (_jsxs("div", { className: b('', className), "data-qa": qa, children: [_jsxs("div", { className: b('left'), children: [toolIcon, _jsx(Text, { children: toolName }), content] }), _jsxs("div", { className: b('right'), children: [hasActions && (_jsx(ButtonGroup, { children: actions.map((action, index) => (_jsx(ActionButton, Object.assign({ tooltipTitle: action.label, view: "flat-secondary", size: "s" }, action, { children: action.icon }), index))) })), _jsx(ToolStatus, { status: status })] })] }));
19
13
  }
@@ -0,0 +1,6 @@
1
+ @use '../../../styles/variables';
2
+
3
+ $block: '.#{variables.$ns}tool-status';
4
+
5
+ #{$block} {
6
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "status-cancelled": "Cancelled"
3
+ }
@@ -0,0 +1,13 @@
1
+ export declare const i18n: ((key: "status-cancelled", params?: import("@gravity-ui/i18n").Params) => string) & {
2
+ Translation: import("react").ComponentType<{
3
+ children: (props: {
4
+ t: (key: "status-cancelled", params?: import("@gravity-ui/i18n").Params) => string;
5
+ }) => React.ReactNode;
6
+ }>;
7
+ useTranslation: () => {
8
+ t: (key: "status-cancelled", params?: import("@gravity-ui/i18n").Params) => string;
9
+ };
10
+ keysetData: {
11
+ "g-aikit-ToolStatus": Record<"status-cancelled", import("@gravity-ui/i18n").KeyData>;
12
+ };
13
+ };
@@ -0,0 +1,5 @@
1
+ import { addComponentKeysets } from '@gravity-ui/uikit/i18n';
2
+ import { NAMESPACE } from '../../../../utils/cn';
3
+ import en from './en.json';
4
+ import ru from './ru.json';
5
+ export const i18n = addComponentKeysets({ en, ru }, `${NAMESPACE}ToolStatus`);
@@ -0,0 +1,3 @@
1
+ {
2
+ "status-cancelled": "Отменено"
3
+ }
@@ -0,0 +1,8 @@
1
+ import type { TToolStatus as ToolStatusType } from '../../../types/tool';
2
+ import './ToolStatus.scss';
3
+ export type ToolStatusProps = {
4
+ status?: ToolStatusType;
5
+ className?: string;
6
+ qa?: string;
7
+ };
8
+ export declare function ToolStatus(props: ToolStatusProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Text } from '@gravity-ui/uikit';
3
+ import { block } from '../../../utils/cn';
4
+ import { ToolIndicator } from '../../atoms';
5
+ import { i18n } from './i18n';
6
+ import './ToolStatus.scss';
7
+ const b = block('tool-status');
8
+ function getIndicatorStatus(status) {
9
+ if (status === 'success' || status === 'error' || status === 'loading') {
10
+ return status;
11
+ }
12
+ return undefined;
13
+ }
14
+ export function ToolStatus(props) {
15
+ const { status, className, qa } = props;
16
+ const indicatorStatus = getIndicatorStatus(status);
17
+ if (status === 'cancelled') {
18
+ return (_jsx(Text, { color: "secondary", className: b('', className), "data-qa": qa, children: i18n('status-cancelled') }));
19
+ }
20
+ if (indicatorStatus) {
21
+ return _jsx(ToolIndicator, { status: indicatorStatus, className: className, qa: qa });
22
+ }
23
+ return null;
24
+ }
@@ -9,3 +9,4 @@ export * from './Suggestions';
9
9
  export * from './Tabs';
10
10
  export * from './ToolFooter';
11
11
  export * from './ToolHeader';
12
+ export * from './ToolStatus';
@@ -10,3 +10,4 @@ export * from './Suggestions';
10
10
  export * from './Tabs';
11
11
  export * from './ToolFooter';
12
12
  export * from './ToolHeader';
13
+ export * from './ToolStatus';
@@ -14,12 +14,14 @@ export function PromptInputFull(props) {
14
14
  const { hookState, headerProps = {}, bodyProps = {}, footerProps = {}, className, qa } = props;
15
15
  const { topContent, contextItems = [], showContextIndicator = false, contextIndicatorProps, } = headerProps;
16
16
  const { placeholder = 'Plan, code, build and test anything', minRows = 1, maxRows = 15, autoFocus = false, } = bodyProps;
17
- const { bottomContent, showSettings = false, onSettingsClick, showAttachment = false, onAttachmentClick, showMicrophone = false, onMicrophoneClick, } = footerProps;
17
+ const { bottomContent, showSettings = false, onSettingsClick, showAttachment = false, onAttachmentClick, showMicrophone = false, onMicrophoneClick, submitButtonTooltipSend, submitButtonTooltipCancel, } = footerProps;
18
18
  const { value, submitButtonState, handleChange, handleKeyDown, handleSubmit } = hookState;
19
19
  const shouldShowHeader = topContent || contextItems.length > 0 || showContextIndicator;
20
20
  const shouldShowFooter = true;
21
21
  return (_jsxs("div", { className: b({ view: 'full' }, className), "data-qa": qa, children: [shouldShowHeader && (_jsx(PromptInputHeader, { contextItems: contextItems, showContextIndicator: showContextIndicator, contextIndicatorProps: contextIndicatorProps, children: topContent })), _jsx(PromptInputBody, { value: value, placeholder: placeholder, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, onChange: handleChange, onKeyDown: handleKeyDown }), shouldShowFooter && (_jsx(PromptInputFooter, { submitButton: {
22
22
  onClick: handleSubmit,
23
23
  state: submitButtonState,
24
+ tooltipSend: submitButtonTooltipSend,
25
+ tooltipCancel: submitButtonTooltipCancel,
24
26
  }, showSettings: showSettings, onSettingsClick: onSettingsClick, showAttachment: showAttachment, onAttachmentClick: onAttachmentClick, showMicrophone: showMicrophone, onMicrophoneClick: onMicrophoneClick, children: bottomContent }))] }));
25
27
  }
@@ -12,10 +12,12 @@ const b = block('prompt-input');
12
12
  export function PromptInputSimple(props) {
13
13
  const { hookState, bodyProps = {}, footerProps = {}, className, qa } = props;
14
14
  const { placeholder = 'Plan, code, build and test anything', minRows = 1, maxRows = 15, autoFocus = false, } = bodyProps;
15
- const { bottomContent, showAttachment = false, onAttachmentClick, showMicrophone = false, onMicrophoneClick, } = footerProps;
15
+ const { bottomContent, showAttachment = false, onAttachmentClick, showMicrophone = false, onMicrophoneClick, submitButtonTooltipSend, submitButtonTooltipCancel, } = footerProps;
16
16
  const { value, submitButtonState, handleChange, handleKeyDown, handleSubmit } = hookState;
17
17
  return (_jsx("div", { className: b({ view: 'simple' }, className), "data-qa": qa, children: _jsxs("div", { className: b('content'), children: [_jsx(PromptInputBody, { value: value, placeholder: placeholder, minRows: minRows, maxRows: maxRows, autoFocus: autoFocus, onChange: handleChange, onKeyDown: handleKeyDown }), _jsx(PromptInputFooter, { submitButton: {
18
18
  onClick: handleSubmit,
19
19
  state: submitButtonState,
20
+ tooltipSend: submitButtonTooltipSend,
21
+ tooltipCancel: submitButtonTooltipCancel,
20
22
  }, showAttachment: showAttachment, onAttachmentClick: onAttachmentClick, showMicrophone: showMicrophone, onMicrophoneClick: onMicrophoneClick, buttonSize: "l", children: bottomContent })] }) }));
21
23
  }
@@ -54,6 +54,10 @@ export type PromptInputFooterConfig = {
54
54
  showMicrophone?: boolean;
55
55
  /** Microphone icon click handler */
56
56
  onMicrophoneClick?: () => void;
57
+ /** Custom tooltip for submit button in enabled state */
58
+ submitButtonTooltipSend?: string;
59
+ /** Custom tooltip for submit button in cancelable state */
60
+ submitButtonTooltipCancel?: string;
57
61
  };
58
62
  /**
59
63
  * Props for the suggestions section of PromptInput
@@ -63,8 +67,8 @@ export type PromptInputSuggestionsConfig = {
63
67
  suggestions?: SuggestionsItem[];
64
68
  /** Show submit suggestions */
65
69
  showSuggestions?: boolean;
66
- /** Title for the suggestions section */
67
- suggestTitle?: string;
70
+ /** Title for the suggestions section - can be string or custom React element */
71
+ suggestTitle?: string | ReactNode;
68
72
  /** Layout orientation for suggestions: 'grid' for horizontal, 'list' for vertical */
69
73
  suggestionsLayout?: SuggestionsProps['layout'];
70
74
  /** Text alignment inside suggestion buttons */
@@ -2,7 +2,7 @@ import type { OptionsType } from '@diplodoc/transform/lib/typings';
2
2
  import type { BaseMessageProps } from '../../../types/messages';
3
3
  import './UserMessage.scss';
4
4
  export type UserMessageProps = Pick<BaseMessageProps, 'actions' | 'showActionsOnHover' | 'showTimestamp' | 'timestamp'> & {
5
- content: string | React.ReactNode;
5
+ content: React.ReactNode;
6
6
  format?: 'plain' | 'markdown';
7
7
  showAvatar?: boolean;
8
8
  avatarUrl?: string;
@@ -54,17 +54,25 @@ export function ChatContainer(props) {
54
54
  }, [welcomeConfig, i18nConfig.emptyState, emptyContainerProps, onSendMessage]);
55
55
  // Build props for MessageList
56
56
  const messageListProps = useMemo(() => (Object.assign(Object.assign({}, messageListConfig), { messages,
57
- status, errorMessage: error ? { text: error.message } : undefined, onRetry,
57
+ status, errorMessage: (messageListConfig === null || messageListConfig === void 0 ? void 0 : messageListConfig.errorMessage) || (error ? { text: error.message } : undefined), onRetry,
58
58
  showActionsOnHover,
59
59
  transformOptions })), [messages, status, error, onRetry, showActionsOnHover, transformOptions, messageListConfig]);
60
60
  // Build props for PromptInput
61
61
  const finalPromptInputProps = useMemo(() => {
62
- var _a, _b;
62
+ var _a, _b, _c, _d;
63
63
  return (Object.assign(Object.assign({}, promptInputProps), { onSend: onSendMessage, onCancel,
64
64
  status, headerProps: Object.assign(Object.assign({}, promptInputProps === null || promptInputProps === void 0 ? void 0 : promptInputProps.headerProps), { contextItems }), bodyProps: Object.assign(Object.assign({}, promptInputProps === null || promptInputProps === void 0 ? void 0 : promptInputProps.bodyProps), { placeholder: ((_a = i18nConfig.promptInput) === null || _a === void 0 ? void 0 : _a.placeholder) ||
65
65
  ((_b = promptInputProps === null || promptInputProps === void 0 ? void 0 : promptInputProps.bodyProps) === null || _b === void 0 ? void 0 : _b.placeholder) ||
66
- i18n('prompt-placeholder') }) }));
67
- }, [onSendMessage, onCancel, status, contextItems, i18nConfig.promptInput, promptInputProps]);
66
+ i18n('prompt-placeholder') }), footerProps: Object.assign(Object.assign({}, promptInputProps === null || promptInputProps === void 0 ? void 0 : promptInputProps.footerProps), { submitButtonTooltipSend: (_c = i18nConfig.submitButton) === null || _c === void 0 ? void 0 : _c.sendTooltip, submitButtonTooltipCancel: (_d = i18nConfig.submitButton) === null || _d === void 0 ? void 0 : _d.cancelTooltip }) }));
67
+ }, [
68
+ onSendMessage,
69
+ onCancel,
70
+ status,
71
+ contextItems,
72
+ i18nConfig.promptInput,
73
+ i18nConfig.submitButton,
74
+ promptInputProps,
75
+ ]);
68
76
  // Build props for Disclaimer
69
77
  const disclaimerProps = useMemo(() => {
70
78
  var _a;
@@ -38,9 +38,12 @@ export interface ChatContainerI18nConfig {
38
38
  promptInput?: {
39
39
  /** Placeholder text */
40
40
  placeholder?: string;
41
- /** Send button tooltip */
41
+ };
42
+ /** Submit button tooltips */
43
+ submitButton?: {
44
+ /** Send button tooltip (enabled state) */
42
45
  sendTooltip?: string;
43
- /** Cancel button tooltip */
46
+ /** Cancel button tooltip (cancelable state) */
44
47
  cancelTooltip?: string;
45
48
  };
46
49
  /** History texts */
@@ -63,11 +66,11 @@ export interface WelcomeConfig {
63
66
  /** Image or icon to display */
64
67
  image?: React.ReactNode;
65
68
  /** Title text or custom React element */
66
- title?: string | React.ReactNode;
69
+ title?: React.ReactNode;
67
70
  /** Description text or custom React element */
68
- description?: string | React.ReactNode;
69
- /** Suggestions section title */
70
- suggestionTitle?: string;
71
+ description?: React.ReactNode;
72
+ /** Suggestions section title - can be string or custom React element */
73
+ suggestionTitle?: React.ReactNode;
71
74
  /** Array of suggestions (title will be used as message content) */
72
75
  suggestions?: SuggestionsItem[];
73
76
  /** Alignment configuration for image, title, and description */
@@ -84,7 +87,7 @@ export interface WelcomeConfig {
84
87
  /**
85
88
  * MessageList configuration
86
89
  */
87
- export type MessageListConfig = Omit<MessageListProps, 'messages' | 'status' | 'errorMessage' | 'onRetry' | 'showActionsOnHover' | 'transformOptions'>;
90
+ export type MessageListConfig = Omit<MessageListProps, 'messages' | 'status' | 'onRetry' | 'showActionsOnHover' | 'transformOptions'>;
88
91
  /**
89
92
  * Props for ChatContainer component
90
93
  */
@@ -27,11 +27,11 @@ export interface EmptyContainerProps {
27
27
  /** Image or icon to display at the top */
28
28
  image?: React.ReactNode;
29
29
  /** Title text or custom React element for the welcome screen */
30
- title?: string | React.ReactNode;
30
+ title?: React.ReactNode;
31
31
  /** Description text or custom React element explaining the functionality */
32
- description?: string | React.ReactNode;
33
- /** Title for the suggestions section */
34
- suggestionTitle?: string;
32
+ description?: React.ReactNode;
33
+ /** Title for the suggestions section - can be string or custom React element */
34
+ suggestionTitle?: React.ReactNode;
35
35
  /** Array of suggestion items */
36
36
  suggestions?: Suggestion[];
37
37
  /** Callback when a suggestion is clicked */
@@ -22,5 +22,5 @@ export function EmptyContainer(props) {
22
22
  const descriptionAlignment = (alignment === null || alignment === void 0 ? void 0 : alignment.description) || 'left';
23
23
  // Define text for "Show more" button with localization support
24
24
  const showMoreButtonText = showMoreText || i18n('show-more-button');
25
- return (_jsx("div", { className: b(null, className), "data-qa": qa, children: _jsx("div", { className: b('content'), children: hasContent && (_jsxs(_Fragment, { children: [_jsxs("div", { className: b('welcome-section'), children: [image && (_jsx("div", { className: b('image-container', { align: imageAlignment }), children: image })), _jsxs("div", { className: b('text-container'), children: [title && (_jsx(Text, { variant: "header-2", className: b('title', { align: titleAlignment }), children: title })), description && (_jsx(Text, { variant: "body-2", color: "complementary", className: b('description', { align: descriptionAlignment }), children: description }))] })] }), suggestions && suggestions.length > 0 && onSuggestionClick && (_jsxs("div", { className: b('suggestions-section'), children: [suggestionTitle && (_jsx("div", { className: b('suggestions-title'), children: _jsx(Text, { variant: "subheader-3", color: "primary", children: suggestionTitle }) })), _jsx("div", { children: _jsx(Suggestions, { items: suggestions, onClick: onSuggestionClick, layout: layout, wrapText: wrapText }) }), showMore && (_jsx("div", { className: b('show-more'), children: _jsxs(Button, { view: "flat-secondary", size: "l", onClick: showMore, className: b('show-more-button'), children: [_jsx(Button.Icon, { children: _jsx(ArrowRotateRight, {}) }), showMoreButtonText] }) }))] }))] })) }) }));
25
+ return (_jsx("div", { className: b(null, className), "data-qa": qa, children: _jsx("div", { className: b('content'), children: hasContent && (_jsxs(_Fragment, { children: [_jsxs("div", { className: b('welcome-section'), children: [image && (_jsx("div", { className: b('image-container', { align: imageAlignment }), children: image })), _jsxs("div", { className: b('text-container'), children: [title && (_jsx(Text, { variant: "header-2", className: b('title', { align: titleAlignment }), children: title })), description && (_jsx(Text, { variant: "body-2", color: "complementary", className: b('description', { align: descriptionAlignment }), children: description }))] })] }), suggestions && suggestions.length > 0 && onSuggestionClick && (_jsxs("div", { className: b('suggestions-section'), children: [suggestionTitle && (_jsx("div", { className: b('suggestions-title'), children: typeof suggestionTitle === 'string' ? (_jsx(Text, { variant: "subheader-3", color: "primary", children: suggestionTitle })) : (suggestionTitle) })), _jsx("div", { children: _jsx(Suggestions, { items: suggestions, onClick: onSuggestionClick, layout: layout, wrapText: wrapText }) }), showMore && (_jsx("div", { className: b('show-more'), children: _jsxs(Button, { view: "flat-secondary", size: "l", onClick: showMore, className: b('show-more-button'), children: [_jsx(Button.Icon, { children: _jsx(ArrowRotateRight, {}) }), showMoreButtonText] }) }))] }))] })) }) }));
26
26
  }
@@ -2,3 +2,5 @@ export * from './useDateFormatter';
2
2
  export * from './useToolMessage';
3
3
  export * from './useSmartScroll';
4
4
  export * from './useScrollPreservation';
5
+ export * from './useAutoCollapseOnSuccess';
6
+ export * from './useAutoCollapseOnCancelled';
@@ -2,3 +2,5 @@ export * from './useDateFormatter';
2
2
  export * from './useToolMessage';
3
3
  export * from './useSmartScroll';
4
4
  export * from './useScrollPreservation';
5
+ export * from './useAutoCollapseOnSuccess';
6
+ export * from './useAutoCollapseOnCancelled';
@@ -0,0 +1,6 @@
1
+ import type { TToolStatus } from '../types/tool';
2
+ export declare function useAutoCollapseOnCancelled(options: {
3
+ enabled: boolean;
4
+ status: TToolStatus | undefined;
5
+ setIsExpanded: (expanded: boolean) => void;
6
+ }): void;
@@ -0,0 +1,10 @@
1
+ import { useEffect } from 'react';
2
+ export function useAutoCollapseOnCancelled(options) {
3
+ const { enabled, status, setIsExpanded } = options;
4
+ const isCancelled = status === 'cancelled';
5
+ useEffect(() => {
6
+ if (enabled && isCancelled) {
7
+ setIsExpanded(false);
8
+ }
9
+ }, [enabled, isCancelled, setIsExpanded]);
10
+ }
@@ -0,0 +1,6 @@
1
+ import type { TToolStatus } from '../types/tool';
2
+ export declare function useAutoCollapseOnSuccess(options: {
3
+ enabled: boolean;
4
+ status: TToolStatus | undefined;
5
+ setIsExpanded: (expanded: boolean) => void;
6
+ }): void;
@@ -0,0 +1,10 @@
1
+ import { useEffect } from 'react';
2
+ export function useAutoCollapseOnSuccess(options) {
3
+ const { enabled, status, setIsExpanded } = options;
4
+ const isSuccess = status === 'success';
5
+ useEffect(() => {
6
+ if (enabled && isSuccess) {
7
+ setIsExpanded(false);
8
+ }
9
+ }, [enabled, isSuccess, setIsExpanded]);
10
+ }
@@ -3,6 +3,8 @@ import { useCallback, useMemo, useState } from 'react';
3
3
  import { ChevronDown, ChevronUp } from '@gravity-ui/icons';
4
4
  import { Icon } from '@gravity-ui/uikit';
5
5
  import { i18n } from '../components/organisms/ToolMessage/i18n';
6
+ import { useAutoCollapseOnCancelled } from './useAutoCollapseOnCancelled';
7
+ import { useAutoCollapseOnSuccess } from './useAutoCollapseOnSuccess';
6
8
  function getDefaultFooterActions(status, footerActions, onAccept, onReject) {
7
9
  if (footerActions !== undefined) {
8
10
  return footerActions;
@@ -60,8 +62,10 @@ function getDefaultInitialExpanded(status, initialExpanded) {
60
62
  }
61
63
  const defaultHeaderActions = [];
62
64
  export function useToolMessage(options) {
63
- const { footerActions, headerActions = defaultHeaderActions, bodyContent, status, footerContent, expandable = Boolean(bodyContent), initialExpanded, onAccept, onReject, } = options;
65
+ const { footerActions, headerActions = defaultHeaderActions, bodyContent, status, footerContent, expandable = Boolean(bodyContent), initialExpanded, autoCollapseOnSuccess, autoCollapseOnCancelled, onAccept, onReject, } = options;
64
66
  const [isExpanded, setIsExpanded] = useState(getDefaultInitialExpanded(status, initialExpanded));
67
+ useAutoCollapseOnSuccess({ enabled: Boolean(autoCollapseOnSuccess), status, setIsExpanded });
68
+ useAutoCollapseOnCancelled({ enabled: Boolean(autoCollapseOnCancelled), status, setIsExpanded });
65
69
  const toggleExpanded = useCallback(() => {
66
70
  setIsExpanded((prev) => !prev);
67
71
  }, []);
@@ -1,11 +1,11 @@
1
1
  import { Action } from './common';
2
- export type ToolStatus = 'success' | 'error' | 'loading' | 'waitingConfirmation' | 'waitingSubmission';
2
+ export type TToolStatus = 'success' | 'error' | 'loading' | 'waitingConfirmation' | 'waitingSubmission' | 'cancelled';
3
3
  export type ToolHeaderProps = {
4
4
  toolIcon?: React.ReactNode;
5
5
  toolName: string;
6
6
  content?: React.ReactNode;
7
7
  actions?: Action[];
8
- status?: ToolStatus;
8
+ status?: TToolStatus;
9
9
  className?: string;
10
10
  qa?: string;
11
11
  };
@@ -24,9 +24,11 @@ export type ToolMessageProps = {
24
24
  bodyContent?: React.ReactNode;
25
25
  headerContent?: React.ReactNode;
26
26
  footerContent?: React.ReactNode;
27
- status?: ToolStatus;
27
+ status?: TToolStatus;
28
28
  expandable?: boolean;
29
29
  initialExpanded?: boolean;
30
+ autoCollapseOnSuccess?: boolean;
31
+ autoCollapseOnCancelled?: boolean;
30
32
  onAccept?: () => void;
31
33
  onReject?: () => void;
32
34
  className?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/aikit",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Gravity UI base kit for building ai assistant chats",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",