@redocly/theme 0.62.0-next.6 → 0.62.0-next.8

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 (51) hide show
  1. package/lib/components/Breadcrumbs/Breadcrumb.js +1 -1
  2. package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +1 -1
  3. package/lib/components/Catalog/CatalogTagsWithTooltip.js +1 -1
  4. package/lib/components/CodeBlock/CodeBlockControls.js +5 -5
  5. package/lib/components/Menu/variables.js +3 -3
  6. package/lib/components/Search/SearchAiDialog.d.ts +4 -2
  7. package/lib/components/Search/SearchAiDialog.js +23 -4
  8. package/lib/components/Search/SearchAiMessage.d.ts +4 -2
  9. package/lib/components/Search/SearchAiMessage.js +72 -16
  10. package/lib/components/Search/SearchDialog.js +1 -1
  11. package/lib/components/Tooltip/Tooltip.d.ts +2 -3
  12. package/lib/components/Tooltip/Tooltip.js +66 -113
  13. package/lib/components/Tooltip/variables.dark.js +4 -0
  14. package/lib/components/Tooltip/variables.js +3 -3
  15. package/lib/components/UserMenu/LoginButton.js +1 -1
  16. package/lib/core/constants/search.d.ts +5 -1
  17. package/lib/core/constants/search.js +24 -1
  18. package/lib/core/hooks/use-outside-click.d.ts +3 -1
  19. package/lib/core/hooks/use-outside-click.js +8 -4
  20. package/lib/core/types/hooks.d.ts +10 -1
  21. package/lib/core/types/l10n.d.ts +1 -1
  22. package/lib/core/types/search.d.ts +24 -0
  23. package/lib/core/types/search.js +9 -1
  24. package/lib/core/utils/content-segments.d.ts +2 -0
  25. package/lib/core/utils/content-segments.js +22 -0
  26. package/lib/core/utils/index.d.ts +1 -0
  27. package/lib/core/utils/index.js +1 -0
  28. package/package.json +7 -7
  29. package/src/components/Breadcrumbs/Breadcrumb.tsx +3 -3
  30. package/src/components/Breadcrumbs/BreadcrumbDropdown.tsx +3 -3
  31. package/src/components/Catalog/CatalogTagsWithTooltip.tsx +3 -3
  32. package/src/components/CodeBlock/CodeBlockControls.tsx +13 -9
  33. package/src/components/Menu/variables.ts +3 -3
  34. package/src/components/Search/SearchAiDialog.tsx +31 -2
  35. package/src/components/Search/SearchAiMessage.tsx +94 -10
  36. package/src/components/Search/SearchDialog.tsx +2 -0
  37. package/src/components/Tooltip/Tooltip.tsx +77 -120
  38. package/src/components/Tooltip/variables.dark.ts +4 -0
  39. package/src/components/Tooltip/variables.ts +3 -3
  40. package/src/components/UserMenu/LoginButton.tsx +2 -2
  41. package/src/core/constants/search.ts +27 -1
  42. package/src/core/hooks/__mocks__/use-theme-hooks.ts +9 -1
  43. package/src/core/hooks/use-outside-click.ts +16 -5
  44. package/src/core/types/hooks.ts +9 -0
  45. package/src/core/types/l10n.ts +3 -0
  46. package/src/core/types/search.ts +19 -0
  47. package/src/core/utils/content-segments.ts +27 -0
  48. package/src/core/utils/index.ts +1 -0
  49. package/lib/components/Tooltip/TooltipWrapper.d.ts +0 -12
  50. package/lib/components/Tooltip/TooltipWrapper.js +0 -34
  51. package/src/components/Tooltip/TooltipWrapper.tsx +0 -70
@@ -51,7 +51,7 @@ function Breadcrumb({ label, link, isActive, onClick, icon }) {
51
51
  react_1.default.createElement(BreadcrumbIcon_1.BreadcrumbIcon, { icon: icon }),
52
52
  displayLabel));
53
53
  const breadcrumbContent = link ? (react_1.default.createElement(BreadcrumbLink, { "data-component-name": "Breadcrumbs/BreadcrumbLink", to: link, onClick: onClick, "$isActive": isActive }, content)) : (react_1.default.createElement(BreadcrumbWrapper, { "data-component-name": "Breadcrumbs/BreadcrumbWrapper", "$isActive": isActive, onClick: onClick, tabIndex: -1 }, content));
