@redocly/theme 0.59.0-next.0 → 0.59.0-next.10

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 (262) hide show
  1. package/LICENSE +7 -1
  2. package/lib/components/Accordion/Accordion.d.ts +12 -0
  3. package/lib/components/Accordion/Accordion.js +85 -0
  4. package/lib/components/Accordion/AccordionBody.d.ts +8 -0
  5. package/lib/components/Accordion/AccordionBody.js +73 -0
  6. package/lib/components/Accordion/AccordionHeader.d.ts +10 -0
  7. package/lib/components/Accordion/AccordionHeader.js +37 -0
  8. package/lib/components/Accordion/AccordionTitle.d.ts +6 -0
  9. package/lib/components/Accordion/AccordionTitle.js +20 -0
  10. package/lib/components/Accordion/variables.d.ts +1 -0
  11. package/lib/components/Accordion/variables.js +59 -0
  12. package/lib/components/Admonition/Admonition.js +17 -7
  13. package/lib/components/Badge/Badge.js +17 -7
  14. package/lib/components/Breadcrumbs/Breadcrumb.js +17 -7
  15. package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +17 -7
  16. package/lib/components/Button/Button.js +17 -7
  17. package/lib/components/Buttons/AIAssistantButton.d.ts +2 -0
  18. package/lib/components/Buttons/AIAssistantButton.js +139 -0
  19. package/lib/components/Buttons/CopyButton.js +17 -7
  20. package/lib/components/Buttons/variables.d.ts +1 -0
  21. package/lib/components/Buttons/variables.dark.d.ts +1 -0
  22. package/lib/components/Buttons/variables.dark.js +10 -0
  23. package/lib/components/Buttons/variables.js +51 -0
  24. package/lib/components/Catalog/Catalog.d.ts +6 -0
  25. package/lib/components/Catalog/Catalog.js +9 -8
  26. package/lib/components/Catalog/CatalogEntities.js +17 -7
  27. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.js +17 -7
  28. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.js +17 -7
  29. package/lib/components/Catalog/CatalogEntity/CatalogEntityInfoBar.js +1 -0
  30. package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +17 -7
  31. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.js +1 -1
  32. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.js +17 -7
  33. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.js +1 -1
  34. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +17 -7
  35. package/lib/components/Catalog/CatalogEntityIcon.js +2 -1
  36. package/lib/components/Catalog/CatalogFilter/CatalogFilter.d.ts +6 -0
  37. package/lib/components/Catalog/CatalogFilter/CatalogFilter.js +39 -0
  38. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.d.ts +6 -0
  39. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +152 -0
  40. package/lib/components/Catalog/CatalogFilter/CatalogFilterContent.d.ts +13 -0
  41. package/lib/components/Catalog/CatalogFilter/CatalogFilterContent.js +102 -0
  42. package/lib/components/Catalog/CatalogFilter/CatalogFilterDateRange.d.ts +6 -0
  43. package/lib/components/Catalog/CatalogFilter/CatalogFilterDateRange.js +121 -0
  44. package/lib/components/Catalog/CatalogFilter/CatalogFilterSelect.d.ts +6 -0
  45. package/lib/components/Catalog/CatalogFilter/CatalogFilterSelect.js +126 -0
  46. package/lib/components/Catalog/CatalogSelector.js +0 -1
  47. package/lib/components/Catalog/CatalogSortButton.js +17 -7
  48. package/lib/components/Catalog/CatalogTableView/CatalogTableHeaderCell.js +17 -7
  49. package/lib/components/Catalog/CatalogViewModeToggle.js +17 -7
  50. package/lib/components/Catalog/variables.js +1 -2
  51. package/lib/components/CatalogClassic/CatalogClassicActions.js +17 -7
  52. package/lib/components/CatalogClassic/CatalogClassicCard.js +17 -7
  53. package/lib/components/CatalogClassic/CatalogClassicHighlight.js +17 -7
  54. package/lib/components/CatalogClassic/CatalogClassicVirtualizedGroups.js +17 -7
  55. package/lib/components/CodeBlock/CodeBlock.js +17 -7
  56. package/lib/components/CodeBlock/CodeBlockContainer.js +17 -7
  57. package/lib/components/CodeBlock/CodeBlockTabs.js +17 -7
  58. package/lib/components/Dropdown/Dropdown.d.ts +16 -2
  59. package/lib/components/Dropdown/Dropdown.js +22 -12
  60. package/lib/components/Dropdown/DropdownMenuItem.js +17 -7
  61. package/lib/components/Feedback/Comment.js +17 -7
  62. package/lib/components/Feedback/Feedback.js +17 -7
  63. package/lib/components/Feedback/Mood.js +17 -7
  64. package/lib/components/Feedback/Rating.js +17 -7
  65. package/lib/components/Feedback/Reasons.js +17 -7
  66. package/lib/components/Feedback/Scale.js +17 -7
  67. package/lib/components/Feedback/Sentiment.js +17 -7
  68. package/lib/components/Feedback/Stars.js +17 -7
  69. package/lib/components/Filter/FilterContent.js +17 -7
  70. package/lib/components/Filter/FilterInput.d.ts +1 -0
  71. package/lib/components/Filter/FilterInput.js +19 -9
  72. package/lib/components/Filter/FilterOptions.js +2 -0
  73. package/lib/components/Filter/variables.js +7 -4
  74. package/lib/components/Image/Image.js +17 -7
  75. package/lib/components/JsonViewer/JsonViewer.js +17 -7
  76. package/lib/components/JsonViewer/helpers.js +17 -7
  77. package/lib/components/LastUpdated/LastUpdated.js +17 -7
  78. package/lib/components/Link/Link.js +17 -7
  79. package/lib/components/Markdown/Markdown.js +17 -7
  80. package/lib/components/Marker/Marker.js +17 -7
  81. package/lib/components/Menu/MenuContainer.js +17 -7
  82. package/lib/components/Menu/MenuItem.js +18 -8
  83. package/lib/components/Menu/MenuMobile.js +17 -7
  84. package/lib/components/Navbar/NavbarItem.js +3 -3
  85. package/lib/components/PageActions/PageActions.js +17 -7
  86. package/lib/components/PageNavigation/NextButton.js +17 -7
  87. package/lib/components/Panel/Panel.js +17 -7
  88. package/lib/components/Panel/PanelBody.js +17 -7
  89. package/lib/components/Search/FilterFields/SearchFilterFieldSelect.js +17 -7
  90. package/lib/components/Search/FilterFields/SearchFilterFieldTags.js +1 -2
  91. package/lib/components/Search/SearchAiActionButtons.d.ts +10 -0
  92. package/lib/components/Search/SearchAiActionButtons.js +43 -0
  93. package/lib/components/Search/SearchAiConversationInput.d.ts +3 -1
  94. package/lib/components/Search/SearchAiConversationInput.js +56 -14
  95. package/lib/components/Search/SearchAiDialog.d.ts +3 -6
  96. package/lib/components/Search/SearchAiDialog.js +39 -19
  97. package/lib/components/Search/SearchAiMessage.d.ts +9 -5
  98. package/lib/components/Search/SearchAiMessage.js +146 -22
  99. package/lib/components/Search/SearchAiNegativeFeedbackForm.d.ts +8 -0
  100. package/lib/components/Search/SearchAiNegativeFeedbackForm.js +169 -0
  101. package/lib/components/Search/SearchAiResponse.js +2 -3
  102. package/lib/components/Search/SearchDialog.d.ts +2 -1
  103. package/lib/components/Search/SearchDialog.js +55 -14
  104. package/lib/components/Search/SearchFilter.js +17 -7
  105. package/lib/components/Search/SearchGroups.js +19 -9
  106. package/lib/components/Search/SearchHighlight.js +17 -7
  107. package/lib/components/Search/SearchItem.js +17 -7
  108. package/lib/components/Search/SearchRecent.js +17 -7
  109. package/lib/components/Search/SearchShortcut.js +17 -7
  110. package/lib/components/Search/SearchSuggestedPages.js +17 -7
  111. package/lib/components/Search/SearchTrigger.js +17 -7
  112. package/lib/components/Search/variables.js +36 -64
  113. package/lib/components/Segmented/Segmented.js +17 -7
  114. package/lib/components/Select/Select.js +17 -7
  115. package/lib/components/Select/SelectInput.js +18 -8
  116. package/lib/components/Sidebar/Sidebar.js +17 -7
  117. package/lib/components/SidebarActions/styled.js +17 -7
  118. package/lib/components/SkipContent/SkipContent.js +17 -7
  119. package/lib/components/Switch/Switch.js +17 -7
  120. package/lib/components/TableOfContent/TableOfContent.js +17 -7
  121. package/lib/components/Tag/Tag.d.ts +2 -1
  122. package/lib/components/Tag/Tag.js +67 -18
  123. package/lib/components/Tag/variables.dark.js +137 -38
  124. package/lib/components/Tag/variables.js +78 -61
  125. package/lib/components/Tooltip/Tooltip.js +17 -7
  126. package/lib/components/VersionPicker/VersionPicker.js +17 -7
  127. package/lib/core/constants/search.d.ts +5 -4
  128. package/lib/core/constants/search.js +4 -5
  129. package/lib/core/contexts/CodeSnippetContext.js +17 -7
  130. package/lib/core/hooks/index.d.ts +1 -0
  131. package/lib/core/hooks/index.js +1 -0
  132. package/lib/core/hooks/menu/use-nested-menu.js +1 -1
  133. package/lib/core/hooks/search/use-feedback-tooltip.d.ts +6 -0
  134. package/lib/core/hooks/search/use-feedback-tooltip.js +26 -0
  135. package/lib/core/hooks/use-product-picker.js +2 -1
  136. package/lib/core/hooks/use-tabs.d.ts +3 -2
  137. package/lib/core/hooks/use-tabs.js +115 -57
  138. package/lib/core/hooks/use-telemetry-fallback.d.ts +10 -8
  139. package/lib/core/hooks/use-telemetry-fallback.js +10 -8
  140. package/lib/core/styles/dark.js +33 -26
  141. package/lib/core/styles/global.js +68 -59
  142. package/lib/core/templates/Markdown.js +17 -7
  143. package/lib/core/types/hooks.d.ts +6 -3
  144. package/lib/core/types/l10n.d.ts +1 -1
  145. package/lib/core/types/search.d.ts +11 -4
  146. package/lib/core/types/search.js +6 -0
  147. package/lib/core/utils/download-code-walkthrough.js +17 -7
  148. package/lib/core/utils/frontmatter-translate.d.ts +6 -0
  149. package/lib/core/utils/frontmatter-translate.js +14 -0
  150. package/lib/core/utils/get-file-icon.js +17 -7
  151. package/lib/core/utils/index.d.ts +1 -0
  152. package/lib/core/utils/index.js +1 -0
  153. package/lib/icons/AiStarsGradientIcon/AiStarsGradientIcon.js +44 -4
  154. package/lib/icons/AiStarsIcon/AiStarsIcon.js +11 -2
  155. package/lib/icons/CubeIcon/CubeIcon.d.ts +9 -0
  156. package/lib/icons/CubeIcon/CubeIcon.js +17 -0
  157. package/lib/icons/GenericIcon/GenericIcon.js +17 -7
  158. package/lib/icons/HashtagIcon/HashtagIcon.d.ts +9 -0
  159. package/lib/icons/HashtagIcon/HashtagIcon.js +22 -0
  160. package/lib/icons/RedoclyIcon/RedoclyIcon.d.ts +9 -0
  161. package/lib/icons/RedoclyIcon/RedoclyIcon.js +24 -0
  162. package/lib/icons/Spinner/Spinner.js +17 -7
  163. package/lib/icons/ThumbDownFilledIcon/ThumbDownFilledIcon.d.ts +9 -0
  164. package/lib/icons/ThumbDownFilledIcon/ThumbDownFilledIcon.js +34 -0
  165. package/lib/icons/ThumbUpFilledIcon/ThumbUpFilledIcon.d.ts +9 -0
  166. package/lib/icons/ThumbUpFilledIcon/ThumbUpFilledIcon.js +34 -0
  167. package/lib/index.d.ts +3 -0
  168. package/lib/index.js +20 -7
  169. package/lib/layouts/OIDCForbidden.js +17 -7
  170. package/lib/layouts/RootLayout.js +6 -1
  171. package/lib/layouts/ThreePanelLayout.js +17 -7
  172. package/lib/markdoc/components/Cards/Card.js +1 -28
  173. package/lib/markdoc/components/Cards/Cards.js +17 -7
  174. package/lib/markdoc/components/CodeGroup/CodeGroup.js +17 -7
  175. package/lib/markdoc/components/CodeWalkthrough/CodeContainer.js +17 -7
  176. package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +17 -7
  177. package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.js +17 -7
  178. package/lib/markdoc/components/CodeWalkthrough/CodePanelPreview.js +17 -7
  179. package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.js +17 -7
  180. package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +17 -7
  181. package/lib/markdoc/components/CodeWalkthrough/CodeToggle.js +17 -7
  182. package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.js +17 -7
  183. package/lib/markdoc/components/CodeWalkthrough/Input.js +17 -7
  184. package/lib/markdoc/components/Heading/Heading.js +17 -7
  185. package/lib/markdoc/components/HtmlBlock/HtmlBlock.js +17 -7
  186. package/lib/markdoc/components/InlineSvg/InlineSvg.js +17 -7
  187. package/lib/markdoc/components/MarkdocExample/MarkdocExample.js +17 -7
  188. package/lib/markdoc/components/Tabs/TabList.d.ts +3 -1
  189. package/lib/markdoc/components/Tabs/TabList.js +214 -54
  190. package/lib/markdoc/components/Tabs/Tabs.d.ts +2 -1
  191. package/lib/markdoc/components/Tabs/Tabs.js +74 -19
  192. package/lib/markdoc/default.d.ts +104 -1
  193. package/lib/markdoc/default.js +17 -7
  194. package/lib/markdoc/tags/card.js +0 -1
  195. package/package.json +8 -8
  196. package/src/components/Accordion/Accordion.tsx +100 -0
  197. package/src/components/Accordion/AccordionBody.tsx +65 -0
  198. package/src/components/Accordion/AccordionHeader.tsx +68 -0
  199. package/src/components/Accordion/AccordionTitle.tsx +26 -0
  200. package/src/components/Accordion/variables.ts +56 -0
  201. package/src/components/Buttons/AIAssistantButton.tsx +145 -0
  202. package/src/components/Buttons/variables.dark.ts +7 -0
  203. package/src/components/Buttons/variables.ts +48 -0
  204. package/src/components/Catalog/Catalog.tsx +18 -6
  205. package/src/components/Catalog/CatalogEntity/CatalogEntityInfoBar.tsx +1 -0
  206. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.tsx +1 -1
  207. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.tsx +1 -1
  208. package/src/components/Catalog/CatalogEntityIcon.tsx +2 -1
  209. package/src/components/Catalog/CatalogFilter/CatalogFilter.tsx +61 -0
  210. package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +169 -0
  211. package/src/components/Catalog/CatalogFilter/CatalogFilterContent.tsx +121 -0
  212. package/src/components/Catalog/CatalogFilter/CatalogFilterDateRange.tsx +147 -0
  213. package/src/components/Catalog/CatalogFilter/CatalogFilterSelect.tsx +136 -0
  214. package/src/components/Catalog/CatalogSelector.tsx +0 -1
  215. package/src/components/Catalog/variables.ts +1 -2
  216. package/src/components/Dropdown/Dropdown.tsx +84 -79
  217. package/src/components/Filter/FilterInput.tsx +3 -2
  218. package/src/components/Filter/FilterOptions.tsx +2 -0
  219. package/src/components/Filter/variables.ts +7 -4
  220. package/src/components/Menu/MenuItem.tsx +1 -0
  221. package/src/components/Navbar/NavbarItem.tsx +6 -5
  222. package/src/components/Search/FilterFields/SearchFilterFieldTags.tsx +3 -3
  223. package/src/components/Search/SearchAiActionButtons.tsx +76 -0
  224. package/src/components/Search/SearchAiConversationInput.tsx +61 -18
  225. package/src/components/Search/SearchAiDialog.tsx +54 -25
  226. package/src/components/Search/SearchAiMessage.tsx +172 -43
  227. package/src/components/Search/SearchAiNegativeFeedbackForm.tsx +210 -0
  228. package/src/components/Search/SearchAiResponse.tsx +2 -2
  229. package/src/components/Search/SearchDialog.tsx +56 -15
  230. package/src/components/Search/SearchGroups.tsx +2 -0
  231. package/src/components/Search/variables.ts +36 -64
  232. package/src/components/Select/SelectInput.tsx +1 -0
  233. package/src/components/Tag/Tag.tsx +36 -20
  234. package/src/components/Tag/variables.dark.ts +137 -38
  235. package/src/components/Tag/variables.ts +78 -61
  236. package/src/core/constants/search.ts +8 -4
  237. package/src/core/hooks/index.ts +1 -0
  238. package/src/core/hooks/menu/use-nested-menu.ts +2 -2
  239. package/src/core/hooks/search/use-feedback-tooltip.ts +32 -0
  240. package/src/core/hooks/use-product-picker.ts +2 -1
  241. package/src/core/hooks/use-tabs.ts +168 -86
  242. package/src/core/hooks/use-telemetry-fallback.ts +10 -8
  243. package/src/core/styles/dark.ts +15 -8
  244. package/src/core/styles/global.ts +11 -2
  245. package/src/core/types/hooks.ts +6 -1
  246. package/src/core/types/l10n.ts +6 -0
  247. package/src/core/types/search.ts +13 -4
  248. package/src/core/utils/frontmatter-translate.ts +9 -0
  249. package/src/core/utils/index.ts +1 -0
  250. package/src/icons/AiStarsGradientIcon/AiStarsGradientIcon.tsx +13 -4
  251. package/src/icons/AiStarsIcon/AiStarsIcon.tsx +11 -2
  252. package/src/icons/CubeIcon/CubeIcon.tsx +27 -0
  253. package/src/icons/HashtagIcon/HashtagIcon.tsx +23 -0
  254. package/src/icons/RedoclyIcon/RedoclyIcon.tsx +26 -0
  255. package/src/icons/ThumbDownFilledIcon/ThumbDownFilledIcon.tsx +38 -0
  256. package/src/icons/ThumbUpFilledIcon/ThumbUpFilledIcon.tsx +35 -0
  257. package/src/index.ts +3 -0
  258. package/src/layouts/RootLayout.tsx +6 -0
  259. package/src/markdoc/components/Cards/Card.tsx +1 -28
  260. package/src/markdoc/components/Tabs/TabList.tsx +312 -105
  261. package/src/markdoc/components/Tabs/Tabs.tsx +136 -11
  262. package/src/markdoc/tags/card.ts +0 -1
