@redocly/theme 0.58.0-next.8 → 0.58.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.
Files changed (56) hide show
  1. package/lib/components/Catalog/CatalogEntity/CatalogEntity.d.ts +5 -1
  2. package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +4 -4
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +3 -3
  4. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.d.ts +5 -1
  5. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +9 -7
  6. package/lib/components/CatalogClassic/CatalogClassic.js +9 -2
  7. package/lib/components/CodeBlock/CodeBlock.d.ts +5 -12
  8. package/lib/components/CodeBlock/CodeBlockControls.d.ts +3 -3
  9. package/lib/components/CodeBlock/CodeBlockControls.js +1 -1
  10. package/lib/components/CodeBlock/CodeBlockDropdown.d.ts +2 -2
  11. package/lib/components/CodeBlock/CodeBlockDropdown.js +4 -13
  12. package/lib/components/CodeBlock/CodeBlockTabs.d.ts +2 -2
  13. package/lib/components/CodeBlock/CodeBlockTabs.js +4 -3
  14. package/lib/components/JsonViewer/JsonViewer.d.ts +1 -1
  15. package/lib/components/JsonViewer/JsonViewer.js +9 -10
  16. package/lib/components/PageActions/PageActions.d.ts +4 -1
  17. package/lib/components/PageActions/PageActions.js +2 -2
  18. package/lib/core/constants/catalog.js +4 -0
  19. package/lib/core/contexts/CodeSnippetContext.d.ts +14 -6
  20. package/lib/core/contexts/CodeSnippetContext.js +57 -14
  21. package/lib/core/hooks/use-codeblock-tabs-controls.d.ts +2 -2
  22. package/lib/core/hooks/use-local-state.js +22 -18
  23. package/lib/core/hooks/use-page-actions.d.ts +2 -1
  24. package/lib/core/hooks/use-page-actions.js +48 -6
  25. package/lib/core/openapi/index.d.ts +1 -0
  26. package/lib/core/openapi/index.js +3 -1
  27. package/lib/core/types/l10n.d.ts +1 -1
  28. package/lib/core/types/open-api-server.d.ts +1 -0
  29. package/lib/icons/CursorIcon/CursorIcon.d.ts +9 -0
  30. package/lib/icons/CursorIcon/CursorIcon.js +22 -0
  31. package/lib/layouts/DocumentationLayout.js +1 -3
  32. package/lib/markdoc/components/CodeGroup/CodeGroup.js +49 -27
  33. package/lib/markdoc/components/Tabs/TabList.js +2 -0
  34. package/package.json +4 -4
  35. package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +15 -2
  36. package/src/components/Catalog/CatalogEntity/CatalogEntityMetadata.tsx +3 -3
  37. package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +27 -18
  38. package/src/components/CatalogClassic/CatalogClassic.tsx +26 -10
  39. package/src/components/CodeBlock/CodeBlock.tsx +5 -11
  40. package/src/components/CodeBlock/CodeBlockControls.tsx +4 -7
  41. package/src/components/CodeBlock/CodeBlockDropdown.tsx +11 -20
  42. package/src/components/CodeBlock/CodeBlockTabs.tsx +8 -8
  43. package/src/components/JsonViewer/JsonViewer.tsx +16 -9
  44. package/src/components/PageActions/PageActions.tsx +6 -4
  45. package/src/core/constants/catalog.ts +4 -0
  46. package/src/core/contexts/CodeSnippetContext.tsx +54 -18
  47. package/src/core/hooks/use-codeblock-tabs-controls.ts +2 -2
  48. package/src/core/hooks/use-local-state.ts +28 -19
  49. package/src/core/hooks/use-page-actions.ts +63 -6
  50. package/src/core/openapi/index.ts +1 -0
  51. package/src/core/types/l10n.ts +13 -0
  52. package/src/core/types/open-api-server.ts +1 -0
  53. package/src/icons/CursorIcon/CursorIcon.tsx +35 -0
  54. package/src/layouts/DocumentationLayout.tsx +3 -10
  55. package/src/markdoc/components/CodeGroup/CodeGroup.tsx +81 -52
  56. package/src/markdoc/components/Tabs/TabList.tsx +1 -0
@@ -19,9 +19,11 @@ const use_theme_hooks_1 = require("./use-theme-hooks");
19
19
  const use_theme_config_1 = require("./use-theme-config");
20
20
  const clipboard_service_1 = require("../utils/clipboard-service");
21
21
  const dom_1 = require("../utils/dom");
22
+ const CursorIcon_1 = require("../../icons/CursorIcon/CursorIcon");
22
23
  const DEFAULT_ENABLED_ACTIONS = ['copy', 'view', 'chatgpt', 'claude'];