54
- return isTruncated ? (react_1.default.createElement(Tooltip_1.TooltipComponent, { tip: label, placement: "bottom", width: "max-content" }, breadcrumbContent)) : (breadcrumbContent);
54
+ return isTruncated ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: label, placement: "bottom" }, breadcrumbContent)) : (breadcrumbContent);
55
55
  }
56
56
  const baseBreadcrumbStyles = `
57
57
  display: flex;
@@ -55,7 +55,7 @@ function BreadcrumbDropdown({ children, label, items, onItemClick, className, })
55
55
  return null;
56
56
  }
57
57
  const isTruncated = label.length > constants_1.BREADCRUMB_MAX_LENGTH;
58
- const triggerContent = isTruncated ? (react_1.default.createElement(Tooltip_1.TooltipComponent, { tip: label, placement: "bottom", width: "max-content" },
58
+ const triggerContent = isTruncated ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: label, placement: "bottom" },
59
59
  react_1.default.createElement(TriggerContentWrapper, null, children))) : (children);
60
60
  const trigger = react_1.default.createElement(StyledDropdownTrigger, null, triggerContent);
61
61
  return (react_1.default.createElement(BreadcrumbDropdownWrapper, { "data-component-name": "Breadcrumbs/BreadcrumbDropdown", className: className, "data-testid": "breadcrumb-dropdown" },
@@ -27,7 +27,7 @@ function CatalogTagsWithTooltip({ items, itemsToShow = 1, showPlaceholder = true
27
27
  }
28
28
  const displayedItems = items.slice(0, itemsToShow);
29
29
  const remainingCount = items.length - itemsToShow;
30
- return (react_1.default.createElement(Tooltip_1.TooltipComponent, { tip: items.join(', '), placement: "bottom", className: "catalog", width: "400px" },
30
+ return (react_1.default.createElement(Tooltip_1.Tooltip, { tip: items.join(', '), placement: "bottom", className: "catalog", width: "400px" },
31
31
  react_1.default.createElement(CatalogTagsWrapper, { "data-component-name": "Catalog/CatalogTagsWithTooltip" },
32
32
  displayedItems.map((item, index) => (react_1.default.createElement(Tag_1.Tag, Object.assign({ key: `${item}-${index}` }, tagProps, { textTransform: "none", maxLength: constants_1.CATALOG_TAG_MAX_LENGTH }),
33
33
  react_1.default.createElement(CatalogHighlight_1.CatalogHighlight, null, item)))),
@@ -8,7 +8,7 @@ const react_1 = __importDefault(require("react"));
8
8
  const styled_components_1 = __importDefault(require("styled-components"));
9
9
  const CodeBlockTabs_1 = require("../../components/CodeBlock/CodeBlockTabs");
10
10
  const CopyButton_1 = require("../../components/Buttons/CopyButton");
11
- const TooltipWrapper_1 = require("../../components/Tooltip/TooltipWrapper");
11
+ const Tooltip_1 = require("../../components/Tooltip/Tooltip");
12
12
  const hooks_1 = require("../../core/hooks");
13
13
  const DeselectIcon_1 = require("../../icons/DeselectIcon/DeselectIcon");
14
14
  const MaximizeIcon_1 = require("../../icons/MaximizeIcon/MaximizeIcon");
@@ -38,15 +38,15 @@ function CodeBlockControls({ children, className, title, controls, tabs, dropdow
38
38
  tabs && react_1.default.createElement(CodeBlockTabs_1.CodeBlockTabs, { tabs: tabs }),
39
39
  react_1.default.createElement(ControlsWrapper, null,
40
40
  dropdown && react_1.default.createElement(CodeBlockDropdown_1.CodeBlockDropdown, Object.assign({}, dropdown)),
41
- report && !report.hidden && !((_a = report === null || report === void 0 ? void 0 : report.props) === null || _a === void 0 ? void 0 : _a.hide) ? (react_1.default.createElement(TooltipWrapper_1.TooltipWrapper, { tip: translate('codeSnippet.report.tooltipText', 'Report a problem'), placement: "top" },
41
+ report && !report.hidden && !((_a = report === null || report === void 0 ? void 0 : report.props) === null || _a === void 0 ? void 0 : _a.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.report.tooltipText', 'Report a problem'), placement: "top", arrowPosition: "right" },
42
42
  react_1.default.createElement(ControlButton, Object.assign({ variant: "text", size: "small", "data-testid": "report-button", icon: controlsType === 'icon' ? react_1.default.createElement(WarningSquareIcon_1.WarningSquareIcon, { size: "18px" }) : undefined }, report.props), controlsType != 'icon' && (((_b = report.props) === null || _b === void 0 ? void 0 : _b.buttonText) || 'Report')))) : null,
43
- expand && !((_c = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.expand) === null || _c === void 0 ? void 0 : _c.hide) ? (react_1.default.createElement(TooltipWrapper_1.TooltipWrapper, { tip: translate('codeSnippet.expand.tooltipText', 'Expand all'), placement: "top" },
43
+ expand && !((_c = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.expand) === null || _c === void 0 ? void 0 : _c.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.expand.tooltipText', 'Expand all'), placement: "top", arrowPosition: "right" },
44
44
  react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "expand-all", icon: controlsType === 'icon' ? react_1.default.createElement(MaximizeIcon_1.MaximizeIcon, null) : undefined, onClick: expand === null || expand === void 0 ? void 0 : expand.onClick }, controlsType !== 'icon' && ((expand === null || expand === void 0 ? void 0 : expand.label) || 'Expand all')))) : null,
45
- collapse && !((_d = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.collapse) === null || _d === void 0 ? void 0 : _d.hide) ? (react_1.default.createElement(TooltipWrapper_1.TooltipWrapper, { tip: translate('codeSnippet.collapse.tooltipText', 'Collapse all'), placement: "top" },
45
+ collapse && !((_d = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.collapse) === null || _d === void 0 ? void 0 : _d.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.collapse.tooltipText', 'Collapse all'), placement: "top", arrowPosition: "right" },
46
46
  react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "collapse-all", icon: controlsType === 'icon' ? react_1.default.createElement(MinimizeIcon_1.MinimizeIcon, null) : undefined, onClick: collapse === null || collapse === void 0 ? void 0 : collapse.onClick }, controlsType !== 'icon' && ((expand === null || expand === void 0 ? void 0 : expand.label) || 'Collapse all')))) : null,
47
47
  select ? (react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "select-all", icon: controlsType === 'icon' ? react_1.default.createElement(SelectIcon_1.SelectIcon, null) : undefined, onClick: select === null || select === void 0 ? void 0 : select.onClick }, controlsType !== 'icon' && (select === null || select === void 0 ? void 0 : select.label) ? select.label : 'Select all')) : null,
48
48
  deselect ? (react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "clear-all", icon: controlsType === 'icon' ? react_1.default.createElement(DeselectIcon_1.DeselectIcon, null) : undefined, onClick: deselect === null || deselect === void 0 ? void 0 : deselect.onClick }, controlsType !== 'icon' && (deselect === null || deselect === void 0 ? void 0 : deselect.label) ? deselect.label : 'Clear all')) : null,
49
- copy && !((_e = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.copy) === null || _e === void 0 ? void 0 : _e.hide) ? (react_1.default.createElement(TooltipWrapper_1.TooltipWrapper, { tip: translate('codeSnippet.copy.tooltipText', 'Copy to clipboard'), placement: "top" },
49
+ copy && !((_e = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.copy) === null || _e === void 0 ? void 0 : _e.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.copy.tooltipText', 'Copy to clipboard'), placement: "top", arrowPosition: "right" },
50
50
  react_1.default.createElement(StyledCopyButton, { data: copy.data, "data-source": copy.dataSource, "data-hash": copy.dataHash, type: controlsType, toasterPlacement: copy.toasterPlacement, toasterDuration: copy.toasterDuration, buttonText: copy.label, onCopyClick: () => {
51
51
  var _a;
52
52
  // If there already is a click handler, events should be handled there, cause they pass additional data
@@ -131,12 +131,12 @@ exports.mobileMenu = (0, styled_components_1.css) `
131
131
  * @tokens Mobile Menu
