@redocly/theme 0.61.1 → 0.62.0-custom.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.d.ts +1 -0
- package/lib/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.js +12 -0
- package/lib/components/Badge/Badge.d.ts +2 -1
- package/lib/components/Badge/Badge.js +24 -2
- package/lib/components/Banner/Banner.js +19 -1
- package/lib/components/Banner/variables.js +1 -0
- package/lib/components/Breadcrumbs/Breadcrumb.js +1 -1
- package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +9 -6
- package/lib/components/Breadcrumbs/Breadcrumbs.js +24 -15
- package/lib/components/Buttons/AIAssistantButton.js +7 -4
- package/lib/components/Catalog/CatalogEntities.js +10 -8
- package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +2 -2
- package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.js +2 -2
- package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.js +13 -11
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +7 -5
- package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +9 -7
- package/lib/components/Catalog/CatalogTableView/CatalogTableViewRow.js +1 -1
- package/lib/components/Catalog/CatalogTagsWithTooltip.js +2 -2
- package/lib/components/CatalogClassic/CatalogClassicInfoBlock.js +1 -1
- package/lib/components/CodeBlock/CodeBlockControls.js +8 -6
- package/lib/components/Filter/FilterCheckboxes.js +1 -1
- package/lib/components/JsonViewer/JsonViewer.js +2 -2
- package/lib/components/JsonViewer/{Helpers.js → helpers.js} +2 -1
- package/lib/components/LanguagePicker/LanguagePicker.js +1 -1
- package/lib/components/Markdown/Markdown.js +2 -2
- package/lib/components/Menu/MenuItem.js +41 -15
- package/lib/components/Navbar/NavbarItem.js +1 -1
- package/lib/components/OpenApiDocs/hooks/AdditionalOverviewInfo.d.ts +1 -0
- package/lib/components/OpenApiDocs/hooks/AdditionalOverviewInfo.js +12 -0
- package/lib/components/OpenApiDocs/hooks/AfterOpenApiDescription.d.ts +1 -0
- package/lib/components/OpenApiDocs/hooks/AfterOpenApiDescription.js +6 -0
- package/lib/components/PageActions/PageActions.js +25 -8
- package/lib/components/Search/SearchAiDialog.d.ts +4 -2
- package/lib/components/Search/SearchAiDialog.js +23 -4
- package/lib/components/Search/SearchAiMessage.d.ts +4 -2
- package/lib/components/Search/SearchAiMessage.js +82 -23
- package/lib/components/Search/SearchDialog.js +50 -25
- package/lib/components/Select/variables.js +2 -2
- package/lib/components/SvgViewer/SvgViewer.d.ts +15 -0
- package/lib/components/SvgViewer/SvgViewer.js +312 -0
- package/lib/components/SvgViewer/variables.d.ts +1 -0
- package/lib/components/SvgViewer/variables.dark.d.ts +1 -0
- package/lib/components/SvgViewer/variables.dark.js +8 -0
- package/lib/components/SvgViewer/variables.js +17 -0
- package/lib/components/Tag/Tag.js +1 -1
- package/lib/components/Tag/variables.dark.js +6 -0
- package/lib/components/Tag/variables.js +6 -0
- package/lib/components/Tooltip/Tooltip.d.ts +2 -3
- package/lib/components/Tooltip/Tooltip.js +66 -113
- package/lib/components/Tooltip/variables.dark.js +4 -0
- package/lib/components/Tooltip/variables.js +3 -3
- package/lib/components/UserMenu/LoginButton.d.ts +8 -2
- package/lib/components/UserMenu/LoginButton.js +4 -3
- package/lib/core/constants/search.d.ts +5 -1
- package/lib/core/constants/search.js +24 -1
- package/lib/core/hooks/search/use-search-dialog.js +2 -2
- package/lib/core/hooks/use-color-switcher.js +3 -1
- package/lib/core/hooks/use-mcp-config.js +2 -1
- package/lib/core/hooks/use-modal-scroll-lock.js +24 -10
- package/lib/core/hooks/use-outside-click.d.ts +3 -1
- package/lib/core/hooks/use-outside-click.js +8 -4
- package/lib/core/hooks/use-page-actions.d.ts +1 -1
- package/lib/core/hooks/use-page-actions.js +44 -11
- package/lib/core/hooks/use-product-picker.js +1 -1
- package/lib/core/hooks/use-unique-svg-ids.d.ts +6 -0
- package/lib/core/hooks/use-unique-svg-ids.js +15 -0
- package/lib/core/openapi/index.d.ts +1 -0
- package/lib/core/openapi/index.js +3 -1
- package/lib/core/styles/dark.js +2 -0
- package/lib/core/styles/global.js +31 -15
- package/lib/core/types/catalog.d.ts +1 -1
- package/lib/core/types/hooks.d.ts +23 -2
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/search.d.ts +24 -0
- package/lib/core/types/search.js +9 -1
- package/lib/core/utils/content-segments.d.ts +2 -0
- package/lib/core/utils/content-segments.js +22 -0
- package/lib/core/utils/index.d.ts +1 -0
- package/lib/core/utils/index.js +1 -0
- package/lib/core/utils/transform-revisions-to-version-history.js +8 -51
- package/lib/ext/process-scorecard.d.ts +5 -0
- package/lib/ext/process-scorecard.js +11 -0
- package/lib/icons/FitToViewIcon/FitToViewIcon.d.ts +9 -0
- package/lib/icons/FitToViewIcon/FitToViewIcon.js +25 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +8 -0
- package/lib/layouts/DocumentationLayout.js +4 -25
- package/lib/layouts/DocumentationLayoutBottom.d.ts +11 -0
- package/lib/layouts/DocumentationLayoutBottom.js +28 -0
- package/lib/layouts/DocumentationLayoutTop.d.ts +13 -0
- package/lib/layouts/DocumentationLayoutTop.js +33 -0
- package/lib/layouts/Forbidden.js +22 -18
- package/lib/markdoc/components/Cards/Card.js +1 -0
- package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +1 -1
- package/lib/markdoc/components/Heading/Heading.js +40 -2
- package/lib/markdoc/components/LoginButton/LoginButton.d.ts +9 -0
- package/lib/markdoc/components/LoginButton/LoginButton.js +48 -0
- package/lib/markdoc/components/Mermaid/Mermaid.js +70 -2
- package/lib/markdoc/components/default.d.ts +1 -0
- package/lib/markdoc/components/default.js +1 -0
- package/lib/markdoc/default.d.ts +6 -0
- package/lib/markdoc/default.js +2 -0
- package/lib/markdoc/tags/login-button.d.ts +2 -0
- package/lib/markdoc/tags/login-button.js +32 -0
- package/package.json +8 -8
- package/src/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.tsx +10 -0
- package/src/components/Badge/Badge.tsx +18 -2
- package/src/components/Banner/Banner.tsx +23 -1
- package/src/components/Banner/variables.ts +1 -0
- package/src/components/Breadcrumbs/Breadcrumb.tsx +3 -3
- package/src/components/Breadcrumbs/BreadcrumbDropdown.tsx +11 -8
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +24 -15
- package/src/components/Buttons/AIAssistantButton.tsx +7 -4
- package/src/components/Catalog/CatalogEntities.tsx +10 -8
- package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +1 -2
- package/src/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.tsx +13 -11
- package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +7 -5
- package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +9 -7
- package/src/components/Catalog/CatalogTableView/CatalogTableViewRow.tsx +1 -2
- package/src/components/Catalog/CatalogTagsWithTooltip.tsx +9 -5
- package/src/components/CatalogClassic/CatalogClassicInfoBlock.tsx +3 -1
- package/src/components/CodeBlock/CodeBlockControls.tsx +16 -10
- package/src/components/Filter/FilterCheckboxes.tsx +1 -1
- package/src/components/JsonViewer/JsonViewer.tsx +1 -2
- package/src/components/JsonViewer/{Helpers.tsx → helpers.tsx} +1 -0
- package/src/components/LanguagePicker/LanguagePicker.tsx +1 -1
- package/src/components/Markdown/Markdown.tsx +2 -2
- package/src/components/Menu/MenuItem.tsx +61 -16
- package/src/components/Navbar/NavbarItem.tsx +3 -1
- package/src/components/OpenApiDocs/hooks/AdditionalOverviewInfo.tsx +10 -0
- package/src/components/OpenApiDocs/hooks/AfterOpenApiDescription.tsx +2 -0
- package/src/components/PageActions/PageActions.tsx +38 -15
- package/src/components/Search/SearchAiDialog.tsx +31 -2
- package/src/components/Search/SearchAiMessage.tsx +103 -17
- package/src/components/Search/SearchDialog.tsx +70 -37
- package/src/components/Select/variables.ts +2 -2
- package/src/components/SvgViewer/SvgViewer.tsx +405 -0
- package/src/components/SvgViewer/variables.dark.ts +5 -0
- package/src/components/SvgViewer/variables.ts +14 -0
- package/src/components/Tag/Tag.tsx +2 -1
- package/src/components/Tag/variables.dark.ts +6 -0
- package/src/components/Tag/variables.ts +6 -0
- package/src/components/Tooltip/Tooltip.tsx +77 -120
- package/src/components/Tooltip/variables.dark.ts +4 -0
- package/src/components/Tooltip/variables.ts +3 -3
- package/src/components/UserMenu/LoginButton.tsx +23 -8
- package/src/core/constants/search.ts +27 -1
- package/src/core/hooks/__mocks__/use-theme-hooks.ts +10 -1
- package/src/core/hooks/search/use-search-dialog.ts +2 -2
- package/src/core/hooks/use-color-switcher.ts +3 -1
- package/src/core/hooks/use-mcp-config.ts +2 -1
- package/src/core/hooks/use-modal-scroll-lock.ts +29 -10
- package/src/core/hooks/use-outside-click.ts +16 -5
- package/src/core/hooks/use-page-actions.ts +66 -25
- package/src/core/hooks/use-product-picker.ts +1 -1
- package/src/core/hooks/use-unique-svg-ids.ts +12 -0
- package/src/core/openapi/index.ts +1 -0
- package/src/core/styles/dark.ts +2 -0
- package/src/core/styles/global.ts +31 -15
- package/src/core/types/catalog.ts +1 -1
- package/src/core/types/hooks.ts +29 -1
- package/src/core/types/l10n.ts +12 -1
- package/src/core/types/search.ts +19 -0
- package/src/core/utils/content-segments.ts +27 -0
- package/src/core/utils/index.ts +1 -0
- package/src/core/utils/transform-revisions-to-version-history.ts +8 -80
- package/src/ext/process-scorecard.ts +14 -0
- package/src/icons/FitToViewIcon/FitToViewIcon.tsx +26 -0
- package/src/index.ts +8 -0
- package/src/layouts/DocumentationLayout.tsx +4 -30
- package/src/layouts/DocumentationLayoutBottom.tsx +42 -0
- package/src/layouts/DocumentationLayoutTop.tsx +52 -0
- package/src/layouts/Forbidden.tsx +36 -21
- package/src/markdoc/components/Cards/Card.tsx +1 -0
- package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +1 -1
- package/src/markdoc/components/Heading/Heading.tsx +52 -4
- package/src/markdoc/components/LoginButton/LoginButton.tsx +38 -0
- package/src/markdoc/components/Mermaid/Mermaid.tsx +57 -8
- package/src/markdoc/components/default.ts +1 -0
- package/src/markdoc/default.ts +2 -0
- package/src/markdoc/tags/login-button.ts +30 -0
- package/lib/components/Tooltip/TooltipWrapper.d.ts +0 -12
- package/lib/components/Tooltip/TooltipWrapper.js +0 -34
- package/src/components/Tooltip/TooltipWrapper.tsx +0 -70
- /package/lib/components/JsonViewer/{Helpers.d.ts → helpers.d.ts} +0 -0
|
@@ -32,6 +32,7 @@ const DEFAULT_ENABLED_ACTIONS = [
|
|
|
32
32
|
'claude',
|
|
33
33
|
'docs-mcp-cursor',
|
|
34
34
|
'docs-mcp-vscode',
|
|
35
|
+
'docs-mcp-json',
|
|
35
36
|
] as const;
|
|
36
37
|
|
|
37
38
|
export type PageActionType =
|
|
@@ -41,6 +42,7 @@ export type PageActionType =
|
|
|
41
42
|
| 'claude'
|
|
42
43
|
| 'docs-mcp-cursor'
|
|
43
44
|
| 'docs-mcp-vscode'
|
|
45
|
+
| 'docs-mcp-json'
|
|
44
46
|
| 'mcp-cursor'
|
|
45
47
|
| 'mcp-vscode';
|
|
46
48
|
|
|
@@ -88,10 +90,12 @@ export function usePageActions(
|
|
|
88
90
|
translate,
|
|
89
91
|
onClickCallback: isDocsMcp
|
|
90
92
|
? () =>
|
|
91
|
-
telemetry.sendPageActionsButtonClickedMessage(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
telemetry.sendPageActionsButtonClickedMessage([
|
|
94
|
+
{
|
|
95
|
+
...createPageActionResource(pageSlug, pageUrl),
|
|
96
|
+
action_type: `docs-mcp-${clientType}` as const,
|
|
97
|
+
},
|
|
98
|
+
])
|
|
95
99
|
: undefined,
|
|
96
100
|
});
|
|
97
101
|
},
|
|
@@ -99,7 +103,7 @@ export function usePageActions(
|
|
|
99
103
|
);
|
|
100
104
|
|
|
101
105
|
const result: PageAction[] = useMemo(() => {
|
|
102
|
-
if (shouldHideAllActions) {
|
|
106
|
+
if (shouldHideAllActions && !actions?.length) {
|
|
103
107
|
return [];
|
|
104
108
|
}
|
|
105
109
|
|
|
@@ -131,10 +135,12 @@ export function usePageActions(
|
|
|
131
135
|
}
|
|
132
136
|
const text = await result.text();
|
|
133
137
|
ClipboardService.copyCustom(text);
|
|
134
|
-
telemetry.sendPageActionsButtonClickedMessage(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
telemetry.sendPageActionsButtonClickedMessage([
|
|
139
|
+
{
|
|
140
|
+
...createPageActionResource(pageSlug, pageUrl),
|
|
141
|
+
action_type: 'copy',
|
|
142
|
+
},
|
|
143
|
+
]);
|
|
138
144
|
} catch (error) {
|
|
139
145
|
console.error(error);
|
|
140
146
|
}
|
|
@@ -148,10 +154,13 @@ export function usePageActions(
|
|
|
148
154
|
iconComponent: MarkdownFullIcon,
|
|
149
155
|
link: mdPageUrl,
|
|
150
156
|
onClick: () => {
|
|
151
|
-
telemetry.sendPageActionsButtonClickedMessage(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
telemetry.sendPageActionsButtonClickedMessage([
|
|
158
|
+
{
|
|
159
|
+
...createPageActionResource(pageSlug, pageUrl),
|
|
160
|
+
action_type: 'view',
|
|
161
|
+
},
|
|
162
|
+
]);
|
|
163
|
+
window.location.href = mdPageUrl;
|
|
155
164
|
},
|
|
156
165
|
}),
|
|
157
166
|
|
|
@@ -159,17 +168,21 @@ export function usePageActions(
|
|
|
159
168
|
if (!isPublic) {
|
|
160
169
|
return null;
|
|
161
170
|
}
|
|
171
|
+
const link = getExternalAiPromptLink('https://chat.openai.com', mdPageUrl);
|
|
162
172
|
return {
|
|
163
173
|
buttonText: translate('page.actions.chatGptButtonText', 'Open in ChatGPT'),
|
|
164
174
|
title: translate('page.actions.chatGptTitle', 'Open in ChatGPT'),
|
|
165
175
|
description: translate('page.actions.chatGptDescription', 'Get insights from ChatGPT'),
|
|
166
176
|
iconComponent: ChatGptIcon,
|
|
167
|
-
link
|
|
177
|
+
link,
|
|
168
178
|
onClick: () => {
|
|
169
|
-
telemetry.sendPageActionsButtonClickedMessage(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
telemetry.sendPageActionsButtonClickedMessage([
|
|
180
|
+
{
|
|
181
|
+
...createPageActionResource(pageSlug, pageUrl),
|
|
182
|
+
action_type: 'chatgpt',
|
|
183
|
+
},
|
|
184
|
+
]);
|
|
185
|
+
window.location.href = link;
|
|
173
186
|
},
|
|
174
187
|
};
|
|
175
188
|
},
|
|
@@ -178,17 +191,43 @@ export function usePageActions(
|
|
|
178
191
|
if (!isPublic) {
|
|
179
192
|
return null;
|
|
180
193
|
}
|
|
194
|
+
const link = getExternalAiPromptLink('https://claude.ai/new', mdPageUrl);
|
|
181
195
|
return {
|
|
182
196
|
buttonText: translate('page.actions.claudeButtonText', 'Open in Claude'),
|
|
183
197
|
title: translate('page.actions.claudeTitle', 'Open in Claude'),
|
|
184
198
|
description: translate('page.actions.claudeDescription', 'Get insights from Claude'),
|
|
185
199
|
iconComponent: ClaudeIcon,
|
|
186
|
-
link
|
|
200
|
+
link,
|
|
187
201
|
onClick: () => {
|
|
188
|
-
telemetry.sendPageActionsButtonClickedMessage(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
telemetry.sendPageActionsButtonClickedMessage([
|
|
203
|
+
{
|
|
204
|
+
...createPageActionResource(pageSlug, pageUrl),
|
|
205
|
+
action_type: 'claude',
|
|
206
|
+
},
|
|
207
|
+
]);
|
|
208
|
+
window.location.href = link;
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
'docs-mcp-json': () => {
|
|
213
|
+
return {
|
|
214
|
+
buttonText: 'Copy MCP configuration',
|
|
215
|
+
title: 'Copy MCP JSON configuration',
|
|
216
|
+
description: 'Copy MCP JSON configuration',
|
|
217
|
+
iconComponent: CopyIcon,
|
|
218
|
+
onClick: async () => {
|
|
219
|
+
ClipboardService.copyCustom(
|
|
220
|
+
JSON.stringify(
|
|
221
|
+
{
|
|
222
|
+
'mcp-server': {
|
|
223
|
+
url: mcpUrl,
|
|
224
|
+
description: 'MCP Server',
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
null,
|
|
228
|
+
2,
|
|
229
|
+
),
|
|
230
|
+
);
|
|
192
231
|
},
|
|
193
232
|
};
|
|
194
233
|
},
|
|
@@ -205,6 +244,7 @@ export function usePageActions(
|
|
|
205
244
|
translate,
|
|
206
245
|
isPublic,
|
|
207
246
|
createMCPHandler,
|
|
247
|
+
mcpUrl,
|
|
208
248
|
telemetry,
|
|
209
249
|
]);
|
|
210
250
|
|
|
@@ -280,9 +320,10 @@ function shouldHidePageActions(
|
|
|
280
320
|
}
|
|
281
321
|
|
|
282
322
|
// Page is excluded from search
|
|
323
|
+
const isOpenApiPage =
|
|
324
|
+
pageProps?.metadata?.type === 'openapi' || pageProps?.metadata?.subType === 'openapi-operation';
|
|
283
325
|
const isPageExcludedFromSearch =
|
|
284
|
-
pageProps?.frontmatter?.excludeFromSearch ||
|
|
285
|
-
(pageProps?.metadata?.type === 'openapi' && openapiExcludeFromSearch);
|
|
326
|
+
pageProps?.frontmatter?.excludeFromSearch || (isOpenApiPage && openapiExcludeFromSearch);
|
|
286
327
|
|
|
287
328
|
if (isPageExcludedFromSearch) {
|
|
288
329
|
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,4 @@ 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';
|
package/src/core/styles/dark.ts
CHANGED
|
@@ -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
|
/**
|
|
@@ -332,6 +333,7 @@ export const darkMode = css`
|
|
|
332
333
|
${tooltipDarkMode}
|
|
333
334
|
${bannerDarkMode}
|
|
334
335
|
${admonitionDarkMode}
|
|
336
|
+
${svgViewerDarkMode}
|
|
335
337
|
|
|
336
338
|
/**
|
|
337
339
|
* @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
|
|
|
@@ -971,23 +972,41 @@ const pages = css`
|
|
|
971
972
|
*/
|
|
972
973
|
|
|
973
974
|
--page-403-font-family: var(--font-family-base); // @presenter FontFamily
|
|
975
|
+
--page-403-margin-vertical: var(--spacing-xl); // @presenter Spacing
|
|
976
|
+
--page-403-margin-horizontal: calc(var(--spacing-xxl) * 2); // @presenter Spacing
|
|
977
|
+
--page-403-gap: var(--spacing-lg); // @presenter Spacing
|
|
978
|
+
--page-403-max-width: 680px; // @presenter Width
|
|
979
|
+
|
|
980
|
+
--page-403-status-text-color: var(--text-color-helper); // @presenter Color
|
|
981
|
+
--page-403-status-font-size: var(--font-size-lg); // @presenter FontSize
|
|
982
|
+
--page-403-status-font-weight: var(--font-weight-semibold); // @presenter FontWeight
|
|
983
|
+
--page-403-status-line-height: var(--line-height-lg); // @presenter LineHeight
|
|
984
|
+
|
|
985
|
+
--page-403-title-text-color: var(--text-color-primary); // @presenter Color
|
|
986
|
+
--page-403-title-font-size: 42px; // @presenter FontSize
|
|
987
|
+
--page-403-title-font-weight: var(--font-weight-bold); // @presenter FontWeight
|
|
988
|
+
--page-403-title-line-height: 50px; // @presenter LineHeight
|
|
989
|
+
|
|
990
|
+
--page-403-description-text-color: var(--text-color-secondary); // @presenter Color
|
|
991
|
+
--page-403-description-font-size: var(--font-size-xl); // @presenter FontSize
|
|
992
|
+
--page-403-description-font-weight: var(--font-weight-regular); // @presenter FontWeight
|
|
993
|
+
--page-403-description-line-height: var(--line-height-xl); // @presenter LineHeight
|
|
994
|
+
|
|
995
|
+
// @tokens End
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
* @tokens 403 Page OIDC Forbidden
|
|
999
|
+
* @presenter Color
|
|
1000
|
+
*/
|
|
974
1001
|
|
|
975
|
-
--page-403-header-text-color: var(--h1-text-color);
|
|
1002
|
+
--page-403-header-text-color: var(--h1-text-color); // @presenter Color
|
|
976
1003
|
--page-403-header-font-size: var(--h1-font-size); // @presenter FontSize
|
|
977
1004
|
--page-403-header-font-weight: var(--h1-font-weight); // @presenter FontWeight
|
|
978
1005
|
--page-403-header-line-height: var(--h1-line-height); // @presenter LineHeight
|
|
979
1006
|
--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
1007
|
--page-403-description-margin: 0; // @presenter Spacing
|
|
986
|
-
|
|
987
|
-
--page-403-
|
|
988
|
-
|
|
989
|
-
--page-403-oidc-description-font-size: var(--font-size-lg);
|
|
990
|
-
--page-403-oidc-description-margin: var(--spacing-md) var(--spacing-sm);
|
|
1008
|
+
--page-403-oidc-description-font-size: var(--font-size-lg); // @presenter FontSize
|
|
1009
|
+
--page-403-oidc-description-margin: var(--spacing-md) var(--spacing-sm); // @presenter Spacing
|
|
991
1010
|
|
|
992
1011
|
// @tokens End
|
|
993
1012
|
|
|
@@ -1085,10 +1104,6 @@ const error = css`
|
|
|
1085
1104
|
`;
|
|
1086
1105
|
|
|
1087
1106
|
const modal = css`
|
|
1088
|
-
body:has(.scroll-lock) {
|
|
1089
|
-
overflow: hidden;
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
1107
|
--modal-box-shadow: var(--bg-raised-shadow);
|
|
1093
1108
|
--modal-bg-color: var(--bg-color);
|
|
1094
1109
|
`;
|
|
@@ -1301,6 +1316,7 @@ export const styles = css`
|
|
|
1301
1316
|
${replay}
|
|
1302
1317
|
${skipContent}
|
|
1303
1318
|
${pageActions}
|
|
1319
|
+
${svgViewer}
|
|
1304
1320
|
|
|
1305
1321
|
background-color: var(--bg-color);
|
|
1306
1322
|
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: '
|
|
157
|
+
readonly source: 'remote' | 'file';
|
|
158
158
|
relationRole: 'source' | 'target';
|
|
159
159
|
relationType: EntityRelationType;
|
|
160
160
|
sourceFile?: string | null;
|
package/src/core/types/hooks.ts
CHANGED
|
@@ -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;
|
package/src/core/types/l10n.ts
CHANGED
|
@@ -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'
|
|
@@ -412,7 +417,13 @@ export type TranslationKey =
|
|
|
412
417
|
| 'select.noResults'
|
|
413
418
|
| 'loaders.loading'
|
|
414
419
|
| 'filter.dateRange.from'
|
|
415
|
-
| 'filter.dateRange.to'
|
|
420
|
+
| 'filter.dateRange.to'
|
|
421
|
+
| 'mermaid.openFullscreen'
|
|
422
|
+
| 'mermaid.zoomIn'
|
|
423
|
+
| 'mermaid.zoomOut'
|
|
424
|
+
| 'mermaid.reset'
|
|
425
|
+
| 'mermaid.close'
|
|
426
|
+
| 'mermaid.viewer';
|
|
416
427
|
|
|
417
428
|
export type Locale = { code: string; name: string };
|
|
418
429
|
|
package/src/core/types/search.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/core/utils/index.ts
CHANGED
|
@@ -8,72 +8,6 @@ import { VERSION_NOT_SPECIFIED } from '@redocly/theme/core/constants';
|
|
|
8
8
|
|
|
9
9
|
import { toLocalizedShortDate, toLocalizedShortDateTime } from './date';
|
|
10
10
|
|
|
11
|
-
function compareVersionsDescending(versionA: string, versionB: string): number {
|
|
12
|
-
return versionB.localeCompare(versionA, undefined, { numeric: true });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function extractGroupComparisonData(group: CatalogEntityVersionHistoryGroup): {
|
|
16
|
-
version: string;
|
|
17
|
-
isNotSpecified: boolean;
|
|
18
|
-
time: number;
|
|
19
|
-
hasCurrent: boolean;
|
|
20
|
-
} {
|
|
21
|
-
const version = group.version;
|
|
22
|
-
const isNotSpecified = version === VERSION_NOT_SPECIFIED;
|
|
23
|
-
|
|
24
|
-
// Get version dates (oldest revision date for each group - the version's creation date)
|
|
25
|
-
// This ensures versions stay in their original order even when new revisions are added
|
|
26
|
-
const date =
|
|
27
|
-
group.singleRevisionDate ||
|
|
28
|
-
(group.revisions && group.revisions.length > 0
|
|
29
|
-
? group.revisions[group.revisions.length - 1]?.revisionDate
|
|
30
|
-
: undefined) ||
|
|
31
|
-
'';
|
|
32
|
-
const time = date ? new Date(date).getTime() : 0;
|
|
33
|
-
|
|
34
|
-
const hasCurrent = group.hasCurrentRevisionFromBackend ?? false;
|
|
35
|
-
|
|
36
|
-
return { version, isNotSpecified, time, hasCurrent };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function compareVersionGroupsDescending(
|
|
40
|
-
groupA: CatalogEntityVersionHistoryGroup,
|
|
41
|
-
groupB: CatalogEntityVersionHistoryGroup,
|
|
42
|
-
): number {
|
|
43
|
-
const {
|
|
44
|
-
version: versionA,
|
|
45
|
-
isNotSpecified: isNotSpecifiedA,
|
|
46
|
-
time: timeA,
|
|
47
|
-
hasCurrent: hasCurrentA,
|
|
48
|
-
} = extractGroupComparisonData(groupA);
|
|
49
|
-
const {
|
|
50
|
-
version: versionB,
|
|
51
|
-
isNotSpecified: isNotSpecifiedB,
|
|
52
|
-
time: timeB,
|
|
53
|
-
hasCurrent: hasCurrentB,
|
|
54
|
-
} = extractGroupComparisonData(groupB);
|
|
55
|
-
|
|
56
|
-
// First, compare by version date (oldest first, so most recent versions come first)
|
|
57
|
-
const dateComparison = timeB - timeA;
|
|
58
|
-
if (dateComparison !== 0) {
|
|
59
|
-
return dateComparison;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// If dates are equal, prioritize the one with isCurrent from backend
|
|
63
|
-
if (hasCurrentA !== hasCurrentB) {
|
|
64
|
-
return hasCurrentB ? 1 : -1; // hasCurrentB comes first if true
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// If both have same isCurrent status, compare by version
|
|
68
|
-
// If both are unknown or both are real versions, compare by version
|
|
69
|
-
if (isNotSpecifiedA === isNotSpecifiedB) {
|
|
70
|
-
return compareVersionsDescending(versionA, versionB);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// If one is unknown and one is a real version, unknown comes last
|
|
74
|
-
return isNotSpecifiedA ? 1 : -1;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
11
|
export type TransformRevisionsToVersionHistoryParams = {
|
|
78
12
|
revisions: BffCatalogEntityRevision[];
|
|
79
13
|
currentRevisionDate?: string;
|
|
@@ -100,13 +34,7 @@ export function transformRevisionsToVersionHistory({
|
|
|
100
34
|
});
|
|
101
35
|
|
|
102
36
|
const versionGroups = Array.from(versionMap.entries()).map(([version, versionRevisions]) => {
|
|
103
|
-
const
|
|
104
|
-
const dateA = a.revision ? new Date(a.revision).getTime() : 0;
|
|
105
|
-
const dateB = b.revision ? new Date(b.revision).getTime() : 0;
|
|
106
|
-
return dateB - dateA;
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
const latestRevision = sortedRevisions[0];
|
|
37
|
+
const latestRevision = versionRevisions[0];
|
|
110
38
|
|
|
111
39
|
const versionMatches =
|
|
112
40
|
normalizedCurrentVersion === undefined || normalizedCurrentVersion === version;
|
|
@@ -114,7 +42,7 @@ export function transformRevisionsToVersionHistory({
|
|
|
114
42
|
let isCurrent: boolean;
|
|
115
43
|
if (currentRevisionDate !== undefined) {
|
|
116
44
|
// Check if revision matches AND version matches
|
|
117
|
-
const revisionMatches =
|
|
45
|
+
const revisionMatches = versionRevisions.some((rev) => rev.revision === currentRevisionDate);
|
|
118
46
|
isCurrent = revisionMatches && versionMatches;
|
|
119
47
|
} else {
|
|
120
48
|
// When no revision is specified, use isCurrent flag from the latest revision
|
|
@@ -123,11 +51,11 @@ export function transformRevisionsToVersionHistory({
|
|
|
123
51
|
}
|
|
124
52
|
|
|
125
53
|
// Check if any revision in this version group is the default version
|
|
126
|
-
const isDefaultVersion =
|
|
54
|
+
const isDefaultVersion = versionRevisions.some((rev) => rev.isDefaultVersion === true);
|
|
127
55
|
|
|
128
56
|
const revisions =
|
|
129
|
-
|
|
130
|
-
?
|
|
57
|
+
versionRevisions.length > 1
|
|
58
|
+
? versionRevisions.map((rev, index): CatalogEntityRevision => {
|
|
131
59
|
const revisionMatches = currentRevisionDate
|
|
132
60
|
? rev.revision === currentRevisionDate
|
|
133
61
|
: false;
|
|
@@ -138,7 +66,7 @@ export function transformRevisionsToVersionHistory({
|
|
|
138
66
|
index === 0 &&
|
|
139
67
|
isCurrent;
|
|
140
68
|
return {
|
|
141
|
-
name: `r.${
|
|
69
|
+
name: `r.${versionRevisions.length - index}`,
|
|
142
70
|
date: toLocalizedShortDateTime(rev.revision, locale),
|
|
143
71
|
revisionDate: rev.revision,
|
|
144
72
|
isActive: isActiveRevision || isCurrentByDefault,
|
|
@@ -155,9 +83,9 @@ export function transformRevisionsToVersionHistory({
|
|
|
155
83
|
hasCurrentRevisionFromBackend: latestRevision?.isCurrent ?? false,
|
|
156
84
|
isDefaultVersion,
|
|
157
85
|
revisions,
|
|
158
|
-
singleRevisionDate:
|
|
86
|
+
singleRevisionDate: versionRevisions.length === 1 ? versionRevisions[0]?.revision : undefined,
|
|
159
87
|
};
|
|
160
88
|
});
|
|
161
89
|
|
|
162
|
-
return versionGroups
|
|
90
|
+
return versionGroups;
|
|
163
91
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { CatalogItem } from '@redocly/theme';
|
|
4
|
+
|
|
5
|
+
export function useProcessScorecard(): {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
processScorecard: <T = any>(scorecard: T, api: CatalogItem) => T;
|
|
8
|
+
processInfo: <T>(info: T) => T;
|
|
9
|
+
} {
|
|
10
|
+
return {
|
|
11
|
+
processScorecard: useCallback((scorecard) => scorecard, []),
|
|
12
|
+
processInfo: useCallback((info) => info, []),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import type { IconProps } from '@redocly/theme/icons/types';
|
|
5
|
+
|
|
6
|
+
import { getCssColorVariable } from '@redocly/theme/core/utils';
|
|
7
|
+
|
|
8
|
+
const Icon = (props: IconProps) => (
|
|
9
|
+
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
|
10
|
+
<path d="M1 1H5V2.5H2.5V5H1V1Z" />
|
|
11
|
+
<path d="M15 1H11V2.5H13.5V5H15V1Z" />
|
|
12
|
+
<path d="M1 15H5V13.5H2.5V11H1V15Z" />
|
|
13
|
+
<path d="M15 15H11V13.5H13.5V11H15V15Z" />
|
|
14
|
+
</svg>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export const FitToViewIcon = styled(Icon).attrs(() => ({
|
|
18
|
+
'data-component-name': 'icons/FitToViewIcon/FitToViewIcon',
|
|
19
|
+
}))<IconProps>`
|
|
20
|
+
path {
|
|
21
|
+
fill: ${({ color }) => getCssColorVariable(color)};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
height: ${({ size }) => size || '16px'};
|
|
25
|
+
width: ${({ size }) => size || '16px'};
|
|
26
|
+
`;
|