@redocly/theme 0.61.1 → 0.62.0-custom.1

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 (217) hide show
  1. package/lib/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.d.ts +1 -0
  2. package/lib/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.js +12 -0
  3. package/lib/components/Badge/Badge.d.ts +2 -1
  4. package/lib/components/Badge/Badge.js +24 -2
  5. package/lib/components/Banner/Banner.js +19 -1
  6. package/lib/components/Banner/variables.js +1 -0
  7. package/lib/components/Breadcrumbs/Breadcrumb.js +1 -1
  8. package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +9 -6
  9. package/lib/components/Breadcrumbs/Breadcrumbs.js +24 -15
  10. package/lib/components/Buttons/AIAssistantButton.js +7 -4
  11. package/lib/components/Buttons/EditPageButton.js +4 -26
  12. package/lib/components/Catalog/CatalogEntities.js +10 -8
  13. package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +2 -2
  14. package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +3 -3
  15. package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem.js +6 -13
  16. package/lib/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.js +2 -2
  17. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.js +13 -11
  18. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +7 -5
  19. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +9 -7
  20. package/lib/components/Catalog/CatalogTableView/CatalogTableViewRow.js +1 -1
  21. package/lib/components/Catalog/CatalogTagsWithTooltip.js +2 -2
  22. package/lib/components/CatalogClassic/CatalogClassicInfoBlock.js +1 -1
  23. package/lib/components/CodeBlock/CodeBlockControls.js +8 -6
  24. package/lib/components/Dropdown/Dropdown.js +1 -1
  25. package/lib/components/Dropdown/variables.js +1 -0
  26. package/lib/components/Feedback/Comment.js +17 -4
  27. package/lib/components/Feedback/Mood.js +6 -3
  28. package/lib/components/Feedback/Rating.js +6 -3
  29. package/lib/components/Feedback/Scale.js +6 -3
  30. package/lib/components/Feedback/Sentiment.js +6 -3
  31. package/lib/components/Filter/FilterCheckboxes.js +1 -1
  32. package/lib/components/JsonViewer/JsonViewer.js +2 -2
  33. package/lib/components/JsonViewer/{Helpers.js → helpers.js} +2 -1
  34. package/lib/components/LanguagePicker/LanguagePicker.js +1 -1
  35. package/lib/components/Markdown/Markdown.js +2 -2
  36. package/lib/components/Menu/MenuItem.js +41 -15
  37. package/lib/components/Menu/variables.js +3 -3
  38. package/lib/components/Navbar/NavbarItem.js +1 -1
  39. package/lib/components/OpenApiDocs/hooks/AdditionalOverviewInfo.d.ts +1 -0
  40. package/lib/components/OpenApiDocs/hooks/AdditionalOverviewInfo.js +12 -0
  41. package/lib/components/OpenApiDocs/hooks/AfterOpenApiDescription.d.ts +1 -0
  42. package/lib/components/OpenApiDocs/hooks/AfterOpenApiDescription.js +6 -0
  43. package/lib/components/PageActions/PageActions.js +25 -8
  44. package/lib/components/Search/SearchAiDialog.d.ts +4 -2
  45. package/lib/components/Search/SearchAiDialog.js +23 -4
  46. package/lib/components/Search/SearchAiMessage.d.ts +4 -2
  47. package/lib/components/Search/SearchAiMessage.js +82 -23
  48. package/lib/components/Search/SearchDialog.js +50 -25
  49. package/lib/components/Select/variables.js +2 -2
  50. package/lib/components/SvgViewer/SvgViewer.d.ts +15 -0
  51. package/lib/components/SvgViewer/SvgViewer.js +312 -0
  52. package/lib/components/SvgViewer/variables.d.ts +1 -0
  53. package/lib/components/SvgViewer/variables.dark.d.ts +1 -0
  54. package/lib/components/SvgViewer/variables.dark.js +8 -0
  55. package/lib/components/SvgViewer/variables.js +17 -0
  56. package/lib/components/Tag/Tag.js +1 -1
  57. package/lib/components/Tag/variables.dark.js +6 -0
  58. package/lib/components/Tag/variables.js +6 -0
  59. package/lib/components/Tooltip/Tooltip.d.ts +2 -3
  60. package/lib/components/Tooltip/Tooltip.js +66 -113
  61. package/lib/components/Tooltip/variables.dark.js +4 -0
  62. package/lib/components/Tooltip/variables.js +3 -3
  63. package/lib/components/UserMenu/LoginButton.d.ts +8 -2
  64. package/lib/components/UserMenu/LoginButton.js +4 -3
  65. package/lib/core/constants/feedback.d.ts +2 -0
  66. package/lib/core/constants/feedback.js +6 -0
  67. package/lib/core/constants/index.d.ts +1 -0
  68. package/lib/core/constants/index.js +1 -0
  69. package/lib/core/constants/search.d.ts +5 -1
  70. package/lib/core/constants/search.js +24 -1
  71. package/lib/core/hooks/search/use-search-dialog.js +2 -2
  72. package/lib/core/hooks/use-color-switcher.js +3 -1
  73. package/lib/core/hooks/use-mcp-config.js +2 -1
  74. package/lib/core/hooks/use-modal-scroll-lock.js +24 -10
  75. package/lib/core/hooks/use-outside-click.d.ts +3 -1
  76. package/lib/core/hooks/use-outside-click.js +8 -4
  77. package/lib/core/hooks/use-page-actions.d.ts +1 -1
  78. package/lib/core/hooks/use-page-actions.js +50 -14
  79. package/lib/core/hooks/use-product-picker.js +1 -1
  80. package/lib/core/hooks/use-unique-svg-ids.d.ts +6 -0
  81. package/lib/core/hooks/use-unique-svg-ids.js +15 -0
  82. package/lib/core/openapi/index.d.ts +2 -0
  83. package/lib/core/openapi/index.js +5 -1
  84. package/lib/core/styles/dark.js +13 -0
  85. package/lib/core/styles/global.js +38 -15
  86. package/lib/core/types/catalog.d.ts +1 -1
  87. package/lib/core/types/hooks.d.ts +23 -2
  88. package/lib/core/types/l10n.d.ts +1 -1
  89. package/lib/core/types/search.d.ts +24 -0
  90. package/lib/core/types/search.js +9 -1
  91. package/lib/core/utils/content-segments.d.ts +2 -0
  92. package/lib/core/utils/content-segments.js +22 -0
  93. package/lib/core/utils/index.d.ts +1 -0
  94. package/lib/core/utils/index.js +1 -0
  95. package/lib/core/utils/transform-revisions-to-version-history.js +18 -68
  96. package/lib/ext/process-scorecard.d.ts +49 -0
  97. package/lib/ext/process-scorecard.js +12 -0
  98. package/lib/icons/DirectionRightIcon/DirectionRightIcon.d.ts +5 -0
  99. package/lib/icons/DirectionRightIcon/DirectionRightIcon.js +24 -0
  100. package/lib/icons/FitToViewIcon/FitToViewIcon.d.ts +9 -0
  101. package/lib/icons/FitToViewIcon/FitToViewIcon.js +25 -0
  102. package/lib/index.d.ts +8 -0
  103. package/lib/index.js +8 -0
  104. package/lib/layouts/DocumentationLayout.js +4 -25
  105. package/lib/layouts/DocumentationLayoutBottom.d.ts +11 -0
  106. package/lib/layouts/DocumentationLayoutBottom.js +28 -0
  107. package/lib/layouts/DocumentationLayoutTop.d.ts +13 -0
  108. package/lib/layouts/DocumentationLayoutTop.js +33 -0
  109. package/lib/layouts/Forbidden.js +22 -18
  110. package/lib/markdoc/components/Cards/Card.js +1 -0
  111. package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +1 -1
  112. package/lib/markdoc/components/Heading/Heading.js +40 -2
  113. package/lib/markdoc/components/LoginButton/LoginButton.d.ts +9 -0
  114. package/lib/markdoc/components/LoginButton/LoginButton.js +48 -0
  115. package/lib/markdoc/components/Mermaid/Mermaid.js +70 -2
  116. package/lib/markdoc/components/default.d.ts +1 -0
  117. package/lib/markdoc/components/default.js +1 -0
  118. package/lib/markdoc/default.d.ts +6 -0
  119. package/lib/markdoc/default.js +2 -0
  120. package/lib/markdoc/tags/login-button.d.ts +2 -0
  121. package/lib/markdoc/tags/login-button.js +32 -0
  122. package/package.json +10 -10
  123. package/src/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.tsx +10 -0
  124. package/src/components/Badge/Badge.tsx +18 -2
  125. package/src/components/Banner/Banner.tsx +23 -1
  126. package/src/components/Banner/variables.ts +1 -0
  127. package/src/components/Breadcrumbs/Breadcrumb.tsx +3 -3
  128. package/src/components/Breadcrumbs/BreadcrumbDropdown.tsx +11 -8
  129. package/src/components/Breadcrumbs/Breadcrumbs.tsx +24 -15
  130. package/src/components/Buttons/AIAssistantButton.tsx +7 -4
  131. package/src/components/Buttons/EditPageButton.tsx +13 -34
  132. package/src/components/Catalog/CatalogEntities.tsx +10 -8
  133. package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +1 -1
  134. package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +3 -4
  135. package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem.tsx +5 -21
  136. package/src/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.tsx +1 -1
  137. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.tsx +13 -11
  138. package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +7 -5
  139. package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +9 -7
  140. package/src/components/Catalog/CatalogTableView/CatalogTableViewRow.tsx +1 -2
  141. package/src/components/Catalog/CatalogTagsWithTooltip.tsx +9 -5
  142. package/src/components/CatalogClassic/CatalogClassicInfoBlock.tsx +3 -1
  143. package/src/components/CodeBlock/CodeBlockControls.tsx +16 -10
  144. package/src/components/Dropdown/Dropdown.tsx +1 -1
  145. package/src/components/Dropdown/variables.ts +1 -0
  146. package/src/components/Feedback/Comment.tsx +22 -4
  147. package/src/components/Feedback/Mood.tsx +6 -2
  148. package/src/components/Feedback/Rating.tsx +6 -2
  149. package/src/components/Feedback/Scale.tsx +6 -2
  150. package/src/components/Feedback/Sentiment.tsx +6 -2
  151. package/src/components/Filter/FilterCheckboxes.tsx +1 -1
  152. package/src/components/JsonViewer/JsonViewer.tsx +1 -2
  153. package/src/components/JsonViewer/{Helpers.tsx → helpers.tsx} +1 -0
  154. package/src/components/LanguagePicker/LanguagePicker.tsx +1 -1
  155. package/src/components/Markdown/Markdown.tsx +2 -2
  156. package/src/components/Menu/MenuItem.tsx +61 -16
  157. package/src/components/Menu/variables.ts +3 -3
  158. package/src/components/Navbar/NavbarItem.tsx +3 -1
  159. package/src/components/OpenApiDocs/hooks/AdditionalOverviewInfo.tsx +10 -0
  160. package/src/components/OpenApiDocs/hooks/AfterOpenApiDescription.tsx +2 -0
  161. package/src/components/PageActions/PageActions.tsx +38 -15
  162. package/src/components/Search/SearchAiDialog.tsx +31 -2
  163. package/src/components/Search/SearchAiMessage.tsx +103 -17
  164. package/src/components/Search/SearchDialog.tsx +70 -37
  165. package/src/components/Select/variables.ts +2 -2
  166. package/src/components/SvgViewer/SvgViewer.tsx +405 -0
  167. package/src/components/SvgViewer/variables.dark.ts +5 -0
  168. package/src/components/SvgViewer/variables.ts +14 -0
  169. package/src/components/Tag/Tag.tsx +2 -1
  170. package/src/components/Tag/variables.dark.ts +6 -0
  171. package/src/components/Tag/variables.ts +6 -0
  172. package/src/components/Tooltip/Tooltip.tsx +77 -120
  173. package/src/components/Tooltip/variables.dark.ts +4 -0
  174. package/src/components/Tooltip/variables.ts +3 -3
  175. package/src/components/UserMenu/LoginButton.tsx +23 -8
  176. package/src/core/constants/feedback.ts +2 -0
  177. package/src/core/constants/index.ts +1 -0
  178. package/src/core/constants/search.ts +27 -1
  179. package/src/core/hooks/__mocks__/use-theme-hooks.ts +10 -1
  180. package/src/core/hooks/search/use-search-dialog.ts +2 -2
  181. package/src/core/hooks/use-color-switcher.ts +3 -1
  182. package/src/core/hooks/use-mcp-config.ts +2 -1
  183. package/src/core/hooks/use-modal-scroll-lock.ts +29 -10
  184. package/src/core/hooks/use-outside-click.ts +16 -5
  185. package/src/core/hooks/use-page-actions.ts +77 -30
  186. package/src/core/hooks/use-product-picker.ts +1 -1
  187. package/src/core/hooks/use-unique-svg-ids.ts +12 -0
  188. package/src/core/openapi/index.ts +2 -0
  189. package/src/core/styles/dark.ts +14 -0
  190. package/src/core/styles/global.ts +38 -15
  191. package/src/core/types/catalog.ts +1 -1
  192. package/src/core/types/hooks.ts +29 -1
  193. package/src/core/types/l10n.ts +13 -1
  194. package/src/core/types/search.ts +19 -0
  195. package/src/core/utils/content-segments.ts +27 -0
  196. package/src/core/utils/index.ts +1 -0
  197. package/src/core/utils/transform-revisions-to-version-history.ts +19 -99
  198. package/src/ext/process-scorecard.ts +59 -0
  199. package/src/icons/DirectionRightIcon/DirectionRightIcon.tsx +35 -0
  200. package/src/icons/FitToViewIcon/FitToViewIcon.tsx +26 -0
  201. package/src/index.ts +8 -0
  202. package/src/layouts/DocumentationLayout.tsx +4 -30
  203. package/src/layouts/DocumentationLayoutBottom.tsx +42 -0
  204. package/src/layouts/DocumentationLayoutTop.tsx +52 -0
  205. package/src/layouts/Forbidden.tsx +36 -21
  206. package/src/markdoc/components/Cards/Card.tsx +1 -0
  207. package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +1 -1
  208. package/src/markdoc/components/Heading/Heading.tsx +52 -4
  209. package/src/markdoc/components/LoginButton/LoginButton.tsx +38 -0
  210. package/src/markdoc/components/Mermaid/Mermaid.tsx +57 -8
  211. package/src/markdoc/components/default.ts +1 -0
  212. package/src/markdoc/default.ts +2 -0
  213. package/src/markdoc/tags/login-button.ts +30 -0
  214. package/lib/components/Tooltip/TooltipWrapper.d.ts +0 -12
  215. package/lib/components/Tooltip/TooltipWrapper.js +0 -34
  216. package/src/components/Tooltip/TooltipWrapper.tsx +0 -70
  217. /package/lib/components/JsonViewer/{Helpers.d.ts → helpers.d.ts} +0 -0