132
132
  * */
133
133
  /* Fallback for older browsers. dvh accounts for dynamic UI elements like mobile address bars */
134
- --menu-mobile-height: calc(100vh - var(--navbar-height));
135
- --menu-mobile-height: calc(100dvh - var(--navbar-height));
134
+ --menu-mobile-height: calc(100vh - var(--navbar-height) - var(--banner-height));
135
+ --menu-mobile-height: calc(100dvh - var(--navbar-height) - var(--banner-height));
136
136
  --menu-mobile-width: 100%;
137
137
  --menu-mobile-z-index: var(--z-index-raised);
138
138
  --menu-mobile-left: 0;
139
- --menu-mobile-top: var(--navbar-height);
139
+ --menu-mobile-top: calc(var(--navbar-height) + var(--banner-height));
140
140
  --menu-mobile-transition: 0.5s;
141
141
  --menu-mobile-bg: var(--bg-color); // @presenter Color
142
142
  --menu-mobile-margin: var(--menu-mobile-items-margin-top) var(--menu-mobile-margin-horizontal) 0 var(--menu-mobile-margin-horizontal);
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { JSX } from 'react';
3
- import type { AiSearchConversationItem, SearchAiMessageResource } from '../../core/types';
3
+ import type { AiSearchConversationItem, SearchAiMessageResource, ToolCall, ContentSegment } from '../../core/types';
4
4
  import { AiSearchError } from '../../core/constants';
