@cloud-ru/uikit-product-claudia 1.6.5 → 1.8.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 (52) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +6 -3
  3. package/dist/cjs/components/ChatStatusAnnouncement/ChatStatusAnnouncement.d.ts +1 -1
  4. package/dist/cjs/components/ChatStatusAnnouncement/ChatStatusAnnouncement.js +4 -3
  5. package/dist/cjs/components/ChatStatusAnnouncement/types.d.ts +4 -3
  6. package/dist/cjs/components/RecommendPannel/RecommendPanel.d.ts +4 -3
  7. package/dist/cjs/components/RecommendPannel/RecommendPanel.js +4 -3
  8. package/dist/cjs/components/RecommendPannel/helperComponents/AiAssistantChip/AiAssistantChip.d.ts +12 -0
  9. package/dist/cjs/components/RecommendPannel/helperComponents/AiAssistantChip/AiAssistantChip.js +20 -0
  10. package/dist/cjs/components/RecommendPannel/helperComponents/AiAssistantChip/index.d.ts +1 -0
  11. package/dist/cjs/components/RecommendPannel/helperComponents/{ClaudiaChip → AiAssistantChip}/index.js +1 -1
  12. package/dist/cjs/components/SshField/SshField.d.ts +5 -1
  13. package/dist/cjs/components/SshField/SshField.js +2 -2
  14. package/dist/cjs/components/SshField/components/MobileFieldAi/MobileFieldAi.d.ts +1 -1
  15. package/dist/esm/components/ChatStatusAnnouncement/ChatStatusAnnouncement.d.ts +1 -1
  16. package/dist/esm/components/ChatStatusAnnouncement/ChatStatusAnnouncement.js +4 -3
  17. package/dist/esm/components/ChatStatusAnnouncement/types.d.ts +4 -3
  18. package/dist/esm/components/RecommendPannel/RecommendPanel.d.ts +4 -3
  19. package/dist/esm/components/RecommendPannel/RecommendPanel.js +4 -3
  20. package/dist/esm/components/RecommendPannel/helperComponents/AiAssistantChip/AiAssistantChip.d.ts +12 -0
  21. package/dist/esm/components/RecommendPannel/helperComponents/AiAssistantChip/AiAssistantChip.js +17 -0
  22. package/dist/esm/components/RecommendPannel/helperComponents/AiAssistantChip/index.d.ts +1 -0
  23. package/dist/esm/components/RecommendPannel/helperComponents/AiAssistantChip/index.js +1 -0
  24. package/dist/esm/components/SshField/SshField.d.ts +5 -1
  25. package/dist/esm/components/SshField/SshField.js +2 -2
  26. package/dist/esm/components/SshField/components/MobileFieldAi/MobileFieldAi.d.ts +1 -1
  27. package/package.json +3 -2
  28. package/src/components/ChatStatusAnnouncement/ChatStatusAnnouncement.tsx +6 -2
  29. package/src/components/ChatStatusAnnouncement/types.ts +4 -3
  30. package/src/components/RecommendPannel/RecommendPanel.tsx +26 -7
  31. package/src/components/RecommendPannel/helperComponents/AiAssistantChip/AiAssistantChip.tsx +58 -0
  32. package/src/components/RecommendPannel/helperComponents/AiAssistantChip/index.ts +1 -0
  33. package/src/components/SshField/SshField.tsx +4 -2
  34. package/dist/cjs/components/ChatStatusAnnouncement/helperComponents/TextContent/TextContent.d.ts +0 -7
  35. package/dist/cjs/components/ChatStatusAnnouncement/helperComponents/TextContent/TextContent.js +0 -12
  36. package/dist/cjs/components/ChatStatusAnnouncement/helperComponents/TextContent/index.d.ts +0 -1
  37. package/dist/cjs/components/ChatStatusAnnouncement/helperComponents/TextContent/index.js +0 -17
  38. package/dist/cjs/components/RecommendPannel/helperComponents/ClaudiaChip/ClaudiaChip.d.ts +0 -11
  39. package/dist/cjs/components/RecommendPannel/helperComponents/ClaudiaChip/ClaudiaChip.js +0 -18
  40. package/dist/cjs/components/RecommendPannel/helperComponents/ClaudiaChip/index.d.ts +0 -1
  41. package/dist/esm/components/ChatStatusAnnouncement/helperComponents/TextContent/TextContent.d.ts +0 -7
  42. package/dist/esm/components/ChatStatusAnnouncement/helperComponents/TextContent/TextContent.js +0 -9
  43. package/dist/esm/components/ChatStatusAnnouncement/helperComponents/TextContent/index.d.ts +0 -1
  44. package/dist/esm/components/ChatStatusAnnouncement/helperComponents/TextContent/index.js +0 -1
  45. package/dist/esm/components/RecommendPannel/helperComponents/ClaudiaChip/ClaudiaChip.d.ts +0 -11
  46. package/dist/esm/components/RecommendPannel/helperComponents/ClaudiaChip/ClaudiaChip.js +0 -15
  47. package/dist/esm/components/RecommendPannel/helperComponents/ClaudiaChip/index.d.ts +0 -1
  48. package/dist/esm/components/RecommendPannel/helperComponents/ClaudiaChip/index.js +0 -1
  49. package/src/components/ChatStatusAnnouncement/helperComponents/TextContent/TextContent.tsx +0 -18
  50. package/src/components/ChatStatusAnnouncement/helperComponents/TextContent/index.ts +0 -1
  51. package/src/components/RecommendPannel/helperComponents/ClaudiaChip/ClaudiaChip.tsx +0 -40
  52. package/src/components/RecommendPannel/helperComponents/ClaudiaChip/index.ts +0 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 1.8.0 (2025-11-17)