@@ -16,6 +16,12 @@ import { useMCPConfig } from './use-mcp-config';
16
16
  import { ClipboardService } from '../utils/clipboard-service';
17
17
  import { IS_BROWSER } from '../utils/dom';
18
18
  import { generateMCPDeepLink } from '../utils/mcp';
19
+ import {
20
+ addTrailingSlash,
21
+ combineUrls,
22
+ removeTrailingSlash,
23
+ withoutPathPrefix,
24
+ } from '../utils/urls';
19
25
 
20
26
  function createPageActionResource(pageSlug: string, pageUrl: string) {
21
27
  return {
@@ -32,6 +38,7 @@ const DEFAULT_ENABLED_ACTIONS = [
32
38
  'claude',
33
39
  'docs-mcp-cursor',
34
40
  'docs-mcp-vscode',
41
+ 'docs-mcp-json',
35
42
  ] as const;
36
43
 
37
44
  export type PageActionType =
@@ -41,6 +48,7 @@ export type PageActionType =
41
48
  | 'claude'
42
49
  | 'docs-mcp-cursor'
43
50
  | 'docs-mcp-vscode'
51
+ | 'docs-mcp-json'
44
52
  | 'mcp-cursor'
45
53
  | 'mcp-vscode';
46
54
 
@@ -88,10 +96,12 @@ export function usePageActions(
88
96
  translate,
89
97
  onClickCallback: isDocsMcp
90
98
  ? () =>
91
- telemetry.sendPageActionsButtonClickedMessage({
92
- ...createPageActionResource(pageSlug, pageUrl),
93
- action_type: `docs-mcp-${clientType}` as const,
94
- })
99
+ telemetry.sendPageActionsButtonClickedMessage([
100
+ {
101
+ ...createPageActionResource(pageSlug, pageUrl),
102
+ action_type: `docs-mcp-${clientType}` as const,
103
+ },
104
+ ])
95
105
  : undefined,
96
106
  });
97
107
  },
