@redocly/theme 0.70.0-next.7 → 0.70.0-next.8

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 (71) hide show
  1. package/lib/components/Buttons/ConnectMCPButton.js +11 -1
  2. package/lib/components/Buttons/variables.d.ts +1 -0
  3. package/lib/components/Buttons/variables.js +4 -1
  4. package/lib/components/Catalog/Catalog.js +2 -2
  5. package/lib/components/JsonViewer/Helpers.js +3 -3
  6. package/lib/components/MCP/McpConnectionTabs.js +9 -2
  7. package/lib/components/Search/SearchItem.js +1 -1
  8. package/lib/components/Search/SearchTrigger.js +33 -8
  9. package/lib/components/Search/variables.js +2 -0
  10. package/lib/core/constants/mcp.d.ts +2 -2
  11. package/lib/core/constants/mcp.js +1 -1
  12. package/lib/core/hooks/code-walkthrough/use-code-panel.d.ts +1 -1
  13. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.d.ts +1 -1
  14. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +1 -1
  15. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.d.ts +1 -1
  16. package/lib/core/hooks/code-walkthrough/use-code-walkthrough.d.ts +1 -2
  17. package/lib/core/hooks/code-walkthrough/use-renderable-files.d.ts +1 -1
  18. package/lib/core/hooks/use-connect-mcp-button.js +1 -0
  19. package/lib/core/hooks/use-page-actions.d.ts +1 -1
  20. package/lib/core/hooks/use-page-actions.js +6 -0
  21. package/lib/core/styles/global.js +1 -0
  22. package/lib/core/types/code-walkthrough.d.ts +84 -0
  23. package/lib/core/types/hooks.d.ts +1 -1
  24. package/lib/core/types/l10n.d.ts +1 -1
  25. package/lib/core/types/mcp.d.ts +1 -1
  26. package/lib/core/utils/download-code-walkthrough.d.ts +1 -1
  27. package/lib/core/utils/get-code-walkthrough-file-text.d.ts +1 -1
  28. package/lib/core/utils/match-code-walkthrough-conditions.d.ts +1 -1
  29. package/lib/core/utils/mcp.js +7 -2
  30. package/lib/markdoc/components/CodeWalkthrough/CodeFilters.d.ts +1 -1
  31. package/lib/markdoc/components/CodeWalkthrough/CodePanel.d.ts +1 -1
  32. package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.d.ts +1 -1
  33. package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.d.ts +1 -1
  34. package/lib/markdoc/components/CodeWalkthrough/CodeStep.d.ts +1 -1
  35. package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.d.ts +1 -1
  36. package/lib/markdoc/components/Tabs/TabList.js +8 -6
  37. package/lib/markdoc/tags/code-walkthrough.d.ts +1 -1
  38. package/package.json +3 -3
  39. package/src/components/Buttons/ConnectMCPButton.tsx +13 -2
  40. package/src/components/Buttons/variables.ts +4 -0
  41. package/src/components/Catalog/Catalog.tsx +5 -3
  42. package/src/components/JsonViewer/Helpers.tsx +5 -3
  43. package/src/components/MCP/McpConnectionTabs.tsx +22 -5
  44. package/src/components/Search/SearchItem.tsx +3 -1
  45. package/src/components/Search/SearchTrigger.tsx +42 -7
  46. package/src/components/Search/variables.ts +2 -0
  47. package/src/core/constants/mcp.ts +1 -1
  48. package/src/core/hooks/code-walkthrough/use-code-panel.ts +1 -1
  49. package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +2 -2
  50. package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +1 -1
  51. package/src/core/hooks/code-walkthrough/use-code-walkthrough.ts +3 -3
  52. package/src/core/hooks/code-walkthrough/use-renderable-files.ts +1 -1
  53. package/src/core/hooks/use-connect-mcp-button.ts +7 -1
  54. package/src/core/hooks/use-page-actions.ts +17 -0
  55. package/src/core/styles/global.ts +2 -1
  56. package/src/core/types/code-walkthrough.ts +103 -0
  57. package/src/core/types/hooks.ts +1 -0
  58. package/src/core/types/l10n.ts +3 -0
  59. package/src/core/types/mcp.ts +1 -1
  60. package/src/core/utils/download-code-walkthrough.ts +1 -1
  61. package/src/core/utils/get-code-walkthrough-file-text.ts +1 -1
  62. package/src/core/utils/match-code-walkthrough-conditions.ts +1 -1
  63. package/src/core/utils/mcp.ts +8 -2
  64. package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +1 -1
  65. package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +1 -1
  66. package/src/markdoc/components/CodeWalkthrough/CodePanelHeader.tsx +1 -1
  67. package/src/markdoc/components/CodeWalkthrough/CodePanelToolbar.tsx +1 -1
  68. package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +1 -1
  69. package/src/markdoc/components/CodeWalkthrough/CodeWalkthrough.tsx +1 -1
  70. package/src/markdoc/components/Tabs/TabList.tsx +9 -12
  71. package/src/markdoc/tags/code-walkthrough.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { JSX } from 'react';