@@ -0,0 +1,210 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { FeedbackType } from '@redocly/theme/core/types';
6
+
7
+ import { Button } from '@redocly/theme/components/Button/Button';
8
+ import { CloseIcon } from '@redocly/theme/icons/CloseIcon/CloseIcon';
9
+ import { ArrowLeftIcon } from '@redocly/theme/icons/ArrowLeftIcon/ArrowLeftIcon';
10
+ import { SendIcon } from '@redocly/theme/icons/SendIcon/SendIcon';
11
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
12
+
13
+ export type SearchAiNegativeFeedbackFormProps = {
14
+ messageId: string;
15
+ onClose: (messageId: string, feedback: FeedbackType | undefined) => void;
16
+ onSubmit: (reason: string) => void;
17
+ };
18
+
19
+ const NEGATIVE_FEEDBACK_DEFAULT_REASONS = [
20
+ "Didn't answer my question",
21
+ "Couldn't find what I was looking for",
22
+ 'Wrong topic',
23
+ 'Partially helpful, but missing details',
24
+ ];
25
+
26
+ export function SearchAiNegativeFeedbackForm({
27
+ messageId,
28
+ onClose,
29
+ onSubmit,
30
+ }: SearchAiNegativeFeedbackFormProps): JSX.Element {
31
+ const { useTranslate } = useThemeHooks();
32
+ const { translate } = useTranslate();
33
+ const [showMoreInput, setShowMoreInput] = useState(false);
34
+ const [detailedFeedback, setDetailedFeedback] = useState('');
35
+ const textAreaRef = React.useRef<HTMLTextAreaElement>(null);
36
+
37
+ const adjustTextAreaHeight = () => {
38
+ const textArea = textAreaRef.current;
39
+ if (textArea) {
40
+ textArea.style.height = 'auto';
41
+ textArea.style.height = `${textArea.scrollHeight}px`;
42
+ }
43
+ };
44
+
45
+ const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
46
+ setDetailedFeedback(e.target.value);
47
+ adjustTextAreaHeight();
48
+ };
49
+
50
+ useEffect(() => {
51
+ if (showMoreInput) {
52
+ adjustTextAreaHeight();
53
+ }
54
+ }, [showMoreInput]);
55
+
56
+ return (
57
+ <FeedbackFormWrapper data-component-name="Search/SearchAiNegativeFeedbackForm">
58
+ <FeedbackHeader>
59
+ {showMoreInput ? (
60
+ <BackButton
61
+ variant="text"
62
+ size="small"
63
+ icon={<ArrowLeftIcon />}
64
+ onClick={() => setShowMoreInput(false)}
65
+ aria-label="Back to feedback reasons"
66
+ />
67
+ ) : null}
68
+ <FeedbackTitle data-translation-key="search.ai.feedback.title">
69
+ {translate('search.ai.feedback.title', "What didn't you like about this response?")}
70
+ </FeedbackTitle>
71
+ <CloseButton
72
+ variant="text"
73
+ size="small"
74
+ icon={<CloseIcon />}
75
+ onClick={() => onClose(messageId, undefined)}
76
+ aria-label="Close feedback form"
77
+ />
78
+ </FeedbackHeader>
79
+
80
+ {!showMoreInput ? (
81
+ <FeedbackReasonsWrapper>
82
+ {NEGATIVE_FEEDBACK_DEFAULT_REASONS.map((reason) => (
83
+ <Button key={reason} variant="outlined" size="small" onClick={() => onSubmit(reason)}>
84
+ {reason}
85
+ </Button>
86
+ ))}
87
+ <Button variant="outlined" size="small" onClick={() => setShowMoreInput(true)}>
88
+ More...
89
+ </Button>
90
+ </FeedbackReasonsWrapper>
91
+ ) : (
92
+ <FeedbackInputWrapper>
93
+ <FeedbackTextArea
94
+ ref={textAreaRef}
95
+ placeholder={translate('search.ai.feedback.detailsPlaceholder', 'Add specific details')}
96
+ value={detailedFeedback}
97
+ onChange={handleTextChange}
98
+ rows={1}
99
+ autoFocus
100
+ />
101
+ <SendButton
102
+ size="small"
103
+ icon={
104
+ <SendIcon
105
+ color={
106
+ !detailedFeedback.trim()
107
+ ? '--button-content-color-disabled'
108
+ : 'var(--search-ai-conversation-input-send-button-icon-color)'
109
+ }
110
+ />
111
+ }
112
+ onClick={() => onSubmit(detailedFeedback)}
113
+ disabled={!detailedFeedback.trim()}
114
+ aria-label="Send feedback"
115
+ />
116
+ </FeedbackInputWrapper>
117
+ )}
118
+ </FeedbackFormWrapper>
119
+ );
120
+ }
121
+
122
+ const FeedbackFormWrapper = styled.div`
123
+ display: flex;
124
+ flex-direction: column;
125
+ gap: var(--spacing-sm);
126
+ padding: var(--spacing-xs);
127
+ background: var(--search-ai-feedback-form-bg-color);
128
+ border: 1px solid var(--search-ai-feedback-form-border-color);
129
+ border-radius: var(--border-radius-lg);
130
+ `;
131
+
132
+ const FeedbackHeader = styled.div`
133
+ display: flex;
134
+ justify-content: space-between;
135
+ align-items: center;
136
+ gap: var(--spacing-sm);
137
+ `;
138
+
139
+ const FeedbackTitle = styled.div`
140
+ font-size: var(--font-size-base);
141
+ color: var(--text-color);
142
+ flex: 1;
143
+ `;
144
+
145
+ const BackButton = styled(Button)`
146
+ flex-shrink: 0;
147
+ `;
148
+
149
+ const CloseButton = styled(Button)`
150
+ flex-shrink: 0;
151
+ `;
152
+
153
+ const FeedbackReasonsWrapper = styled.div`
154
+ display: flex;
155
+ flex-wrap: wrap;
156
+ gap: var(--spacing-xs);
157
+ `;
158
+
159
+ const FeedbackInputWrapper = styled.div`
160
+ position: relative;
161
+ width: 100%;
162
+ `;
163
+
164
+ const FeedbackTextArea = styled.textarea`
165
+ width: 100%;
166
+ min-height: 5rem;
167
+ max-height: 12.5rem;
168
+ padding: var(--spacing-xs);
169
+ padding-right: 3rem;
170
+ border: 1px solid var(--border-color-primary);
171
+ border-radius: var(--border-radius-md);
172
+ font-family: inherit;
173
+ font-size: var(--font-size-base);
174
+ line-height: var(--line-height-base);
175
+ background: var(--background-color);
176
+ color: var(--text-color);
177
+ resize: none;
178
+ overflow-y: auto;
179
+
180
+ &:focus {
181
+ outline: 1px solid var(--button-border-color-focused);
182
+ border-color: var(--button-border-color-focused);
183
+ }
184
+
185
+ &::placeholder {
186
+ color: var(--text-color-helper);
187
+ }
188
+ `;
189
+
190
+ const SendButton = styled(Button)`
191
+ position: absolute;
192
+ right: var(--search-ai-conversation-input-send-button-right);
193
+ bottom: var(--spacing-sm);
194
+ transition: background-color 0.2s ease;
195
+ background-color: var(--search-ai-conversation-input-send-button-bg-color);
196
+ display: flex;
197
+ align-items: center;
198
+ justify-content: center;
199
+ border-radius: var(--search-ai-conversation-input-send-button-border-radius);
200
+ padding: var(--search-ai-conversation-input-send-button-padding);
201
+
202
+ &:hover {
203
+ background-color: var(--search-ai-conversation-input-send-button-bg-color-hover);
204
+ }
205
+
206
+ &:disabled {
207
+ background-color: var(--search-ai-conversation-input-send-button-bg-color-disabled);
208
+ border: var(--search-ai-conversation-input-send-button-border-disabled);
209
+ }
210
+ `;
@@ -34,7 +34,7 @@ export function SearchAiResponse(props: SearchAiResponseProps): JSX.Element {
34
34
  const { useMarkdownText } = useThemeHooks();
35
35
  const { question, response, isGeneratingResponse, resources, error, onSuggestionClick } = props;
36
36
 
37
- const { search } = useThemeConfig();
37
+ const { aiAssistant } = useThemeConfig();
38
38
  const { useTranslate } = useThemeHooks();
39
39
 
40
40
  const { translate } = useTranslate();
@@ -42,7 +42,7 @@ export function SearchAiResponse(props: SearchAiResponseProps): JSX.Element {
42
42
 
43
43
  let responseContainer = null;
44
44
 
45
- const suggestions = search?.ai?.suggestions;
45
+ const suggestions = aiAssistant?.suggestions;
46
46
 
47
47
  const hasPendingOrReceivedResponse = response || isGeneratingResponse || error;
48
48
  if (hasPendingOrReceivedResponse) {
@@ -34,16 +34,22 @@ import { AiStarsGradientIcon } from '@redocly/theme/icons/AiStarsGradientIcon/Ai
34
34
  export type SearchDialogProps = {
35
35
  onClose: () => void;
36
36
  className?: string;
37
+ initialMode?: 'search' | 'ai-dialog';
37
38
  };
38
39
 
39
- export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Element {
40
+ export function SearchDialog({
41
+ onClose,
42
+ className,
43
+ initialMode = 'search',
44
+ }: SearchDialogProps): JSX.Element {
40
45
  const { useTranslate, useCurrentProduct, useSearch, useProducts, useAiSearch, useTelemetry } =
41
46
  useThemeHooks();
42
47
  const telemetry = useTelemetry();
43
48
  const products = useProducts();
44
49
  const currentProduct = useCurrentProduct();
45
50
  const [product, setProduct] = useState(currentProduct);
46
- const [mode, setMode] = useState<'search' | 'ai-dialog'>('search');
51
+ const searchSessionId = `search-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
52
+ const [mode, setMode] = useState<'search' | 'ai-dialog'>(initialMode);
47
53
  const autoSearchDisabled = mode !== 'search';
48
54
  const {
49
55
  query,
@@ -57,7 +63,7 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
57
63
  advancedSearch,
58
64
  askAi,
59
65
  groupField,
60
- } = useSearch(product?.name, autoSearchDisabled);
66
+ } = useSearch(product?.name, autoSearchDisabled, searchSessionId);
61
67
  const {
62
68
  isFilterOpen,
63
69
  onFilterToggle,
@@ -67,10 +73,24 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
67
73
  onQuickFilterReset,
68
74
  } = useSearchFilter(filter, setFilter);
69
75
  const { addSearchHistoryItem } = useRecentSearches();
70
- const aiSearch = useAiSearch({ filter });
76
+ const aiSearch = useAiSearch({ filter }, searchSessionId);
71
77
 
72
78
  const searchInputRef = useRef<HTMLInputElement>(null);
73
79
  const modalRef = useRef<HTMLDivElement>(null);
80
+
81
+ const [isMobile, setIsMobile] = useState(false);
82
+
83
+ useEffect(() => {
84
+ const mediaQuery = window.matchMedia(`(max-width: ${breakpoints.small})`);
85
+ setIsMobile(mediaQuery.matches);
86
+
87
+ const handleChange = (e: MediaQueryListEvent) => {
88
+ setIsMobile(e.matches);
89
+ };
90
+ mediaQuery.addEventListener('change', handleChange);
91
+ return () => mediaQuery.removeEventListener('change', handleChange);
92
+ }, []);
93
+
74
94
  const aiQueryRef = useRef<HTMLDivElement>(null);
75
95
  const firstSearchResultRef = useRef<HTMLAnchorElement>(null);
76
96
  const searchKeysWithResults = items ? Object.keys(items).filter((key) => items[key]?.length) : [];
@@ -145,13 +165,14 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
145
165
  totalResults: results.length.toString(),
146
166
  index: index.toString(),
147
167
  searchEngine: mode,
168
+ searchSessionId,
148
169
  });
149
170
  onClose();
150
171
  }}
151
172
  />
152
173
  );
153
174
  },
154
- [onClose, product, products, addSearchHistoryItem, query, telemetry, mode],
175
+ [onClose, product, products, addSearchHistoryItem, query, telemetry, mode, searchSessionId],
155
176
  );
156
177
 
157
178
  const showLoadMore = useCallback(
@@ -221,6 +242,9 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
221
242
  if (query.trim()) {
222
243
  aiSearch.askQuestion(query);
223
244
  }
245
+ telemetry.sendSearchAiOpenedMessage({
246
+ method: 'ai_search_button',
247
+ });
224
248
  }}
225
249
  >
226
250
  {translate('search.ai.button', 'Search with AI')}
@@ -244,17 +268,22 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
244
268
  tabIndex={0}
245
269
  icon={<ChevronLeftIcon />}
246
270
  >
247
- {translate('search.ai.backToSearch', 'Back to search')}
248
- </Button>
249
- <Button
250
- variant="secondary"
251
- disabled={!aiSearch.conversation.length}
252
- onClick={() => aiSearch.clearConversation()}
253
- tabIndex={0}
254
- icon={<EditIcon />}
255
- >
256
- {translate('search.ai.newConversation', 'New conversation')}
271
+ {isMobile
272
+ ? translate('search.ai.back', 'Back')
273
+ : translate('search.ai.backToSearch', 'Back to search')}
257
274
  </Button>
275
+ <AiDialogHeaderActionsWrapper>
276
+ <Button
277
+ variant="secondary"
278
+ disabled={!aiSearch.conversation.length}
279
+ onClick={() => aiSearch.clearConversation()}
280
+ tabIndex={0}
281
+ icon={<EditIcon />}
282
+ >
283
+ {translate('search.ai.newConversation', 'New conversation')}
284
+ </Button>
285
+ {isMobile && <Button variant="text" icon={<CloseIcon />} onClick={handleClose} />}
286
+ </AiDialogHeaderActionsWrapper>
258
287
  </AiDialogHeaderWrapper>
259
288
  )}
260
289
  </SearchDialogHeader>
@@ -291,6 +320,9 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
291
320
  if (query.trim()) {
292
321
  aiSearch.askQuestion(query);
293
322
  }
323
+ telemetry.sendSearchAiOpenedMessage({
324
+ method: 'ai_search_input',
325
+ });
294
326
  }}
295
327
  onKeyDown={(e) => {
296
328
  if (e.key === 'Enter') {
@@ -298,6 +330,9 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
298
330
  if (query.trim()) {
299
331
  aiSearch.askQuestion(query);
300
332
  }
333
+ telemetry.sendSearchAiOpenedMessage({
334
+ method: 'ai_search_input',
335
+ });
301
336
  }
302
337
  }}
303
338
  ref={aiQueryRef}
@@ -384,6 +419,7 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
384
419
  telemetry.sendSearchRecentClickedMessage({
385
420
  query,
386
421
  index: index.toString(),
422
+ searchSessionId,
387
423
  });
388
424
  setQuery(query);
389
425
  focusSearchInput();
@@ -519,6 +555,10 @@ const AiDialogHeaderWrapper = styled.div`
519
555
  align-items: center;
520
556
  width: 100%;
521
557
  `;
558
+ const AiDialogHeaderActionsWrapper = styled.div`
559
+ display: flex;
560
+ gap: var(--spacing-xxs);
561
+ `;
522
562
 
523
563
  const SearchDialogBody = styled.div`
524
564
  display: flex;
@@ -635,6 +675,7 @@ const AiDisclaimer = styled.div`
635
675
  line-height: var(--search-ai-disclaimer-line-height);
636
676
  color: var(--search-ai-disclaimer-text-color);
637
677
  margin: 0 auto;
678
+ text-align: center;
638
679
  `;
639
680
 
640
681
  const SearchWithAI = styled.div`
@@ -45,6 +45,7 @@ export function SearchGroups({
45
45
  borderless
46
46
  active={!searchFilter.some((item) => item.isQuickFilter)}
47
47
  onClick={() => searchFilter.some((item) => item.isQuickFilter) && onQuickFilterReset()}
48
+ selectable
48
49
  >
49
50
  All
50
51
  </GroupTag>
@@ -61,6 +62,7 @@ export function SearchGroups({
61
62
  onClick={() => handleGroupTagClick(value, facet.field, active, currentValues)}
62
63
  active={active}
63
64
  borderless
65
+ selectable
64
66
  >
65
67
  {value} {isCounterVisible && <span>{count}</span>}
66
68
  </GroupTag>
@@ -144,68 +144,76 @@ export const search = css`
144
144
  /**
145
145
  * @tokens AI Search
146
146
  */
147
-
147
+
148
148
  --search-ai-gradient: linear-gradient(to right, #715efe, #ff5cdc);
149
149
 
150
- --search-ai-spinner-icon-color: var(--icon-color-interactive);
151
- --search-ai-checkmark-icon-color: var(--icon-color-interactive);
152
150
  --search-ai-response-padding: var(--spacing-lg);
153
151
  --search-ai-response-gap: var(--spacing-sm);
154
-
155
152
  --search-ai-response-header-gap: var(--spacing-md);
153
+ --search-ai-response-body-gap: var(--spacing-xl);
154
+ --search-ai-response-body-padding: 0 40px;
156
155
 
157
156
  --search-ai-question-font-size: var(--font-size-xl);
158
157
  --search-ai-question-font-weight: var(--font-weight-semibold);
159
158
  --search-ai-question-line-height: var(--line-height-xl);
160
159
  --search-ai-question-text-color: var(--text-color-primary);
161
160
 
162
- --search-ai-response-body-gap: var(--spacing-xl);
163
- --search-ai-response-body-padding: 0 40px;
164
-
165
161
  --search-ai-text-color: var(--text-color-secondary);
166
162
  --search-ai-text-font-size: var(--font-size-lg);
167
163
  --search-ai-text-line-height: var(--line-height-lg);
164
+ --search-ai-thinking-text-margin: var(--md-pre-margin) 0;
168
165
 
169
166
  --search-ai-user-bg-color: var(--color-blue-6);
170
167
  --search-ai-user-text-color: var(--color-static-white);
171
168
  --search-ai-assistant-bg-color: var(--layer-color);
172
169
  --search-ai-assistant-text-color: var(--text-color-primary);
173
170
  --search-ai-assistant-border: 1px solid var(--border-color-primary);
171
+ --search-ai-assistant-message-max-width: 80%;
174
172
 
175
- --search-ai-resources-gap: var(--spacing-base);
173
+ --search-ai-icon-size: 32px;
174
+ --search-ai-icon-bg-color: var(--search-ai-gradient);
175
+ --search-ai-icon-color: var(--color-static-white);
176
+ --search-ai-icon-wrapper-padding: var(--spacing-xs);
177
+
178
+ --search-ai-resources-gap: var(--spacing-xxs);
176
179
  --search-ai-resources-title-font-weight: var(--font-weight-medium);
177
180
  --search-ai-resources-title-font-size: var(--font-size-lg);
178
181
  --search-ai-resources-title-line-height: var(--line-height-lg);
179
182
 
180
- --search-ai-resource-tags-gap: var(--spacing-base);
183
+ --search-ai-resource-tags-gap: var(--spacing-xxs);
181
184
  --search-ai-resource-tag-text-color: var(--text-color-secondary);
182
185
  --search-ai-resource-tag-icon-color: var(--text-color-secondary);
183
186
  --search-ai-resource-tag-icon-size: 16px;
184
187
 
185
- --search-ai-icon-size: 32px;
186
- --search-ai-icon-bg-color: var(--search-ai-gradient);
187
- --search-ai-icon-color: var(--color-static-white);
188
-
189
- --search-ai-button-icon-color: none;
188
+ --search-ai-suggestions-gap: var(--spacing-sm);
189
+ --search-ai-suggestions-margin-left: var(--spacing-xs);
190
+ --search-ai-suggestion-item-gap: var(--spacing-xxs);
191
+ --search-ai-suggestions-title-text-color: var(--text-color-description);
192
+ --search-ai-suggestions-title-font-size: var(--font-size-base);
193
+ --search-ai-suggestions-title-line-height: var(--line-height-base);
194
+ --search-ai-suggestions-title-font-weight: var(--font-weight-light);
195
+ --search-ai-suggestions-text-color: var(--text-color-description);
190
196
 
191
197
  --search-ai-thinking-dots-gap: 4px;
192
198
  --search-ai-thinking-dots-padding: 4px 0;
193
199
  --search-ai-thinking-dot-size: 6px;
194
200
  --search-ai-thinking-dot-color: var(--search-ai-gradient);
195
201
 
202
+ --search-ai-spinner-icon-color: var(--icon-color-interactive);
203
+ --search-ai-checkmark-icon-color: var(--icon-color-interactive);
204
+
205
+ --search-ai-feedback-gap: var(--spacing-xxs);
206
+
207
+ --search-ai-feedback-form-bg-color: var(--background-color-secondary);
208
+ --search-ai-feedback-form-border-color: var(--border-color-primary);
209
+
196
210
  --search-ai-disclaimer-font-size: var(--font-size-sm);
197
211
  --search-ai-disclaimer-line-height: var(--line-height-sm);
198
212
  --search-ai-disclaimer-text-color: var(--text-color-secondary);
199
213
 
200
-
201
214
  --search-ai-welcome-margin: var(--spacing-md);
202
- --search-ai-icon-wrapper-padding: var(--spacing-xs);
203
215
 
204
- --search-ai-suggestions-title-text-color: var(--text-color-description);
205
- --search-ai-suggestions-title-font-size: var(--font-size-base);
206
- --search-ai-suggestions-title-line-height: var(--line-height-base);
207
- --search-ai-suggestions-title-font-weight: var(--font-weight-light);
208
- --search-ai-suggestions-text-color: var(--text-color-description);
216
+ --search-ai-button-icon-color: none;
209
217
 
210
218
  --search-ai-conversation-input-send-button-bg-color: var(--button-bg-color-primary);
211
219
  --search-ai-conversation-input-send-button-bg-color-hover: var(--button-bg-color-primary-hover);
@@ -232,6 +240,7 @@ export const search = css`
232
240
  * @tokens AI Search Conversation Input
233
241
  */
234
242
  --search-ai-conversation-input-bg-color: var(--bg-color);
243
+ --search-ai-conversation-input-bg-color-disabled: var(--color-warm-grey-1);
235
244
  --search-ai-conversation-input-padding: var(--spacing-sm) var(--spacing-md);
236
245
  --search-ai-conversation-input-border: 1px solid var(--border-color-secondary);
237
246
  --search-ai-conversation-input-border-radius: var(--border-radius-lg);
@@ -241,51 +250,14 @@ export const search = css`
241
250
  --search-ai-conversation-input-border-color-disabled: var(--border-color-secondary);
242
251
 
243
252
  --search-ai-conversation-input-send-button-right: 12px;
244
- --search-ai-conversation-input-send-button-bg-color: var(--button-bg-color-primary);
245
- --search-ai-conversation-input-send-button-bg-color-hover: var(--button-bg-color-primary-hover);
246
- --search-ai-conversation-input-send-button-bg-color-disabled: var(--button-bg-color-disabled);
253
+ --search-ai-conversation-input-send-button-padding: 5px;
254
+ --search-ai-conversation-input-send-button-border-radius: var(--border-radius);
247
255
  --search-ai-conversation-input-send-button-border-disabled: 1px solid var(--button-border-color-disabled);
248
256
 
249
- /**
250
- * @tokens AI Search Response
251
- */
252
- --search-ai-response-padding: var(--spacing-lg);
253
- --search-ai-response-gap: var(--spacing-sm);
254
- --search-ai-response-header-gap: var(--spacing-md);
255
- --search-ai-response-body-gap: var(--spacing-xl);
256
- --search-ai-response-body-padding: 0 40px;
257
-
258
- --search-ai-text-color: var(--text-color-secondary);
259
- --search-ai-text-font-size: var(--font-size-lg);
260
- --search-ai-text-line-height: var(--line-height-lg);
261
-
262
- --search-ai-thinking-text-margin: var(--md-pre-margin) 0;
263
-
264
- --search-ai-question-font-size: var(--font-size-xl);
265
- --search-ai-question-font-weight: var(--font-weight-semibold);
266
- --search-ai-question-line-height: var(--line-height-xl);
267
- --search-ai-question-text-color: var(--text-color-primary);
268
-
269
- --search-ai-resources-gap: var(--spacing-base);
270
- --search-ai-resources-title-font-weight: var(--font-weight-medium);
271
- --search-ai-resources-title-font-size: var(--font-size-lg);
272
- --search-ai-resources-title-line-height: var(--line-height-lg);
273
-
274
- --search-ai-resource-tags-gap: var(--spacing-base);
275
- --search-ai-resource-tag-text-color: var(--text-color-secondary);
276
- --search-ai-resource-tag-icon-color: var(--text-color-secondary);
277
-
278
- --search-ai-suggestions-gap: var(--spacing-sm);
279
- --search-ai-suggestions-margin-left: var(--spacing-xs);
280
- --search-ai-suggestion-item-gap: var(--spacing-xs);
281
-
282
- --search-ai-suggestions-title-text-color: var(--text-color-description);
283
- --search-ai-suggestions-title-font-size: var(--font-size-base);
284
- --search-ai-suggestions-title-line-height: var(--line-height-base);
285
- --search-ai-suggestions-title-font-weight: var(--font-weight-light);
286
-
287
- --search-ai-spinner-icon-color: var(--icon-color-interactive);
288
- --search-ai-checkmark-icon-color: var(--icon-color-interactive);
257
+ --search-ai-conversation-input-min-height: 48px;
258
+ --search-ai-conversation-input-max-height: 120px;
259
+ --search-ai-conversation-input-padding-right: calc(var(--search-ai-conversation-input-send-button-right) + 30px);
260
+ --search-ai-conversation-input-send-button-bottom: calc(var(--search-ai-conversation-input-min-height) / 2);
289
261
 
290
262
  // @tokens End
291
263
  `;
@@ -83,6 +83,7 @@ export function SelectInput<T>(props: SelectInputProps<T>): React.ReactNode {
83
83
  const selectTags = selectedOptions.map((option, index) => (
84
84
  <SelectInputTag
85
85
  closable
86
+ tabIndex={0}
86
87
  key={index}
87
88
  onClose={() => {
88
89
  clearHandler?.(option);