@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,145 @@
1
+ import * as React from 'react';
2
+ import { useState } from 'react';
3
+ import styled from 'styled-components';
4
+
5
+ import { Button } from '@redocly/theme/components/Button/Button';
6
+ import { SearchDialog } from '@redocly/theme/components/Search/SearchDialog';
7
+ import { useThemeConfig, useThemeHooks } from '@redocly/theme/core/hooks';
8
+ import { ChatIcon } from '@redocly/theme/icons/ChatIcon/ChatIcon';
9
+ import { AiStarsGradientIcon } from '@redocly/theme/icons/AiStarsGradientIcon/AiStarsGradientIcon';
10
+ import { RedoclyIcon } from '@redocly/theme/icons/RedoclyIcon/RedoclyIcon';
11
+
12
+ type AIAssistantButtonIconType = 'chat' | 'sparkles' | 'redocly';
13
+ type AIAssistantButtonType = 'button' | 'icon';
14
+
15
+ interface AIAssistantButtonConfig {
16
+ hide?: boolean;
17
+ inputType?: AIAssistantButtonType;
18
+ inputIcon?: AIAssistantButtonIconType;
19
+ }
20
+
21
+ const defaultConfig: Required<AIAssistantButtonConfig> = {
22
+ hide: false,
23
+ inputType: 'button',
24
+ inputIcon: 'sparkles',
25
+ };
26
+
27
+ const getIcon = (
28
+ iconType: AIAssistantButtonIconType,
29
+ inputType: AIAssistantButtonType = 'button',
30
+ ) => {
31
+ const iconSize =
32
+ inputType === 'icon'
33
+ ? 'var(--ai-assistant-button-icon-icon-size)'
34
+ : 'var(--ai-assistant-button-text-icon-size)';
35
+
36
+ const redoclyIcon = (
37
+ <RedoclyIcon size={iconSize} color="var(--ai-assistant-button-redocly-icon-color)" />
38
+ );
39
+ const sparklesIcon = (
40
+ <AiStarsGradientIcon size={iconSize} color="var(--search-ai-button-icon-color)" />
41
+ );
42
+ const chatIcon = <ChatIcon size={iconSize} />;
43
+
44
+ switch (iconType) {
45
+ case 'chat':
46
+ return chatIcon;
47
+ case 'sparkles':
48
+ return sparklesIcon;
49
+ case 'redocly':
50
+ return redoclyIcon;
51
+ default:
52
+ return redoclyIcon;
53
+ }
54
+ };
55
+
56
+ export function AIAssistantButton() {
57
+ const [isOpen, setIsOpen] = useState(false);
58
+ const themeConfig = useThemeConfig();
59
+ const { useTranslate, useTelemetry } = useThemeHooks();
60
+ const { translate } = useTranslate();
61
+ const telemetry = useTelemetry();
62
+
63
+ const buttonConfig = {
64
+ ...defaultConfig,
65
+ ...(themeConfig.aiAssistant?.trigger ?? {}),
66
+ };
67
+
68
+ const { hide, inputIcon, inputType } = buttonConfig;
69
+
70
+ if (hide) {
71
+ return null;
72
+ }
73
+
74
+ const icon = getIcon(inputIcon, inputType);
75
+ const text = translate('aiAssistant.trigger', 'Ask AI');
76
+
77
+ const handleOpen = () => {
78
+ setIsOpen(true);
79
+ telemetry.sendSearchAiOpenedMessage({
80
+ method: 'ai_trigger_button',
81
+ });
82
+ };
83
+
84
+ const handleClose = () => {
85
+ setIsOpen(false);
86
+ };
87
+
88
+ return (
89
+ <>
90
+ <StyledAIAssistantButton
91
+ variant="outlined"
92
+ size="medium"
93
+ $inputType={inputType}
94
+ onClick={handleOpen}
95
+ aria-label={`AI Assistant button - ${inputIcon}`}
96
+ data-component-name="Buttons/AIAssistantButton"
97
+ >
98
+ {icon}
99
+ {inputType === 'button' && text}
100
+ </StyledAIAssistantButton>
101
+
102
+ {isOpen && <SearchDialog onClose={handleClose} initialMode="ai-dialog" />}
103
+ </>
104
+ );
105
+ }
106
+
107
+ const StyledAIAssistantButton = styled(Button)<{ $inputType?: AIAssistantButtonType }>`
108
+ position: fixed;
109
+ bottom: var(--ai-assistant-button-bottom);
110
+ right: var(--ai-assistant-button-right);
111
+ ${({ $inputType }) =>
112
+ $inputType === 'icon'
113
+ ? `
114
+ border-radius: var(--ai-assistant-button-border-radius-icon);
115
+ width: var(--ai-assistant-button-icon-size);
116
+ height: var(--ai-assistant-button-icon-size);
117
+ `
118
+ : `
119
+ border-radius: var(--ai-assistant-button-border-radius-text);
120
+ padding: var(--ai-assistant-button-text-padding);
121
+ height: var(--ai-assistant-button-text-height);
122
+ `}
123
+ min-width: var(--ai-assistant-button-min-width);
124
+ font-size: var(--ai-assistant-button-font-size);
125
+ font-weight: var(--ai-assistant-button-font-weight);
126
+ box-shadow: var(--bg-raised-shadow);
127
+ z-index: var(--ai-assistant-button-z-index);
128
+ display: flex;
129
+ align-items: center;
130
+ justify-content: center;
131
+ gap: var(--ai-assistant-button-gap);
132
+ background-color: var(--ai-assistant-button-bg-color) !important;
133
+
134
+ transition: var(--ai-assistant-button-transition);
135
+
136
+ &:hover {
137
+ box-shadow: var(--ai-assistant-button-shadow-hover);
138
+ transform: var(--ai-assistant-button-transform-hover);
139
+ }
140
+
141
+ &:active {
142
+ transform: var(--bg-raised-shadow);
143
+ box-shadow: var(--ai-assistant-button-shadow-active);
144
+ }
145
+ `;
@@ -0,0 +1,7 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const aiAssistantButtonDarkMode = css`
4
+
5
+ /* Background color */
6
+ --ai-assistant-button-bg-color: var(--color-warm-grey-4);
7
+ `;
@@ -0,0 +1,48 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const aiAssistantButton = css`
4
+ /**
5
+ * @tokens AI Assistant Button
6
+ * @presenter Color
7
+ */
8
+
9
+ /* Button sizing */
10
+ --ai-assistant-button-icon-size: 40px;
11
+ --ai-assistant-button-text-height: 40px;
12
+ --ai-assistant-button-text-padding: var(--spacing-sm) var(--spacing-md);
13
+ --ai-assistant-button-border-radius-icon: 50%;
14
+ --ai-assistant-button-border-radius-text: 1.75rem;
15
+ --ai-assistant-button-min-width: auto;
16
+
17
+ /* Icon sizing */
18
+ --ai-assistant-button-icon-icon-size: 18px;
19
+ --ai-assistant-button-text-icon-size: 20px;
20
+
21
+ /* Positioning */
22
+ --ai-assistant-button-bottom: var(--spacing-xl);
23
+ --ai-assistant-button-right: var(--spacing-xl);
24
+ --ai-assistant-button-z-index: 50
25
+
26
+ /* Typography */
27
+ --ai-assistant-button-font-size: var(--font-size-base);
28
+ --ai-assistant-button-font-weight: var(--font-weight-medium);
29
+ --ai-assistant-button-gap: var(--spacing-xs);
30
+
31
+ /* Background color */
32
+ --ai-assistant-button-bg-color: var(--color-static-white);
33
+
34
+ /* Icon colors */
35
+ --ai-assistant-button-redocly-icon-color: #297AFE;
36
+
37
+ /* Transform */
38
+ --ai-assistant-button-transform-hover: none;
39
+ --ai-assistant-button-transform-active: translateY(0);
40
+
41
+ /* Shadow */
42
+ --ai-assistant-button-shadow-hover:
43
+ 2px 1px 12px 4px rgba(143, 98, 254, 0.2),
44
+ -3px -2px 24px 0px rgba(41, 122, 254, 0.2);
45
+
46
+ /* Transition */
47
+ --ai-assistant-button-transition: box-shadow 0.3s ease, transform 0.2s ease;
48
+ `;
@@ -10,7 +10,7 @@ import {
10
10
  import { breakpoints } from '@redocly/theme/core/utils';
11
11
  import { useThemeHooks } from '@redocly/theme/core/hooks';
12
12
  import { H3 } from '@redocly/theme/components/Typography/H3';
13
- import { FilterContent } from '@redocly/theme/components/Filter/FilterContent';
13
+ import { CatalogFilterContent } from '@redocly/theme/components/Catalog/CatalogFilter/CatalogFilterContent';
14
14
  import { Sidebar, SidebarHeader } from '@redocly/theme/components/Sidebar/Sidebar';
15
15
  import { CatalogSelector } from '@redocly/theme/components/Catalog/CatalogSelector';
16
16
  import { SidebarActions } from '@redocly/theme/components/SidebarActions/SidebarActions';
@@ -20,8 +20,11 @@ import { CatalogViewModeToggle } from '@redocly/theme/components/Catalog/Catalog
20
20
  import { CatalogSortButton } from '@redocly/theme/components/Catalog/CatalogSortButton';
21
21
  import { CatalogEntities } from '@redocly/theme/components/Catalog/CatalogEntities';
22
22
 
23
+ type CatalogFiltersWithCounts = Record<string, { value: string; count: number }[]>;
24
+
23
25
  export type CatalogProps = {
24
26
  catalogConfig: CatalogEntityConfig;
27
+ filters?: CatalogFiltersWithCounts;
25
28
  entitiesTypes: string[];
26
29
  initialEntitiesList?: BffCatalogEntityList;
27
30
  catalogSwitcherItems: CatalogSwitcherItem[];
@@ -29,9 +32,11 @@ export type CatalogProps = {
29
32
  };
30
33
 
31
34
  const customCatalogOptionsCasing = (str: string): string => {
32
- if (!str) return str;
35
+ const trimmedStr = str.trim();
36
+ if (!trimmedStr) return trimmedStr;
37
+
38
+ const words = trimmedStr.split(/[\s-_]+/);
33
39
 
34
- const words = str.split(/[\s-_]+/);
35
40
  return words
36
41
  .map((word, index) => {
37
42
  if (index === 0 && word.toLowerCase() === 'api') {
@@ -45,6 +50,7 @@ const customCatalogOptionsCasing = (str: string): string => {
45
50
  export function Catalog(props: CatalogProps): JSX.Element {
46
51
  const {
47
52
  catalogConfig,
53
+ filters: serverFilters,
48
54
  entitiesTypes,
49
55
  initialEntitiesList,
50
56
  catalogSwitcherItems,
@@ -72,7 +78,12 @@ export function Catalog(props: CatalogProps): JSX.Element {
72
78
  onChangeCollapseSidebarClick,
73
79
  layout,
74
80
  collapsedSidebar,
75
- } = useCatalog(catalogConfig, initialEntitiesList?.page.total || 0, initialViewMode);
81
+ } = useCatalog(
82
+ catalogConfig,
83
+ serverFilters,
84
+ initialEntitiesList?.page.total || 0,
85
+ initialViewMode,
86
+ );
76
87
 
77
88
  return (
78
89
  <>
@@ -89,12 +100,12 @@ export function Catalog(props: CatalogProps): JSX.Element {
89
100
  )
90
101
  }
91
102
  menu={
92
- <FilterContent
103
+ <CatalogFilterContent
93
104
  setFilterTerm={setSearchQuery}
94
105
  filters={filters}
95
106
  filterTerm={searchQuery}
96
107
  hideSearch={true}
97
- showCounter={false}
108
+ showCounter={true}
98
109
  filterValuesCasing={customCatalogOptionsCasing}
99
110
  />
100
111
  }
@@ -128,6 +139,7 @@ export function Catalog(props: CatalogProps): JSX.Element {
128
139
  <FilterInput
129
140
  value={searchQuery}
130
141
  onChange={(updatedTerm) => setSearchQuery(updatedTerm)}
142
+ dataTestId="catalog-search-input"
131
143
  />
132
144
  </CatalogSearchInputWrapper>
133
145
 
@@ -41,6 +41,7 @@ const InfoBarWrapper = styled.div<{ hoverEffect: boolean }>`
41
41
  transition: all 0.2s ease-in-out;
42
42
  height: 100%;
43
43
  padding: var(--catalog-card-gap);
44
+ margin-bottom: var(--spacing-xs);
44
45
 
45
46
  ${({ hoverEffect }) =>
46
47
  hoverEffect &&
@@ -46,7 +46,7 @@ export function CatalogEntityApiDescriptionRelations({
46
46
  }: CatalogEntityApiDescriptionRelationsProps): JSX.Element {
47
47
  return (
48
48
  <div data-component-name="Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations">
49
- <Tabs key={entity.id} size={TabsSize.MEDIUM}>
49
+ <Tabs key={entity.id} forceReady={relations.length > 0} size={TabsSize.MEDIUM}>
50
50
  <TabItem
51
51
  label="Operations"
52
52
  icon={<MoleculesIcon />}
@@ -74,7 +74,7 @@ export function CatalogEntityTeamRelations({
74
74
  }: CatalogEntityTeamRelationsProps): JSX.Element {
75
75
  return (
76
76
  <div data-component-name="Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations">
77
- <Tabs size={TabsSize.MEDIUM}>
77
+ <Tabs forceReady={relations.length > 0} size={TabsSize.MEDIUM}>
78
78
  <TabItem label="Members" icon={<PeopleIcon />} onClick={() => setFilter('type:user')}>
79
79
  <CatalogEntityRelationsTable
80
80
  key="members-table"
@@ -11,6 +11,7 @@ import { HierarchyIcon } from '@redocly/theme/icons/HierarchyIcon/HierarchyIcon'
11
11
  import { Image } from '@redocly/theme/components/Image/Image';
12
12
  import { PREDEFINED_ENTITY_TYPES, useThemeConfig } from '@redocly/theme/core';
13
13
  import { NoteIcon } from '@redocly/theme/icons/NoteIcon/NoteIcon';
14
+ import { CubeIcon } from '@redocly/theme/icons/CubeIcon/CubeIcon';
14
15
 
15
16
  export type CatalogEntityIconProps = {
16
17
  entityType: string;
@@ -59,7 +60,7 @@ const getEntityIcon = ({
59
60
  );
60
61
  }
61
62
 
62
- return <CodeIcon color="var(--catalog-entity-icon-color)" />; // @TODO: add default icon
63
+ return <CubeIcon color="var(--catalog-entity-icon-color)" />;
63
64
  };
64
65
 
65
66
  export function CatalogEntityIcon({
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { FilterProps, FilterTypes } from '@redocly/theme/core/types';
6
+
7
+ import { CatalogFilterSelect } from '@redocly/theme/components/Catalog/CatalogFilter/CatalogFilterSelect';
8
+ import { CatalogFilterCheckboxes } from '@redocly/theme/components/Catalog/CatalogFilter/CatalogFilterCheckboxes';
9
+ import { CatalogFilterDateRange } from '@redocly/theme/components/Catalog/CatalogFilter/CatalogFilterDateRange';
10
+
11
+ const filterComponents = {
12
+ select: CatalogFilterSelect,
13
+ 'date-range': CatalogFilterDateRange,
14
+ checkboxes: CatalogFilterCheckboxes,
15
+ } as const;
16
+
17
+ export type CatalogFilterProps = FilterProps & {
18
+ className?: string;
19
+ };
20
+
21
+ export function CatalogFilter({
22
+ filter,
23
+ filterValuesCasing,
24
+ showCounter = true,
25
+ className,
26
+ }: CatalogFilterProps): JSX.Element | null {
27
+ if (!filter.parentUsed) return null;
28
+
29
+ const filteredOptions = filter.filteredOptions || filter.options;
30
+ if (!filteredOptions || filteredOptions.length === 0) {
31
+ return null;
32
+ }
33
+
34
+ const FilterComponent = filterComponents[(filter.type || 'checkboxes') as FilterTypes];
35
+
36
+ return (
37
+ <CatalogFilterGroup
38
+ className={className}
39
+ data-component-name="Catalog/CatalogFilter"
40
+ key={filter.property + filter.title}
41
+ >
42
+ <FilterComponent
43
+ filter={filter}
44
+ filterValuesCasing={filterValuesCasing}
45
+ showCounter={showCounter}
46
+ />
47
+ </CatalogFilterGroup>
48
+ );
49
+ }
50
+
51
+ const CatalogFilterGroup = styled.div`
52
+ padding: var(--filter-group-padding);
53
+ display: flex;
54
+ flex-direction: column;
55
+ gap: var(--filter-group-gap);
56
+ border-bottom: 1px solid var(--catalog-table-border-color);
57
+
58
+ &:first-child {
59
+ border-top: 1px solid var(--catalog-table-border-color);
60
+ }
61
+ `;
@@ -0,0 +1,169 @@
1
+ import React, { useState, useMemo } from 'react';
2
+ import styled from 'styled-components';
3
+ import { findAll } from 'highlight-words-core';
4
+
5
+ import type { JSX } from 'react';
6
+ import type { FilterProps } from '@redocly/theme/core/types';
7
+
8
+ import { FilterOptions } from '@redocly/theme/components/Filter/FilterOptions';
9
+ import { FilterOption } from '@redocly/theme/components/Filter/FilterOption';
10
+ import { FilterOptionLabel } from '@redocly/theme/components/Filter/FilterOptionLabel';
11
+ import { FilterInput } from '@redocly/theme/components/Filter/FilterInput';
12
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
13
+ import { CheckboxIcon } from '@redocly/theme/icons/CheckboxIcon/CheckboxIcon';
14
+ import { CounterTag } from '@redocly/theme/components/Tags/CounterTag';
15
+ import { changeTextCasing } from '@redocly/theme/core/utils';
16
+ import { Accordion } from '@redocly/theme/components/Accordion/Accordion';
17
+
18
+ export type CatalogFilterCheckboxesProps = FilterProps & {
19
+ className?: string;
20
+ };
21
+
22
+ export function CatalogFilterCheckboxes({
23
+ filter,
24
+ filterValuesCasing,
25
+ showCounter = true,
26
+ className,
27
+ }: CatalogFilterCheckboxesProps): JSX.Element {
28
+ const { useTranslate, useTelemetry } = useThemeHooks();
29
+ const { translate } = useTranslate();
30
+ const telemetry = useTelemetry();
31
+
32
+ const [searchTerm, setSearchTerm] = useState('');
33
+ const [isExpanded, setIsExpanded] = useState(false);
34
+
35
+ const filteredOptions = useMemo(() => {
36
+ const options = filter.filteredOptions || filter.options;
37
+ if (!searchTerm.trim()) return options;
38
+
39
+ const lowerSearchTerm = searchTerm.toLowerCase();
40
+ return options.filter(({ value }) => {
41
+ const translatedValue = changeTextCasing(translate(value), filterValuesCasing);
42
+ if (!translatedValue) return false;
43
+ return translatedValue.toLowerCase().includes(lowerSearchTerm);
44
+ });
45
+ }, [searchTerm, filter.filteredOptions, filter.options, translate, filterValuesCasing]);
46
+
47
+ const selectedCount = useMemo(() => {
48
+ if (filter.selectedOptions instanceof Set) {
49
+ return filter.selectedOptions.size;
50
+ }
51
+ return 0;
52
+ }, [filter.selectedOptions]);
53
+
54
+ const highlightText = (text: string): JSX.Element => {
55
+ if (!searchTerm.trim()) {
56
+ return <>{text}</>;
57
+ }
58
+
59
+ const chunks = findAll({
60
+ searchWords: [searchTerm],
61
+ textToHighlight: text,
62
+ });
63
+
64
+ return (
65
+ <>
66
+ {chunks.map((chunk, idx) => {
67
+ const { end, highlight, start } = chunk;
68
+ const chunkText = text.substr(start, end - start);
69
+ if (highlight) {
70
+ return <HighlightedText key={idx}>{chunkText}</HighlightedText>;
71
+ } else {
72
+ return <span key={idx}>{chunkText}</span>;
73
+ }
74
+ })}
75
+ </>
76
+ );
77
+ };
78
+
79
+ const headerContent = (
80
+ <AccordionHeaderContent>
81
+ <span>{translate(filter.titleTranslationKey, filter.title)}</span>
82
+ {selectedCount > 0 && <CounterTag borderless>{selectedCount}</CounterTag>}
83
+ </AccordionHeaderContent>
84
+ );
85
+
86
+ return (
87
+ <AccordionWrapper
88
+ className={className}
89
+ $hasSelection={selectedCount > 0 && !isExpanded}
90
+ data-component-name="Catalog/CatalogFilterCheckboxes"
91
+ >
92
+ <Accordion expanded={isExpanded} header={headerContent} onToggle={setIsExpanded}>
93
+ <FilterSearchWrapper>
94
+ <FilterInput value={searchTerm} onChange={setSearchTerm} />
95
+ </FilterSearchWrapper>
96
+ <FilterOptions>
97
+ {filteredOptions.map(({ value, count }) => {
98
+ const id = 'filter--' + filter.property + '--' + value;
99
+ return (
100
+ <FilterCheckboxOption
101
+ key={id}
102
+ role="link"
103
+ onClick={() => {
104
+ filter.toggleOption(value);
105
+ telemetry.sendFilterCheckboxToggledMessage({ id });
106
+ }}
107
+ >
108
+ <CheckboxIcon
109
+ checked={
110
+ filter.selectedOptions instanceof Set
111
+ ? filter.selectedOptions.has(value) ||
112
+ filter.selectedOptions.has(value?.toLowerCase())
113
+ : false
114
+ }
115
+ />
116
+ <FilterOptionLabel data-translation-key={value}>
117
+ {highlightText(changeTextCasing(translate(value), filterValuesCasing) || '')}
118
+ </FilterOptionLabel>
119
+ {showCounter && <CounterTag borderless>{count}</CounterTag>}
120
+ </FilterCheckboxOption>
121
+ );
122
+ })}
123
+ </FilterOptions>
124
+ </Accordion>
125
+ </AccordionWrapper>
126
+ );
127
+ }
128
+
129
+ const AccordionWrapper = styled.div<{ $hasSelection: boolean }>`
130
+ position: relative;
131
+ border-right: 4px solid transparent;
132
+
133
+ ${({ $hasSelection }) =>
134
+ $hasSelection &&
135
+ `
136
+ border-right-color: var(--color-blueberry-6);
137
+
138
+ &::after {
139
+ content: '';
140
+ position: absolute;
141
+ bottom: -1px;
142
+ right: -4px;
143
+ width: 4px;
144
+ height: 1px;
145
+ background-color: var(--color-blueberry-6);
146
+ z-index: 1;
147
+ }
148
+ `}
149
+ `;
150
+
151
+ const AccordionHeaderContent = styled.div`
152
+ display: flex;
153
+ align-items: center;
154
+ gap: var(--spacing-xs);
155
+ width: 100%;
156
+ `;
157
+
158
+ const HighlightedText = styled.span`
159
+ background-color: var(--catalog-highlight-bg-color);
160
+ color: var(--catalog-highlight-text-color);
161
+ `;
162
+
163
+ const FilterCheckboxOption = styled(FilterOption)`
164
+ padding-left: var(--filter-option-checkbox-padding-left);
165
+ `;
166
+
167
+ const FilterSearchWrapper = styled.div`
168
+ padding: var(--filter-content-search-padding);
169
+ `;
@@ -0,0 +1,121 @@
1
+ import React from 'react';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { ResolvedFilter } from '@redocly/theme/core/types';
6
+ import type { RedoclyConfig } from '@redocly/theme/config';
7
+
8
+ import { FilterInput } from '@redocly/theme/components/Filter/FilterInput';
9
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
10
+ import { Button } from '@redocly/theme/components/Button/Button';
11
+ import { CatalogFilter } from '@redocly/theme/components/Catalog/CatalogFilter/CatalogFilter';
12
+ import { isFromToSelectedOptions } from '@redocly/theme/core/utils';
13
+
14
+ export type CatalogFilterContentProps = {
15
+ setFilterTerm: (value: string) => void;
16
+ filters: ResolvedFilter[];
17
+ filterTerm: string;
18
+ filterValuesCasing?:
19
+ | NonNullable<RedoclyConfig['catalog']>[string]['filterValuesCasing']
20
+ | ((str: string) => string);
21
+ hideSearch?: boolean;
22
+ showCounter?: boolean;
23
+ className?: string;
24
+ };
25
+
26
+ export function CatalogFilterContent({
27
+ setFilterTerm,
28
+ filters,
29
+ filterTerm,
30
+ filterValuesCasing,
31
+ hideSearch,
32
+ showCounter = true,
33
+ className,
34
+ }: CatalogFilterContentProps): JSX.Element | null {
35
+ const { useTranslate } = useThemeHooks();
36
+ const { translate } = useTranslate();
37
+
38
+ const hasActiveFilters = filters.some((filter) => {
39
+ if (filterTerm) return true;
40
+ if (filter.selectedOptions && filter.selectedOptions instanceof Set) {
41
+ return filter.selectedOptions.size;
42
+ } else if (
43
+ isFromToSelectedOptions(filter.selectedOptions) &&
44
+ filter.selectedOptions.from &&
45
+ filter.selectedOptions.to
46
+ ) {
47
+ return true;
48
+ }
49
+ });
50
+
51
+ const handleClearAll = (): void => {
52
+ filters.forEach((filter) => filter.selectOption(''));
53
+ setFilterTerm('');
54
+ };
55
+
56
+ if (!filters.length) {
57
+ return null;
58
+ }
59
+
60
+ return (
61
+ <CatalogFilterContentWrapper
62
+ className={className}
63
+ data-component-name="Catalog/CatalogFilterContent"
64
+ >
65
+ <FiltersHeader>
66
+ <FiltersTitle data-translation-key="catalog.filters.title">
67
+ {translate('catalog.filters.title', 'Filters')}
68
+ </FiltersTitle>
69
+ {hasActiveFilters ? (
70
+ <Button size="medium" tone="danger" variant="ghost" onClick={handleClearAll}>
71
+ {translate('catalog.filters.clearAll', 'Clear filters')}
72
+ </Button>
73
+ ) : null}
74
+ </FiltersHeader>
75
+ {!hideSearch && (
76
+ <FilterInput value={filterTerm} onChange={(updatedTerm) => setFilterTerm(updatedTerm)} />
77
+ )}
78
+ <FilterItems hideSearch={hideSearch}>
79
+ {filters.map((filter, idx) => (
80
+ <CatalogFilter
81
+ filter={filter}
82
+ key={filter.property + '-' + idx}
83
+ filterValuesCasing={filterValuesCasing}
84
+ showCounter={showCounter}
85
+ />
86
+ ))}
87
+ </FilterItems>
88
+ </CatalogFilterContentWrapper>
89
+ );
90
+ }
91
+
92
+ const CatalogFilterContentWrapper = styled.div`
93
+ padding: 0 0 var(--filter-content-padding-vertical) 0;
94
+ display: flex;
95
+ flex-direction: column;
96
+ `;
97
+
98
+ const FiltersHeader = styled.div`
99
+ display: flex;
100
+ padding: var(--filter-content-header-padding-vertical)
101
+ var(--filter-content-header-padding-horizontal);
102
+ `;
103
+
104
+ const FiltersTitle = styled.div`
105
+ margin-right: auto;
106
+ font-size: var(--filter-content-title-font-size);
107
+ font-weight: var(--filter-content-title-font-weight);
108
+ line-height: var(--filter-content-title-line-height);
109
+ `;
110
+
111
+ const FilterItems = styled.div<{ hideSearch?: boolean }>`
112
+ height: 100%;
113
+ display: flex;
114
+ flex-direction: column;
115
+ border-top: 1px solid var(--border-color-secondary);
116
+ ${({ hideSearch }) =>
117
+ hideSearch &&
118
+ css`
119
+ border-top: none;
120
+ `}
121
+ `;