5
5
  export type SearchAiDialogProps = {
6
6
  response: string | undefined;
@@ -12,5 +12,7 @@ export type SearchAiDialogProps = {
12
12
  conversation: AiSearchConversationItem[];
13
13
  setConversation: React.Dispatch<React.SetStateAction<AiSearchConversationItem[]>>;
14
14
  onMessageSent: (message: string, history?: AiSearchConversationItem[], messageId?: string) => void;
15
+ toolCalls?: ToolCall[];
16
+ contentSegments?: ContentSegment[];
15
17
  };
16
- export declare function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, }: SearchAiDialogProps): JSX.Element;
18
+ export declare function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, toolCalls, contentSegments, }: SearchAiDialogProps): JSX.Element;
@@ -46,7 +46,7 @@ const constants_1 = require("../../core/constants");
46
46
  const SearchAiMessage_1 = require("../../components/Search/SearchAiMessage");
47
47
  const Admonition_1 = require("../../components/Admonition/Admonition");
48
48
  const AiStarsIcon_1 = require("../../icons/AiStarsIcon/AiStarsIcon");
49
- function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, }) {
49
+ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, toolCalls = [], contentSegments, }) {
50
50
  const { useTranslate } = (0, hooks_1.useThemeHooks)();
51
51
  const { aiAssistant } = (0, hooks_1.useThemeConfig)();
52
52
  const { translate } = useTranslate();
@@ -99,12 +99,31 @@ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error,
99
99
  content,
100
100
  resources,
101
101
  messageId: lastMessage.messageId,
102
+ toolCalls,
103
+ contentSegments,
102
104
  },
103
105
  ];
104
106
  }
105
- return [...prev, { role: constants_1.AiSearchConversationRole.ASSISTANT, content, resources }];
107
+ return [
108
+ ...prev,
109
+ {
110
+ role: constants_1.AiSearchConversationRole.ASSISTANT,
111
+ content,
112
+ resources,
113
+ toolCalls,
114
+ contentSegments,
115
+ },
116
+ ];
106
117
  });
107
- }, [response, conversation.length, error, resources, setConversation]);
118
+ }, [
119
+ response,
120
+ conversation.length,
121
+ error,
122
+ resources,
123
+ toolCalls,
124
+ contentSegments,
125
+ setConversation,
126
+ ]);
108
127
  (0, react_1.useEffect)(() => {
109
128
  if (error) {
110
129
  setConversation((prev) => prev.slice(0, -1));
@@ -123,7 +142,7 @@ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error,
123
142
  react_1.default.createElement(ConversationWrapper, null,
124
143
  conversation.map((item, index) => (react_1.default.createElement(SearchAiMessage_1.SearchAiMessage, { key: `search-ai-message-${index}`, role: item.role, content: item.content, isThinking: item.role === constants_1.AiSearchConversationRole.ASSISTANT &&
125
144
  isGeneratingResponse &&
126
- index === conversation.length - 1, resources: item.resources, messageId: item.messageId, feedback: item.feedback, onFeedbackChange: handleFeedbackChange }))),
145
+ index === conversation.length - 1, resources: item.resources, messageId: item.messageId, feedback: item.feedback, onFeedbackChange: handleFeedbackChange, toolCalls: item.toolCalls || (index === conversation.length - 1 ? toolCalls : undefined), contentSegments: item.contentSegments }))),
127
146
  error && (react_1.default.createElement(Admonition_1.Admonition, { type: "danger", name: translate(constants_1.AI_SEARCH_ERROR_CONFIG[error].headerKey, constants_1.AI_SEARCH_ERROR_CONFIG[error].headerDefault) }, translate(constants_1.AI_SEARCH_ERROR_CONFIG[error].messageKey, constants_1.AI_SEARCH_ERROR_CONFIG[error].messageDefault))),