3
- import type { CodeWalkthroughFile } from '@redocly/config';
3
+ import type { CodeWalkthroughFile } from '../../../core/types';
4
4
  export type CodePanelProps = {
5
5
  files: CodeWalkthroughFile[];
6
6
  downloadAssociatedFiles: CodeWalkthroughFile[];
@@ -1,5 +1,5 @@
1
1
  import type { JSX } from 'react';
2
- import type { CodeWalkthroughFile } from '@redocly/config';
2
+ import type { CodeWalkthroughFile } from '../../../core/types';
3
3
  export type CodePanelHeaderProps = {
4
4
  files: CodeWalkthroughFile[];
5
5
  handleTabSwitch: (name: string) => void;
@@ -1,5 +1,5 @@
1
1
  import type { JSX } from 'react';
2
- import type { CodeWalkthroughFile } from '@redocly/config';
2
+ import type { CodeWalkthroughFile } from '../../../core/types';
3
3
  export type CodeToolbarProps = {
4
4
  file: CodeWalkthroughFile;
5
5
  };
@@ -1,5 +1,5 @@
1
1
  import React, { type PropsWithChildren } from 'react';
2
- import type { WithConditions } from '@redocly/config';
2
+ import type { WithConditions } from '../../../core/types';
3
3
  export type CodeStepProps = WithConditions<{
4
4
  id: string;
5
5
  heading?: string;
@@ -1,4 +1,4 @@
1
1
  import React, { type PropsWithChildren } from 'react';
2
- import type { CodeWalkthroughAttr } from '@redocly/config';
2
+ import type { CodeWalkthroughAttr } from '../../../core/types';
3
3
  export type CodeWalkthroughProps = PropsWithChildren<CodeWalkthroughAttr>;
4
4
  export declare function CodeWalkthrough({ children, steps, preview, ...attributes }: CodeWalkthroughProps): React.JSX.Element;
@@ -152,7 +152,7 @@ function TabList({ childrenArray, size, activeTab, onTabChange, containerRef, on
152
152
  overflowTabs.some((i) => childrenArray[i] && activeTab === childrenArray[i].props.label);
153
153
  // Show as selector when no visible tabs (all tabs in dropdown)
154
154
  const showAsSelector = visibleTabs.length === 0 && hasOverflow;
155
- const { dropdownPosition, setIsDropdownOpen, setDropdownPosition } = useDropdownPosition(hasOverflow, dropdownRef);
155
+ const { dropdownPosition, isDropdownOpen, setIsDropdownOpen, setDropdownPosition } = useDropdownPosition(hasOverflow, dropdownRef);
156
156
  return (react_1.default.createElement(exports.TabListContainer, { role: "tablist", ref: containerRef },
157
157
  react_1.default.createElement(HighlightBar, { $size: size, style: highlightStyle },
158
158
  react_1.default.createElement("div", null)),
@@ -163,11 +163,9 @@ function TabList({ childrenArray, size, activeTab, onTabChange, containerRef, on
163
163
  return null;
164
164
  return renderTab(child, index, size, setTabRef, handleKeyboard, onTabClick);
165
165
  }),
166
- hasOverflow && (react_1.default.createElement(exports.TabItem, { size: size, active: isMoreActive || showAsSelector, tabIndex: 0, className: "dropdown-tab" },
167
- react_1.default.createElement(DropdownWrapper, { $top: dropdownPosition.top, $left: dropdownPosition.left, onClickCapture: () => {
168
- setIsDropdownOpen(true);
169
- } },
170
- react_1.default.createElement(FixedPositionDropdown, { ref: dropdownRef, trigger: react_1.default.createElement(exports.TabButtonLink, { size: size, className: isMoreActive || showAsSelector ? 'active' : undefined }, showAsSelector ? react_1.default.createElement(TabButtonText, null, activeTab) : 'More'), alignment: "start", withArrow: true, onClose: () => {
166
+ hasOverflow && (react_1.default.createElement(exports.TabItem, { size: size, active: isMoreActive || showAsSelector, tabIndex: 0, className: isDropdownOpen ? 'dropdown-tab dropdown-tab-open' : 'dropdown-tab' },
167
+ react_1.default.createElement(DropdownWrapper, { $top: dropdownPosition.top, $left: dropdownPosition.left },
168
+ react_1.default.createElement(FixedPositionDropdown, { ref: dropdownRef, trigger: react_1.default.createElement(exports.TabButtonLink, { size: size, className: isMoreActive || showAsSelector ? 'active' : undefined }, showAsSelector ? react_1.default.createElement(TabButtonText, null, activeTab) : 'More'), alignment: "start", withArrow: true, onOpen: () => setIsDropdownOpen(true), onClose: () => {
171
169
  setIsDropdownOpen(false);
172
170
  setDropdownPosition({});
173
171
  } },
@@ -259,6 +257,10 @@ exports.TabListContainer = styled_components_1.default.ul `
259
257
  min-width: 0;
260
258
  max-width: 100%;
261
259
  }
260
+
261
+ &.dropdown-tab-open {
262
+ z-index: var(--dropdown-menu-z-index);
263
+ }
262
264
  }
263
265
  }
264
266
  `;
@@ -1,6 +1,6 @@
1
1
  import type { Node, RenderableTreeNode } from '@markdoc/markdoc';
2
2
  import type { MarkdocSchemaWrapper } from '../../markdoc/tags/types';
3
- import type { CodeWalkthroughConditions, CodeWalkthroughFilter, TogglesMarkdocAttr, InputsMarkdocAttr } from '@redocly/config';
3
+ import type { CodeWalkthroughConditions, CodeWalkthroughFilter, TogglesMarkdocAttr, InputsMarkdocAttr } from '../../core/types';
4
4
  export declare const codeWalkthrough: MarkdocSchemaWrapper;
5
5
  export declare function collectStepsFromChildren(children: RenderableTreeNode[], idx?: number): RenderableTreeNode[];
6
6
  export declare function collectTogglesFromChildren(children: Node[], toggles?: TogglesMarkdocAttr): TogglesMarkdocAttr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.70.0-next.7",
3
+ "version": "0.70.0-next.8",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -42,7 +42,7 @@
42
42
  "devDependencies": {
43
43
  "@babel/core": "7.29.7",
44
44
  "@markdoc/markdoc": "0.5.2",
45
- "@redocly/realm-asyncapi-sdk": "0.16.0-next.2",
45
+ "@redocly/realm-asyncapi-sdk": "0.16.0-next.4",
46
46
  "@redocly/tooling-test-utils": "0.0.0",
47
47
  "@shikijs/types": "3.21.0",
48
48
  "@testing-library/react": "16.3.0",
@@ -72,7 +72,7 @@
72
72
  "webpack": "5.105.2"
73
73
  },
74
74
  "dependencies": {
75
- "@redocly/config": "0.62.0",
75
+ "@redocly/config": "0.65.0",
76
76
  "@tanstack/react-query": "5.62.3",
77
77
  "@tanstack/react-virtual": "3.13.0",
78
78
  "@xyflow/react": "12.8.3",
@@ -41,6 +41,13 @@ const MENU_OPTIONS: Record<MCPOption, MenuOption> = {
41
41
  descriptionTranslationKey: 'page.actions.connectMcp.vscodeDescription',
42
42
  descriptionDefault: 'Install MCP server on VS Code',
43
43
  },
44
+ claude: {
45
+ icon: ClaudeIcon,
46
+ titleTranslationKey: 'page.actions.connectMcp.claude',
47
+ titleDefault: 'Connect to Claude',
48
+ descriptionTranslationKey: 'page.actions.connectMcp.claudeDescription',
49
+ descriptionDefault: 'Add MCP server to your Claude account',
50
+ },
44
51
  'claude-code': {
45
52
  icon: ClaudeIcon,
46
53
  titleTranslationKey: 'page.actions.connectMcp.claudeCode',
@@ -118,7 +125,7 @@ export function ConnectMCPButton({
118
125
  >
119
126
  {dropdownOptions.length > 0
120
127
  ? ({ close }: { close: () => void }) => (
121
- <DropdownMenu>
128
+ <StyledDropdownMenu>
122
129
  {dropdownOptions.map((option) => {
123
130
  const Icon = option.icon;
124
131
  const showCheckmark = copiedOption === option.key;
@@ -150,7 +157,7 @@ export function ConnectMCPButton({
150
157
  </DropdownMenuItem>
151
158
  );
152
159
  })}
153
- </DropdownMenu>
160
+ </StyledDropdownMenu>
154
161
  )
155
162
  : null}
156
163
  </SplitButton>
@@ -158,6 +165,10 @@ export function ConnectMCPButton({
158
165
  );
159
166
  }
160
167
 
168
+ const StyledDropdownMenu = styled(DropdownMenu)`
169
+ --dropdown-menu-max-height: var(--connect-mcp-button-dropdown-max-height);
170
+ `;
171
+
161
172
  const ConnectMCPButtonWrapper = styled.div`
162
173
  display: inline-block;
163
174
  position: relative;
@@ -50,3 +50,7 @@ export const aiAssistantButton = css`
50
50
  // @tokens End
51
51
  `;
52
52
  /* eslint-enable theme/no-raw-colors-in-styles */
53
+
54
+ export const connectMcpButton = css`
55
+ --connect-mcp-button-dropdown-max-height: fit-content;
56
+ `;
@@ -162,9 +162,11 @@ export function Catalog(props: CatalogProps): JSX.Element {
162
162
  <CatalogPageContentWrapper>
163
163
  <CatalogTitleWrapper>
164
164
  <CatalogTitle data-translation-key={catalogConfig?.titleTranslationKey}>
165
- {catalogConfig?.titleTranslationKey
166
- ? translate(catalogConfig?.titleTranslationKey)
167
- : catalogConfig?.slug}{' '}
165
+ <span>
166
+ {catalogConfig?.titleTranslationKey
167
+ ? translate(catalogConfig?.titleTranslationKey)
168
+ : catalogConfig?.slug}
169
+ </span>{' '}
168
170
  </CatalogTitle>
169
171
  <CounterTag borderless>{entitiesCounter}</CounterTag>
170
172
  </CatalogTitleWrapper>
@@ -79,7 +79,7 @@ export function JsonValue(props: {
79
79
  fold={fold}
80
80
  maxStringLength={maxStringLength}
81
81
  />
82
- {index < value.length - 1 ? ',\n' : null}
82
+ {index < value.length - 1 ? <span>{',\n'}</span> : null}
83
83
  </React.Fragment>
84
84
  ))
85
85
  : keys.map((key, index) => (
@@ -92,7 +92,7 @@ export function JsonValue(props: {
92
92
  fold={fold}
93
93
  maxStringLength={maxStringLength}
94
94
  />
95
- {index < keys.length - 1 ? ',\n' : null}
95
+ {index < keys.length - 1 ? <span>{',\n'}</span> : null}
96
96
  </React.Fragment>
97
97
  ));
98
98
 
@@ -177,7 +177,9 @@ function JsonKeyValue(props: {
177
177
  {isFoldable(value) ? (
178
178
  <ExpandIcon onClick={() => fold.setExpanded(path, !isExpanded)} isExpanded={isExpanded} />
179
179
  ) : null}
180
- <span className="property token string">{`"${name}"`}</span>: {valueElement}
180
+ <span className="property token string">{`"${name}"`}</span>
181
+ <span>{': '}</span>
182
+ {valueElement}
181
183
  </>
182
184
  );
183
185
  }
@@ -10,9 +10,11 @@ import { useMCPConfig, useThemeHooks } from '@redocly/theme/core/hooks';
10
10
  import {
11
11
  generateClaudeCodeCommand,
12
12
  generateCodexCommand,
13
+ generateMCPDeepLink,
13
14
  generateMcpInstallPrompt,
14
15
  getBaseDataAttributes,
15
16
  } from '@redocly/theme/core/utils';
17
+ import { Button } from '@redocly/theme/components/Button/Button';
16
18
  import { CodeBlock } from '@redocly/theme/components/CodeBlock/CodeBlock';
17
19
  import { ClaudeIcon } from '@redocly/theme/icons/ClaudeIcon/ClaudeIcon';
18
20
  import { ChatGptIcon } from '@redocly/theme/icons/ChatGptIcon/ChatGptIcon';
@@ -167,16 +169,26 @@ function renderTabContent(
167
169
  ),
168
170
  },
169
171
  {
170
- headline: translate(
171
- 'page.mcpNotAllowed.snippets.claudeDesktop.headline',
172
- 'Claude Desktop',
173
- ),
172
+ headline: translate('page.mcpNotAllowed.snippets.claudeDesktop.headline', 'Claude app'),
174
173
  content: (
175
174
  <>
175
+ <TabHint>
176
+ {translate(
177
+ 'page.mcpNotAllowed.snippets.claudeDesktop.accountHint',
178
+ 'Claude adds the connector to your account and syncs it between Claude on the web and Claude Desktop.',
179
+ )}
180
+ </TabHint>
181
+ <ConnectButton
182
+ variant="secondary"
183
+ icon={<ClaudeIcon />}
184
+ onClick={() => window.open(generateMCPDeepLink('claude', connection), '_blank')}
185
+ >
186
+ {translate('page.actions.connectMcp.claude', 'Connect to Claude')}
187
+ </ConnectButton>
176
188
  <TabHint>
177
189
  {translate(
178
190
  'page.mcpNotAllowed.snippets.claudeDesktop.instruction',
179
- 'Open Customize → Connectors → Add custom connector and paste this server URL:',
191
+ 'Or open Customize → Connectors → Add custom connector and paste this server URL:',
180
192
  )}
181
193
  </TabHint>
182
194
  <CodeBlock
@@ -278,6 +290,11 @@ const McpConnectionTabsWrapper = styled.div`
278
290
  }
279
291
  `;
280
292
 
293
+ const ConnectButton = styled(Button)`
294
+ align-self: flex-start;
295
+ margin-bottom: var(--spacing-sm);
296
+ `;
297
+
281
298
  const TabHint = styled.p`
282
299
  margin: 0 0 var(--spacing-xs);
283
300
  color: var(--page-mcp-405-snippets-hint-text-color);
@@ -78,7 +78,9 @@ export function SearchItem({
78
78
  <SearchItemOperationTag color={httpColor}>
79
79
  {document.httpMethod.toUpperCase()}
80
80
  </SearchItemOperationTag>
81
- {highlight.httpPath ? searchHighlight(highlight.httpPath) : document.httpPath}
81
+ <span>
82
+ {highlight.httpPath ? searchHighlight(highlight.httpPath) : document.httpPath}
83
+ </span>
82
84
  </SearchItemOperation>
83
85
  ) : null}
84
86
  <SearchItemTitleWrapper>
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import styled from 'styled-components';
2
+ import styled, { keyframes } from 'styled-components';
3
3
 
4
4
  import type { JSX } from 'react';
5
5
 
@@ -9,6 +9,9 @@ import { SearchIcon } from '@redocly/theme/icons/SearchIcon/SearchIcon';
9
9
  import { breakpoints, getUserAgent } from '@redocly/theme/core/utils';
10
10
  import { DEFAULT_KEYBOARD_SHORTCUTS } from '@redocly/theme/core/constants';
11
11
 
12
+ const MAC_SHORTCUT_LABEL = '⌘K';
13
+ const SHORTCUT_LABEL = 'Ctrl+K';
14
+
12
15
  export type SearchTriggerProps = {
13
16
  onClick: () => void;
14
17
  className?: string;
@@ -31,8 +34,8 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
31
34
  }
32
35
 
33
36
  mainShortcutKey = mainShortcutKey?.toUpperCase();
34
- // A page can be cached and served to every platform, so the server renders a hidden
35
- // placeholder and the browser picks the label after hydration.
37
+ // A page can be cached and served to every platform, so the server renders an empty
38
+ // slot and the browser picks the label after hydration.
36
39
  const [isMac, setIsMac] = React.useState<boolean | undefined>(undefined);
37
40
  React.useEffect(() => setIsMac(getUserAgent().includes('Mac')), []);
38
41
 
@@ -56,8 +59,12 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
56
59
  <SearchIcon />
57
60
  {translate('search.navbar.label', 'Search')}
58
61
  {mainShortcutKey === DEFAULT_KEYBOARD_SHORTCUTS ? (
59
- <SearchTriggerShortcut $isPending={isMac === undefined}>
60
- {isMac ? '⌘K' : 'Ctrl+K'}
62
+ <SearchTriggerShortcut>
63
+ {isMac === undefined ? null : (
64
+ <SearchTriggerShortcutLabel>
65
+ {isMac ? MAC_SHORTCUT_LABEL : SHORTCUT_LABEL}
66
+ </SearchTriggerShortcutLabel>
67
+ )}
61
68
  </SearchTriggerShortcut>
62
69
  ) : (
63
70
  <span>{mainShortcutKey}</span>
@@ -85,8 +92,36 @@ const SearchTriggerButton = styled(Button)`
85
92
  }
86
93
  `;
87
94
 
88
- const SearchTriggerShortcut = styled.span<{ $isPending: boolean }>`
89
- visibility: ${({ $isPending }) => ($isPending ? 'hidden' : 'visible')};
95
+ // The hidden copy of the wider label keeps the slot the same width before and after
96
+ // hydration on every platform, so the trigger does not shift when the label appears.
97
+ const SearchTriggerShortcut = styled.span`
98
+ display: inline-flex;
99
+ flex-direction: column;
100
+ align-items: flex-end;
101
+
102
+ &::after {
103
+ content: '${SHORTCUT_LABEL}';
104
+ height: 0;
105
+ overflow: hidden;
106
+ visibility: hidden;
107
+ }
108
+ `;
109
+
110
+ const shortcutAppear = keyframes`
111
+ from {
112
+ opacity: 0;
113
+ filter: blur(2px);
114
+ transform: translateY(3px);
115
+ }
116
+ `;
117
+
118
+ const SearchTriggerShortcutLabel = styled.span`
119
+ animation: ${shortcutAppear} var(--search-trigger-shortcut-appear-duration)
120
+ var(--search-trigger-shortcut-appear-easing);
121
+
122
+ @media (prefers-reduced-motion: reduce) {
123
+ animation: none;
124
+ }
90
125
  `;
91
126
 
92
127
  const SearchTriggerInput = styled.div`
@@ -145,6 +145,8 @@ export const search = css`
145
145
  --search-trigger-bg-color: var(--navbar-bg-color);
146
146
  --search-trigger-icon-size: 16px;
147
147
  --search-trigger-line-height: var(--line-height-base);
148
+ --search-trigger-shortcut-appear-duration: 300ms;
149
+ --search-trigger-shortcut-appear-easing: ease-out;
148
150
 
149
151
  /**
150
152
  * @tokens AI Search
@@ -4,6 +4,6 @@ export const MCP_ROUTE = '/mcp';
4
4
 
5
5
  export const PUBLIC_MCP_ROUTE = '/mcp-public';
6
6
 
7
- export const MCP_OPTIONS = ['cursor', 'vscode', 'claude-code', 'codex', 'copy'] as const;
7
+ export const MCP_OPTIONS = ['cursor', 'vscode', 'claude', 'claude-code', 'codex', 'copy'] as const;
8
8
 
9
9
  export const DEFAULT_MCP_OPTIONS = [...MCP_OPTIONS];
@@ -4,7 +4,7 @@ import type {
4
4
  CodeWalkthroughFile,
5
5
  CodeWalkthroughNode,
6
6
  CodeWalkthroughConditionsObject,
7
- } from '@redocly/config';
7
+ } from '@redocly/theme/core/types';
8
8
 
9
9
  import { CodeWalkthroughControlsStateContext } from '../../contexts/CodeWalkthrough/CodeWalkthroughControlsContext';
10
10
  import { CodeWalkthroughStepsContext } from '../../contexts/CodeWalkthrough/CodeWalkthroughStepsContext';
@@ -10,7 +10,7 @@ import type {
10
10
  CodeWalkthroughFilterItem,
11
11
  CodeWalkthroughConditionsObject,
12
12
  CodeWalkthroughControlsState,
13
- } from '@redocly/config';
13
+ } from '@redocly/theme/core/types';
14
14
 
15
15
  import { downloadCodeWalkthrough } from '../../utils/download-code-walkthrough';
16
16
  import { matchCodeWalkthroughConditions } from '../../utils/match-code-walkthrough-conditions';
@@ -98,7 +98,7 @@ export function useCodeWalkthroughControls(
98
98
  Object.entries(newState).forEach(([id, control]) => {
99
99
  const existingControl = controlsState[id];
100
100
  if (existingControl && existingControl.type === control.type) {
101
- // @ts-expect-error
101
+ // @ts-expect-error: TS2322 - the spread loses the link between `type` and `value` in the control union
102
102
  newState[id] = {
103
103
  ...control,
104
104
  value: existingControl.value,
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useEffect, useRef, useState, useMemo } from 'react';
2
2
  import { useLocation, useNavigate } from 'react-router';
3
3
 
4
- import type { CodeWalkthroughStepAttr } from '@redocly/config';
4
+ import type { CodeWalkthroughStepAttr } from '@redocly/theme/core/types';
5
5
  import type { ActiveStep, WalkthroughStepsState } from '../../types/code-walkthrough';
6
6
  import type { MarkerArea } from '../../types/marker';
7
7
 
@@ -1,9 +1,9 @@
1
1
  import type {
2
+ CodeWalkthroughAttr,
2
3
  CodeWalkthroughFile,
3
4
  CodeWalkthroughStepAttr,
4
- CodeWalkthroughAttr,
5
- } from '@redocly/config';
6
- import type { WalkthroughStepsState } from '../../types/code-walkthrough';
5
+ WalkthroughStepsState,
6
+ } from '../../types/code-walkthrough';
7
7
 
8
8
  import {
9
9
  useCodeWalkthroughControls,
@@ -1,6 +1,6 @@
1
1
  import { useMemo } from 'react';
2
2
 
3
- import type { CodeWalkthroughFile } from '@redocly/config';
3
+ import type { CodeWalkthroughFile } from '@redocly/theme/core/types';
4
4
 
5
5
  import { findClosestCommonDirectory } from '../../utils/find-closest-common-directory';
6
6
  import { getFileIconByExt } from '../../utils/GetFileIcon';
@@ -7,7 +7,12 @@ import { useThemeHooks } from './use-theme-hooks';
7
7
  import { useMCPConfig } from './use-mcp-config';
8
8
  import { ClipboardService } from '../utils/clipboard-service';
9
9
  import { DEFAULT_MCP_OPTIONS } from '../constants/mcp';
10
- import { generateClaudeCodeCommand, generateCodexCommand, isMCPOption } from '../utils/mcp';
10
+ import {
11
+ generateClaudeCodeCommand,
12
+ generateCodexCommand,
13
+ generateMCPDeepLink,
14
+ isMCPOption,
15
+ } from '../utils/mcp';
11
16
  import { getBaseDataAttributes } from '../utils/telemetry/get-base-data-attributes';
12
17
 
13
18
  export type McpButtonOptions = {
@@ -68,6 +73,7 @@ export function useConnectMCPButton({
68
73
  const urlMap: Partial<Record<MCPOption, string>> = {
69
74
  cursor: cursorUrl,
70
75
  vscode: vscodeUrl,
76
+ claude: generateMCPDeepLink('claude', connection),
71
77
  };
72
78
 
73
79
  window.open(urlMap[action], '_blank');
@@ -31,6 +31,7 @@ const DEFAULT_ENABLED_ACTIONS = [
31
31
  'claude',
32
32
  'docs-mcp-cursor',
33
33
  'docs-mcp-vscode',
34
+ 'docs-mcp-claude',
34
35
  ] as const;
35
36
 
36
37
  export type PageActionType =
@@ -40,6 +41,7 @@ export type PageActionType =
40
41
  | 'claude'
41
42
  | 'docs-mcp-cursor'
42
43
  | 'docs-mcp-vscode'
44
+ | 'docs-mcp-claude'
43
45
  // Used in OpenAPI docs x-mcp
44
46
  | 'mcp-cursor'
45
47
  | 'mcp-vscode';
@@ -114,6 +116,7 @@ export function usePageActions(
114
116
  const actionHandlers: Record<PageActionType, () => PageAction> = {
115
117
  'docs-mcp-cursor': createMCPHandler('cursor', false),
116
118
  'docs-mcp-vscode': createMCPHandler('vscode', false),
119
+ 'docs-mcp-claude': createMCPHandler('claude', false),
117
120
  'mcp-cursor': createMCPHandler('cursor', true),
118
121
  'mcp-vscode': createMCPHandler('vscode', true),
119
122
 
@@ -261,6 +264,19 @@ function createMCPAction({
261
264
  };
262
265
  }
263
266
 
267
+ if (clientType === 'claude') {
268
+ return {
269
+ ...sharedProps,
270
+ buttonText: translate('page.actions.connectMcp.claude', 'Connect to Claude'),
271
+ title: translate('page.actions.connectMcp.claude', 'Connect to Claude'),
272
+ description: translate(
273
+ 'page.actions.connectMcp.claudeDescription',
274
+ 'Add MCP server to your Claude account',
275
+ ),
276
+ iconComponent: ClaudeIcon,
277
+ };
278
+ }
279
+
264
280
  return {
265
281
  ...sharedProps,
266
282
  buttonText: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'),
@@ -337,6 +353,7 @@ function shouldHideActionByType(
337
353
  return !isPublic;
338
354
  case 'docs-mcp-cursor':
339
355
  case 'docs-mcp-vscode':
356
+ case 'docs-mcp-claude':
340
357
  return Boolean(mcpUrl) || isMcpDisabled;
341
358
  case 'mcp-cursor':
342
359
  case 'mcp-vscode':
@@ -20,7 +20,7 @@ import { checkbox } from '@redocly/theme/icons/CheckboxIcon/variables';
20
20
  import { admonition } from '@redocly/theme/components/Admonition/variables';
21
21
  import { footer } from '@redocly/theme/components/Footer/variables';
22
22
  import { button } from '@redocly/theme/components/Button/variables';
23
- import { aiAssistantButton } from '@redocly/theme/components/Buttons/variables';
23
+ import { aiAssistantButton, connectMcpButton } from '@redocly/theme/components/Buttons/variables';
24
24
  import { navbar } from '@redocly/theme/components/Navbar/variables';
25
25
  import { search } from '@redocly/theme/components/Search/variables';
26
26
  import { menu, mobileMenu } from '@redocly/theme/components/Menu/variables';
@@ -1343,6 +1343,7 @@ export const tokens = css`
1343
1343
  ${breadcrumbs}
1344
1344
  ${button}
1345
1345
  ${aiAssistantButton}
1346
+ ${connectMcpButton}
1346
1347
  ${cards}
1347
1348
  ${catalog}
1348
1349
  ${catalogClassic}
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from 'react';
1
2
  import type { MarkerArea } from './marker';
2
3
 
3
4
  export type ActiveStep = string | null;
@@ -13,3 +14,105 @@ export type WalkthroughStepsState = {
13
14
  lockObserver?: React.RefObject<boolean>;
14
15
  filtersElementRef?: React.RefObject<HTMLDivElement | null>;
15
16
  };
17
+
18
+ export type CodeWalkthroughStepAttr = {
19
+ id: string;
20
+ title?: string;
21
+ };
22
+
23
+ export type FilesetsMarkdocAttr = WithConditions<{
24
+ files?: string[];
25
+ downloadAssociatedFiles?: string[];
26
+ }>[];
27
+
28
+ export type InputsMarkdocAttr = {
29
+ [id: string]: WithConditions<{ value: string }>;
30
+ };
31
+
32
+ export type TogglesMarkdocAttr = {
33
+ [id: string]: CodeWalkthroughConditionsObject;
34
+ };
35
+
36
+ export type CodeWalkthroughConditions = {
37
+ [key: string]: string | string[] | undefined | boolean;
38
+ };
39
+
40
+ export type CodeWalkthroughFileset = WithConditions<{
41
+ files?: CodeWalkthroughFile[];
42
+ downloadAssociatedFiles?: CodeWalkthroughFile[];
43
+ }>;
44
+ export type CodeWalkthroughFile = {
45
+ path: string;
46
+ content: CodeWalkthroughNode[];
47
+ basename: string;
48
+ metadata: CodeWalkthroughFileMetadata;
49
+ language: string;
50
+ };
51
+
52
+ export type CodeWalkthroughChunk = {
53
+ start: number;
54
+ children: CodeWalkthroughNode[];
55
+ condition: CodeWalkthroughChunkCondition;
56
+ };
57
+
58
+ export type CodeWalkthroughChunkCondition = WithConditions<{
59
+ steps: string[];
60
+ }>;
61
+
62
+ export type CodeWalkthroughNode = CodeWalkthroughChunk | string;
63
+
64
+ export type CodeWalkthroughFileMetadata = {
65
+ steps: string[];
66
+ };
67
+
68
+ export type CodeWalkthroughFilter = WithConditions<{
69
+ id: string;
70
+ label?: string;
71
+ items: CodeWalkthroughFilterItem[];
72
+ }>;
73
+
74
+ export type CodeWalkthroughFilterItem = WithConditions<{
75
+ value: string;
76
+ }>;
77
+
78
+ export type CodeWalkthroughConditionsObject = {
79
+ when?: CodeWalkthroughConditions;
80
+ unless?: CodeWalkthroughConditions;
81
+ };
82
+
83
+ export type WithConditions<T> = T & CodeWalkthroughConditionsObject;
84
+
85
+ export type CodeWalkthroughControls = {
86
+ toggle: boolean;
87
+ input: string;
88
+ filter: string;
89
+ };
90
+
91
+ export type CodeWalkthroughControlState = WithConditions<
92
+ | {
93
+ value: string;
94
+ render: boolean;
95
+ type: 'input';
96
+ }
97
+ | {
98
+ value: string;
99
+ render: boolean;
100
+ type: 'filter';
101
+ }
102
+ | {
103
+ value: boolean;
104
+ render: boolean;
105
+ type: 'toggle';
106
+ }
107
+ >;
108
+ export type CodeWalkthroughControlsState = Record<string, CodeWalkthroughControlState>;
109
+
110
+ export type CodeWalkthroughAttr = {
111
+ steps: CodeWalkthroughStepAttr[];
112
+ filters: Record<string, CodeWalkthroughFilter>;
113
+ filesets: CodeWalkthroughFileset[];
114
+ preview: ReactNode[];
115
+ inputs: InputsMarkdocAttr;
116
+ toggles: TogglesMarkdocAttr;
117
+ __idx: number;
118
+ };
@@ -191,6 +191,7 @@ export type ThemeHooks = {
191
191
  | 'startSpan'
192
192
  | 'constructCloudEvent'
193
193
  | 'sendToOtelService'
194
+ | 'withTracer'
194
195
  > & {
195
196
  send<TEventType extends AsyncApiRealmUI.EventType>(
196
197
  event: TEventType,