23
- function usePageActions(pageSlug) {
24
- var _a;
24
+ const CURSOR_URL = 'cursor://anysphere.cursor-deeplink/mcp/install?name=$NAME&config=$BASE64_ENCODED_CONFIG';
25
+ function usePageActions(pageSlug, mcpUrl, actions) {
26
+ var _a, _b, _c;
25
27
  const { useTranslate, usePageData, usePageProps, usePageSharedData } = (0, use_theme_hooks_1.useThemeHooks)();
26
28
  const { translate } = useTranslate();
27
29
  const themeConfig = (0, use_theme_config_1.useThemeConfig)();
@@ -29,7 +31,7 @@ function usePageActions(pageSlug) {
29
31
  const openApiSharedData = usePageSharedData('openAPIDocsStore');
30
32
  const shouldHideAllActions = shouldHidePageActions(pageProps, themeConfig, (_a = openApiSharedData === null || openApiSharedData === void 0 ? void 0 : openApiSharedData.options) === null || _a === void 0 ? void 0 : _a.excludeFromSearch);
31
33
  const { isPublic } = usePageData() || {};
32
- const actions = (0, react_1.useMemo)(() => {
34
+ const result = (0, react_1.useMemo)(() => {
33
35
  var _a, _b;
34
36
  if (shouldHideAllActions) {
35
37
  return [];
@@ -43,9 +45,41 @@ function usePageActions(pageSlug) {
43
45
  url.searchParams.set('q', externalAiPrompt);
44
46
  return url.toString();
45
47
  }
46
- return (((_b = (_a = themeConfig.navigation) === null || _a === void 0 ? void 0 : _a.actions) === null || _b === void 0 ? void 0 : _b.items) || DEFAULT_ENABLED_ACTIONS)
48
+ return (((_b = (_a = themeConfig.navigation) === null || _a === void 0 ? void 0 : _a.actions) === null || _b === void 0 ? void 0 : _b.items) || actions || DEFAULT_ENABLED_ACTIONS)
47
49
  .map((action) => {
50
+ function generateMCPConfig(isCursor) {
51
+ const jsonConfig = {
52
+ 'mcp-server': {
53
+ url: mcpUrl,
54
+ description: 'MCP Server',
55
+ },
56
+ };
57
+ if (isCursor) {
58
+ const url = CURSOR_URL.replace('$NAME', 'mcp-server').replace('$BASE64_ENCODED_CONFIG', btoa(JSON.stringify(jsonConfig['mcp-server'])));
59
+ return url;
60
+ }
61
+ return JSON.stringify(jsonConfig, null, 2);
62
+ }
48
63
  switch (action) {
64
+ case 'mcp-cursor':
65
+ if (!mcpUrl) {
66
+ return null;
67
+ }
68
+ return {
69
+ buttonText: translate('page.actions.cursorMcpButtonText', 'Connect to Cursor'),
70
+ title: translate('page.actions.cursorMcpTitle', 'Connect to Cursor'),
71
+ description: translate('page.actions.cursorMcpDescription', 'Install MCP server on Cursor'),
72
+ iconComponent: CursorIcon_1.CursorIcon,
73
+ onClick: () => {
74
+ try {
75
+ const url = generateMCPConfig(true);
76
+ window.open(url, '_blank');
77
+ }
78
+ catch (error) {
79
+ console.error(error);
80
+ }
81
+ },
82
+ };
49
83
  case 'copy':
50
84
  return {
51
85
  buttonText: translate('page.actions.copyButtonText', 'Copy'),
@@ -99,8 +133,16 @@ function usePageActions(pageSlug) {
99
133
  }
100
134
  })
101
135
  .filter((action) => action !== null);
102
- }, [themeConfig, translate, pageSlug, isPublic, shouldHideAllActions]);
103
- return actions;
136
+ }, [
137
+ shouldHideAllActions,
138
+ pageSlug,
139
+ (_c = (_b = themeConfig.navigation) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.items,
140
+ actions,
141
+ mcpUrl,
142
+ translate,
143
+ isPublic,
144
+ ]);
145
+ return result;
104
146
  }
105
147
  function shouldHidePageActions(pageProps, themeConfig, openapiExcludeFromSearch) {
106
148
  var _a, _b, _c, _d, _e, _f;
@@ -4,6 +4,7 @@ export type { TFunction, TOptions } from '../types/l10n';
4
4
  export type { SelectOption, SelectProps } from '../types/select';
5
5
  export { IS_BROWSER } from '../utils/dom';
6
6
  export { addLeadingSlash, removeLeadingSlash, getPathPrefix, combineUrls, addTrailingSlash, withPathPrefix, } from '../utils/urls';
7
+ export { capitalize } from '../utils/string';
7
8
  export { typedMemo } from '../hoc/typedMemo';
8
9
  export { useMount } from '../hooks/use-mount';
9
10
  export { GlobalStyle } from '../styles/global';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ThemeDataContext = exports.isObject = exports.isNotNull = exports.isString = exports.isUndefined = exports.SecurityVariablesEnvSuffix = exports.useDialogHotKeys = exports.useSearchDialog = exports.useModalScrollLock = exports.useActiveSectionId = exports.useOutsideClick = exports.useThemeHooks = exports.useFocusTrap = exports.getUserAgent = exports.ClipboardService = exports.isPrimitive = exports.breakpoints = exports.GlobalStyle = exports.useMount = exports.typedMemo = exports.withPathPrefix = exports.addTrailingSlash = exports.combineUrls = exports.getPathPrefix = exports.removeLeadingSlash = exports.addLeadingSlash = exports.IS_BROWSER = void 0;
3
+ exports.ThemeDataContext = exports.isObject = exports.isNotNull = exports.isString = exports.isUndefined = exports.SecurityVariablesEnvSuffix = exports.useDialogHotKeys = exports.useSearchDialog = exports.useModalScrollLock = exports.useActiveSectionId = exports.useOutsideClick = exports.useThemeHooks = exports.useFocusTrap = exports.getUserAgent = exports.ClipboardService = exports.isPrimitive = exports.breakpoints = exports.GlobalStyle = exports.useMount = exports.typedMemo = exports.capitalize = exports.withPathPrefix = exports.addTrailingSlash = exports.combineUrls = exports.getPathPrefix = exports.removeLeadingSlash = exports.addLeadingSlash = exports.IS_BROWSER = void 0;
4
4
  var dom_1 = require("../utils/dom");
5
5
  Object.defineProperty(exports, "IS_BROWSER", { enumerable: true, get: function () { return dom_1.IS_BROWSER; } });
6
6
  var urls_1 = require("../utils/urls");
@@ -10,6 +10,8 @@ Object.defineProperty(exports, "getPathPrefix", { enumerable: true, get: functio
10
10
  Object.defineProperty(exports, "combineUrls", { enumerable: true, get: function () { return urls_1.combineUrls; } });
11
11
  Object.defineProperty(exports, "addTrailingSlash", { enumerable: true, get: function () { return urls_1.addTrailingSlash; } });
12
12
  Object.defineProperty(exports, "withPathPrefix", { enumerable: true, get: function () { return urls_1.withPathPrefix; } });
13
+ var string_1 = require("../utils/string");
14
+ Object.defineProperty(exports, "capitalize", { enumerable: true, get: function () { return string_1.capitalize; } });
13
15
  var typedMemo_1 = require("../hoc/typedMemo");
14
16
  Object.defineProperty(exports, "typedMemo", { enumerable: true, get: function () { return typedMemo_1.typedMemo; } });
15
17
  var use_mount_1 = require("../hooks/use-mount");
@@ -1,5 +1,5 @@
1
1
  import type { TOptions } from 'i18next';
2
- export type TranslationKey = 'dev.newApp' | 'dev.newApp.text' | 'dev.sidebar.header' | 'dev.sidebar.footer.text' | 'dev.create.app.dialog.appName.placeholder' | 'dev.create.app.dialog.appName.error' | 'dev.create.app.dialog.selectAPIs' | 'dev.create.app.dialog.description' | 'dev.create.app.dialog.description.placeholder' | 'dev.create.app.dialog.create' | 'dev.create.app.dialog.cancel' | 'dev.main.tab.appKeys' | 'dev.main.tab.logs' | 'dev.app.description.title' | 'dev.edit.description.dialog.title' | 'dev.edit.description.dialog.save' | 'dev.edit.description.dialog.cancel' | 'dev.edit.apis.dialog.selectedAPIs' | 'dev.app.key.create' | 'dev.create.key.dialog.title' | 'dev.create.key.dialog.create' | 'dev.create.key.dialog.cancel' | 'dev.app.edit' | 'dev.app.delete' | 'dev.edit.app.dialog.title' | 'dev.edit.app.dialog.save' | 'dev.edit.app.dialog.cancel' | 'dev.delete.app.dialog.title' | 'dev.delete.app.dialog.confirmation' | 'dev.delete.app.dialog.delete' | 'dev.delete.app.dialog.cancel' | 'dev.app.key.roll' | 'dev.roll.key.dialog.title' | 'dev.roll.key.dialog.apiKey' | 'dev.roll.key.dialog.expires' | 'dev.roll.key.dialog.confirmation' | 'dev.roll.key.dialog.cancel' | 'dev.roll.key.dialog.roll' | 'dev.update.key.dialog.title' | 'dev.update.key.dialog.update' | 'dev.update.key.dialog.cancel' | 'dev.app.key.api.name' | 'dev.app.key.api.status' | 'dev.app.key.api.edit' | 'dev.edit.apis.dialog.title' | 'dev.edit.apis.dialog.apiKey' | 'dev.edit.apis.dialog.save' | 'dev.edit.apis.dialog.cancel' | 'dev.select.placeholder' | 'dev.app.overview.status.pending' | 'dev.app.overview.status.approved' | 'dev.app.overview.status.revoked' | 'dev.app.overview.status' | 'dev.app.overview.non-production' | 'dev.app.overview.production' | 'dev.app.overview.clientId' | 'dev.app.overview.apiKey' | 'dev.app.key.revoke' | 'dev.revoke.key.dialog.title' | 'dev.revoke.key.dialog.apiKey' | 'dev.revoke.key.dialog.expires' | 'dev.revoke.key.dialog.confirmation' | 'dev.revoke.key.dialog.revoke' | 'dev.revoke.key.dialog.cancel' | 'dev.app.overview.expires' | 'dev.app.overview.created' | 'dev.app.overview.visibilityToggle.hide' | 'dev.app.overview.visibilityToggle.show' | 'search.loading' | 'search.noResults.title' | 'search.keys.navigate' | 'search.keys.select' | 'search.keys.exit' | 'search.label' | 'search.cancel' | 'search.recent' | 'search.navbar.label' | 'search.suggested' | 'search.showMore' | 'search.filter.title' | 'search.filter.reset' | 'search.filter.field.reset' | 'search.ai.welcomeText' | 'search.ai.newConversation' | 'search.ai.backToSearch' | 'search.ai.placeholder' | 'search.ai.generatingResponse' | 'search.ai.followUpQuestion' | 'search.ai.suggestionsTitle' | 'search.ai.thinkingText' | 'search.ai.resourcesFound' | 'search.ai.resourcesFound.basedOn' | 'search.ai.resourcesFound.resources' | 'search.ai.button' | 'search.ai.label' | 'search.ai.disclaimer' | 'search.ai.error.description' | 'search.ai.error.description.forbidden' | 'search.ai.error.description.unauthorized' | 'search.ai.error.header' | 'search.ai.error.header.forbidden' | 'search.ai.error.header.unauthorized' | 'toc.header' | 'footer.copyrightText' | 'page.homeButton' | 'page.forbidden.title' | 'page.notFound.title' | 'page.notFound.description' | 'page.lastUpdated.timeago' | 'page.lastUpdated.on' | 'catalog.filters.placeholder' | 'catalog.filters.title' | 'catalog.filters.add' | 'catalog.filters.clearAll' | 'catalog.filters.select.addFilter' | 'catalog.filters.select.all' | 'catalog.filters.done' | 'catalog.catalogs.all.title' | 'catalog.catalogs.all.description' | 'catalog.catalogs.all.switcherLabel' | 'catalog.catalogs.service.title' | 'catalog.catalogs.service.description' | 'catalog.catalogs.service.switcherLabel' | 'catalog.catalogs.user.title' | 'catalog.catalogs.user.description' | 'catalog.catalogs.user.switcherLabel' | 'catalog.catalogs.team.title' | 'catalog.catalogs.team.description' | 'catalog.catalogs.team.switcherLabel' | 'catalog.catalogs.domain.title' | 'catalog.catalogs.domain.description' | 'catalog.catalogs.domain.switcherLabel' | 'catalog.catalogs.apiDescription.title' | 'catalog.catalogs.apiDescription.description' | 'catalog.catalogs.apiDescription.switcherLabel' | 'catalog.catalogs.dataSchema.title' | 'catalog.catalogs.dataSchema.description' | 'catalog.catalogs.dataSchema.switcherLabel' | 'catalog.catalogs.apiOperation.title' | 'catalog.catalogs.apiOperation.description' | 'catalog.catalogs.apiOperation.switcherLabel' | 'catalog.entity.metadata.title' | 'catalog.entity.schema.title' | 'catalog.entity.properties.apiDescription.title' | 'sidebar.menu.backLabel' | 'sidebar.menu.backToLabel' | 'sidebar.actions.show' | 'sidebar.actions.hide' | 'sidebar.actions.changeToSingleColumn' | 'sidebar.actions.changeToTwoColumns' | 'sidebar.actions.singleColumn' | 'sidebar.actions.twoColumns' | 'versionPicker.label' | 'versionPicker.unversioned' | 'codeSnippet.copy.buttonText' | 'codeSnippet.copy.tooltipText' | 'codeSnippet.copy.toasterText' | 'markdown.editPage.text' | 'feedback.settings.comment.submitText' | 'feedback.settings.comment.label' | 'feedback.settings.comment.send' | 'feedback.settings.comment.cancel' | 'feedback.settings.comment.satisfiedLabel' | 'feedback.settings.comment.neutralLabel' | 'feedback.settings.comment.dissatisfiedLabel' | 'feedback.settings.submitText' | 'feedback.settings.label' | 'feedback.settings.reasons.label' | 'feedback.submit' | 'feedback.cancel' | 'feedback.settings.comment.likeLabel' | 'feedback.settings.comment.dislikeLabel' | 'feedback.sentiment.thumbUp' | 'feedback.sentiment.thumbDown' | 'feedback.settings.leftScaleLabel' | 'feedback.settings.rightScaleLabel' | 'feedback.settings.optionalEmail.placeholder' | 'feedback.settings.optionalEmail.label' | 'codeSnippet.report.buttonText' | 'codeSnippet.report.tooltipText' | 'codeSnippet.report.label' | 'codeSnippet.expand.tooltipText' | 'codeSnippet.collapse.tooltipText' | 'userMenu.login' | 'userMenu.logout' | 'userMenu.devOnboardingLabel' | 'mobileMenu.mainMenu' | 'mobileMenu.previous' | 'mobileMenu.products' | 'mobileMenu.version' | 'navbar.products' | 'page.nextButton' | 'page.previousButton' | 'page.actions.copyButtonText' | 'page.actions.copyTitle' | 'page.actions.copyDescription' | 'page.actions.viewAsMdTitle' | 'page.actions.viewAsMdButtonText' | 'page.actions.viewAsMdDescription' | 'page.actions.chatGptTitle' | 'page.actions.chatGptButtonText' | 'page.actions.chatGptDescription' | 'page.actions.claudeTitle' | 'page.actions.claudeButtonText' | 'page.actions.claudeDescription' | 'openapi.download.description.title' | 'openapi.info.title' | 'openapi.info.contact.url' | 'openapi.info.contact.name' | 'openapi.info.license' | 'openapi.info.termsOfService' | 'openapi.info.metadata.title' | 'openapi.key' | 'openapi.value' | 'openapi.enum' | 'openapi.items' | 'openapi.default' | 'openapi.variable' | 'openapi.variables' | 'openapi.actions.show' | 'openapi.actions.hide' | 'openapi.actions.more' | 'openapi.languages.title' | 'openapi.servers.title' | 'openapi.operations' | 'openapi.webhooks' | 'openapi.description' | 'openapi.badges.deprecated' | 'openapi.badges.required' | 'openapi.badges.webhook' | 'openapi.request' | 'openapi.path' | 'openapi.query' | 'openapi.cookie' | 'openapi.header' | 'openapi.body' | 'openapi.responses' | 'openapi.response' | 'openapi.callbacks' | 'openapi.callbackRequest' | 'openapi.callbackResponse' | 'openapi.payload' | 'openapi.discriminator' | 'openapi.contentType' | 'openapi.tryIt' | 'openapi.loading' | 'openapi.example' | 'openapi.examples' | 'openapi.additionalProperties' | 'openapi.patternProperties' | 'openapi.required' | 'openapi.recursive' | 'openapi.complex' | 'openapi.hideExample' | 'openapi.showExample' | 'openapi.expandAll' | 'openapi.collapseAll' | 'openapi.viewSecurityDetails' | 'openapi.noResponseExample' | 'openapi.discriminator.searchPlaceholder' | 'openapi.discriminator.searchNoResults' | 'openapi.noResponseContent' | 'openapi.noRequestPayload' | 'openapi.hidePattern' | 'openapi.showPattern' | 'openapi.authorizationUrl' | 'openapi.tokenUrl' | 'openapi.refreshUrl' | 'openapi.showOptionalScopes' | 'openapi.hideOptionalScopes' | 'openapi.security' | 'openapi.httpAuthorizationScheme' | 'openapi.bearerFormat' | 'openapi.parameterName' | 'openapi.flowType' | 'openapi.connectUrl' | 'openapi.requiredScopes' | 'openapi.unsupportedLanguage' | 'openapi.failedToGenerateCodeSample' | 'openapi.schemaCatalogLink.title' | 'openapi.schemaCatalogLink.copyButtonTooltip' | 'openapi.schemaCatalogLink.copiedTooltip' | 'asyncapi.download.description.title' | 'asyncapi.info.title' | 'graphql.queries' | 'graphql.mutations' | 'graphql.subscriptions' | 'graphql.directives' | 'graphql.objects' | 'graphql.interfaces' | 'graphql.unions' | 'graphql.enums' | 'graphql.inputs' | 'graphql.scalars' | 'graphql.arguments.label' | 'graphql.arguments.show' | 'graphql.arguments.hide' | 'graphql.arguments.here' | 'graphql.returnTypes.label' | 'graphql.returnTypes.show' | 'graphql.returnTypes.hide' | 'graphql.possibleTypes' | 'graphql.defaultValue' | 'graphql.deprecationReason' | 'graphql.requiredScopes' | 'graphql.viewSecurityDetails' | 'graphql.objectScopes' | 'graphql.fieldScopes' | 'graphql.implementedInterfaces' | 'graphql.nonNull' | 'graphql.required' | 'graphql.deprecated' | 'graphql.variables' | 'graphql.querySample' | 'graphql.mutationSample' | 'graphql.subscriptionSample' | 'graphql.responseSample' | 'graphql.locations' | 'graphql.sample' | 'graphql.referenced' | 'graphql.content.fragment' | 'codeWalkthrough.download' | 'codeWalkthrough.preview' | 'time.justNow' | 'time.past.second' | 'time.past.seconds' | 'time.past.minute' | 'time.past.minutes' | 'time.past.hour' | 'time.past.hours' | 'time.past.day' | 'time.past.days' | 'time.past.week' | 'time.past.weeks' | 'time.past.month' | 'time.past.months' | 'time.past.year' | 'time.past.years' | 'page.internalServerError.title' | 'page.internalServerError.description' | 'page.skipToContent.label';
2
+ export type TranslationKey = 'dev.newApp' | 'dev.newApp.text' | 'dev.sidebar.header' | 'dev.sidebar.footer.text' | 'dev.create.app.dialog.appName.placeholder' | 'dev.create.app.dialog.appName.error' | 'dev.create.app.dialog.selectAPIs' | 'dev.create.app.dialog.description' | 'dev.create.app.dialog.description.placeholder' | 'dev.create.app.dialog.create' | 'dev.create.app.dialog.cancel' | 'dev.main.tab.appKeys' | 'dev.main.tab.logs' | 'dev.app.description.title' | 'dev.edit.description.dialog.title' | 'dev.edit.description.dialog.save' | 'dev.edit.description.dialog.cancel' | 'dev.edit.apis.dialog.selectedAPIs' | 'dev.app.key.create' | 'dev.create.key.dialog.title' | 'dev.create.key.dialog.create' | 'dev.create.key.dialog.cancel' | 'dev.app.edit' | 'dev.app.delete' | 'dev.edit.app.dialog.title' | 'dev.edit.app.dialog.save' | 'dev.edit.app.dialog.cancel' | 'dev.delete.app.dialog.title' | 'dev.delete.app.dialog.confirmation' | 'dev.delete.app.dialog.delete' | 'dev.delete.app.dialog.cancel' | 'dev.app.key.roll' | 'dev.roll.key.dialog.title' | 'dev.roll.key.dialog.apiKey' | 'dev.roll.key.dialog.expires' | 'dev.roll.key.dialog.confirmation' | 'dev.roll.key.dialog.cancel' | 'dev.roll.key.dialog.roll' | 'dev.update.key.dialog.title' | 'dev.update.key.dialog.update' | 'dev.update.key.dialog.cancel' | 'dev.app.key.api.name' | 'dev.app.key.api.status' | 'dev.app.key.api.edit' | 'dev.edit.apis.dialog.title' | 'dev.edit.apis.dialog.apiKey' | 'dev.edit.apis.dialog.save' | 'dev.edit.apis.dialog.cancel' | 'dev.select.placeholder' | 'dev.app.overview.status.pending' | 'dev.app.overview.status.approved' | 'dev.app.overview.status.revoked' | 'dev.app.overview.status' | 'dev.app.overview.non-production' | 'dev.app.overview.production' | 'dev.app.overview.clientId' | 'dev.app.overview.apiKey' | 'dev.app.key.revoke' | 'dev.revoke.key.dialog.title' | 'dev.revoke.key.dialog.apiKey' | 'dev.revoke.key.dialog.expires' | 'dev.revoke.key.dialog.confirmation' | 'dev.revoke.key.dialog.revoke' | 'dev.revoke.key.dialog.cancel' | 'dev.app.overview.expires' | 'dev.app.overview.created' | 'dev.app.overview.visibilityToggle.hide' | 'dev.app.overview.visibilityToggle.show' | 'search.loading' | 'search.noResults.title' | 'search.keys.navigate' | 'search.keys.select' | 'search.keys.exit' | 'search.label' | 'search.cancel' | 'search.recent' | 'search.navbar.label' | 'search.suggested' | 'search.showMore' | 'search.filter.title' | 'search.filter.reset' | 'search.filter.field.reset' | 'search.ai.welcomeText' | 'search.ai.newConversation' | 'search.ai.backToSearch' | 'search.ai.placeholder' | 'search.ai.generatingResponse' | 'search.ai.followUpQuestion' | 'search.ai.suggestionsTitle' | 'search.ai.thinkingText' | 'search.ai.resourcesFound' | 'search.ai.resourcesFound.basedOn' | 'search.ai.resourcesFound.resources' | 'search.ai.button' | 'search.ai.label' | 'search.ai.disclaimer' | 'search.ai.error.description' | 'search.ai.error.description.forbidden' | 'search.ai.error.description.unauthorized' | 'search.ai.error.header' | 'search.ai.error.header.forbidden' | 'search.ai.error.header.unauthorized' | 'toc.header' | 'footer.copyrightText' | 'page.homeButton' | 'page.forbidden.title' | 'page.notFound.title' | 'page.notFound.description' | 'page.lastUpdated.timeago' | 'page.lastUpdated.on' | 'catalog.filters.placeholder' | 'catalog.filters.title' | 'catalog.filters.add' | 'catalog.filters.clearAll' | 'catalog.filters.select.addFilter' | 'catalog.filters.select.all' | 'catalog.filters.done' | 'catalog.catalogs.all.title' | 'catalog.catalogs.all.description' | 'catalog.catalogs.all.switcherLabel' | 'catalog.catalogs.service.title' | 'catalog.catalogs.service.description' | 'catalog.catalogs.service.switcherLabel' | 'catalog.catalogs.user.title' | 'catalog.catalogs.user.description' | 'catalog.catalogs.user.switcherLabel' | 'catalog.catalogs.team.title' | 'catalog.catalogs.team.description' | 'catalog.catalogs.team.switcherLabel' | 'catalog.catalogs.domain.title' | 'catalog.catalogs.domain.description' | 'catalog.catalogs.domain.switcherLabel' | 'catalog.catalogs.apiDescription.title' | 'catalog.catalogs.apiDescription.description' | 'catalog.catalogs.apiDescription.switcherLabel' | 'catalog.catalogs.dataSchema.title' | 'catalog.catalogs.dataSchema.description' | 'catalog.catalogs.dataSchema.switcherLabel' | 'catalog.catalogs.apiOperation.title' | 'catalog.catalogs.apiOperation.description' | 'catalog.catalogs.apiOperation.switcherLabel' | 'catalog.entity.metadata.title' | 'catalog.entity.schema.title' | 'catalog.entity.properties.apiDescription.title' | 'sidebar.menu.backLabel' | 'sidebar.menu.backToLabel' | 'sidebar.actions.show' | 'sidebar.actions.hide' | 'sidebar.actions.changeToSingleColumn' | 'sidebar.actions.changeToTwoColumns' | 'sidebar.actions.singleColumn' | 'sidebar.actions.twoColumns' | 'versionPicker.label' | 'versionPicker.unversioned' | 'codeSnippet.copy.buttonText' | 'codeSnippet.copy.tooltipText' | 'codeSnippet.copy.toasterText' | 'markdown.editPage.text' | 'feedback.settings.comment.submitText' | 'feedback.settings.comment.label' | 'feedback.settings.comment.send' | 'feedback.settings.comment.cancel' | 'feedback.settings.comment.satisfiedLabel' | 'feedback.settings.comment.neutralLabel' | 'feedback.settings.comment.dissatisfiedLabel' | 'feedback.settings.submitText' | 'feedback.settings.label' | 'feedback.settings.reasons.label' | 'feedback.submit' | 'feedback.cancel' | 'feedback.settings.comment.likeLabel' | 'feedback.settings.comment.dislikeLabel' | 'feedback.sentiment.thumbUp' | 'feedback.sentiment.thumbDown' | 'feedback.settings.leftScaleLabel' | 'feedback.settings.rightScaleLabel' | 'feedback.settings.optionalEmail.placeholder' | 'feedback.settings.optionalEmail.label' | 'codeSnippet.report.buttonText' | 'codeSnippet.report.tooltipText' | 'codeSnippet.report.label' | 'codeSnippet.expand.tooltipText' | 'codeSnippet.collapse.tooltipText' | 'userMenu.login' | 'userMenu.logout' | 'userMenu.devOnboardingLabel' | 'mobileMenu.mainMenu' | 'mobileMenu.previous' | 'mobileMenu.products' | 'mobileMenu.version' | 'navbar.products' | 'page.nextButton' | 'page.previousButton' | 'page.actions.copyButtonText' | 'page.actions.copyTitle' | 'page.actions.copyDescription' | 'page.actions.viewAsMdTitle' | 'page.actions.viewAsMdButtonText' | 'page.actions.viewAsMdDescription' | 'page.actions.chatGptTitle' | 'page.actions.chatGptButtonText' | 'page.actions.chatGptDescription' | 'page.actions.claudeTitle' | 'page.actions.claudeButtonText' | 'page.actions.claudeDescription' | 'page.actions.cursorMcpButtonText' | 'page.actions.cursorMcpTitle' | 'page.actions.cursorMcpDescription' | 'openapi.download.description.title' | 'openapi.info.title' | 'openapi.info.contact.url' | 'openapi.info.contact.name' | 'openapi.info.license' | 'openapi.info.termsOfService' | 'openapi.info.metadata.title' | 'openapi.key' | 'openapi.value' | 'openapi.enum' | 'openapi.items' | 'openapi.default' | 'openapi.variable' | 'openapi.variables' | 'openapi.actions.show' | 'openapi.actions.hide' | 'openapi.actions.more' | 'openapi.languages.title' | 'openapi.servers.title' | 'openapi.operations' | 'openapi.webhooks' | 'openapi.description' | 'openapi.badges.deprecated' | 'openapi.badges.required' | 'openapi.badges.webhook' | 'openapi.request' | 'openapi.path' | 'openapi.query' | 'openapi.cookie' | 'openapi.header' | 'openapi.body' | 'openapi.responses' | 'openapi.response' | 'openapi.callbacks' | 'openapi.callbackRequest' | 'openapi.callbackResponse' | 'openapi.payload' | 'openapi.discriminator' | 'openapi.contentType' | 'openapi.tryIt' | 'openapi.loading' | 'openapi.example' | 'openapi.examples' | 'openapi.additionalProperties' | 'openapi.patternProperties' | 'openapi.required' | 'openapi.recursive' | 'openapi.complex' | 'openapi.hideExample' | 'openapi.showExample' | 'openapi.expandAll' | 'openapi.collapseAll' | 'openapi.viewSecurityDetails' | 'openapi.noResponseExample' | 'openapi.discriminator.searchPlaceholder' | 'openapi.discriminator.searchNoResults' | 'openapi.noResponseContent' | 'openapi.noRequestPayload' | 'openapi.hidePattern' | 'openapi.showPattern' | 'openapi.authorizationUrl' | 'openapi.tokenUrl' | 'openapi.refreshUrl' | 'openapi.showOptionalScopes' | 'openapi.hideOptionalScopes' | 'openapi.security' | 'openapi.httpAuthorizationScheme' | 'openapi.bearerFormat' | 'openapi.parameterName' | 'openapi.flowType' | 'openapi.connectUrl' | 'openapi.requiredScopes' | 'openapi.unsupportedLanguage' | 'openapi.failedToGenerateCodeSample' | 'openapi.schemaCatalogLink.title' | 'openapi.schemaCatalogLink.copyButtonTooltip' | 'openapi.schemaCatalogLink.copiedTooltip' | 'openapi.mcp.title' | 'openapi.mcp.endpoint' | 'openapi.mcp.tools' | 'openapi.mcp.protocolVersion' | 'openapi.mcp.capabilities' | 'openapi.mcp.experimentalCapabilities' | 'openapi.mcp.inputSchema' | 'openapi.mcp.inputExample' | 'openapi.mcp.outputSchema' | 'openapi.mcp.outputExample' | 'asyncapi.download.description.title' | 'asyncapi.info.title' | 'graphql.queries' | 'graphql.mutations' | 'graphql.subscriptions' | 'graphql.directives' | 'graphql.objects' | 'graphql.interfaces' | 'graphql.unions' | 'graphql.enums' | 'graphql.inputs' | 'graphql.scalars' | 'graphql.arguments.label' | 'graphql.arguments.show' | 'graphql.arguments.hide' | 'graphql.arguments.here' | 'graphql.returnTypes.label' | 'graphql.returnTypes.show' | 'graphql.returnTypes.hide' | 'graphql.possibleTypes' | 'graphql.defaultValue' | 'graphql.deprecationReason' | 'graphql.requiredScopes' | 'graphql.viewSecurityDetails' | 'graphql.objectScopes' | 'graphql.fieldScopes' | 'graphql.implementedInterfaces' | 'graphql.nonNull' | 'graphql.required' | 'graphql.deprecated' | 'graphql.variables' | 'graphql.querySample' | 'graphql.mutationSample' | 'graphql.subscriptionSample' | 'graphql.responseSample' | 'graphql.locations' | 'graphql.sample' | 'graphql.referenced' | 'graphql.content.fragment' | 'codeWalkthrough.download' | 'codeWalkthrough.preview' | 'time.justNow' | 'time.past.second' | 'time.past.seconds' | 'time.past.minute' | 'time.past.minutes' | 'time.past.hour' | 'time.past.hours' | 'time.past.day' | 'time.past.days' | 'time.past.week' | 'time.past.weeks' | 'time.past.month' | 'time.past.months' | 'time.past.year' | 'time.past.years' | 'page.internalServerError.title' | 'page.internalServerError.description' | 'page.skipToContent.label';
3
3
  export type Locale = {
4
4
  code: string;
5
5
  name: string;
@@ -1,6 +1,7 @@
1
1
  export type OpenAPIServer = {
2
2
  url: string;
3
3
  description?: string;
4
+ name?: string;
4
5
  variables?: Record<string, {
5
6
  default: string;
6
7
  enum?: string[];
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { IconProps } from '../../icons/types';
3
+ export declare const CursorIcon: import("styled-components").StyledComponent<(props: IconProps) => React.JSX.Element, any, {
4
+ 'data-component-name': string;
5
+ } & {
6
+ color?: string;
7
+ size?: string;
8
+ className?: string;
9
+ } & React.SVGProps<SVGSVGElement>, "data-component-name">;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CursorIcon = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const styled_components_1 = __importDefault(require("styled-components"));
9
+ const Icon = (props) => (react_1.default.createElement("svg", Object.assign({ width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, props),
10
+ react_1.default.createElement("path", { d: "M7.99956 15V8.0001L2 11.4999L7.99956 15Z", fill: "#939393" }),
11
+ react_1.default.createElement("path", { d: "M14 4.49979L7.99956 15V8.0001L14 4.49979Z", fill: "#E3E3E3" }),
12
+ react_1.default.createElement("path", { d: "M2 4.49979H14L7.99956 8.0001L2 4.49979Z", fill: "white" }),
13
+ react_1.default.createElement("path", { d: "M8.00025 1V4.49995L14 4.49979L8.00025 1Z", fill: "#444444" }),
14
+ react_1.default.createElement("path", { d: "M2 4.49979L8.00025 4.49995V1L2 4.49979ZM13.9999 11.4998L10.9999 9.74987L7.99956 15L13.9999 11.4998Z", fill: "#939393" }),
15
+ react_1.default.createElement("path", { d: "M14 4.49979L10.9999 9.74987L13.9999 11.4998L14 4.49979ZM7.99956 8.0001L2 11.4999V4.49979L7.99956 8.0001Z", fill: "#444444" })));
16
+ exports.CursorIcon = (0, styled_components_1.default)(Icon).attrs(() => ({
17
+ 'data-component-name': 'icons/CursorIcon/CursorIcon',
18
+ })) `
19
+ height: ${({ size }) => size || '16px'};
20
+ width: ${({ size }) => size || '16px'};
21
+ `;
22
+ //# sourceMappingURL=CursorIcon.js.map
@@ -12,13 +12,11 @@ const PageNavigation_1 = require("../components/PageNavigation/PageNavigation");
12
12
  const LastUpdated_1 = require("../components/LastUpdated/LastUpdated");
13
13
  const Breadcrumbs_1 = require("../components/Breadcrumbs/Breadcrumbs");
14
14
  const CodeSnippetContext_1 = require("../core/contexts/CodeSnippetContext");
15
- const use_local_state_1 = require("../core/hooks/use-local-state");
16
15
  function DocumentationLayout({ tableOfContent, feedback, config, editPage, lastModified, nextPage, prevPage, className, children, }) {
17
16
  var _a;
18
17
  const { editPage: themeEditPage } = config || {};
19
18
  const mergedConf = editPage ? Object.assign(Object.assign({}, themeEditPage), editPage) : undefined;
20
- const [activeSnippetName, setActiveSnippetName] = (0, use_local_state_1.useLocalState)(CodeSnippetContext_1.CODE_GROUP_SNIPPET_NAME_KEY, '');
21
- return (react_1.default.createElement(CodeSnippetContext_1.CodeSnippetContext.Provider, { value: { activeSnippetName, setActiveSnippetName } },
19
+ return (react_1.default.createElement(CodeSnippetContext_1.CodeSnippetProvider, null,
22
20
  react_1.default.createElement(LayoutWrapper, { "data-component-name": "Layout/DocumentationLayout", className: className },
23
21
  react_1.default.createElement(ContentWrapper, { withToc: !((_a = config === null || config === void 0 ? void 0 : config.toc) === null || _a === void 0 ? void 0 : _a.hide) },
24
22
  react_1.default.createElement(Breadcrumbs, null),
@@ -31,42 +31,64 @@ const contexts_1 = require("../../../core/contexts");
31
31
  function CodeGroup(props) {
32
32
  const mode = props.mode || 'tabs';
33
33
  const isTabsMode = mode === 'tabs';
34
- const rawSnippets = React.useMemo(() => React.Children.toArray(props.children).map((child, idx) => {
35
- const childProps = child;
36
- return {
37
- name: getTabName(childProps.props, idx),
38
- languageName: (0, utils_1.langToName)(childProps.props.lang || 'Default'),
39
- lang: childProps.props.lang || '',
40
- props: childProps.props,
41
- };
42
- }), [props.children]);
43
- const [activeSnippetName, setActiveSnippetName] = (0, contexts_1.useActiveCodeSnippetName)(mode);
44
- const snippets = React.useMemo(() => Object.fromEntries(rawSnippets.map((snippet) => {
45
- const getItemName = (snippet) => isTabsMode ? snippet === null || snippet === void 0 ? void 0 : snippet.name : (snippet === null || snippet === void 0 ? void 0 : snippet.languageName) || '';
46
- const name = getItemName(snippet);
47
- const items = rawSnippets.map((item) => ({
48
- name: getItemName(item),
49
- lang: item.lang,
50
- }));
34
+ const rawSnippets = React.useMemo(() => parseSnippetsFromChildren(props.children), [props.children]);
35
+ const groupId = React.useMemo(() => generateGroupId(rawSnippets, mode), [rawSnippets, mode]);
36
+ const [activeSnippetId, setActiveSnippetId] = (0, contexts_1.useActiveCodeSnippetId)(groupId, rawSnippets);
37
+ const snippets = React.useMemo(() => {
38
+ const items = createItemsFromSnippets(rawSnippets, isTabsMode);
51
39
  const itemsProps = {
52
40
  items,
53
- onChange: (name) => {
54
- setActiveSnippetName(name);
55
- },
56
- value: activeSnippetName || getItemName(rawSnippets[0]),
41
+ onChange: (id) => setActiveSnippetId(id),
42
+ value: activeSnippetId,
57
43
  };
58
- const snippetProps = Object.assign(Object.assign(Object.assign({}, snippet.props), { header: Object.assign(Object.assign({}, snippet.props.header), { title: isTabsMode ? undefined : snippet.name }) }), (isTabsMode ? { tabs: itemsProps } : { dropdown: itemsProps }));
59
- return [name, snippetProps];
60
- })), [rawSnippets, activeSnippetName, isTabsMode, setActiveSnippetName]);
61
- const firstName = Object.keys(snippets)[0];
62
- const activeSnippet = snippets[activeSnippetName] || snippets[firstName];
44
+ return Object.fromEntries(rawSnippets.map((snippet) => {
45
+ const snippetProps = Object.assign(Object.assign(Object.assign({}, snippet.props), { header: Object.assign(Object.assign({}, snippet.props.header), { title: isTabsMode ? undefined : snippet.name }) }), (isTabsMode ? { tabs: itemsProps } : { dropdown: itemsProps }));
46
+ return [snippet.id, snippetProps];
47
+ }));
48
+ }, [rawSnippets, activeSnippetId, isTabsMode, setActiveSnippetId]);
49
+ const activeSnippet = snippets[activeSnippetId];
63
50
  if (!activeSnippet) {
64
51
  return null;
65
52
  }
66
53
  return React.createElement(CodeBlock_1.CodeBlock, Object.assign({}, activeSnippet));
67
54
  }
55
+ function generateContentHash(content) {
56
+ let hash = 0;
57
+ for (let i = 0; i < content.length; i++) {
58
+ hash = content.charCodeAt(i) + ((hash << 5) - hash);
59
+ }
60
+ return Math.abs(hash);
61
+ }
62
+ // Generate unique group ID for CodeGroup instance
63
+ // Examples: "dropdown-8901234", "tabs-1234567"
64
+ function generateGroupId(rawSnippets, mode) {
65
+ const content = rawSnippets.map((s) => s.id + (s.props.source || '')).join('|') + `|${mode}`;
66
+ const hash = generateContentHash(content);
67
+ return `${mode}-${hash}`;
68
+ }
68
69
  function getTabName(props, idx) {
69
70
  var _a;
70
- return String(((_a = props.header) === null || _a === void 0 ? void 0 : _a.title) || props.file || (0, utils_1.langToName)(props.lang || '') || 'Tab ' + String(idx + 1));
71
+ const fallbackName = `Tab ${idx + 1}`;
72
+ return String(((_a = props.header) === null || _a === void 0 ? void 0 : _a.title) || props.file || (0, utils_1.langToName)(props.lang || '') || fallbackName);
73
+ }
74
+ function parseSnippetsFromChildren(children) {
75
+ return React.Children.toArray(children).map((child, idx) => {
76
+ const childProps = child;
77
+ const props = childProps.props;
78
+ return {
79
+ name: getTabName(props, idx),
80
+ languageName: String((0, utils_1.langToName)(props.lang || 'Default') || ''),
81
+ lang: props.lang || '',
82
+ props,
83
+ id: `${props.lang || ''}-${idx}`,
84
+ };
85
+ });
86
+ }
87
+ function createItemsFromSnippets(snippets, isTabsMode) {
88
+ return snippets.map((snippet) => ({
89
+ name: isTabsMode ? snippet.name : snippet.languageName || '',
90
+ lang: snippet.lang,
91
+ id: snippet.id,
92
+ }));
71
93
  }
72
94
  //# sourceMappingURL=CodeGroup.js.map
@@ -63,6 +63,8 @@ function TabList({ childrenArray, size, overflowTabs, visibleTabs, setTabRef, on
63
63
  const { label } = childrenArray[index].props;
64
64
  const tabId = getTabId(label, index);
65
65
  return (react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, { key: `more-${tabId}`, active: activeTab === label, onAction: () => {
66
+ var _a, _b;
67
+ (_b = (_a = childrenArray[index].props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a);
66
68
  onTabClick(index);
67
69
  }, disabled: childrenArray[index].props.disable }, label));
68
70
  })))))));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.58.0-next.8",
3
+ "version": "0.58.0",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -32,7 +32,7 @@
32
32
  "react": "^19.1.0",
33
33
  "react-dom": "^19.1.0",
34
34
  "react-router-dom": "^6.21.1",
35
- "styled-components": "^4.1.1 || ^5.3.11",
35
+ "styled-components": "^4.1.1 || ^5.3.11 || ^6.0.0",
36
36
  "styled-system": "^5.1.5"
37
37
  },
38
38
  "devDependencies": {
@@ -87,8 +87,8 @@
87
87
  "openapi-sampler": "1.6.1",
88
88
  "react-calendar": "5.1.0",
89
89
  "react-date-picker": "11.0.0",
90
- "@redocly/config": "0.35.0",
91
- "@redocly/realm-asyncapi-sdk": "0.4.0-next.3"
90
+ "@redocly/realm-asyncapi-sdk": "0.4.0",
91
+ "@redocly/config": "0.35.1"
92
92
  },
93
93
  "scripts": {
94
94
  "watch": "tsc -p tsconfig.build.json && (concurrently \"tsc -w -p tsconfig.build.json\" \"tsc-alias -w -p tsconfig.build.json\")",
@@ -24,6 +24,7 @@ import { CatalogEntityRelationsGraph } from '@redocly/theme/components/Catalog/C
24
24
  export type CatalogEntityProps = {
25
25
  RedocSchema: React.ComponentType<any>;
26
26
  StoreProvider: React.ComponentType<any>;
27
+ GraphqlTypeRenderer?: React.ComponentType<{ sdl: string; typeName: string }>;
27
28
  };
28
29
 
29
30
  type CatalogEntityPageProps = {
@@ -50,6 +51,7 @@ const renderDataSchemaSection = (
50
51
  relatedEntity: BffCatalogRelatedEntity | null,
51
52
  RedocSchema: React.ComponentType<any>,
52
53
  StoreProvider: React.ComponentType<any>,
54
+ GraphqlTypeRenderer?: React.ComponentType<{ sdl: string; typeName: string }>,
53
55
  ): React.ReactElement | null => {
54
56
  if (entity.type !== 'data-schema') {
55
57
  return null;
@@ -61,11 +63,16 @@ const renderDataSchemaSection = (
61
63
  relatedEntity={relatedEntity}
62
64
  RedocSchema={RedocSchema}
63
65
  StoreProvider={StoreProvider}
66
+ GraphqlTypeRenderer={GraphqlTypeRenderer}
64
67
  />
65
68
  );
66
69
  };
67
70
 
68
- export function CatalogEntity({ RedocSchema, StoreProvider }: CatalogEntityProps) {
71
+ export function CatalogEntity({
72
+ RedocSchema,
73
+ StoreProvider,
74
+ GraphqlTypeRenderer,
75
+ }: CatalogEntityProps) {
69
76
  const { useTranslate, useCatalog, usePageProps } = useThemeHooks();
70
77
  const { translate } = useTranslate();
71
78
  const { entity, relations, catalogConfig, entitiesCatalogConfig, relatedEntity } =
@@ -98,7 +105,13 @@ export function CatalogEntity({ RedocSchema, StoreProvider }: CatalogEntityProps
98
105
  tag={entity.key}
99
106
  />
100
107
  <CatalogEntityProperties entity={entity} />
101
- {renderDataSchemaSection(entity, relatedEntity, RedocSchema, StoreProvider)}
108
+ {renderDataSchemaSection(
109
+ entity,
110
+ relatedEntity,
111
+ RedocSchema,
112
+ StoreProvider,
113
+ GraphqlTypeRenderer,
114
+ )}
102
115
  <CatalogTwoColumnsSection>
103
116
  {renderFirstColumnEntitySection(entity)}
104
117
  <CatalogEntityLinks entity={entity} />
@@ -16,7 +16,7 @@ export type CatalogEntityMetadataProps = {
16
16
 
17
17
  function renderMetadataValue(value: any): React.JSX.Element {
18
18
  if (isPlainObject(value)) {
19
- return <JsonViewerWrapper data={value} expandLevel={3} hideHeader={true} />;
19
+ return <JsonViewerWrapper data={value} expandLevel={3} controls={false} />;
20
20
  }
21
21
 
22
22
  if (Array.isArray(value)) {
@@ -25,7 +25,7 @@ function renderMetadataValue(value: any): React.JSX.Element {
25
25
  {value.map((item, index) => (
26
26
  <div key={index}>
27
27
  {isPlainObject(item) ? (
28
- <JsonViewerWrapper data={item} expandLevel={3} hideHeader={true} />
28
+ <JsonViewerWrapper data={item} expandLevel={3} controls={false} />
29
29
  ) : (
30
30
  <span>{String(item)}</span>
31
31
  )}
@@ -41,7 +41,7 @@ function renderMetadataValue(value: any): React.JSX.Element {
41
41
  export function CatalogEntityMetadata({ entity }: CatalogEntityMetadataProps) {
42
42
  const { useTranslate } = useThemeHooks();
43
43
  const { translate } = useTranslate();
44
- const { schema, ...metadata } = entity.metadata || {};
44
+ const { schema, sdl, ...metadata } = entity.metadata || {};
45
45
  const metadataToShow = Object.entries(metadata).filter(
46
46
  ([key]) => !(entity.type === 'api-description' && key === 'descriptionFile'),
47
47
  );
@@ -13,6 +13,7 @@ export type CatalogEntitySchemaProps = {
13
13
  relatedEntity: BffCatalogRelatedEntity | null;
14
14
  RedocSchema: React.ComponentType<any>;
15
15
  StoreProvider: React.ComponentType<any>;
16
+ GraphqlTypeRenderer?: React.ComponentType<{ sdl: string; typeName: string }>;
16
17
  };
17
18
 
18
19
  export function CatalogEntitySchema({
@@ -20,37 +21,45 @@ export function CatalogEntitySchema({
20
21
  relatedEntity,
21
22
  RedocSchema,
22
23
  StoreProvider,
24
+ GraphqlTypeRenderer,
23
25
  }: CatalogEntitySchemaProps) {
24
26
  const { useTranslate } = useThemeHooks();
25
27
  const { translate } = useTranslate();
26
28
  const { definition, parsedSchema, rawSchema } = useCatalogEntitySchema({ entity, relatedEntity });
29
+ const isGraphql = entity.metadata?.specType === 'graphql';
30
+ const graphqlSDL = entity?.metadata?.sdl;
27
31
 
28
32
  return (
29
33
  <MetadataWrapper data-component-name="Catalog/CatalogEntity/CatalogEntityMetadata">
30
34
  <HeaderWrapper>
31
35
  <Heading>{translate('catalog.entity.schema.title')}</Heading>
32
- <CopyButton
33
- data={rawSchema}
34
- buttonText="Copy Schema"
35
- type="compound"
36
- variant="secondary"
37
- iconPosition="right"
38
- size="medium"
39
- ></CopyButton>
36
+ {!isGraphql && (
37
+ <CopyButton
38
+ data={rawSchema}
39
+ buttonText="Copy Schema"
40
+ type="compound"
41
+ variant="secondary"
42
+ iconPosition="right"
43
+ size="medium"
44
+ ></CopyButton>
45
+ )}
40
46
  </HeaderWrapper>
41
47
  <SplitViewWrapper>
42
48
  <SchemaContentWrapper>
43
- <StoreProvider definition={definition}>
44
- <RedocSchema schema={parsedSchema} />
45
- </StoreProvider>
49
+ {isGraphql && graphqlSDL && GraphqlTypeRenderer ? (
50
+ <GraphqlTypeRenderer sdl={graphqlSDL} typeName={entity.title} />
51
+ ) : (
52
+ <StoreProvider definition={definition}>
53
+ <RedocSchema schema={parsedSchema} />
54
+ </StoreProvider>
55
+ )}
46
56
  </SchemaContentWrapper>
47
- <SchemaSampleWrapper>
48
- <JsonViewer
49
- data={Sampler.sample({ ...parsedSchema })}
50
- expandLevel={3}
51
- hideHeader={false}
52
- />
53
- </SchemaSampleWrapper>
57
+
58
+ {!isGraphql && (
59
+ <SchemaSampleWrapper>
60
+ <JsonViewer data={Sampler.sample({ ...parsedSchema })} expandLevel={3} />
61
+ </SchemaSampleWrapper>
62
+ )}
54
63
  </SplitViewWrapper>
55
64
  </MetadataWrapper>
56
65
  );
@@ -8,6 +8,7 @@ import { breakpoints } from '@redocly/theme/core/utils';
8
8
  import { useThemeHooks, useModalScrollLock } from '@redocly/theme/core/hooks';
9
9
  import { H2 } from '@redocly/theme/components/Typography/H2';
10
10
  import { FilterContent } from '@redocly/theme/components/Filter/FilterContent';
11
+ import { FilterInput } from '@redocly/theme/components/Filter/FilterInput';
11
12
  import { FilterPopover } from '@redocly/theme/components/Filter/FilterPopover';
12
13
  import { HighlightContext } from '@redocly/theme/components/CatalogClassic/CatalogClassicHighlight';
13
14
  import { CatalogClassicActions } from '@redocly/theme/components/CatalogClassic/CatalogClassicActions';
@@ -37,16 +38,18 @@ export default function CatalogClassic(props: CatalogClassicProps): JSX.Element
37
38
  data-component-name="CatalogClassic/CatalogClassic"
38
39
  withoutFilters={!filters.length}
39
40
  >
40
- <FiltersSidebar
41
- menu={
42
- <FilterContent
43
- setFilterTerm={setFilterTerm}
44
- filters={filters}
45
- filterTerm={filterTerm}
46
- filterValuesCasing={catalogConfig.filterValuesCasing}
47
- />
48
- }
49
- />
41
+ {Boolean(filters.length) && (
42
+ <FiltersSidebar
43
+ menu={
44
+ <FilterContent
45
+ setFilterTerm={setFilterTerm}
46
+ filters={filters}
47
+ filterTerm={filterTerm}
48
+ filterValuesCasing={catalogConfig.filterValuesCasing}
49
+ />
50
+ }
51
+ />
52
+ )}
50
53
  {filterPopoverVisible && (
51
54
  <FilterPopover
52
55
  onClose={() => setFilterPopoverVisible(false)}
@@ -75,6 +78,14 @@ export default function CatalogClassic(props: CatalogClassicProps): JSX.Element
75
78
  {translate(catalogConfig.descriptionTranslationKey, catalogConfig.description)}{' '}
76
79
  </CatalogDescription>
77
80
  ) : null}
81
+ {!filters.length && (
82
+ <CatalogSearchWrapper>
83
+ <FilterInput
84
+ value={filterTerm}
85
+ onChange={(updatedTerm) => setFilterTerm(updatedTerm)}
86
+ />
87
+ </CatalogSearchWrapper>
88
+ )}
78
89
  </CatalogPageDescriptionWrapper>
79
90
 
80
91
  <CatalogClassicVirtualizedGroups
@@ -163,3 +174,8 @@ const FiltersSidebar = styled(Sidebar)`
163
174
  }
164
175
  --menu-container-padding-top: 0;
165
176
  `;
177
+
178
+ const CatalogSearchWrapper = styled.div`
179
+ margin-top: var(--spacing-base);
180
+ max-width: 300px;
181
+ `;
@@ -18,8 +18,8 @@ export type CodeBlockProps = {
18
18
  header?: CodeBlockControlsProps;
19
19
  dataTestId?: string;
20
20
  className?: string;
21
- tabs?: CodeBlockTabItems;
22
- dropdown?: CodeBlockDropdownItems;
21
+ tabs?: CodeBlockItems;
22
+ dropdown?: CodeBlockItems;
23
23
  withLineNumbers?: boolean;
24
24
  startLineNumber?: number;
25
25
  highlightedHtml?: string;
@@ -37,15 +37,9 @@ type UnstableExternalCodeSample = {
37
37
  get: (source: ExternalSource) => string;
38
38
  };
39
39
 
40
- export type CodeBlockTabItems = {
41
- items: { name: string; lang?: string }[];
42
- onChange: (name: string) => void;
43
- value: string;
44
- };
45
-
46
- export type CodeBlockDropdownItems = {
47
- items: { name: string; lang?: string }[];
48
- onChange: (name: string | string[]) => void;
40
+ export type CodeBlockItems = {
41
+ items: { name: string; lang?: string; id: string }[];
42
+ onChange: (id: string) => void;
49
43
  value: string;
50
44
  };
51
45