7
+
8
+
9
+ ### Features
10
+
11
+ * **AINFR-4479:** add onCancel ([e3dbed9](https://gitverse.ru/cloud-ru-tech/uikit-product/commits/e3dbed92b1435c7d53b51d2da1cbf64c86674b5a))
12
+
13
+
14
+
15
+
16
+
17
+ # 1.7.0 (2025-11-13)
18
+
19
+
20
+ ### Features
21
+
22
+ * **RM-3714:** replace claudia button by giga for recommend panel ([9114db7](https://gitverse.ru/cloud-ru-tech/uikit-product/commits/9114db7e67cc17a4e134b3d3b7a12055b6d5edae))
23
+
24
+
25
+
26
+
27
+
6
28
  ## 1.6.5 (2025-11-13)
7
29
 
8
30
 
package/README.md CHANGED
@@ -102,8 +102,9 @@
102
102
  |------|------|---------------|-------------|
103
103
  | layoutType* | enum LayoutType: `"mobile"`, `"tablet"`, `"desktop"`, `"desktopSmall"` | - | |
104
104
  | actionLabel* | `string` | - | |
105
- | content* | `ReactNode \| TextItem[]` | - | |
105
+ | content* | `string \| TextItem[]` | - | |
106
106
  | icon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | |
107
+ | contentClassName | `string` | - | |
107
108
  | onActionClick | `() => void` | - | |
108
109
  | className | `string` | - | CSS-класс |
109
110
  ## IconGiga
@@ -545,13 +546,15 @@
545
546
  | layoutType | enum LayoutType: `"mobile"`, `"tablet"`, `"desktop"`, `"desktopSmall"` | - | |
546
547
  | onCloseClick | `() => void` | - | |
547
548
  | onCloseChipLabel | `ReactNode` | - | |
548
- | tooltip | `ReactNode` | - | |
549
- | onClaudiaClick | `() => void` | - | |
549
+ | onAiAssistantClick | `() => void` | - | |
550
+ | docsUrl | `string` | https://cloud.ru/docs/ai_assistant_cloudia/ug/index | |
551
+ | dataTestId | `string` | recommend-panel | |
550
552
  ## SshField
551
553
  ### Props
552
554
  | name | type | default value | description |
553
555
  |------|------|---------------|-------------|
554
556
  | layoutType* | enum LayoutType: `"mobile"`, `"tablet"`, `"desktop"`, `"desktopSmall"` | - | |
557
+ | onCancel* | `() => void` | - | Колбек отмены действия |
555
558
  | onSubmit* | `(value: string) => void` | - | Колбек действия при отправке |
556
559
  | className | `string` | - | CSS-класс |
557
560
  | disabled | `boolean` | - | Является ли поле деактивированным |
@@ -1,2 +1,2 @@
1
1
  import { ChatStatusAnnouncementProps } from './types';
2
- export declare function ChatStatusAnnouncement({ content, onActionClick, actionLabel, icon, layoutType, className, }: ChatStatusAnnouncementProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ChatStatusAnnouncement({ content, contentClassName, onActionClick, actionLabel, icon, layoutType, className, }: ChatStatusAnnouncementProps): import("react/jsx-runtime").JSX.Element;
@@ -9,12 +9,13 @@ const classnames_1 = __importDefault(require("classnames"));
9
9
  const react_1 = require("react");
10
10
  const uikit_product_icons_1 = require("@cloud-ru/uikit-product-icons");
11
11
  const uikit_product_utils_1 = require("@cloud-ru/uikit-product-utils");
12
+ const truncate_string_1 = require("@snack-uikit/truncate-string");
13
+ const typography_1 = require("@snack-uikit/typography");
12
14
  const constants_1 = require("./constants");
13
15
  const AlertButton_1 = require("./helperComponents/AlertButton");
14
- const TextContent_1 = require("./helperComponents/TextContent");
15
16
  const styled_module_scss_1 = __importDefault(require('./styled.module.css'));
16
17
  const utils_1 = require("./utils");
17
- function ChatStatusAnnouncement({ content, onActionClick, actionLabel, icon, layoutType, className, }) {
18
+ function ChatStatusAnnouncement({ content, contentClassName, onActionClick, actionLabel, icon, layoutType, className, }) {
18
19
  const [currentIndex, setCurrentIndex] = (0, react_1.useState)(0);
19
20
  const [isAnimationEnded, setAnimationEnded] = (0, react_1.useState)(false);
20
21
  const [mouseEntered, setMouseEntered] = (0, react_1.useState)(false);
@@ -69,6 +70,6 @@ function ChatStatusAnnouncement({ content, onActionClick, actionLabel, icon, lay
69
70
  ? styled_module_scss_1.default.textBlockPrevious
70
71
  : styled_module_scss_1.default.textBlockNext;
71
72
  const currentTextStyle = index === currentIndex ? styled_module_scss_1.default.textBlockCurrent : currentTextNextOrPreviousStyle;
72
- return ((0, jsx_runtime_1.jsx)(TextContent_1.TextContent, { content: item.content, className: (0, classnames_1.default)(styled_module_scss_1.default.textBlock, currentTextStyle) }, index));
73
+ return ((0, jsx_runtime_1.jsx)(typography_1.Typography.SansBodyS, { className: (0, classnames_1.default)(styled_module_scss_1.default.textBlock, currentTextStyle, contentClassName), children: (0, jsx_runtime_1.jsx)(truncate_string_1.TruncateString, { text: String(item.content) }) }, index));
73
74
  }) })] }), (0, jsx_runtime_1.jsx)(AlertButton_1.AlertButton, { onClick: onActionClick, text: actionLabel, layoutType: layoutType })] }));
74
75
  }
@@ -1,12 +1,13 @@
1
- import { ReactElement, ReactNode } from 'react';
1
+ import { ReactElement } from 'react';
2
2
  import { LayoutType } from '@cloud-ru/uikit-product-utils';
3
3
  export type TextItem = {
4
- content: ReactNode;
4
+ content: string;
5
5
  shouldFocusOnHover?: boolean;
6
6
  };
7
7
  export type ChatStatusAnnouncementProps = {
8
8
  icon?: ReactElement;
9
- content: ReactNode | TextItem[];
9
+ content: string | TextItem[];
10
+ contentClassName?: string;
10
11
  actionLabel: string;
11
12
  onActionClick?: () => void;
12
13
  layoutType: LayoutType;
@@ -8,7 +8,8 @@ export type RecommendPanelProps = {
8
8
  layoutType?: LayoutType;
9
9
  onCloseClick?: () => void;
10
10
  onCloseChipLabel?: ReactNode;
11
- tooltip?: ReactNode;
12
- onClaudiaClick?: () => void;
11
+ onAiAssistantClick?: () => void;
12
+ docsUrl?: string;
13
+ dataTestId?: string;
13
14
  };
14
- export declare function RecommendPanel({ chips, type, size, layoutType, onCloseClick, onCloseChipLabel, tooltip, onClaudiaClick, }: RecommendPanelProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function RecommendPanel({ chips, type, size, layoutType, onCloseClick, onCloseChipLabel, onAiAssistantClick, docsUrl, dataTestId, }: RecommendPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -7,14 +7,15 @@ exports.RecommendPanel = RecommendPanel;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = require("react");
9
9
  const uikit_product_utils_1 = require("@cloud-ru/uikit-product-utils");
10
+ const AiAssistantChip_1 = require("./helperComponents/AiAssistantChip");
10
11
  const Chip_1 = require("./helperComponents/Chip");
11
- const ClaudiaChip_1 = require("./helperComponents/ClaudiaChip");
12
12
  const CloseChip_1 = require("./helperComponents/CloseChip");
13
13
  const DropdownChip_1 = require("./helperComponents/DropdownChip");
14
14
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
15
15
  const types_1 = require("./types");
16
16
  const gitVisibleChipsCount_1 = require("./utils/gitVisibleChipsCount");
17
- function RecommendPanel({ chips, type = types_1.CHIP_TYPE.Default, size = types_1.SIZE.S, layoutType, onCloseClick, onCloseChipLabel, tooltip, onClaudiaClick, }) {
17
+ const AI_ASSISTANT_DOCUMENTATION_URL = 'https://cloud.ru/docs/ai_assistant_cloudia/ug/index';
18
+ function RecommendPanel({ chips, type = types_1.CHIP_TYPE.Default, size = types_1.SIZE.S, layoutType, onCloseClick, onCloseChipLabel, onAiAssistantClick, docsUrl = AI_ASSISTANT_DOCUMENTATION_URL, dataTestId = 'recommend-panel', }) {
18
19
  const [containerWidth, setContainerWidth] = (0, react_1.useState)(0);
19
20
  const [isCloseIconVisible, setCloseIconVisible] = (0, react_1.useState)(false);
20
21
  const [chipWidths, setChipWidths] = (0, react_1.useState)([]);
@@ -70,5 +71,5 @@ function RecommendPanel({ chips, type = types_1.CHIP_TYPE.Default, size = types_
70
71
  return;
71
72
  setCloseIconVisible(false);
72
73
  };
73
- return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.container, ref: containerRef, onMouseEnter: showCloseIcon, onMouseLeave: hideCloseIcon, children: [(0, jsx_runtime_1.jsx)(ClaudiaChip_1.ClaudiaChip, { layoutType: layoutType, onClick: onClaudiaClick, size: size, tooltip: tooltip }), visibleChips.map((chip, index) => ((0, jsx_runtime_1.jsx)(Chip_1.Chip, { ref: chipElement => (allChipsRefs.current[index] = chipElement), label: chip.label, size: size, type: type, layoutType: layoutType, onClick: chip.onClick }, chip.id))), hasHiddenChips && ((0, jsx_runtime_1.jsx)(DropdownChip_1.DropdownChip, { layoutType: layoutType, type: type, size: size, label: `+${hiddenChips.length}`, dropdownItems: hiddenChips })), onCloseClick && onCloseChipLabel && ((0, jsx_runtime_1.jsx)(CloseChip_1.CloseChip, { size: size, layoutType: layoutType, content: onCloseChipLabel, onClick: onCloseClick, isVisible: isCloseIconVisible }))] }));
74
+ return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.container, ref: containerRef, onMouseEnter: showCloseIcon, onMouseLeave: hideCloseIcon, "data-test-id": dataTestId, children: [(0, jsx_runtime_1.jsx)(AiAssistantChip_1.AiAssistantChip, { layoutType: layoutType, onClick: onAiAssistantClick, size: size, "data-test-id": `${dataTestId}__ai-assistant-chip`, docsUrl: docsUrl }), visibleChips.map((chip, index) => ((0, jsx_runtime_1.jsx)(Chip_1.Chip, { ref: chipElement => (allChipsRefs.current[index] = chipElement), label: chip.label, size: size, type: type, layoutType: layoutType, onClick: chip.onClick, "data-test-id": `${dataTestId}__chip-${chip.id}` }, chip.id))), hasHiddenChips && ((0, jsx_runtime_1.jsx)(DropdownChip_1.DropdownChip, { layoutType: layoutType, type: type, size: size, label: `+${hiddenChips.length}`, dropdownItems: hiddenChips, "data-test-id": `${dataTestId}__dropdown-chip` })), onCloseClick && onCloseChipLabel && ((0, jsx_runtime_1.jsx)(CloseChip_1.CloseChip, { size: size, layoutType: layoutType, content: onCloseChipLabel, onClick: onCloseClick, isVisible: isCloseIconVisible, "data-test-id": `${dataTestId}__close-chip` }))] }));
74
75
  }