128
147
  !conversation.length && !error && (react_1.default.createElement(SuggestionsWrapper, null, suggestions === null || suggestions === void 0 ? void 0 : suggestions.map((suggestion) => (react_1.default.createElement(Button_1.Button, { key: suggestion, variant: "outlined", onClick: () => handleOnMessageSent(suggestion) }, suggestion))))),
129
148
  react_1.default.createElement("div", { ref: conversationEndRef })),
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { JSX } from 'react';
3
- import { FeedbackType, type SearchAiMessageResource } from '../../core/types';
3
+ import { FeedbackType, type SearchAiMessageResource, type ToolCall, type ContentSegment } from '../../core/types';
4
4
  import { AiSearchConversationRole } from '../../core/constants';
5
5
  export type SearchAiMessageProps = {
6
6
  role: AiSearchConversationRole;
@@ -11,7 +11,9 @@ export type SearchAiMessageProps = {
11
11
  messageId?: string;
12
12
  feedback?: FeedbackType;
13
13
  onFeedbackChange: (messageId: string, feedback: FeedbackType | undefined) => void;
14
+ toolCalls?: ToolCall[];
15
+ contentSegments?: ContentSegment[];
14
16
  };
15
- declare function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, }: SearchAiMessageProps): JSX.Element;
17
+ declare function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, toolCalls, contentSegments, }: SearchAiMessageProps): JSX.Element;
16
18
  export declare const SearchAiMessage: React.MemoExoticComponent<typeof SearchAiMessageComponent>;
17
19
  export {};
@@ -40,9 +40,10 @@ exports.SearchAiMessage = void 0;
40
40
  const react_1 = __importStar(require("react"));
41
41
  const styled_components_1 = __importDefault(require("styled-components"));
42
42
  const types_1 = require("../../core/types");
43
+ const constants_1 = require("../../core/constants");
43
44
  const Link_1 = require("../../components/Link/Link");
44
45
  const Tag_1 = require("../../components/Tag/Tag");
45
- const constants_1 = require("../../core/constants");
46
+ const constants_2 = require("../../core/constants");
46
47
  const hooks_1 = require("../../core/hooks");
47
48
  const Markdown_1 = require("../../components/Markdown/Markdown");
48
49
  const DocumentIcon_1 = require("../../icons/DocumentIcon/DocumentIcon");
@@ -50,16 +51,21 @@ const AiStarsIcon_1 = require("../../icons/AiStarsIcon/AiStarsIcon");
50
51
  const CheckmarkOutlineIcon_1 = require("../../icons/CheckmarkOutlineIcon/CheckmarkOutlineIcon");
51
52
  const SearchAiActionButtons_1 = require("../../components/Search/SearchAiActionButtons");
52
53
  const SearchAiNegativeFeedbackForm_1 = require("../../components/Search/SearchAiNegativeFeedbackForm");