@@ -99,18 +109,19 @@ export function usePageActions(
99
109
  );
100
110
 
101
111
  const result: PageAction[] = useMemo(() => {
102
- if (shouldHideAllActions) {
112
+ if (shouldHideAllActions && !actions?.length) {
103
113
  return [];
104
114
  }
105
115
 
106
116
  const origin = IS_BROWSER
107
117
  ? window.location.origin
108
118
  : ((globalThis as { SSR_HOSTNAME?: string })['SSR_HOSTNAME'] ?? '');
109
- const normalizedSlug = pageSlug.startsWith('/') ? pageSlug : '/' + pageSlug;
110
- const pageUrl = `${origin}${normalizedSlug}`;
111
- const mdPageUrl = new URL(
112
- origin + normalizedSlug + (normalizedSlug === '/' ? 'index.html.md' : '.md'),
113
- ).toString();
119
+ const pathname = addTrailingSlash(pageSlug);
120
+ const pageUrl = combineUrls(origin, pathname);
121
+ const isRoot = withoutPathPrefix(pathname) === '/';
122
+ const mdPageUrl = isRoot
123
+ ? combineUrls(origin, pathname, 'index.html.md')
124
+ : combineUrls(origin, removeTrailingSlash(pathname) + '.md');
114
125
 
115
126
  const actionHandlers: Record<PageActionType, () => PageAction | null> = {
116
127
  'docs-mcp-cursor': createMCPHandler('cursor', false),
@@ -131,10 +142,12 @@ export function usePageActions(
131
142
  }
132
143
  const text = await result.text();
133
144
  ClipboardService.copyCustom(text);
134
- telemetry.sendPageActionsButtonClickedMessage({
135
- ...createPageActionResource(pageSlug, pageUrl),
136
- action_type: 'copy',
137
- });
145
+ telemetry.sendPageActionsButtonClickedMessage([
146
+ {
147
+ ...createPageActionResource(pageSlug, pageUrl),
148
+ action_type: 'copy',
149
+ },
150
+ ]);
138
151
  } catch (error) {
139
152
  console.error(error);
140
153
  }
@@ -148,10 +161,12 @@ export function usePageActions(
148
161
  iconComponent: MarkdownFullIcon,
149
162
  link: mdPageUrl,
150
163
  onClick: () => {
151
- telemetry.sendPageActionsButtonClickedMessage({
152
- ...createPageActionResource(pageSlug, pageUrl),
153
- action_type: 'view',
154
- });
164
+ telemetry.sendPageActionsButtonClickedMessage([
165
+ {
166
+ ...createPageActionResource(pageSlug, pageUrl),
167
+ action_type: 'view',
168
+ },
169
+ ]);
155
170
  },
156
171
  }),
157
172
 
@@ -159,17 +174,21 @@ export function usePageActions(
159
174
  if (!isPublic) {
160
175
  return null;
161
176
  }
177
+ const link = getExternalAiPromptLink('https://chat.openai.com', mdPageUrl);
162
178
  return {
163
179
  buttonText: translate('page.actions.chatGptButtonText', 'Open in ChatGPT'),
164
180
  title: translate('page.actions.chatGptTitle', 'Open in ChatGPT'),
165
181
  description: translate('page.actions.chatGptDescription', 'Get insights from ChatGPT'),
166
182
  iconComponent: ChatGptIcon,
167
- link: getExternalAiPromptLink('https://chat.openai.com', mdPageUrl),
183
+ link,
168
184
  onClick: () => {
169
- telemetry.sendPageActionsButtonClickedMessage({
170
- ...createPageActionResource(pageSlug, pageUrl),
171
- action_type: 'chatgpt',
172
- });
185
+ telemetry.sendPageActionsButtonClickedMessage([
186
+ {
187
+ ...createPageActionResource(pageSlug, pageUrl),
188
+ action_type: 'chatgpt',
189
+ },
190
+ ]);
191
+ window.location.href = link;
173
192
  },
174
193
  };
175
194
  },
@@ -178,17 +197,43 @@ export function usePageActions(
178
197
  if (!isPublic) {
179
198
  return null;
180
199
  }
200
+ const link = getExternalAiPromptLink('https://claude.ai/new', mdPageUrl);
181
201
  return {
182
202
  buttonText: translate('page.actions.claudeButtonText', 'Open in Claude'),
183
203
  title: translate('page.actions.claudeTitle', 'Open in Claude'),
184
204
  description: translate('page.actions.claudeDescription', 'Get insights from Claude'),
185
205
  iconComponent: ClaudeIcon,
186
- link: getExternalAiPromptLink('https://claude.ai/new', mdPageUrl),
206
+ link,
187
207
  onClick: () => {
188
- telemetry.sendPageActionsButtonClickedMessage({
189
- ...createPageActionResource(pageSlug, pageUrl),
190
- action_type: 'claude',
191
- });
208
+ telemetry.sendPageActionsButtonClickedMessage([
209
+ {
210
+ ...createPageActionResource(pageSlug, pageUrl),
211
+ action_type: 'claude',
212
+ },
213
+ ]);
214
+ window.location.href = link;
215
+ },
216
+ };
217
+ },
218
+ 'docs-mcp-json': () => {
219
+ return {
220
+ buttonText: 'Copy MCP configuration',
221
+ title: 'Copy MCP JSON configuration',
222
+ description: 'Copy MCP JSON configuration',
223
+ iconComponent: CopyIcon,
224
+ onClick: async () => {
225
+ ClipboardService.copyCustom(
226
+ JSON.stringify(
227
+ {
228
+ 'mcp-server': {
229
+ url: mcpUrl,
230
+ description: 'MCP Server',
231
+ },
232
+ },
233
+ null,
234
+ 2,
235
+ ),
236
+ );
192
237
  },
193
238
  };
194
239
  },
@@ -205,6 +250,7 @@ export function usePageActions(
205
250
  translate,
206
251
  isPublic,
207
252
  createMCPHandler,
253
+ mcpUrl,
208
254
  telemetry,
209
255
  ]);
210
256
 
@@ -280,9 +326,10 @@ function shouldHidePageActions(
280
326
  }
281
327
 
282
328
  // Page is excluded from search
329
+ const isOpenApiPage =
330
+ pageProps?.metadata?.type === 'openapi' || pageProps?.metadata?.subType === 'openapi-operation';
283
331
  const isPageExcludedFromSearch =
284
- pageProps?.frontmatter?.excludeFromSearch ||
285
- (pageProps?.metadata?.type === 'openapi' && openapiExcludeFromSearch);
332
+ pageProps?.frontmatter?.excludeFromSearch || (isOpenApiPage && openapiExcludeFromSearch);
286
333
 
287
334
  if (isPageExcludedFromSearch) {
288
335
  return true;
@@ -14,7 +14,7 @@ export function useProductPicker() {
14
14
  const loadAndNavigate = useLoadAndNavigate();
15
15
  function setProduct(product: typeof currentProduct) {
16
16
  if (!product) return;
17
- telemetry.sendProductPickedMessage({ product: product.slug });
17
+ telemetry.sendProductPickedMessage([{ object: 'product', product: product.slug }]);
18
18
  if (typeof document === 'undefined') return;
19
19
 
20
20
  if (product.name) {
@@ -0,0 +1,12 @@
1
+ import { useId } from 'react';
2
+
3
+ /**
4
+ * Returns a function that appends a per-component-instance suffix to SVG ids.
5
+ * This prevents collisions when multiple identical SVGs are rendered on the same page,
6
+ * which can break `url(#...)` references (gradients, clipPath, masks, filters) on reflow.
7
+ */
8
+ export function useUniqueSvgIds(): (id: string) => string {
9
+ const reactId = useId();
10
+ const safeSuffix = reactId.replace(/:/g, '_');
11
+ return (id: string): string => `${id}-${safeSuffix}`;
12
+ }
@@ -38,3 +38,5 @@ export { SecurityVariablesEnvSuffix } from '../constants/environments';
38
38
  export { isUndefined, isString, isNotNull, isObject } from '../utils/type-guards';
39
39
  export { ThemeDataContext, type ThemeDataTransferObject } from '../contexts/ThemeDataContext';
40
40
  export { SearchSessionProvider, SearchSessionContext } from '../contexts/SearchContext';
41
+ export { useUniqueSvgIds } from '../hooks/use-unique-svg-ids';
42
+ export { trimText } from '../utils/text-trimmer';
@@ -16,6 +16,7 @@ import { pageActionsDarkMode } from '@redocly/theme/components/PageActions/varia
16
16
  import { tooltipDarkMode } from '@redocly/theme/components/Tooltip/variables.dark';
17
17
  import { bannerDarkMode } from '@redocly/theme/components/Banner/variables.dark';
18
18
  import { admonitionDarkMode } from '@redocly/theme/components/Admonition/variables.dark';
19
+ import { svgViewerDarkMode } from '@redocly/theme/components/SvgViewer/variables.dark';
19
20
 
20
21
  const replayDarkMode = css`
21
22
  /**
@@ -45,6 +46,17 @@ const replayDarkMode = css`
45
46
  // @tokens End
46
47
  `;
47
48
 
49
+ const badgesDarkMode = css`
50
+ /**
51
+ * @tokens Audience Badge
52
+ */
53
+
54
+ --badge-audience-text-color: var(--text-color-secondary); // @presenter Color
55
+ --badge-audience-bg-color: var(--color-warm-grey-4); // @presenter Color
56
+
57
+ // @tokens End
58
+ `
59
+
48
60
 
49
61
  export const darkMode = css`
50
62
  /* === Dark Theme Colors === */
@@ -332,6 +344,8 @@ export const darkMode = css`
332
344
  ${tooltipDarkMode}
333
345
  ${bannerDarkMode}
334
346
  ${admonitionDarkMode}
347
+ ${svgViewerDarkMode}
348
+ ${badgesDarkMode}
335
349
 
336
350
  /**
337
351
  * @tokens Dark Theme Scrollbar Config
@@ -42,6 +42,7 @@ import { cards } from '@redocly/theme/markdoc/components/Cards/variables';
42
42
  import { codeWalkthrough } from '@redocly/theme/markdoc/components/CodeWalkthrough/variables';
43
43
  import { skipContent } from '@redocly/theme/components/SkipContent/variables';
44
44
  import { pageActions } from '@redocly/theme/components/PageActions/variables';
45
+ import { svgViewer } from '@redocly/theme/components/SvgViewer/variables';
45
46
 
46
47
  import { darkMode } from './dark';
47
48
 
@@ -822,6 +823,13 @@ const badges = css`
822
823
  --badge-deprecated-bg-color: var(--color-warning-base); // @presenter Color
823
824
  --badge-deprecated-border-radius: var(--border-radius); // @presenter BorderRadius
824
825
 
826
+ /**
827
+ * @tokens Audience Badge
828
+ */
829
+
830
+ --badge-audience-text-color: var(--text-color-secondary); // @presenter Color
831
+ --badge-audience-bg-color: var(--color-warm-grey-2); // @presenter Color
832
+
825
833
  // @tokens End
826
834
  `;
827
835
 
@@ -971,23 +979,41 @@ const pages = css`
971
979
  */
972
980
 
973
981
  --page-403-font-family: var(--font-family-base); // @presenter FontFamily
982
+ --page-403-margin-vertical: var(--spacing-xl); // @presenter Spacing
983
+ --page-403-margin-horizontal: calc(var(--spacing-xxl) * 2); // @presenter Spacing
984
+ --page-403-gap: var(--spacing-lg); // @presenter Spacing
985
+ --page-403-max-width: 680px; // @presenter Width
986
+
987
+ --page-403-status-text-color: var(--text-color-helper); // @presenter Color
988
+ --page-403-status-font-size: var(--font-size-lg); // @presenter FontSize
989
+ --page-403-status-font-weight: var(--font-weight-semibold); // @presenter FontWeight
990
+ --page-403-status-line-height: var(--line-height-lg); // @presenter LineHeight
991
+
992
+ --page-403-title-text-color: var(--text-color-primary); // @presenter Color
993
+ --page-403-title-font-size: 42px; // @presenter FontSize
994
+ --page-403-title-font-weight: var(--font-weight-bold); // @presenter FontWeight
995
+ --page-403-title-line-height: 50px; // @presenter LineHeight
996
+
997
+ --page-403-description-text-color: var(--text-color-secondary); // @presenter Color
998
+ --page-403-description-font-size: var(--font-size-xl); // @presenter FontSize
999
+ --page-403-description-font-weight: var(--font-weight-regular); // @presenter FontWeight
1000
+ --page-403-description-line-height: var(--line-height-xl); // @presenter LineHeight
1001
+
1002
+ // @tokens End
1003
+
1004
+ /**
1005
+ * @tokens 403 Page OIDC Forbidden
1006
+ * @presenter Color
1007
+ */
974
1008
 
975
- --page-403-header-text-color: var(--h1-text-color);
1009
+ --page-403-header-text-color: var(--h1-text-color); // @presenter Color
976
1010
  --page-403-header-font-size: var(--h1-font-size); // @presenter FontSize
977
1011
  --page-403-header-font-weight: var(--h1-font-weight); // @presenter FontWeight
978
1012
  --page-403-header-line-height: var(--h1-line-height); // @presenter LineHeight
979
1013
  --page-403-header-margin: 0; // @presenter Spacing
980
-
981
- --page-403-description-text-color: var(--text-color-secondary);
982
- --page-403-description-font-size: 1.5em; // @presenter FontSize
983
- --page-403-description-font-weight: var(--font-weight-regular); // @presenter FontWeight
984
- --page-403-description-line-height: 1; // @presenter LineHeight
985
1014
  --page-403-description-margin: 0; // @presenter Spacing
986
-
987
- --page-403-button-margin: 4em; // @presenter Spacing
988
-
989
- --page-403-oidc-description-font-size: var(--font-size-lg);
990
- --page-403-oidc-description-margin: var(--spacing-md) var(--spacing-sm);
1015
+ --page-403-oidc-description-font-size: var(--font-size-lg); // @presenter FontSize
1016
+ --page-403-oidc-description-margin: var(--spacing-md) var(--spacing-sm); // @presenter Spacing
991
1017
 
992
1018
  // @tokens End
993
1019
 
@@ -1085,10 +1111,6 @@ const error = css`
1085
1111
  `;
1086
1112
 
1087
1113
  const modal = css`
1088
- body:has(.scroll-lock) {
1089
- overflow: hidden;
1090
- }
1091
-
1092
1114
  --modal-box-shadow: var(--bg-raised-shadow);
1093
1115
  --modal-bg-color: var(--bg-color);
1094
1116
  `;
@@ -1301,6 +1323,7 @@ export const styles = css`
1301
1323
  ${replay}
1302
1324
  ${skipContent}
1303
1325
  ${pageActions}
1326
+ ${svgViewer}
1304
1327
 
1305
1328
  background-color: var(--bg-color);
1306
1329
  color: var(--text-color-primary);
@@ -154,7 +154,7 @@ export type BffCatalogRelatedEntity = {
154
154
  key: string;
155
155
  title: string;
156
156
  summary?: string | null;
157
- readonly source: 'api' | 'file';
157
+ readonly source: 'remote' | 'file';
158
158
  relationRole: 'source' | 'target';
159
159
  relationType: EntityRelationType;
160
160
  sourceFile?: string | null;
@@ -28,6 +28,8 @@ import type {
28
28
  SearchFilterItem,
29
29
  SearchFacetQuery,
30
30
  AiSearchConversationItem,
31
+ ToolCallName,
32
+ ContentSegment,
31
33
  } from './search';
32
34
  import type { SubmitFeedbackParams } from './feedback';
33
35
  import type { TFunction } from './l10n';
@@ -127,6 +129,13 @@ export type ThemeHooks = {
127
129
  error: null | AiSearchError;
128
130
  conversation: AiSearchConversationItem[];
129
131
  setConversation: React.Dispatch<React.SetStateAction<AiSearchConversationItem[]>>;
132
+ toolCalls: Array<{
133
+ name: ToolCallName;
134
+ args: unknown;
135
+ position: number;
136
+ result?: { documentCount: number };
137
+ }>;
138
+ contentSegments: ContentSegment[];
130
139
  };
131
140
  useMarkdownText: (text: string) => React.ReactNode;
132
141
  useFacetQuery: (field: string) => {
@@ -177,7 +186,26 @@ export type ThemeHooks = {
177
186
  | 'startSpan'
178
187
  | 'constructCloudEvent'
179
188
  | 'sendToOtelService'
180
- >;
189
+ > & {
190
+ send<TEventType extends AsyncApiRealmUI.EventType>(
191
+ event: TEventType,
192
+ data?: AsyncApiRealmUI.EventPayload<TEventType>,
193
+ ): void;
194
+ /**
195
+ * @deprecated This method is deprecated. Use send(event, data) instead.
196
+ */
197
+ send<TEventType extends AsyncApiRealmUI.EventType>(
198
+ params: AsyncApiRealmUI.SendEventParams<TEventType>,
199
+ ): void;
200
+ };
201
+ /**
202
+ * @deprecated This hook is deprecated. Use `useTelemetry` instead.
203
+ */
204
+ useOtelTelemetry: () => {
205
+ send<TEventType extends AsyncApiRealmUI.EventType>(
206
+ params: AsyncApiRealmUI.SendEventParams<TEventType>,
207
+ ): void;
208
+ };
181
209
  useUserTeams: () => string[];
182
210
  usePageData: () => PageData | null;
183
211
  usePageSharedData: <T = unknown>(dataId: string) => T;
@@ -87,6 +87,7 @@ export type TranslationKey =
87
87
  | 'search.ai.newConversation'
88
88
  | 'search.ai.backToSearch'
89
89
  | 'search.ai.back'
90
+ | 'search.ai.assistant'
90
91
  | 'search.ai.placeholder'
91
92
  | 'search.ai.generatingResponse'
92
93
  | 'search.ai.followUpQuestion'
@@ -98,6 +99,9 @@ export type TranslationKey =
98
99
  | 'search.ai.feedback.title'
99
100
  | 'search.ai.feedback.detailsPlaceholder'
100
101
  | 'search.ai.feedback.thanks'
102
+ | 'search.ai.toolResult.found'
103
+ | 'search.ai.toolResult.found.documents'
104
+ | 'search.ai.toolCall.searching'
101
105
  | 'search.ai.button'
102
106
  | 'search.ai.label'
103
107
  | 'search.ai.disclaimer'
@@ -116,6 +120,7 @@ export type TranslationKey =
116
120
  | 'footer.copyrightText'
117
121
  | 'page.homeButton'
118
122
  | 'page.forbidden.title'
123
+ | 'page.forbidden.description'
119
124
  | 'page.notFound.title'
120
125
  | 'page.notFound.description'
121
126
  | 'page.lastUpdated.timeago'
@@ -198,6 +203,7 @@ export type TranslationKey =
198
203
  | 'feedback.settings.comment.label'
199
204
  | 'feedback.settings.comment.send'
200
205
  | 'feedback.settings.comment.cancel'
206
+ | 'feedback.settings.comment.maxLength'
201
207
  | 'feedback.settings.comment.satisfiedLabel'
202
208
  | 'feedback.settings.comment.neutralLabel'
203
209
  | 'feedback.settings.comment.dissatisfiedLabel'
@@ -412,7 +418,13 @@ export type TranslationKey =
412
418
  | 'select.noResults'
413
419
  | 'loaders.loading'
414
420
  | 'filter.dateRange.from'
415
- | 'filter.dateRange.to';
421
+ | 'filter.dateRange.to'
422
+ | 'mermaid.openFullscreen'
423
+ | 'mermaid.zoomIn'
424
+ | 'mermaid.zoomOut'
425
+ | 'mermaid.reset'
426
+ | 'mermaid.close'
427
+ | 'mermaid.viewer';
416
428
 
417
429
  export type Locale = { code: string; name: string };
418
430
 
@@ -104,10 +104,29 @@ export type SearchAiMessageResource = {
104
104
  title: string;
105
105
  };
106
106
 
107
+ export type ToolCall = {
108
+ name: ToolCallName;
109
+ args: unknown;
110
+ position: number;
111
+ result?: { documentCount: number };
112
+ };
113
+
114
+ export type ContentSegment = { type: 'text'; text: string } | { type: 'tool'; toolCall: ToolCall };
115
+
107
116
  export type AiSearchConversationItem = {
108
117
  role: AiSearchConversationRole;
109
118
  content: string;
110
119
  resources?: SearchAiMessageResource[];
111
120
  messageId?: string;
112
121
  feedback?: FeedbackType;
122
+ toolCalls?: ToolCall[];
123
+ contentSegments?: ContentSegment[];
113
124
  };
125
+
126
+ export enum ToolCallName {
127
+ SearchDocumentation = 'search_documentation',
128
+ ListApis = 'list-apis',
129
+ GetEndpoints = 'get-endpoints',
130
+ GetSecuritySchemes = 'get-security-schemes',
131
+ GetFullApiDescription = 'get-full-api-description',
132
+ }
@@ -0,0 +1,27 @@
1
+ import type { ToolCall, ContentSegment } from '../types/search';
2
+
3
+ export function splitContentByToolCalls(
4
+ content: string | undefined,
5
+ toolCalls: ToolCall[] | undefined,
6
+ ): ContentSegment[] {
7
+ if (!toolCalls || toolCalls.length === 0) {
8
+ return [{ type: 'text', text: content || '' }];
9
+ }
10
+
11
+ const segments: ContentSegment[] = [];
12
+ let lastPos = 0;
13
+
14
+ for (const toolCall of toolCalls) {
15
+ if (content && toolCall.position > lastPos) {
16
+ segments.push({ type: 'text', text: content.substring(lastPos, toolCall.position) });
17
+ }
18
+ segments.push({ type: 'tool', toolCall });
19
+ lastPos = toolCall.position;
20
+ }
21
+
22
+ if (content && lastPos < content.length) {
23
+ segments.push({ type: 'text', text: content.substring(lastPos) });
24
+ }
25
+
26
+ return segments;
27
+ }
@@ -43,3 +43,4 @@ export * from './get-operation-color';
43
43
  export * from './frontmatter-translate';
44
44
  export * from './transform-revisions-to-version-history';
45
45
  export * from './build-revision-url';
46
+ export * from './content-segments';