@@ -0,0 +1,12 @@
1
+ import { MouseEventHandler } from 'react';
2
+ import { LayoutType } from '@cloud-ru/uikit-product-utils';
3
+ import { Size } from '../../types';
4
+ type AiAssistantChipProps = {
5
+ onClick?: MouseEventHandler<HTMLElement>;
6
+ size: Size;
7
+ layoutType?: LayoutType;
8
+ docsUrl?: string;
9
+ dataTestId?: string;
10
+ };
11
+ export declare const AiAssistantChip: import("react").ForwardRefExoticComponent<AiAssistantChipProps & import("react").RefAttributes<HTMLElement | HTMLButtonElement>>;
12
+ export {};
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AiAssistantChip = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const uikit_product_locale_1 = require("@cloud-ru/uikit-product-locale");
7
+ const uikit_product_utils_1 = require("@cloud-ru/uikit-product-utils");
8
+ const link_1 = require("@snack-uikit/link");
9
+ const tooltip_1 = require("@snack-uikit/tooltip");
10
+ const typography_1 = require("@snack-uikit/typography");
11
+ const ButtonGiga_1 = require("../../../ButtonGiga");
12
+ const IconGiga_1 = require("../../../IconGiga");
13
+ const types_1 = require("../../types");
14
+ exports.AiAssistantChip = (0, react_1.forwardRef)(({ onClick, size, layoutType, docsUrl, dataTestId }, ref) => {
15
+ const isMobile = layoutType === uikit_product_utils_1.LAYOUT_TYPE.Mobile || size === types_1.SIZE.M;
16
+ const totalSize = isMobile ? types_1.SIZE.M : size;
17
+ const { t } = (0, uikit_product_locale_1.useLocale)('Claudia');
18
+ const tooltipContent = ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(typography_1.Typography.SansLabelM, { tag: 'p', "data-test-id": `${dataTestId}__tooltip-title`, children: t('AiAssistantChip.tooltipTitle') }), (0, jsx_runtime_1.jsx)(typography_1.Typography.SansBodyS, { tag: 'p', "data-test-id": `${dataTestId}__tooltip-description`, children: t('AiAssistantChip.tooltipDescription') }), (0, jsx_runtime_1.jsx)(link_1.Link, { text: t('AiAssistantChip.documentationLink'), appearance: 'invert-neutral', textMode: 'accent', target: '_blank', href: docsUrl, "data-test-id": `${dataTestId}__documentation-link` })] }));
19
+ return ((0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { triggerRef: ref, tip: tooltipContent, placement: 'top', "data-test-id": dataTestId, children: (0, jsx_runtime_1.jsx)(ButtonGiga_1.ButtonGigaOutline, { size: totalSize, "data-mobile": isMobile, onClick: onClick, icon: (0, jsx_runtime_1.jsx)(IconGiga_1.IconGiga, { size: 24 }) }) }));
20
+ });
@@ -0,0 +1 @@
1
+ export * from './AiAssistantChip';
@@ -14,4 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./ClaudiaChip"), exports);
17
+ __exportStar(require("./AiAssistantChip"), exports);
@@ -3,10 +3,14 @@ import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
3
3
  export type SshFieldProps = WithLayoutType<Omit<FieldTextAreaProps, 'placeholder' | 'labelTooltip' | 'label' | 'required' | 'size' | 'spellCheck' | 'footer'> & {
4
4
  /** Колбек действия при отправке */
5
5
  onSubmit(value: string): void;
6
+ /** Колбек отмены действия */
7
+ onCancel(): void;
6
8
  }>;
7
- export declare const SshField: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "spellCheck" | "required" | "labelTooltip" | "footer"> & {
9
+ export declare const SshField: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "footer" | "spellCheck" | "required" | "labelTooltip"> & {
8
10
  /** Колбек действия при отправке */
9
11
  onSubmit(value: string): void;
12
+ /** Колбек отмены действия */
13
+ onCancel(): void;
10
14
  } & {
11
15
  layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
12
16
  } & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -45,7 +45,7 @@ const isTouchDevice_1 = require("./utils/isTouchDevice");
45
45
  const readFileContent_1 = require("./utils/readFileContent");
46
46
  const validateSSHKey_1 = require("./utils/validateSSHKey");
47
47
  exports.SshField = (0, react_1.forwardRef)((_a, ref) => {
48
- var { onSubmit: handleSubmitProp, value, disabled, className } = _a, props = __rest(_a, ["onSubmit", "value", "disabled", "className"]);
48
+ var { onSubmit: handleSubmitProp, onCancel, value, disabled, className } = _a, props = __rest(_a, ["onSubmit", "onCancel", "value", "disabled", "className"]);
49
49
  const { layoutType, validationState, onChange } = props;
50
50
  const { t } = (0, uikit_product_locale_1.useLocale)('Claudia');
51
51
  const isTouchDevice = (0, isTouchDevice_1.isTouchDevice)(layoutType);
@@ -133,5 +133,5 @@ exports.SshField = (0, react_1.forwardRef)((_a, ref) => {
133
133
  if (isTouchDevice) {
134
134
  return ((0, jsx_runtime_1.jsx)(MobileFieldAi_1.MobileFieldAi, Object.assign({}, props, (0, uikit_product_mobile_fields_1.getAdaptiveFieldProps)(props), { onSubmit: handleSubmit, submitEnabled: isValueValid && !disabled, ref: ref, value: value })));
135
135
  }
136
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.wrapper, className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, children: [(0, jsx_runtime_1.jsx)(ChatStatusAnnouncement_1.ChatStatusAnnouncement, { className: styles_module_scss_1.default.chatStatus, layoutType: layoutType, icon: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.PasswordLockSVG, { size: 16, color: figma_tokens_1.themeVars.sys.neutral.textSupport }), content: t('SshField.chatStatusAnnouncement.content'), actionLabel: t('SshField.chatStatusAnnouncement.cancel'), onActionClick: () => { } }), isDragOver ? ((0, jsx_runtime_1.jsx)(drop_zone_1.DropZone, { description: (0, jsx_runtime_1.jsx)(DropZoneContent_1.DropZoneContent, {}), className: styles_module_scss_1.default.dropZone, mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]) })) : ((0, jsx_runtime_1.jsx)(uikit_product_mobile_fields_1.AdaptiveFieldTextArea, Object.assign({}, props, { ref: ref, value: value, onChange: handleChange, size: 'm', disabled: isLoading, minRows: 2, maxRows: 4, placeholder: t('SshField.placeholder'), className: isValueHidden ? styles_module_scss_1.default.secured : undefined, onKeyDown: handleKeyDown, validationState: showFileError ? 'error' : validationState, hint: showFileError && fileErrorType ? getErrorMessage(fileErrorType) : props.hint, footer: (0, jsx_runtime_1.jsx)(TextAreaActionsFooter_1.TextAreaActionsFooter, { left: (0, jsx_runtime_1.jsx)(button_1.ButtonFunction, { size: 'xs', icon: isValueHidden ? (0, jsx_runtime_1.jsx)(uikit_product_icons_1.EyeSVG, {}) : (0, jsx_runtime_1.jsx)(uikit_product_icons_1.EyeClosedSVG, {}), onClick: () => setIsValueHidden(prev => !prev), disabled: isLoading }), right: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { tip: t('SshField.attachFileTooltip'), hoverDelayOpen: 600, triggerClassName: styles_module_scss_1.default.uploadTooltip, open: isTouchDevice ? false : undefined, children: (0, jsx_runtime_1.jsx)(drop_zone_1.FileUpload, { mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]), children: (0, jsx_runtime_1.jsx)(button_1.ButtonFunction, { disabled: isLoading, size: isTouchDevice ? 's' : 'xs', icon: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.AttachmentSVG, {}) }) }) }), (0, jsx_runtime_1.jsx)(FieldSubmitButton_1.FieldSubmitButton, { disabled: isLoading, showTooltip: !isTouchDevice, className: isTouchDevice ? styles_module_scss_1.default.mobileSubmitButton : undefined, active: isValueValid && !disabled, handleClick: handleSubmit, size: isTouchDevice ? 's' : 'xs' })] }) }) })))] }));
136
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.wrapper, className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, children: [(0, jsx_runtime_1.jsx)(ChatStatusAnnouncement_1.ChatStatusAnnouncement, { className: styles_module_scss_1.default.chatStatus, layoutType: layoutType, icon: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.PasswordLockSVG, { size: 16, color: figma_tokens_1.themeVars.sys.neutral.textSupport }), content: t('SshField.chatStatusAnnouncement.content'), actionLabel: t('SshField.chatStatusAnnouncement.cancel'), onActionClick: onCancel }), isDragOver ? ((0, jsx_runtime_1.jsx)(drop_zone_1.DropZone, { description: (0, jsx_runtime_1.jsx)(DropZoneContent_1.DropZoneContent, {}), className: styles_module_scss_1.default.dropZone, mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]) })) : ((0, jsx_runtime_1.jsx)(uikit_product_mobile_fields_1.AdaptiveFieldTextArea, Object.assign({}, props, { ref: ref, value: value, onChange: handleChange, size: 'm', disabled: isLoading, minRows: 2, maxRows: 4, placeholder: t('SshField.placeholder'), className: isValueHidden ? styles_module_scss_1.default.secured : undefined, onKeyDown: handleKeyDown, validationState: showFileError ? 'error' : validationState, hint: showFileError && fileErrorType ? getErrorMessage(fileErrorType) : props.hint, footer: (0, jsx_runtime_1.jsx)(TextAreaActionsFooter_1.TextAreaActionsFooter, { left: (0, jsx_runtime_1.jsx)(button_1.ButtonFunction, { size: 'xs', icon: isValueHidden ? (0, jsx_runtime_1.jsx)(uikit_product_icons_1.EyeSVG, {}) : (0, jsx_runtime_1.jsx)(uikit_product_icons_1.EyeClosedSVG, {}), onClick: () => setIsValueHidden(prev => !prev), disabled: isLoading }), right: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { tip: t('SshField.attachFileTooltip'), hoverDelayOpen: 600, triggerClassName: styles_module_scss_1.default.uploadTooltip, open: isTouchDevice ? false : undefined, children: (0, jsx_runtime_1.jsx)(drop_zone_1.FileUpload, { mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]), children: (0, jsx_runtime_1.jsx)(button_1.ButtonFunction, { disabled: isLoading, size: isTouchDevice ? 's' : 'xs', icon: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.AttachmentSVG, {}) }) }) }), (0, jsx_runtime_1.jsx)(FieldSubmitButton_1.FieldSubmitButton, { disabled: isLoading, showTooltip: !isTouchDevice, className: isTouchDevice ? styles_module_scss_1.default.mobileSubmitButton : undefined, active: isValueValid && !disabled, handleClick: handleSubmit, size: isTouchDevice ? 's' : 'xs' })] }) }) })))] }));
137
137
  });