53
- function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, }) {
54
+ function MarkdownSegment({ text }) {
55
+ const { useMarkdownText } = (0, hooks_1.useThemeHooks)();
56
+ const markdown = useMarkdownText(text);
57
+ return react_1.default.createElement(ResponseText, { as: "div", children: markdown, "data-testid": "response-text" });
58
+ }
59
+ function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, toolCalls = [], contentSegments = [{ type: 'text', text: content }], }) {
54
60
  var _a;
55
- const { useMarkdownText, useTranslate, useTelemetry } = (0, hooks_1.useThemeHooks)();
56
- const markDownContent = useMarkdownText(content || '');
61
+ const { useTranslate, useTelemetry } = (0, hooks_1.useThemeHooks)();
57
62
  const { translate } = useTranslate();
58
63
  const telemetry = useTelemetry();
59
64
  const [feedbackSent, setFeedbackSent] = (0, react_1.useState)(false);
60
65
  const hasResources = !isThinking && resources && resources.length > 0;
61
66
  const resourcesCount = (_a = resources === null || resources === void 0 ? void 0 : resources.length) !== null && _a !== void 0 ? _a : 0;
62
67
  const showSuccessMessage = feedbackSent && feedback;
68
+ const isLoading = isThinking && content.length === 0 && toolCalls.length === 0;
63
69
  const sendFeedbackTelemetry = (feedbackValue, dislikeReason) => {
64
70
  if (!messageId)
65
71
  return;
@@ -90,10 +96,25 @@ function SearchAiMessageComponent({ role, content, isThinking, resources, classN
90
96
  }
91
97
  };
92
98
  return (react_1.default.createElement(SearchAiMessageWrapper, { "data-component-name": "Search/SearchAiMessage", role: role, className: className, "data-testid": "search-ai-message" },
93
- role === constants_1.AiSearchConversationRole.ASSISTANT && (react_1.default.createElement(AiStarsIcon_1.AiStarsIcon, { size: "32px", background: "var(--search-ai-icon-bg-color)", borderRadius: "var(--border-radius-lg)", color: "var(--search-ai-icon-color)", margin: "0 var(--spacing-xs) 0 0" })),
94
- react_1.default.createElement(MessageContentWrapper, null, role === constants_1.AiSearchConversationRole.ASSISTANT ? (react_1.default.createElement(react_1.default.Fragment, null,
99
+ role === constants_2.AiSearchConversationRole.ASSISTANT && (react_1.default.createElement(AiStarsIcon_1.AiStarsIcon, { size: "32px", background: "var(--search-ai-icon-bg-color)", borderRadius: "var(--border-radius-lg)", color: "var(--search-ai-icon-color)", margin: "0 var(--spacing-xs) 0 0" })),
100
+ react_1.default.createElement(MessageContentWrapper, null, role === constants_2.AiSearchConversationRole.ASSISTANT ? (react_1.default.createElement(react_1.default.Fragment, null,
95
101
  react_1.default.createElement(MessageWrapper, { role: role },
96
- react_1.default.createElement(ResponseText, { as: "div", children: markDownContent, "data-testid": "response-text" }),
102
+ contentSegments.map((segment, index) => {
103
+ var _a, _b, _c, _d, _e, _f;
104
+ if (segment.type === 'tool') {
105
+ const toolCallCompleted = Boolean(segment.toolCall.result);
106
+ const toolCallCompletedText = (_b = (_a = constants_1.TOOL_CALL_DISPLAY_TEXT[segment.toolCall.name]) === null || _a === void 0 ? void 0 : _a.completedText) !== null && _b !== void 0 ? _b : `${translate('search.ai.toolResult.found', 'Found')} ${(_d = (_c = segment.toolCall.result) === null || _c === void 0 ? void 0 : _c.documentCount) !== null && _d !== void 0 ? _d : 0} ${translate('search.ai.toolResult.found.documents', 'documents')}`;
107
+ const toolCallInProgressText = (_f = (_e = constants_1.TOOL_CALL_DISPLAY_TEXT[segment.toolCall.name]) === null || _e === void 0 ? void 0 : _e.inProgressText) !== null && _f !== void 0 ? _f : translate('search.ai.toolCall.searching', 'Searching...');
108
+ const toolCallDisplayText = toolCallCompleted
109
+ ? toolCallCompletedText
110
+ : toolCallInProgressText;
111
+ return (react_1.default.createElement(ToolCallsInfoWrapper, { key: `tool-${index}`, "data-testid": "tool-calls-info" },
112
+ react_1.default.createElement(ToolCallInfoItem, null,
113
+ react_1.default.createElement(DocumentIcon_1.DocumentIcon, { size: "14px", color: "--search-ai-text-color" }),
114
+ react_1.default.createElement(ToolCallText, { "$isSearching": !toolCallCompleted }, toolCallDisplayText))));
115
+ }
116
+ return react_1.default.createElement(MarkdownSegment, { key: `text-${index}`, text: segment.text });
117
+ }),
97
118
  hasResources && (react_1.default.createElement(react_1.default.Fragment, null,
98
119
  react_1.default.createElement(ResourcesWrapper, { "data-testid": "resources-wrapper" },
99
120
  react_1.default.createElement(ResourcesTitle, { "data-translation-key": "search.ai.resourcesFound" },
@@ -102,9 +123,9 @@ function SearchAiMessageComponent({ role, content, isThinking, resources, classN
102
123
  resourcesCount,
103
124
  ' ',
104
125
  translate('search.ai.resourcesFound.resources', 'resources')),
105
- react_1.default.createElement(ResourceTagsWrapper, null, resources === null || resources === void 0 ? void 0 : resources.map((resource, idx) => (react_1.default.createElement(Link_1.Link, { key: `${resource.url}-${idx}`, to: resource.url, target: "_blank" },
126
+ react_1.default.createElement(ResourceTagsWrapper, null, resources === null || resources === void 0 ? void 0 : resources.map((resource, index) => (react_1.default.createElement(Link_1.Link, { key: `${resource.url}-${index}`, to: resource.url, target: "_blank" },
106
127
  react_1.default.createElement(ResourceTag, { borderless: true, icon: react_1.default.createElement(DocumentIcon_1.DocumentIcon, { color: "--search-ai-resource-tag-icon-color" }) }, resource.title)))))))),
107
- isThinking && content.length === 0 && (react_1.default.createElement(ThinkingDotsWrapper, { "data-testid": "thinking-dots-wrapper" },
128
+ isLoading && (react_1.default.createElement(ThinkingDotsWrapper, { "data-testid": "thinking-dots-wrapper" },
108
129
  react_1.default.createElement(ThinkingDot, null),
109
130
  react_1.default.createElement(ThinkingDot, null),
110
131
  react_1.default.createElement(ThinkingDot, null))),
@@ -129,20 +150,23 @@ function areResourcesEqual(prev, next) {
129
150
  });
130
151
  }
131
152
  exports.SearchAiMessage = (0, react_1.memo)(SearchAiMessageComponent, (prevProps, nextProps) => {
153
+ var _a, _b;
132
154
  return (prevProps.role === nextProps.role &&
133
155
  prevProps.content === nextProps.content &&
134
156
  prevProps.isThinking === nextProps.isThinking &&
135
157
  prevProps.messageId === nextProps.messageId &&
136
158
  prevProps.feedback === nextProps.feedback &&
137
159
  prevProps.onFeedbackChange === nextProps.onFeedbackChange &&
138
- areResourcesEqual(prevProps.resources, nextProps.resources));
160
+ areResourcesEqual(prevProps.resources, nextProps.resources) &&
161
+ ((_a = prevProps.toolCalls) === null || _a === void 0 ? void 0 : _a.length) === ((_b = nextProps.toolCalls) === null || _b === void 0 ? void 0 : _b.length) &&
162
+ prevProps.contentSegments === nextProps.contentSegments);
139
163
  });
140
164
  const SearchAiMessageWrapper = styled_components_1.default.div `
141
165
  display: flex;
142
166
  flex-direction: row;
143
167
  align-items: flex-start;
144
168
  width: 100%;
145
- justify-content: ${({ role }) => role === constants_1.AiSearchConversationRole.USER ? 'flex-end' : 'flex-start'};
169
+ justify-content: ${({ role }) => role === constants_2.AiSearchConversationRole.USER ? 'flex-end' : 'flex-start'};
146
170
  `;
147
171
  const MessageContentWrapper = styled_components_1.default.div `
148
172
  display: flex;
@@ -168,18 +192,19 @@ const ResponseText = (0, styled_components_1.default)(Markdown_1.Markdown) `
168
192
  }
169
193
  `;
170
194
  const MessageWrapper = styled_components_1.default.div `
171
- padding: ${({ role }) => role === constants_1.AiSearchConversationRole.USER ? 'var(--spacing-sm)' : 'var(--spacing-xs)'}
172
- var(--spacing-sm);
195
+ padding: ${({ role }) => role === constants_2.AiSearchConversationRole.USER
196
+ ? 'var(--spacing-sm)'
197
+ : 'var(--spacing-sm) var(--spacing-sm) var(--spacing-xs) var(--spacing-sm)'};
173
198
  border-radius: var(--border-radius-lg);
174
199
  width: fit-content;
175
200
  max-width: 100%;
176
201
  word-wrap: break-word;
177
202
  white-space: pre-wrap;
178
- background-color: ${({ role }) => role === constants_1.AiSearchConversationRole.USER
203
+ background-color: ${({ role }) => role === constants_2.AiSearchConversationRole.USER
179
204
  ? 'var(--search-ai-user-bg-color)'
180
205
  : 'var(--search-ai-assistant-bg-color)'};
181
- border: ${({ role }) => role === constants_1.AiSearchConversationRole.USER ? 'none' : 'var(--search-ai-assistant-border)'};
182
- color: ${({ role }) => role === constants_1.AiSearchConversationRole.USER
206
+ border: ${({ role }) => role === constants_2.AiSearchConversationRole.USER ? 'none' : 'var(--search-ai-assistant-border)'};
207
+ color: ${({ role }) => role === constants_2.AiSearchConversationRole.USER
183
208
  ? 'var(--search-ai-user-text-color)'
184
209
  : 'var(--search-ai-assistant-text-color)'};
185
210
  `;
@@ -273,4 +298,35 @@ const SuccessMessageText = styled_components_1.default.div `
273
298
  font-size: var(--font-size-base);
274
299
  color: var(--color-success-darker);
275
300
  `;
301
+ const ToolCallsInfoWrapper = styled_components_1.default.div `
302
+ display: flex;
303
+ flex-direction: column;
304
+ gap: var(--spacing-xxs);
305
+ margin: 0 0 var(--spacing-sm) 0;
306
+ font-size: var(--font-size-xs);
307
+ color: var(--search-ai-text-color);
308
+ opacity: 0.6;
309
+ `;
310
+ const ToolCallInfoItem = styled_components_1.default.div `
311
+ display: flex;
312
+ align-items: center;
313
+ gap: var(--spacing-xxs);
314
+ `;
315
+ const ToolCallText = styled_components_1.default.span `
316
+ font-weight: var(--font-weight-regular);
317
+
318
+ ${({ $isSearching }) => $isSearching &&
319
+ `
320
+ animation: pulse 1.5s ease-in-out infinite;
321
+
322
+ @keyframes pulse {
323
+ 0%, 100% {
324
+ opacity: 1;
325
+ }
326
+ 50% {
327
+ opacity: 0.4;
328
+ }
329
+ }
330
+ `}
331
+ `;
276
332
  //# sourceMappingURL=SearchAiMessage.js.map
@@ -287,7 +287,7 @@ function SearchDialog({ onClose, className, initialMode = 'search', }) {
287
287
  setQuery(query);
288
288
  focusSearchInput();
289
289
  } }),
290
- react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))))) : (react_1.default.createElement(SearchAiDialog_1.SearchAiDialog, { initialMessage: query, response: aiSearch.response, isGeneratingResponse: aiSearch.isGeneratingResponse, error: aiSearch.error, resources: aiSearch.resources, conversation: aiSearch.conversation, setConversation: aiSearch.setConversation, onMessageSent: aiSearch.askQuestion }))),
290
+ react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))))) : (react_1.default.createElement(SearchAiDialog_1.SearchAiDialog, { initialMessage: query, response: aiSearch.response, isGeneratingResponse: aiSearch.isGeneratingResponse, error: aiSearch.error, resources: aiSearch.resources, conversation: aiSearch.conversation, setConversation: aiSearch.setConversation, onMessageSent: aiSearch.askQuestion, toolCalls: aiSearch.toolCalls, contentSegments: aiSearch.contentSegments }))),
291
291
  react_1.default.createElement(SearchDialogFooter, null, mode === 'ai-dialog' ? (react_1.default.createElement(AiDisclaimer, null, translate('search.ai.disclaimer', 'AI search might provide incomplete or incorrect results. Verify important information.'))) : (react_1.default.createElement(react_1.default.Fragment, null,
292
292
  react_1.default.createElement(SearchShortcuts, null,
293
293
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "search.keys.navigate", combination: "Tab", text: translate('search.keys.navigate', 'to navigate') }),
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { JSX, PropsWithChildren, ReactNode } from 'react';
2
+ import type { ReactNode } from 'react';
3
3
  export type TooltipProps = {
4
4
  tip: string | ReactNode;
5
5
  isOpen?: boolean;
@@ -9,7 +9,6 @@ export type TooltipProps = {
9
9
  width?: string;
10
10
  dataTestId?: string;
11
11
  disabled?: boolean;
12
- arrowPosition?: 'top' | 'bottom' | 'left' | 'right' | 'center';
12
+ arrowPosition?: 'left' | 'right' | 'center';
13
13
  };
14
- export declare function TooltipComponent({ children, isOpen, tip, withArrow, placement, className, width, dataTestId, disabled, arrowPosition, }: PropsWithChildren<TooltipProps>): JSX.Element;
15
14
  export declare const Tooltip: React.NamedExoticComponent<React.PropsWithChildren<TooltipProps>>;