@@ -1,5 +1,5 @@
1
1
  import { FieldTextAreaProps } from '@cloud-ru/uikit-product-mobile-fields';
2
- export declare const MobileFieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "spellCheck" | "required" | "labelTooltip" | "footer"> & {
2
+ export declare const MobileFieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "footer" | "spellCheck" | "required" | "labelTooltip"> & {
3
3
  onSubmit(): void;
4
4
  submitEnabled: boolean;
5
5
  } & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -1,2 +1,2 @@
1
1
  import { ChatStatusAnnouncementProps } from './types';
2
- export declare function ChatStatusAnnouncement({ content, onActionClick, actionLabel, icon, layoutType, className, }: ChatStatusAnnouncementProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ChatStatusAnnouncement({ content, contentClassName, onActionClick, actionLabel, icon, layoutType, className, }: ChatStatusAnnouncementProps): import("react/jsx-runtime").JSX.Element;
@@ -3,12 +3,13 @@ import cn from 'classnames';
3
3
  import { useEffect, useRef, useState } from 'react';
4
4
  import { PlaceholderSVG } from '@cloud-ru/uikit-product-icons';
5
5
  import { LAYOUT_TYPE } from '@cloud-ru/uikit-product-utils';
6
+ import { TruncateString } from '@snack-uikit/truncate-string';
7
+ import { Typography } from '@snack-uikit/typography';
6
8
  import { ANIMATION_INTERVAL } from './constants';
7
9
  import { AlertButton } from './helperComponents/AlertButton';
8
- import { TextContent } from './helperComponents/TextContent';
9
10
  import styles from './styled.module.css';
10
11
  import { getContent, isReactNode } from './utils';
11
- export function ChatStatusAnnouncement({ content, onActionClick, actionLabel, icon, layoutType, className, }) {
12
+ export function ChatStatusAnnouncement({ content, contentClassName, onActionClick, actionLabel, icon, layoutType, className, }) {
12
13
  const [currentIndex, setCurrentIndex] = useState(0);
13
14
  const [isAnimationEnded, setAnimationEnded] = useState(false);
14
15
  const [mouseEntered, setMouseEntered] = useState(false);
@@ -63,6 +64,6 @@ export function ChatStatusAnnouncement({ content, onActionClick, actionLabel, ic
63
64
  ? styles.textBlockPrevious
64
65
  : styles.textBlockNext;
65
66
  const currentTextStyle = index === currentIndex ? styles.textBlockCurrent : currentTextNextOrPreviousStyle;
66
- return (_jsx(TextContent, { content: item.content, className: cn(styles.textBlock, currentTextStyle) }, index));
67
+ return (_jsx(Typography.SansBodyS, { className: cn(styles.textBlock, currentTextStyle, contentClassName), children: _jsx(TruncateString, { text: String(item.content) }) }, index));
67
68
  }) })] }), _jsx(AlertButton, { onClick: onActionClick, text: actionLabel, layoutType: layoutType })] }));
68
69
  }
@@ -1,12 +1,13 @@
1
- import { ReactElement, ReactNode } from 'react';
1
+ import { ReactElement } from 'react';
2
2
  import { LayoutType } from '@cloud-ru/uikit-product-utils';
3
3
  export type TextItem = {
4
- content: ReactNode;
4
+ content: string;
5
5
  shouldFocusOnHover?: boolean;
6
6
  };
7
7
  export type ChatStatusAnnouncementProps = {
8
8
  icon?: ReactElement;
9
- content: ReactNode | TextItem[];
9
+ content: string | TextItem[];
10
+ contentClassName?: string;
10
11
  actionLabel: string;
11
12
  onActionClick?: () => void;
12
13
  layoutType: LayoutType;
@@ -8,7 +8,8 @@ export type RecommendPanelProps = {
8
8
  layoutType?: LayoutType;
9
9
  onCloseClick?: () => void;
10
10
  onCloseChipLabel?: ReactNode;
11
- tooltip?: ReactNode;
12
- onClaudiaClick?: () => void;
11
+ onAiAssistantClick?: () => void;
12
+ docsUrl?: string;
13
+ dataTestId?: string;
13
14
  };
14
- export declare function RecommendPanel({ chips, type, size, layoutType, onCloseClick, onCloseChipLabel, tooltip, onClaudiaClick, }: RecommendPanelProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function RecommendPanel({ chips, type, size, layoutType, onCloseClick, onCloseChipLabel, onAiAssistantClick, docsUrl, dataTestId, }: RecommendPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -1,14 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from 'react';
3
3
  import { LAYOUT_TYPE } from '@cloud-ru/uikit-product-utils';
4
+ import { AiAssistantChip } from './helperComponents/AiAssistantChip';
4
5
  import { Chip } from './helperComponents/Chip';
5
- import { ClaudiaChip } from './helperComponents/ClaudiaChip';
6
6
  import { CloseChip } from './helperComponents/CloseChip';
7
7
  import { DropdownChip } from './helperComponents/DropdownChip';
8
8
  import styles from './styles.module.css';
9
9
  import { CHIP_TYPE, SIZE } from './types';
10
10
  import { getVisibleChipsCount } from './utils/gitVisibleChipsCount';
11
- export function RecommendPanel({ chips, type = CHIP_TYPE.Default, size = SIZE.S, layoutType, onCloseClick, onCloseChipLabel, tooltip, onClaudiaClick, }) {
11
+ const AI_ASSISTANT_DOCUMENTATION_URL = 'https://cloud.ru/docs/ai_assistant_cloudia/ug/index';
12
+ export function RecommendPanel({ chips, type = CHIP_TYPE.Default, size = SIZE.S, layoutType, onCloseClick, onCloseChipLabel, onAiAssistantClick, docsUrl = AI_ASSISTANT_DOCUMENTATION_URL, dataTestId = 'recommend-panel', }) {
12
13
  const [containerWidth, setContainerWidth] = useState(0);
13
14
  const [isCloseIconVisible, setCloseIconVisible] = useState(false);
14
15
  const [chipWidths, setChipWidths] = useState([]);
@@ -64,5 +65,5 @@ export function RecommendPanel({ chips, type = CHIP_TYPE.Default, size = SIZE.S,
64
65
  return;
65
66
  setCloseIconVisible(false);
66
67
  };
67
- return (_jsxs("div", { className: styles.container, ref: containerRef, onMouseEnter: showCloseIcon, onMouseLeave: hideCloseIcon, children: [_jsx(ClaudiaChip, { layoutType: layoutType, onClick: onClaudiaClick, size: size, tooltip: tooltip }), visibleChips.map((chip, index) => (_jsx(Chip, { ref: chipElement => (allChipsRefs.current[index] = chipElement), label: chip.label, size: size, type: type, layoutType: layoutType, onClick: chip.onClick }, chip.id))), hasHiddenChips && (_jsx(DropdownChip, { layoutType: layoutType, type: type, size: size, label: `+${hiddenChips.length}`, dropdownItems: hiddenChips })), onCloseClick && onCloseChipLabel && (_jsx(CloseChip, { size: size, layoutType: layoutType, content: onCloseChipLabel, onClick: onCloseClick, isVisible: isCloseIconVisible }))] }));
68
+ return (_jsxs("div", { className: styles.container, ref: containerRef, onMouseEnter: showCloseIcon, onMouseLeave: hideCloseIcon, "data-test-id": dataTestId, children: [_jsx(AiAssistantChip, { layoutType: layoutType, onClick: onAiAssistantClick, size: size, "data-test-id": `${dataTestId}__ai-assistant-chip`, docsUrl: docsUrl }), visibleChips.map((chip, index) => (_jsx(Chip, { ref: chipElement => (allChipsRefs.current[index] = chipElement), label: chip.label, size: size, type: type, layoutType: layoutType, onClick: chip.onClick, "data-test-id": `${dataTestId}__chip-${chip.id}` }, chip.id))), hasHiddenChips && (_jsx(DropdownChip, { layoutType: layoutType, type: type, size: size, label: `+${hiddenChips.length}`, dropdownItems: hiddenChips, "data-test-id": `${dataTestId}__dropdown-chip` })), onCloseClick && onCloseChipLabel && (_jsx(CloseChip, { size: size, layoutType: layoutType, content: onCloseChipLabel, onClick: onCloseClick, isVisible: isCloseIconVisible, "data-test-id": `${dataTestId}__close-chip` }))] }));
68
69
  }
@@ -0,0 +1,12 @@
1
+ import { MouseEventHandler } from 'react';
2
+ import { LayoutType } from '@cloud-ru/uikit-product-utils';
3
+ import { Size } from '../../types';
4
+ type AiAssistantChipProps = {
5
+ onClick?: MouseEventHandler<HTMLElement>;
6
+ size: Size;
7
+ layoutType?: LayoutType;
8
+ docsUrl?: string;
9
+ dataTestId?: string;
10
+ };
11
+ export declare const AiAssistantChip: import("react").ForwardRefExoticComponent<AiAssistantChipProps & import("react").RefAttributes<HTMLElement | HTMLButtonElement>>;
12
+ export {};
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
4
+ import { LAYOUT_TYPE } from '@cloud-ru/uikit-product-utils';
5
+ import { Link } from '@snack-uikit/link';
6
+ import { Tooltip } from '@snack-uikit/tooltip';
7
+ import { Typography } from '@snack-uikit/typography';
8
+ import { ButtonGigaOutline } from '../../../ButtonGiga';
9
+ import { IconGiga } from '../../../IconGiga';
10
+ import { SIZE } from '../../types';
11
+ export const AiAssistantChip = forwardRef(({ onClick, size, layoutType, docsUrl, dataTestId }, ref) => {
12
+ const isMobile = layoutType === LAYOUT_TYPE.Mobile || size === SIZE.M;
13
+ const totalSize = isMobile ? SIZE.M : size;
14
+ const { t } = useLocale('Claudia');
15
+ const tooltipContent = (_jsxs("div", { children: [_jsx(Typography.SansLabelM, { tag: 'p', "data-test-id": `${dataTestId}__tooltip-title`, children: t('AiAssistantChip.tooltipTitle') }), _jsx(Typography.SansBodyS, { tag: 'p', "data-test-id": `${dataTestId}__tooltip-description`, children: t('AiAssistantChip.tooltipDescription') }), _jsx(Link, { text: t('AiAssistantChip.documentationLink'), appearance: 'invert-neutral', textMode: 'accent', target: '_blank', href: docsUrl, "data-test-id": `${dataTestId}__documentation-link` })] }));
16
+ return (_jsx(Tooltip, { triggerRef: ref, tip: tooltipContent, placement: 'top', "data-test-id": dataTestId, children: _jsx(ButtonGigaOutline, { size: totalSize, "data-mobile": isMobile, onClick: onClick, icon: _jsx(IconGiga, { size: 24 }) }) }));
17
+ });
@@ -0,0 +1 @@
1
+ export * from './AiAssistantChip';
@@ -0,0 +1 @@
1
+ export * from './AiAssistantChip';
@@ -3,10 +3,14 @@ import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
3
3
  export type SshFieldProps = WithLayoutType<Omit<FieldTextAreaProps, 'placeholder' | 'labelTooltip' | 'label' | 'required' | 'size' | 'spellCheck' | 'footer'> & {
4
4
  /** Колбек действия при отправке */
5
5
  onSubmit(value: string): void;
6
+ /** Колбек отмены действия */
7
+ onCancel(): void;
6
8
  }>;
7
- export declare const SshField: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "spellCheck" | "required" | "labelTooltip" | "footer"> & {
9
+ export declare const SshField: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "footer" | "spellCheck" | "required" | "labelTooltip"> & {
8
10
  /** Колбек действия при отправке */
9
11
  onSubmit(value: string): void;
12
+ /** Колбек отмены действия */
13
+ onCancel(): void;
10
14
  } & {
11
15
  layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
12
16
  } & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -39,7 +39,7 @@ import { isTouchDevice as isTouchDeviceHelper } from './utils/isTouchDevice';
39
39
  import { readFileContent } from './utils/readFileContent';
40
40
  import { validateFileSize, validateFileType, validateSSHKeyContent } from './utils/validateSSHKey';
41
41
  export const SshField = forwardRef((_a, ref) => {
42
- var { onSubmit: handleSubmitProp, value, disabled, className } = _a, props = __rest(_a, ["onSubmit", "value", "disabled", "className"]);
42
+ var { onSubmit: handleSubmitProp, onCancel, value, disabled, className } = _a, props = __rest(_a, ["onSubmit", "onCancel", "value", "disabled", "className"]);
43
43
  const { layoutType, validationState, onChange } = props;
44
44
  const { t } = useLocale('Claudia');
45
45
  const isTouchDevice = isTouchDeviceHelper(layoutType);
@@ -127,5 +127,5 @@ export const SshField = forwardRef((_a, ref) => {
127
127
  if (isTouchDevice) {
128
128
  return (_jsx(MobileFieldAi, Object.assign({}, props, getAdaptiveFieldProps(props), { onSubmit: handleSubmit, submitEnabled: isValueValid && !disabled, ref: ref, value: value })));
129
129
  }
130
- return (_jsxs("div", { className: cn(styles.wrapper, className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, children: [_jsx(ChatStatusAnnouncement, { className: styles.chatStatus, layoutType: layoutType, icon: _jsx(PasswordLockSVG, { size: 16, color: themeVars.sys.neutral.textSupport }), content: t('SshField.chatStatusAnnouncement.content'), actionLabel: t('SshField.chatStatusAnnouncement.cancel'), onActionClick: () => { } }), isDragOver ? (_jsx(DropZone, { description: _jsx(DropZoneContent, {}), className: styles.dropZone, mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]) })) : (_jsx(AdaptiveFieldTextArea, Object.assign({}, props, { ref: ref, value: value, onChange: handleChange, size: 'm', disabled: isLoading, minRows: 2, maxRows: 4, placeholder: t('SshField.placeholder'), className: isValueHidden ? styles.secured : undefined, onKeyDown: handleKeyDown, validationState: showFileError ? 'error' : validationState, hint: showFileError && fileErrorType ? getErrorMessage(fileErrorType) : props.hint, footer: _jsx(TextAreaActionsFooter, { left: _jsx(ButtonFunction, { size: 'xs', icon: isValueHidden ? _jsx(EyeSVG, {}) : _jsx(EyeClosedSVG, {}), onClick: () => setIsValueHidden(prev => !prev), disabled: isLoading }), right: _jsxs(_Fragment, { children: [_jsx(Tooltip, { tip: t('SshField.attachFileTooltip'), hoverDelayOpen: 600, triggerClassName: styles.uploadTooltip, open: isTouchDevice ? false : undefined, children: _jsx(FileUpload, { mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]), children: _jsx(ButtonFunction, { disabled: isLoading, size: isTouchDevice ? 's' : 'xs', icon: _jsx(AttachmentSVG, {}) }) }) }), _jsx(FieldSubmitButton, { disabled: isLoading, showTooltip: !isTouchDevice, className: isTouchDevice ? styles.mobileSubmitButton : undefined, active: isValueValid && !disabled, handleClick: handleSubmit, size: isTouchDevice ? 's' : 'xs' })] }) }) })))] }));
130
+ return (_jsxs("div", { className: cn(styles.wrapper, className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, children: [_jsx(ChatStatusAnnouncement, { className: styles.chatStatus, layoutType: layoutType, icon: _jsx(PasswordLockSVG, { size: 16, color: themeVars.sys.neutral.textSupport }), content: t('SshField.chatStatusAnnouncement.content'), actionLabel: t('SshField.chatStatusAnnouncement.cancel'), onActionClick: onCancel }), isDragOver ? (_jsx(DropZone, { description: _jsx(DropZoneContent, {}), className: styles.dropZone, mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]) })) : (_jsx(AdaptiveFieldTextArea, Object.assign({}, props, { ref: ref, value: value, onChange: handleChange, size: 'm', disabled: isLoading, minRows: 2, maxRows: 4, placeholder: t('SshField.placeholder'), className: isValueHidden ? styles.secured : undefined, onKeyDown: handleKeyDown, validationState: showFileError ? 'error' : validationState, hint: showFileError && fileErrorType ? getErrorMessage(fileErrorType) : props.hint, footer: _jsx(TextAreaActionsFooter, { left: _jsx(ButtonFunction, { size: 'xs', icon: isValueHidden ? _jsx(EyeSVG, {}) : _jsx(EyeClosedSVG, {}), onClick: () => setIsValueHidden(prev => !prev), disabled: isLoading }), right: _jsxs(_Fragment, { children: [_jsx(Tooltip, { tip: t('SshField.attachFileTooltip'), hoverDelayOpen: 600, triggerClassName: styles.uploadTooltip, open: isTouchDevice ? false : undefined, children: _jsx(FileUpload, { mode: 'single', onFilesUpload: (files) => onFileUpload(files[0]), children: _jsx(ButtonFunction, { disabled: isLoading, size: isTouchDevice ? 's' : 'xs', icon: _jsx(AttachmentSVG, {}) }) }) }), _jsx(FieldSubmitButton, { disabled: isLoading, showTooltip: !isTouchDevice, className: isTouchDevice ? styles.mobileSubmitButton : undefined, active: isValueValid && !disabled, handleClick: handleSubmit, size: isTouchDevice ? 's' : 'xs' })] }) }) })))] }));
131
131
  });
@@ -1,5 +1,5 @@
1
1
  import { FieldTextAreaProps } from '@cloud-ru/uikit-product-mobile-fields';
2
- export declare const MobileFieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "spellCheck" | "required" | "labelTooltip" | "footer"> & {
2
+ export declare const MobileFieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "label" | "size" | "placeholder" | "footer" | "spellCheck" | "required" | "labelTooltip"> & {
3
3
  onSubmit(): void;
4
4
  submitEnabled: boolean;
5
5
  } & import("react").RefAttributes<HTMLTextAreaElement>>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloud-ru/uikit-product-claudia",
3
3
  "title": "Claudia",
4
- "version": "1.6.5",
4
+ "version": "1.8.0",
5
5
  "sideEffects": [
6
6
  "*.css",
7
7
  "*.woff",
@@ -44,6 +44,7 @@
44
44
  "@snack-uikit/drop-zone": "0.9.6",
45
45
  "@snack-uikit/dropdown": "0.5.3",
46
46
  "@snack-uikit/input-private": "4.8.3",
47
+ "@snack-uikit/link": "0.17.12",
47
48
  "@snack-uikit/loaders": "0.9.9",
48
49
  "@snack-uikit/scroll": "0.10.5",
49
50
  "@snack-uikit/tooltip": "0.18.5",
@@ -57,5 +58,5 @@
57
58
  "@cloud-ru/uikit-product-locale": "*",
58
59
  "@snack-uikit/figma-tokens": "*"
59
60
  },
60
- "gitHead": "ce69097516055b330a0b05da5e29ac5b66e56284"
61
+ "gitHead": "25ab7c8f4ae0f0b91e114fcdaea4f0b8b4b4d53b"
61
62
  }
@@ -3,16 +3,18 @@ import { useEffect, useRef, useState } from 'react';
3
3
 
4
4
  import { PlaceholderSVG } from '@cloud-ru/uikit-product-icons';
5
5
  import { LAYOUT_TYPE } from '@cloud-ru/uikit-product-utils';
6
+ import { TruncateString } from '@snack-uikit/truncate-string';
7
+ import { Typography } from '@snack-uikit/typography';
6
8
 
7
9
  import { ANIMATION_INTERVAL } from './constants';
8
10
  import { AlertButton } from './helperComponents/AlertButton';
9
- import { TextContent } from './helperComponents/TextContent';
10
11
  import styles from './styled.module.scss';
11
12
  import { ChatStatusAnnouncementProps } from './types';
12
13
  import { getContent, isReactNode } from './utils';
13
14
 
14
15
  export function ChatStatusAnnouncement({
15
16
  content,
17
+ contentClassName,
16
18
  onActionClick,
17
19
  actionLabel,
18
20
  icon,
@@ -98,7 +100,9 @@ export function ChatStatusAnnouncement({
98
100
  const currentTextStyle = index === currentIndex ? styles.textBlockCurrent : currentTextNextOrPreviousStyle;
99
101
 
100
102
  return (
101
- <TextContent key={index} content={item.content} className={cn(styles.textBlock, currentTextStyle)} />
103
+ <Typography.SansBodyS key={index} className={cn(styles.textBlock, currentTextStyle, contentClassName)}>
104
+ <TruncateString text={String(item.content)} />
105
+ </Typography.SansBodyS>
102
106
  );
103
107
  })}
104
108
  </div>
@@ -1,15 +1,16 @@
1
- import { ReactElement, ReactNode } from 'react';
1
+ import { ReactElement } from 'react';
2
2
 
3
3
  import { LayoutType } from '@cloud-ru/uikit-product-utils';
4
4
 
5
5
  export type TextItem = {
6
- content: ReactNode;
6
+ content: string;
7
7
  shouldFocusOnHover?: boolean;
8
8
  };
9
9
 
10
10
  export type ChatStatusAnnouncementProps = {
11
11
  icon?: ReactElement;
12
- content: ReactNode | TextItem[];
12
+ content: string | TextItem[];
13
+ contentClassName?: string;
13
14
  actionLabel: string;
14
15
  onActionClick?: () => void;
15
16
  layoutType: LayoutType;
@@ -2,8 +2,8 @@ import { ReactNode, useEffect, useRef, useState } from 'react';
2
2
 
3
3
  import { LAYOUT_TYPE, LayoutType } from '@cloud-ru/uikit-product-utils';
4
4
 
5
+ import { AiAssistantChip } from './helperComponents/AiAssistantChip';
5
6
  import { Chip } from './helperComponents/Chip';
6
- import { ClaudiaChip } from './helperComponents/ClaudiaChip';
7
7
  import { CloseChip } from './helperComponents/CloseChip';
8
8
  import { DropdownChip } from './helperComponents/DropdownChip';
9
9
  import styles from './styles.module.scss';
@@ -17,10 +17,13 @@ export type RecommendPanelProps = {
17
17
  layoutType?: LayoutType;
18
18
  onCloseClick?: () => void;
19
19
  onCloseChipLabel?: ReactNode;
20
- tooltip?: ReactNode;
21
- onClaudiaClick?: () => void;
20
+ onAiAssistantClick?: () => void;
21
+ docsUrl?: string;
22
+ dataTestId?: string;
22
23
  };
23
24
 
25
+ const AI_ASSISTANT_DOCUMENTATION_URL = 'https://cloud.ru/docs/ai_assistant_cloudia/ug/index';
26
+
24
27
  export function RecommendPanel({
25
28
  chips,
26
29
  type = CHIP_TYPE.Default,
@@ -28,8 +31,9 @@ export function RecommendPanel({
28
31
  layoutType,
29
32
  onCloseClick,
30
33
  onCloseChipLabel,
31
- tooltip,
32
- onClaudiaClick,
34
+ onAiAssistantClick,
35
+ docsUrl = AI_ASSISTANT_DOCUMENTATION_URL,
36
+ dataTestId = 'recommend-panel',
33
37
  }: RecommendPanelProps) {
34
38
  const [containerWidth, setContainerWidth] = useState(0);
35
39
  const [isCloseIconVisible, setCloseIconVisible] = useState(false);
@@ -95,8 +99,20 @@ export function RecommendPanel({
95
99
  };
96
100
 
97
101
  return (
98
- <div className={styles.container} ref={containerRef} onMouseEnter={showCloseIcon} onMouseLeave={hideCloseIcon}>
99
- <ClaudiaChip layoutType={layoutType} onClick={onClaudiaClick} size={size} tooltip={tooltip} />
102
+ <div
103
+ className={styles.container}
104
+ ref={containerRef}
105
+ onMouseEnter={showCloseIcon}
106
+ onMouseLeave={hideCloseIcon}
107
+ data-test-id={dataTestId}
108
+ >
109
+ <AiAssistantChip
110
+ layoutType={layoutType}
111
+ onClick={onAiAssistantClick}
112
+ size={size}
113
+ data-test-id={`${dataTestId}__ai-assistant-chip`}
114
+ docsUrl={docsUrl}
115
+ />
100
116
  {visibleChips.map((chip, index) => (
101
117
  <Chip
102
118
  ref={chipElement => (allChipsRefs.current[index] = chipElement)}
@@ -106,6 +122,7 @@ export function RecommendPanel({
106
122
  type={type}
107
123
  layoutType={layoutType}
108
124
  onClick={chip.onClick}
125
+ data-test-id={`${dataTestId}__chip-${chip.id}`}
109
126
  />
110
127
  ))}
111
128
  {hasHiddenChips && (
@@ -115,6 +132,7 @@ export function RecommendPanel({
115
132
  size={size}
116
133
  label={`+${hiddenChips.length}`}
117
134
  dropdownItems={hiddenChips}
135
+ data-test-id={`${dataTestId}__dropdown-chip`}
118
136
  />
119
137
  )}
120
138
  {onCloseClick && onCloseChipLabel && (
@@ -124,6 +142,7 @@ export function RecommendPanel({
124
142
  content={onCloseChipLabel}
125
143
  onClick={onCloseClick}
126
144
  isVisible={isCloseIconVisible}
145
+ data-test-id={`${dataTestId}__close-chip`}
127
146
  />
128
147
  )}
129
148
  </div>
@@ -0,0 +1,58 @@
1
+ import { forwardRef, MouseEventHandler, RefObject } from 'react';
2
+
3
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
4
+ import { LAYOUT_TYPE, LayoutType } from '@cloud-ru/uikit-product-utils';
5
+ import { Link } from '@snack-uikit/link';
6
+ import { Tooltip } from '@snack-uikit/tooltip';
7
+ import { Typography } from '@snack-uikit/typography';
8
+
9
+ import { ButtonGigaOutline } from '../../../ButtonGiga';
10
+ import { IconGiga } from '../../../IconGiga';
11
+ import { SIZE, Size } from '../../types';
12
+
13
+ type AiAssistantChipProps = {
14
+ onClick?: MouseEventHandler<HTMLElement>;
15
+ size: Size;
16
+ layoutType?: LayoutType;
17
+ docsUrl?: string;
18
+ dataTestId?: string;
19
+ };
20
+
21
+ export const AiAssistantChip = forwardRef<HTMLElement | HTMLButtonElement, AiAssistantChipProps>(
22
+ ({ onClick, size, layoutType, docsUrl, dataTestId }, ref) => {
23
+ const isMobile = layoutType === LAYOUT_TYPE.Mobile || size === SIZE.M;
24
+ const totalSize = isMobile ? SIZE.M : size;
25
+
26
+ const { t } = useLocale('Claudia');
27
+
28
+ const tooltipContent = (
29
+ <div>
30
+ <Typography.SansLabelM tag='p' data-test-id={`${dataTestId}__tooltip-title`}>
31
+ {t('AiAssistantChip.tooltipTitle')}
32
+ </Typography.SansLabelM>
33
+ <Typography.SansBodyS tag='p' data-test-id={`${dataTestId}__tooltip-description`}>
34
+ {t('AiAssistantChip.tooltipDescription')}
35
+ </Typography.SansBodyS>
36
+ <Link
37
+ text={t('AiAssistantChip.documentationLink')}
38
+ appearance='invert-neutral'
39
+ textMode='accent'
40
+ target='_blank'
41
+ href={docsUrl}
42
+ data-test-id={`${dataTestId}__documentation-link`}
43
+ ></Link>
44
+ </div>
45
+ );
46
+
47
+ return (
48
+ <Tooltip
49
+ triggerRef={ref as RefObject<HTMLElement>}
50
+ tip={tooltipContent}
51
+ placement='top'
52
+ data-test-id={dataTestId}
53
+ >
54
+ <ButtonGigaOutline size={totalSize} data-mobile={isMobile} onClick={onClick} icon={<IconGiga size={24} />} />
55
+ </Tooltip>
56
+ );
57
+ },
58
+ );
@@ -0,0 +1 @@
1
+ export * from './AiAssistantChip';
@@ -29,11 +29,13 @@ export type SshFieldProps = WithLayoutType<
29
29
  Omit<FieldTextAreaProps, 'placeholder' | 'labelTooltip' | 'label' | 'required' | 'size' | 'spellCheck' | 'footer'> & {
30
30
  /** Колбек действия при отправке */
31
31
  onSubmit(value: string): void;
32
+ /** Колбек отмены действия */
33
+ onCancel(): void;
32
34
  }
33
35
  >;
34
36
 
35
37
  export const SshField = forwardRef<HTMLTextAreaElement, SshFieldProps>(
36
- ({ onSubmit: handleSubmitProp, value, disabled, className, ...props }, ref) => {
38
+ ({ onSubmit: handleSubmitProp, onCancel, value, disabled, className, ...props }, ref) => {
37
39
  const { layoutType, validationState, onChange } = props;
38
40
  const { t } = useLocale('Claudia');
39
41
  const isTouchDevice = isTouchDeviceHelper(layoutType);
@@ -152,7 +154,7 @@ export const SshField = forwardRef<HTMLTextAreaElement, SshFieldProps>(
152
154
  icon={<PasswordLockSVG size={16} color={themeVars.sys.neutral.textSupport} />}
153
155
  content={t('SshField.chatStatusAnnouncement.content')}
154
156
  actionLabel={t('SshField.chatStatusAnnouncement.cancel')}
155
- onActionClick={() => {}}
157
+ onActionClick={onCancel}
156
158
  />
157
159
  {isDragOver ? (
158
160
  <DropZone
@@ -1,7 +0,0 @@
1
- import { ReactNode } from 'react';
2
- type TextContent = {
3
- content: ReactNode;
4
- className?: string;
5
- };
6
- export declare function TextContent({ content, className }: TextContent): string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | null | undefined;
7
- export {};
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TextContent = TextContent;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const typography_1 = require("@snack-uikit/typography");
6
- const utils_1 = require("../../utils");
7
- function TextContent({ content, className }) {
8
- if ((0, utils_1.isReactNode)(content)) {
9
- return content;
10
- }
11
- return (0, jsx_runtime_1.jsx)(typography_1.Typography.SansBodyS, { className: className, children: content });
12
- }
@@ -1 +0,0 @@
1
- export * from './TextContent';
@@ -1,17 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./TextContent"), exports);
@@ -1,11 +0,0 @@
1
- import { MouseEventHandler, ReactNode } from 'react';
2
- import { LayoutType } from '@cloud-ru/uikit-product-utils';
3
- import { Size } from '../../types';
4
- type ClaudiaChipProps = {
5
- onClick?: MouseEventHandler<HTMLElement>;
6
- size: Size;
7
- tooltip?: ReactNode;
8
- layoutType?: LayoutType;
9
- };
10
- export declare const ClaudiaChip: import("react").ForwardRefExoticComponent<ClaudiaChipProps & import("react").RefAttributes<HTMLElement | HTMLButtonElement>>;
11
- export {};
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ClaudiaChip = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
- const uikit_product_icons_1 = require("@cloud-ru/uikit-product-icons");
7
- const uikit_product_utils_1 = require("@cloud-ru/uikit-product-utils");
8
- const tooltip_1 = require("@snack-uikit/tooltip");
9
- const ButtonClaudia_1 = require("../../../ButtonClaudia");
10
- const types_1 = require("../../types");
11
- exports.ClaudiaChip = (0, react_1.forwardRef)(({ onClick, size, tooltip, layoutType }, ref) => {
12
- const isMobile = layoutType === uikit_product_utils_1.LAYOUT_TYPE.Mobile || size === types_1.SIZE.M;
13
- const totalSize = isMobile ? types_1.SIZE.M : size;
14
- if (!tooltip) {
15
- return ((0, jsx_runtime_1.jsx)(ButtonClaudia_1.ButtonClaudia, { size: totalSize, "data-mobile": isMobile, ref: ref, onClick: onClick, icon: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.AgentClaudiaSVG, { size: 24 }) }));
16
- }
17
- return ((0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { triggerRef: ref, tip: tooltip, children: (0, jsx_runtime_1.jsx)(ButtonClaudia_1.ButtonClaudia, { size: totalSize, "data-mobile": isMobile, onClick: onClick, icon: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.AgentClaudiaSVG, { size: 24 }) }) }));
18
- });
@@ -1 +0,0 @@
1
- export * from './ClaudiaChip';
@@ -1,7 +0,0 @@
1
- import { ReactNode } from 'react';
2
- type TextContent = {
3
- content: ReactNode;
4
- className?: string;
5
- };
6
- export declare function TextContent({ content, className }: TextContent): string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | null | undefined;
7
- export {};
@@ -1,9 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Typography } from '@snack-uikit/typography';
3
- import { isReactNode } from '../../utils';
4
- export function TextContent({ content, className }) {
5
- if (isReactNode(content)) {
6
- return content;
7
- }
8
- return _jsx(Typography.SansBodyS, { className: className, children: content });
9
- }
@@ -1 +0,0 @@
1
- export * from './TextContent';
@@ -1 +0,0 @@
1
- export * from './TextContent';
@@ -1,11 +0,0 @@
1
- import { MouseEventHandler, ReactNode } from 'react';
2
- import { LayoutType } from '@cloud-ru/uikit-product-utils';
3
- import { Size } from '../../types';
4
- type ClaudiaChipProps = {
5
- onClick?: MouseEventHandler<HTMLElement>;
6
- size: Size;
7
- tooltip?: ReactNode;
8
- layoutType?: LayoutType;
9
- };
10
- export declare const ClaudiaChip: import("react").ForwardRefExoticComponent<ClaudiaChipProps & import("react").RefAttributes<HTMLElement | HTMLButtonElement>>;
11
- export {};
@@ -1,15 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { forwardRef } from 'react';
3
- import { AgentClaudiaSVG } from '@cloud-ru/uikit-product-icons';
4
- import { LAYOUT_TYPE } from '@cloud-ru/uikit-product-utils';
5
- import { Tooltip } from '@snack-uikit/tooltip';
6
- import { ButtonClaudia } from '../../../ButtonClaudia';
7
- import { SIZE } from '../../types';
8
- export const ClaudiaChip = forwardRef(({ onClick, size, tooltip, layoutType }, ref) => {
9
- const isMobile = layoutType === LAYOUT_TYPE.Mobile || size === SIZE.M;
10
- const totalSize = isMobile ? SIZE.M : size;
11
- if (!tooltip) {
12
- return (_jsx(ButtonClaudia, { size: totalSize, "data-mobile": isMobile, ref: ref, onClick: onClick, icon: _jsx(AgentClaudiaSVG, { size: 24 }) }));
13
- }
14
- return (_jsx(Tooltip, { triggerRef: ref, tip: tooltip, children: _jsx(ButtonClaudia, { size: totalSize, "data-mobile": isMobile, onClick: onClick, icon: _jsx(AgentClaudiaSVG, { size: 24 }) }) }));
15
- });
@@ -1 +0,0 @@
1
- export * from './ClaudiaChip';
@@ -1 +0,0 @@
1
- export * from './ClaudiaChip';
@@ -1,18 +0,0 @@
1
- import { ReactNode } from 'react';
2
-
3
- import { Typography } from '@snack-uikit/typography';
4
-
5
- import { isReactNode } from '../../utils';
6
-
7
- type TextContent = {
8
- content: ReactNode;
9
- className?: string;
10
- };
11
-
12
- export function TextContent({ content, className }: TextContent) {
13
- if (isReactNode(content)) {
14
- return content;
15
- }
16
-
17
- return <Typography.SansBodyS className={className}>{content}</Typography.SansBodyS>;
18
- }
@@ -1 +0,0 @@
1
- export * from './TextContent';
@@ -1,40 +0,0 @@
1
- import { forwardRef, MouseEventHandler, ReactNode, RefObject } from 'react';
2
-
3
- import { AgentClaudiaSVG } from '@cloud-ru/uikit-product-icons';
4
- import { LAYOUT_TYPE, LayoutType } from '@cloud-ru/uikit-product-utils';
5
- import { Tooltip } from '@snack-uikit/tooltip';
6
-
7
- import { ButtonClaudia } from '../../../ButtonClaudia';
8
- import { SIZE, Size } from '../../types';
9
-
10
- type ClaudiaChipProps = {
11
- onClick?: MouseEventHandler<HTMLElement>;
12
- size: Size;
13
- tooltip?: ReactNode;
14
- layoutType?: LayoutType;
15
- };
16
-
17
- export const ClaudiaChip = forwardRef<HTMLElement | HTMLButtonElement, ClaudiaChipProps>(
18
- ({ onClick, size, tooltip, layoutType }, ref) => {
19
- const isMobile = layoutType === LAYOUT_TYPE.Mobile || size === SIZE.M;
20
- const totalSize = isMobile ? SIZE.M : size;
21
-
22
- if (!tooltip) {
23
- return (
24
- <ButtonClaudia
25
- size={totalSize}
26
- data-mobile={isMobile}
27
- ref={ref as RefObject<HTMLButtonElement>}
28
- onClick={onClick}
29
- icon={<AgentClaudiaSVG size={24} />}
30
- />
31
- );
32
- }
33
-
34
- return (
35
- <Tooltip triggerRef={ref as RefObject<HTMLElement>} tip={tooltip}>
36
- <ButtonClaudia size={totalSize} data-mobile={isMobile} onClick={onClick} icon={<AgentClaudiaSVG size={24} />} />
37
- </Tooltip>
38
- );
39
- },
40
- );
@@ -1 +0,0 @@
1
- export * from './ClaudiaChip';