@redocly/theme 0.69.0-next.4 → 0.69.0-next.6

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 (177) hide show
  1. package/lib/components/Accordion/variables.js +1 -1
  2. package/lib/components/Admonition/variables.js +1 -1
  3. package/lib/components/Banner/variables.dark.js +2 -0
  4. package/lib/components/Banner/variables.js +3 -1
  5. package/lib/components/Breadcrumbs/Breadcrumb.js +1 -1
  6. package/lib/components/Breadcrumbs/variables.js +1 -1
  7. package/lib/components/Button/ButtonGroup.d.ts +3 -5
  8. package/lib/components/Button/ButtonGroup.js +25 -5
  9. package/lib/components/Button/variables.js +27 -4
  10. package/lib/components/Buttons/ConnectMCPButton.js +15 -128
  11. package/lib/components/Buttons/CopyButton.js +12 -1
  12. package/lib/components/Buttons/variables.d.ts +0 -1
  13. package/lib/components/Buttons/variables.js +3 -44
  14. package/lib/components/Catalog/CatalogEntity/CatalogEntityLinks.js +1 -1
  15. package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +1 -1
  16. package/lib/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.js +1 -1
  17. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +1 -1
  18. package/lib/components/Catalog/CatalogFilter/CatalogFilterSelect.js +1 -0
  19. package/lib/components/Catalog/variables.js +5 -5
  20. package/lib/components/CatalogClassic/variables.js +2 -2
  21. package/lib/components/CodeBlock/CodeBlock.js +2 -1
  22. package/lib/components/CodeBlock/CodeBlockContainer.js +1 -0
  23. package/lib/components/Dropdown/Dropdown.d.ts +10 -20
  24. package/lib/components/Dropdown/Dropdown.js +13 -2
  25. package/lib/components/Dropdown/DropdownMenuItemContent.d.ts +9 -0
  26. package/lib/components/Dropdown/DropdownMenuItemContent.js +56 -0
  27. package/lib/components/Dropdown/variables.js +19 -2
  28. package/lib/components/Feedback/Mood.js +18 -14
  29. package/lib/components/Feedback/Rating.js +18 -13
  30. package/lib/components/Feedback/Scale.js +27 -22
  31. package/lib/components/Feedback/Sentiment.js +17 -13
  32. package/lib/components/Filter/FilterSelect.js +1 -0
  33. package/lib/components/Filter/variables.js +2 -2
  34. package/lib/components/Image/variables.js +5 -3
  35. package/lib/components/LanguagePicker/variables.js +1 -1
  36. package/lib/components/Markdown/variables.js +1 -1
  37. package/lib/components/Menu/MenuItem.js +1 -1
  38. package/lib/components/Menu/variables.js +1 -1
  39. package/lib/components/Navbar/variables.js +1 -1
  40. package/lib/components/PageActions/PageActions.js +4 -6
  41. package/lib/components/PageActions/PageActionsMenuItem.d.ts +4 -4
  42. package/lib/components/PageActions/PageActionsMenuItem.js +27 -43
  43. package/lib/components/Panel/variables.js +1 -1
  44. package/lib/components/Product/variables.js +2 -1
  45. package/lib/components/ReplayGate/ReplayGate.d.ts +1 -0
  46. package/lib/components/Search/SearchAiMessage.js +1 -1
  47. package/lib/components/Search/SearchAiNegativeFeedbackForm.js +2 -2
  48. package/lib/components/Search/SearchDialog.js +1 -1
  49. package/lib/components/Search/SearchItem.js +1 -0
  50. package/lib/components/Search/SearchRecent.js +1 -0
  51. package/lib/components/Search/SearchSuggestedPages.js +1 -0
  52. package/lib/components/Search/variables.js +8 -5
  53. package/lib/components/Segmented/Segmented.js +3 -3
  54. package/lib/components/Select/Select.js +20 -18
  55. package/lib/components/Select/variables.js +3 -3
  56. package/lib/components/SplitButton/SplitButton.d.ts +21 -0
  57. package/lib/components/SplitButton/SplitButton.js +37 -0
  58. package/lib/components/Switch/variables.dark.js +2 -2
  59. package/lib/components/Switch/variables.js +2 -2
  60. package/lib/components/Tag/variables.js +2 -2
  61. package/lib/components/Tags/variables.js +1 -1
  62. package/lib/components/Toast/variables.js +1 -1
  63. package/lib/components/Tooltip/AnchorTooltip.js +2 -2
  64. package/lib/components/Tooltip/JsTooltip.js +2 -2
  65. package/lib/components/UserMenu/variables.js +1 -1
  66. package/lib/core/constants/mcp.d.ts +2 -0
  67. package/lib/core/constants/mcp.js +3 -1
  68. package/lib/core/hooks/use-control.js +3 -0
  69. package/lib/core/hooks/use-mcp-config.d.ts +2 -0
  70. package/lib/core/hooks/use-mcp-config.js +14 -4
  71. package/lib/core/styles/global.js +11 -11
  72. package/lib/core/styles/palette.js +2 -0
  73. package/lib/core/types/button-group.d.ts +2 -0
  74. package/lib/core/types/button-group.js +3 -0
  75. package/lib/core/types/catalog.d.ts +2 -6
  76. package/lib/core/types/common.d.ts +2 -0
  77. package/lib/core/types/hooks.d.ts +1 -0
  78. package/lib/core/types/index.d.ts +1 -0
  79. package/lib/core/types/l10n.d.ts +1 -1
  80. package/lib/core/utils/RenderWithLink.d.ts +2 -0
  81. package/lib/core/utils/RenderWithLink.js +20 -0
  82. package/lib/core/utils/index.d.ts +1 -0
  83. package/lib/core/utils/index.js +1 -0
  84. package/lib/icons/LinkIcon/LinkIcon.js +1 -1
  85. package/lib/index.d.ts +2 -0
  86. package/lib/index.js +2 -0
  87. package/lib/layouts/McpNotAllowed.js +5 -7
  88. package/lib/markdoc/components/Cards/variables.js +6 -4
  89. package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +1 -0
  90. package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +1 -1
  91. package/lib/markdoc/components/CodeWalkthrough/variables.js +2 -1
  92. package/lib/markdoc/components/Tabs/TabList.js +6 -2
  93. package/lib/markdoc/components/Tabs/Tabs.js +4 -2
  94. package/lib/markdoc/components/Tabs/variables.js +4 -4
  95. package/package.json +12 -3
  96. package/src/components/Accordion/variables.ts +1 -1
  97. package/src/components/Admonition/variables.ts +1 -1
  98. package/src/components/Banner/variables.dark.ts +2 -0
  99. package/src/components/Banner/variables.ts +3 -1
  100. package/src/components/Breadcrumbs/Breadcrumb.tsx +1 -1
  101. package/src/components/Breadcrumbs/variables.ts +1 -1
  102. package/src/components/Button/ButtonGroup.tsx +28 -10
  103. package/src/components/Button/variables.ts +27 -4
  104. package/src/components/Buttons/ConnectMCPButton.tsx +63 -150
  105. package/src/components/Buttons/CopyButton.tsx +14 -2
  106. package/src/components/Buttons/variables.ts +2 -44
  107. package/src/components/Catalog/CatalogEntity/CatalogEntityLinks.tsx +1 -1
  108. package/src/components/Catalog/CatalogEntity/CatalogEntityMetadata.tsx +1 -1
  109. package/src/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.tsx +1 -1
  110. package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +1 -1
  111. package/src/components/Catalog/CatalogFilter/CatalogFilterSelect.tsx +1 -0
  112. package/src/components/Catalog/variables.ts +5 -5
  113. package/src/components/CatalogClassic/variables.ts +2 -2
  114. package/src/components/CodeBlock/CodeBlock.tsx +2 -1
  115. package/src/components/CodeBlock/CodeBlockContainer.tsx +1 -0
  116. package/src/components/Dropdown/Dropdown.tsx +25 -4
  117. package/src/components/Dropdown/DropdownMenuItemContent.tsx +72 -0
  118. package/src/components/Dropdown/variables.ts +19 -2
  119. package/src/components/Feedback/Mood.tsx +22 -15
  120. package/src/components/Feedback/Rating.tsx +22 -14
  121. package/src/components/Feedback/Scale.tsx +40 -32
  122. package/src/components/Feedback/Sentiment.tsx +21 -14
  123. package/src/components/Filter/FilterSelect.tsx +1 -0
  124. package/src/components/Filter/variables.ts +2 -2
  125. package/src/components/Image/variables.ts +5 -3
  126. package/src/components/LanguagePicker/variables.ts +1 -1
  127. package/src/components/Markdown/variables.ts +1 -1
  128. package/src/components/Menu/MenuItem.tsx +2 -2
  129. package/src/components/Menu/variables.ts +1 -1
  130. package/src/components/Navbar/variables.ts +1 -1
  131. package/src/components/PageActions/PageActions.tsx +22 -23
  132. package/src/components/PageActions/PageActionsMenuItem.tsx +41 -55
  133. package/src/components/Panel/variables.ts +1 -1
  134. package/src/components/Product/variables.ts +2 -1
  135. package/src/components/ReplayGate/ReplayGate.tsx +3 -0
  136. package/src/components/Search/SearchAiMessage.tsx +1 -1
  137. package/src/components/Search/SearchAiNegativeFeedbackForm.tsx +2 -2
  138. package/src/components/Search/SearchDialog.tsx +1 -1
  139. package/src/components/Search/SearchItem.tsx +1 -0
  140. package/src/components/Search/SearchRecent.tsx +1 -0
  141. package/src/components/Search/SearchSuggestedPages.tsx +1 -0
  142. package/src/components/Search/variables.ts +8 -5
  143. package/src/components/Segmented/Segmented.tsx +6 -3
  144. package/src/components/Select/Select.tsx +24 -16
  145. package/src/components/Select/variables.ts +3 -3
  146. package/src/components/SplitButton/SplitButton.tsx +95 -0
  147. package/src/components/Switch/variables.dark.ts +2 -2
  148. package/src/components/Switch/variables.ts +2 -2
  149. package/src/components/Tag/variables.ts +2 -2
  150. package/src/components/Tags/variables.ts +1 -1
  151. package/src/components/Toast/variables.ts +1 -1
  152. package/src/components/Tooltip/AnchorTooltip.tsx +2 -2
  153. package/src/components/Tooltip/JsTooltip.tsx +2 -2
  154. package/src/components/UserMenu/variables.ts +1 -1
  155. package/src/core/constants/mcp.ts +4 -0
  156. package/src/core/hooks/use-control.ts +5 -1
  157. package/src/core/hooks/use-mcp-config.ts +15 -4
  158. package/src/core/styles/global.ts +12 -12
  159. package/src/core/styles/palette.ts +2 -0
  160. package/src/core/types/button-group.ts +2 -0
  161. package/src/core/types/catalog.ts +2 -7
  162. package/src/core/types/common.ts +3 -0
  163. package/src/core/types/hooks.ts +1 -0
  164. package/src/core/types/index.ts +1 -0
  165. package/src/core/types/l10n.ts +5 -0
  166. package/src/core/utils/RenderWithLink.tsx +19 -0
  167. package/src/core/utils/index.ts +1 -0
  168. package/src/icons/LinkIcon/LinkIcon.tsx +1 -1
  169. package/src/index.ts +2 -0
  170. package/src/layouts/McpNotAllowed.tsx +33 -9
  171. package/src/markdoc/components/Cards/variables.ts +6 -4
  172. package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +1 -0
  173. package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +1 -1
  174. package/src/markdoc/components/CodeWalkthrough/variables.ts +2 -1
  175. package/src/markdoc/components/Tabs/TabList.tsx +6 -2
  176. package/src/markdoc/components/Tabs/Tabs.tsx +4 -2
  177. package/src/markdoc/components/Tabs/variables.ts +4 -4
@@ -8,7 +8,7 @@ export const banner = css`
8
8
  --banner-button-size: 22px;
9
9
  --banner-button-padding: 3px; // @presenter Spacing
10
10
  --banner-button-font-size: var(--font-size-base);
11
- --banner-button-border-radius: var(--border-radius);
11
+ --banner-button-border-radius: var(--border-radius-md);
12
12
  --banner-button-padding-inline: 1px var(--spacing-sm);
13
13
  --banner-button-line-height: var(--line-height-base); // @presenter LineHeight
14
14
  --banner-button-icon-size: 14px;
@@ -47,5 +47,7 @@ export const banner = css`
47
47
  --banner-error-link-color: var(--banner-error-text-color); // @presenter Color
48
48
  --banner-error-link-decoration: underline 1px var(--banner-error-link-color);
49
49
  --banner-error-link-decoration-hover: underline 2px var(--banner-error-link-color);
50
+
51
+ // @tokens End
50
52
  `;
51
53
 
@@ -61,7 +61,7 @@ const baseBreadcrumbStyles = `
61
61
  align-items: center;
62
62
  gap: var(--breadcrumbs-gap);
63
63
  padding: var(--breadcrumb-padding);
64
- border-radius: var(--border-radius);
64
+ border-radius: var(--breadcrumbs-border-radius);
65
65
  color: var(--breadcrumbs-text-color);
66
66
  text-decoration: none;
67
67
 
@@ -13,7 +13,7 @@ export const breadcrumbs = css`
13
13
  --breadcrumbs-icon-size: var(--font-size-base); // @presenter FontSize
14
14
  --breadcrumbs-font-weight-active: var(--font-weight-medium); // @presenter FontWeight
15
15
 
16
- --breadcrumbs-border-radius: var(--border-radius); // @presenter BorderRadius
16
+ --breadcrumbs-border-radius: var(--border-radius-md); // @presenter BorderRadius
17
17
  --breadcrumbs-gap: var(--spacing-xxs); // @presenter Spacing
18
18
 
19
19
  --breadcrumbs-padding: 2px var(--spacing-xs); // @presenter Spacing
@@ -2,13 +2,11 @@ import React from 'react';
2
2
  import styled from 'styled-components';
3
3
 
4
4
  import type { JSX } from 'react';
5
- import type { ButtonSize } from '@redocly/theme/components/Button/Button';
5
+ import type { ButtonGroupSize, ButtonGroupVariant } from '@redocly/theme/core/types';
6
6
 
7
- type ButtonGroupVariant = 'outlined';
8
-
9
- type ButtonGroupProps = {
7
+ export type ButtonGroupProps = {
10
8
  variant?: ButtonGroupVariant;
11
- size?: ButtonSize;
9
+ size?: ButtonGroupSize;
12
10
  children: React.ReactNode;
13
11
  className?: string;
14
12
  };
@@ -30,24 +28,44 @@ const ButtonGroupWrapper = styled.div`
30
28
  display: flex;
31
29
  line-height: var(--button-line-height);
32
30
 
33
- .button {
31
+ & > .button,
32
+ & > * > .button {
34
33
  border-radius: 0;
35
34
  }
36
35
 
37
36
  & > .button:first-child,
38
- *:first-child > .button {
37
+ & > *:first-child > .button {
39
38
  border-top-left-radius: var(--button-border-radius);
40
39
  border-bottom-left-radius: var(--button-border-radius);
41
40
  }
42
41
 
43
42
  & > .button:last-child,
44
- *:last-child > .button {
43
+ & > *:last-child > .button {
45
44
  border-top-right-radius: var(--button-border-radius);
46
45
  border-bottom-right-radius: var(--button-border-radius);
47
46
  }
48
47
 
48
+ /* Adjacent segments share a single divider line: the leading segment drops its
49
+ own right border and the trailing one draws the divider as its left border. */
50
+ & > .button:not(:last-child),
51
+ & > *:not(:last-child) > .button {
52
+ border-right-style: none;
53
+ border-right-width: 0;
54
+ }
55
+
49
56
  & > .button:not(:first-child),
50
- *:not(:first-child) > .button {
51
- border-left: none;
57
+ & > *:not(:first-child) > .button {
58
+ border-left-width: 1px;
59
+ border-left-style: solid;
60
+ border-left-color: color-mix(
61
+ in srgb,
62
+ var(--button-group-divider-color) calc(var(--button-group-divider-opacity) * 100%),
63
+ transparent
64
+ );
65
+ }
66
+
67
+ & > .button:not(:first-child):disabled,
68
+ & > *:not(:first-child) > .button:disabled {
69
+ border-left-color: var(--button-group-divider-color-disabled);
52
70
  }
53
71
  `;
@@ -68,7 +68,7 @@ export const button = css`
68
68
  --button-font-weight: var(--font-weight-regular);
69
69
  --button-font-size: var(--font-size-base);
70
70
  --button-line-height: var(--line-height-base);
71
- --button-border-radius: var(--border-radius-md);
71
+ --button-border-radius: var(--border-radius-lg);
72
72
  --button-padding: 5px var(--spacing-sm);
73
73
  --button-text-wrap: nowrap;
74
74
  --button-gap: var(--spacing-xs);
@@ -94,7 +94,7 @@ export const button = css`
94
94
  .button-size-small,
95
95
  .button-group-size-small .button {
96
96
  --button-font-size: var(--font-size-base);
97
- --button-border-radius: var(--border-radius);
97
+ --button-border-radius: var(--border-radius-md);
98
98
  --button-padding: 1px var(--spacing-sm);
99
99
  --button-line-height: var(--line-height-base);
100
100
 
@@ -107,7 +107,7 @@ export const button = css`
107
107
  .button-size-medium,
108
108
  .button-group-size-medium .button {
109
109
  --button-font-size: var(--font-size-base);
110
- --button-border-radius: var(--border-radius-md);
110
+ --button-border-radius: var(--border-radius-lg);
111
111
  --button-padding: 5px var(--spacing-sm);
112
112
  --button-line-height: var(--line-height-base);
113
113
 
@@ -120,7 +120,7 @@ export const button = css`
120
120
  .button-size-large,
121
121
  .button-group-size-large .button {
122
122
  --button-font-size: var(--font-size-lg); // @presenter FontSize
123
- --button-border-radius: var(--border-radius-md);
123
+ --button-border-radius: var(--border-radius-xl);
124
124
  --button-padding: var(--spacing-xs) var(--spacing-md);
125
125
  --button-line-height: var(--line-height-lg); // @presenter LineHeight
126
126
 
@@ -241,5 +241,28 @@ export const button = css`
241
241
  --button-icon-right-padding: 0;
242
242
  }
243
243
 
244
+ /**
245
+ * @tokens Button group divider
246
+ */
247
+
248
+ --button-group-divider-color: transparent;
249
+ --button-group-divider-opacity: 1;
250
+ --button-group-divider-color-disabled: var(--color-warm-grey-2); // @presenter Color
251
+
252
+ .button-group-primary {
253
+ --button-group-divider-color: var(--button-content-color-inverse); // @presenter Color
254
+ --button-group-divider-opacity: 0.32;
255
+ }
256
+
257
+ .button-group-secondary {
258
+ --button-group-divider-color: var(--button-content-color); // @presenter Color
259
+ --button-group-divider-opacity: 0.12;
260
+ }
261
+
262
+ .button-group-outlined {
263
+ --button-group-divider-color: var(--button-border-color); // @presenter Color
264
+ --button-group-divider-opacity: 1;
265
+ }
266
+
244
267
  // @tokens End
245
268
  `;
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef } from 'react';
1
+ import React from 'react';
2
2
  import styled from 'styled-components';
3
3
 
4
4
  import type { JSX } from 'react';
@@ -6,16 +6,16 @@ import type { MCPOption } from '@redocly/theme/core/types';
6
6
 
7
7
  import { DropdownMenu } from '@redocly/theme/components/Dropdown/DropdownMenu';
8
8
  import { DropdownMenuItem } from '@redocly/theme/components/Dropdown/DropdownMenuItem';
9
+ import { DropdownMenuItemContent } from '@redocly/theme/components/Dropdown/DropdownMenuItemContent';
9
10
  import { Button } from '@redocly/theme/components/Button/Button';
11
+ import { SplitButton } from '@redocly/theme/components/SplitButton/SplitButton';
10
12
  import { CursorIcon } from '@redocly/theme/icons/CursorIcon/CursorIcon';
11
13
  import { VSCodeIcon } from '@redocly/theme/icons/VSCodeIcon/VSCodeIcon';
12
14
  import { ClaudeIcon } from '@redocly/theme/icons/ClaudeIcon/ClaudeIcon';
13
15
  import { CodexIcon } from '@redocly/theme/icons/CodexIcon/CodexIcon';
14
16
  import { CopyIcon } from '@redocly/theme/icons/CopyIcon/CopyIcon';
15
17
  import { CheckmarkFilledIcon } from '@redocly/theme/icons/CheckmarkFilledIcon/CheckmarkFilledIcon';
16
- import { ChevronDownIcon } from '@redocly/theme/icons/ChevronDownIcon/ChevronDownIcon';
17
- import { ChevronUpIcon } from '@redocly/theme/icons/ChevronUpIcon/ChevronUpIcon';
18
- import { useConnectMCPButton, useOutsideClick, useThemeHooks } from '@redocly/theme/core/hooks';
18
+ import { useConnectMCPButton, useThemeHooks } from '@redocly/theme/core/hooks';
19
19
  import { DEFAULT_MCP_OPTIONS } from '@redocly/theme/core/constants';
20
20
 
21
21
  type MenuOption = {
@@ -86,13 +86,9 @@ export function ConnectMCPButton({
86
86
  }: ConnectMCPButtonProps): JSX.Element | null {
87
87
  const { useTranslate } = useThemeHooks();
88
88
  const { translate } = useTranslate();
89
- const [isOpen, setIsOpen] = useState(false);
90
- const wrapperRef = useRef<HTMLDivElement>(null);
91
89
 
92
90
  const { copiedOption, visibleOptions, handleAction } = useConnectMCPButton({ options });
93
91
 
94
- useOutsideClick(wrapperRef, () => setIsOpen(false));
95
-
96
92
  const menuOptions = MENU_OPTIONS.filter((option) => visibleOptions.includes(option.key));
97
93
  const primaryOption = menuOptions[0];
98
94
  const dropdownOptions = menuOptions.slice(1);
@@ -102,74 +98,68 @@ export function ConnectMCPButton({
102
98
  const PrimaryIcon = primaryOption.icon;
103
99
  const showPrimaryCopied = copiedOption === primaryOption.key;
104
100
 
105
- const handleMenuAction = (key: MCPOption) => {
106
- handleAction(key);
107
- if (!COPY_OPTIONS.includes(key)) {
108
- setIsOpen(false);
109
- }
110
- };
111
-
112
101
  return (
113
- <ConnectMCPButtonWrapper ref={wrapperRef} data-component-name="Buttons/ConnectMCPButton">
114
- <SplitButtonGroup>
115
- <PrimaryButton
116
- variant="secondary"
117
- icon={
118
- showPrimaryCopied ? (
119
- <CheckmarkFilledIcon color="var(--color-success-base)" />
120
- ) : (
121
- <PrimaryIcon />
122
- )
123
- }
124
- onClick={() => handleAction(primaryOption.key)}
125
- >
126
- {translate(primaryOption.titleTranslationKey, primaryOption.titleDefault)}
127
- </PrimaryButton>
128
- {dropdownOptions.length > 0 && (
129
- <ChevronButton
102
+ <ConnectMCPButtonWrapper data-component-name="Buttons/ConnectMCPButton">
103
+ <SplitButton
104
+ variant="secondary"
105
+ placement={placement}
106
+ alignment={alignment}
107
+ closeOnSelect={false}
108
+ toggleAriaLabel={translate('page.actions.connectMcp.moreOptions', 'More options')}
109
+ button={
110
+ <Button
130
111
  variant="secondary"
131
- aria-label={translate('page.actions.connectMcp.moreOptions', 'More options')}
132
- aria-expanded={isOpen}
133
- aria-haspopup="menu"
134
- onClick={() => setIsOpen((prev) => !prev)}
112
+ icon={
113
+ showPrimaryCopied ? (
114
+ <CheckmarkFilledIcon color="var(--color-success-base)" />
115
+ ) : (
116
+ <PrimaryIcon />
117
+ )
118
+ }
119
+ onClick={() => handleAction(primaryOption.key)}
135
120
  >
136
- {isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
137
- </ChevronButton>
138
- )}
139
- </SplitButtonGroup>
140
-
141
- {isOpen && dropdownOptions.length > 0 && (
142
- <DropdownWrapper $placement={placement} $alignment={alignment}>
143
- <DropdownMenu>
144
- {dropdownOptions.map((option) => {
145
- const Icon = option.icon;
146
- const showCheckmark = copiedOption === option.key;
147
-
148
- return (
149
- <DropdownMenuItem key={option.key} onAction={() => handleMenuAction(option.key)}>
150
- <MenuItemContent>
151
- <MenuItemIcon>
152
- {showCheckmark ? (
153
- <CheckmarkFilledIcon color="var(--color-success-base)" />
154
- ) : (
155
- <Icon />
156
- )}
157
- </MenuItemIcon>
158
- <MenuItemText>
159
- <MenuItemTitle>
160
- {translate(option.titleTranslationKey, option.titleDefault)}
161
- </MenuItemTitle>
162
- <MenuItemDescription>
163
- {translate(option.descriptionTranslationKey, option.descriptionDefault)}
164
- </MenuItemDescription>
165
- </MenuItemText>
166
- </MenuItemContent>
167
- </DropdownMenuItem>
168
- );
169
- })}
170
- </DropdownMenu>
171
- </DropdownWrapper>
172
- )}
121
+ {translate(primaryOption.titleTranslationKey, primaryOption.titleDefault)}
122
+ </Button>
123
+ }
124
+ >
125
+ {dropdownOptions.length > 0
126
+ ? ({ close }: { close: () => void }) => (
127
+ <DropdownMenu>
128
+ {dropdownOptions.map((option) => {
129
+ const Icon = option.icon;
130
+ const showCheckmark = copiedOption === option.key;
131
+
132
+ return (
133
+ <DropdownMenuItem
134
+ key={option.key}
135
+ onAction={() => {
136
+ handleAction(option.key);
137
+ if (!COPY_OPTIONS.includes(option.key)) {
138
+ close();
139
+ }
140
+ }}
141
+ >
142
+ <DropdownMenuItemContent
143
+ icon={
144
+ showCheckmark ? (
145
+ <CheckmarkFilledIcon color="var(--color-success-base)" />
146
+ ) : (
147
+ <Icon />
148
+ )
149
+ }
150
+ title={translate(option.titleTranslationKey, option.titleDefault)}
151
+ description={translate(
152
+ option.descriptionTranslationKey,
153
+ option.descriptionDefault,
154
+ )}
155
+ />
156
+ </DropdownMenuItem>
157
+ );
158
+ })}
159
+ </DropdownMenu>
160
+ )
161
+ : null}
162
+ </SplitButton>
173
163
  </ConnectMCPButtonWrapper>
174
164
  );
175
165
  }
@@ -178,80 +168,3 @@ const ConnectMCPButtonWrapper = styled.div`
178
168
  display: inline-block;
179
169
  position: relative;
180
170
  `;
181
-
182
- const SplitButtonGroup = styled.div`
183
- display: inline-flex;
184
- align-items: stretch;
185
- `;
186
-
187
- /* Doubled selectors outrank the base button class in any style injection order,
188
- and margin: 0 keeps themed button margins from splitting the group apart. */
189
- const PrimaryButton = styled(Button)`
190
- && {
191
- --button-gap: var(--connect-mcp-button-gap);
192
- margin: 0;
193
- border-top-right-radius: 0;
194
- border-bottom-right-radius: 0;
195
- }
196
- `;
197
-
198
- const ChevronButton = styled(Button)`
199
- && {
200
- margin: 0;
201
- border-top-left-radius: 0;
202
- border-bottom-left-radius: 0;
203
- border-left: none;
204
- padding-inline: var(--connect-mcp-button-chevron-padding-inline);
205
- }
206
- `;
207
-
208
- const DropdownWrapper = styled.div<{ $placement?: string; $alignment?: string }>`
209
- position: absolute;
210
- top: ${({ $placement }) => ($placement === 'top' ? 'auto' : '100%')};
211
- bottom: ${({ $placement }) => ($placement === 'top' ? '100%' : 'auto')};
212
- left: ${({ $alignment }) => ($alignment === 'start' ? '0' : 'auto')};
213
- right: ${({ $alignment }) => ($alignment === 'end' ? '0' : 'auto')};
214
- padding-top: var(--dropdown-menu-padding-top);
215
- z-index: var(--dropdown-menu-z-index);
216
- `;
217
-
218
- const MenuItemContent = styled.div`
219
- display: flex;
220
- align-items: center;
221
- gap: var(--connect-mcp-button-menu-item-gap);
222
- padding: var(--connect-mcp-button-menu-item-padding-block)
223
- var(--connect-mcp-button-menu-item-padding-inline);
224
- `;
225
-
226
- const MenuItemIcon = styled.div`
227
- display: flex;
228
- align-items: center;
229
- justify-content: center;
230
- width: var(--connect-mcp-button-menu-item-icon-size);
231
- height: var(--connect-mcp-button-menu-item-icon-size);
232
- flex-shrink: 0;
233
- border: var(--connect-mcp-button-menu-item-icon-border);
234
- border-radius: var(--connect-mcp-button-menu-item-icon-border-radius);
235
- color: var(--connect-mcp-button-menu-item-icon-color);
236
- `;
237
-
238
- const MenuItemText = styled.div`
239
- display: flex;
240
- flex-direction: column;
241
- gap: var(--connect-mcp-button-menu-item-text-gap);
242
- flex: 1;
243
- `;
244
-
245
- const MenuItemTitle = styled.div`
246
- font-size: var(--connect-mcp-button-menu-item-title-font-size);
247
- font-weight: var(--connect-mcp-button-menu-item-title-font-weight);
248
- line-height: var(--connect-mcp-button-menu-item-title-line-height);
249
- color: var(--connect-mcp-button-menu-item-title-color);
250
- `;
251
-
252
- const MenuItemDescription = styled.div`
253
- font-size: var(--connect-mcp-button-menu-item-description-font-size);
254
- font-weight: var(--connect-mcp-button-menu-item-description-font-weight);
255
- line-height: var(--connect-mcp-button-menu-item-description-line-height);
256
- color: var(--connect-mcp-button-menu-item-description-color);
257
- `;
@@ -1,4 +1,4 @@
1
- import React, { memo } from 'react';
1
+ import React, { memo, useEffect, useRef } from 'react';
2
2
 
3
3
  import type { JSX } from 'react';
4
4
  import type { TooltipProps } from '@redocly/theme/core/types';
@@ -52,11 +52,23 @@ function CopyButtonComponent({
52
52
  const { useTranslate } = useThemeHooks();
53
53
  const tooltip = useControl();
54
54
  const { translate } = useTranslate();
55
+ const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
56
+
57
+ useEffect(() => {
58
+ return () => {
59
+ if (closeTimerRef.current) {
60
+ clearTimeout(closeTimerRef.current);
61
+ }
62
+ };
63
+ }, []);
55
64
 
56
65
  const showTooltip = (duration: number = 1500): void => {
57
66
  tooltip.handleOpen();
58
67
 
59
- setTimeout(() => {
68
+ if (closeTimerRef.current) {
69
+ clearTimeout(closeTimerRef.current);
70
+ }
71
+ closeTimerRef.current = setTimeout(() => {
60
72
  tooltip.handleClose();
61
73
  }, duration);
62
74
  };
@@ -46,49 +46,7 @@ export const aiAssistantButton = css`
46
46
 
47
47
  /* Transition */
48
48
  --ai-assistant-button-transition: box-shadow 0.3s ease, transform 0.2s ease;
49
- `;
50
- /* eslint-enable theme/no-raw-colors-in-styles */
51
-
52
- export const connectMCPButton = css`
53
- /**
54
- * @tokens Connect MCP Button
55
- * @presenter Color
56
- */
57
-
58
- /* Button gap */
59
- --connect-mcp-button-gap: var(--spacing-xs);
60
49
 
61
- /* Chevron button */
62
- --connect-mcp-button-chevron-padding-inline: var(--spacing-xs);
63
-
64
- /* Menu item layout */
65
- --connect-mcp-button-menu-item-gap: var(--spacing-sm);
66
- --connect-mcp-button-menu-item-padding-block: var(--spacing-xxs);
67
- --connect-mcp-button-menu-item-padding-inline: 0;
68
-
69
- /* Menu item icon */
70
- --connect-mcp-button-menu-item-icon-size: 32px;
71
- --connect-mcp-button-menu-item-icon-border-color: var(--border-color-secondary);
72
- --connect-mcp-button-menu-item-icon-border-style: solid;
73
- --connect-mcp-button-menu-item-icon-border-width: 1px;
74
- --connect-mcp-button-menu-item-icon-border: var(--connect-mcp-button-menu-item-icon-border-width)
75
- var(--connect-mcp-button-menu-item-icon-border-style)
76
- var(--connect-mcp-button-menu-item-icon-border-color);
77
- --connect-mcp-button-menu-item-icon-border-radius: var(--border-radius);
78
- --connect-mcp-button-menu-item-icon-color: var(--icon-color-secondary);
79
-
80
- /* Menu item text */
81
- --connect-mcp-button-menu-item-text-gap: var(--spacing-xxs);
82
-
83
- /* Menu item title */
84
- --connect-mcp-button-menu-item-title-font-size: var(--font-size-base);
85
- --connect-mcp-button-menu-item-title-font-weight: var(--font-weight-regular);
86
- --connect-mcp-button-menu-item-title-line-height: var(--line-height-base);
87
- --connect-mcp-button-menu-item-title-color: var(--text-color-secondary);
88
-
89
- /* Menu item description */
90
- --connect-mcp-button-menu-item-description-font-size: var(--font-size-sm);
91
- --connect-mcp-button-menu-item-description-font-weight: var(--font-weight-regular);
92
- --connect-mcp-button-menu-item-description-line-height: var(--line-height-sm);
93
- --connect-mcp-button-menu-item-description-color: var(--text-color-description);
50
+ // @tokens End
94
51
  `;
52
+ /* eslint-enable theme/no-raw-colors-in-styles */
@@ -45,7 +45,7 @@ export function CatalogEntityLinks({ entity }: CatalogEntityLinksProps) {
45
45
  const LinksWrapper = styled.div`
46
46
  display: flex;
47
47
  flex-direction: column;
48
- border-radius: var(--border-radius);
48
+ border-radius: var(--border-radius-xl);
49
49
  background-color: var(--catalog-metadata-bg-color);
50
50
  transition: all 0.2s ease-in-out;
51
51
  margin: var(--spacing-lg) 0;
@@ -82,7 +82,7 @@ const JsonViewerWrapper = styled(JsonViewer)`
82
82
  const MetadataWrapper = styled.div`
83
83
  display: flex;
84
84
  flex-direction: column;
85
- border-radius: var(--border-radius);
85
+ border-radius: var(--border-radius-xl);
86
86
  background-color: var(--catalog-metadata-bg-color);
87
87
  transition: all 0.2s ease-in-out;
88
88
  margin-bottom: var(--spacing-base);
@@ -49,7 +49,7 @@ const PathLabel = styled.label`
49
49
  const LinksWrapper = styled.div`
50
50
  display: flex;
51
51
  flex-direction: column;
52
- border-radius: var(--border-radius);
52
+ border-radius: var(--border-radius-xl);
53
53
  background-color: var(--catalog-metadata-bg-color);
54
54
  transition: all 0.2s ease-in-out;
55
55
  margin: 0 0 var(--spacing-base) 0;
@@ -85,7 +85,7 @@ export function CatalogEntitySchema({
85
85
  const MetadataWrapper = styled.div`
86
86
  display: flex;
87
87
  flex-direction: column;
88
- border-radius: var(--border-radius);
88
+ border-radius: var(--border-radius-xl);
89
89
  background-color: var(--catalog-metadata-bg-color);
90
90
  margin-bottom: var(--spacing-lg);
91
91
  `;
@@ -127,6 +127,7 @@ const StyledSelect = styled(Select)<SelectProps>`
127
127
  --select-text-color: var(--filter-select-color);
128
128
  border: 1px solid var(--filter-select-border-color);
129
129
  --select-border-radius: var(--filter-select-border-radius);
130
+ --select-input-border-radius: var(--filter-select-border-radius);
130
131
  padding: var(--filter-select-padding);
131
132
 
132
133
  &:hover {
@@ -190,7 +190,7 @@ export const catalog = css`
190
190
  */
191
191
  --catalog-sort-trigger-gap: var(--spacing-xs);
192
192
  --catalog-sort-trigger-padding: 6px 8px;
193
- --catalog-sort-trigger-border-radius: var(--border-radius-md);
193
+ --catalog-sort-trigger-border-radius: var(--border-radius-lg);
194
194
  --catalog-sort-trigger-hover-bg-color: var(--button-bg-color-secondary-hover);
195
195
  --catalog-sort-icon-color: var(--text-color-secondary);
196
196
  --catalog-sort-text-font-size: var(--font-size-sm);
@@ -220,7 +220,7 @@ export const catalog = css`
220
220
  --catalog-card-border-width: var(--border-width);
221
221
  --catalog-card-border-style: var(--border-style);
222
222
  --catalog-card-border-color-hover: var(--border-color-primary);
223
- --catalog-card-border-radius: var(--border-radius-lg);
223
+ --catalog-card-border-radius: var(--border-radius-xl);
224
224
  --catalog-cards-group-margin: 0 0 var(--spacing-base) 0;
225
225
  --catalog-cards-group-gap: var(--spacing-lg);
226
226
 
@@ -229,7 +229,7 @@ export const catalog = css`
229
229
  */
230
230
  --catalog-card-icon-width: 30px;
231
231
  --catalog-card-icon-height: 30px;
232
- --catalog-card-icon-border-radius: 4px;
232
+ --catalog-card-icon-border-radius: var(--border-radius);
233
233
  --catalog-card-icon-bg-color: var(--bg-color);
234
234
  --catalog-card-icon-border-color: var(--border-color-secondary);
235
235
  --catalog-card-icon-border-width: 1px;
@@ -307,7 +307,7 @@ export const catalog = css`
307
307
  --catalog-actions-min-height: 40px;
308
308
  --catalog-actions-bg-color: var(--bg-color-tonal);
309
309
 
310
- --catalog-page-badge-border-radius: var(--border-radius);
310
+ --catalog-page-badge-border-radius: var(--badge-border-radius);
311
311
  --catalog-page-badge-padding: 0 var(--spacing-xs);
312
312
  --catalog-page-badge-font-size: var(--font-size-base);
313
313
  --catalog-page-badge-line-height: var(--line-height-base);
@@ -343,7 +343,7 @@ export const catalog = css`
343
343
  */
344
344
  --catalog-table-icon-width: 32px;
345
345
  --catalog-table-icon-height: 32px;
346
- --catalog-table-icon-border-radius: 4px;
346
+ --catalog-table-icon-border-radius: var(--border-radius);
347
347
  --catalog-table-icon-bg-color: var(--bg-color-tonal);
348
348
  --catalog-table-icon-border-color: var(--border-color-secondary);
349
349
  --catalog-table-icon-border-width: 1px;
@@ -57,7 +57,7 @@ export const catalogClassic = css`
57
57
  --catalog-classic-card-border-width: var(--border-width);
58
58
  --catalog-classic-card-border-style: var(--border-style);
59
59
  --catalog-classic-card-border-color-hover: var(--border-color-primary);
60
- --catalog-classic-card-border-radius: var(--border-radius-xxl);
60
+ --catalog-classic-card-border-radius: var(--border-radius-xl);
61
61
  --catalog-classic-cards-group-margin: 0 0 var(--spacing-base) 0;
62
62
  --catalog-classic-cards-group-gap: var(--spacing-xl);
63
63
 
@@ -94,7 +94,7 @@ export const catalogClassic = css`
94
94
  --catalog-classic-actions-min-height: 40px;
95
95
  --catalog-classic-actions-bg-color: var(--bg-color-tonal);
96
96
 
97
- --catalog-classic-page-badge-border-radius: var(--border-radius);
97
+ --catalog-classic-page-badge-border-radius: var(--border-radius-md);
98
98
  --catalog-classic-page-badge-padding: 0 var(--spacing-xs);
99
99
  --catalog-classic-page-badge-font-size: var(--font-size-base);
100
100
  --catalog-classic-page-badge-line-height: var(--line-height-base);
@@ -130,6 +130,7 @@ export function CodeBlock({
130
130
  useEffect(() => {
131
131
  const _source = source || externalSource?.sample?.get?.(externalSource);
132
132
  if (_source) {
133
+ // oxlint-disable-next-line react-you-might-not-need-an-effect/no-derived-state
133
134
  setSourceCode(_source);
134
135
  }
135
136
  }, [source, externalSource]);
@@ -204,7 +205,7 @@ const ContainerWrapper = styled.div`
204
205
 
205
206
  const CodeBlockWrapper = styled.div`
206
207
  border: 1px solid var(--border-color-secondary);
207
- border-radius: var(--border-radius);
208
+ border-radius: var(--border-radius-xl);
208
209
  background-color: var(--code-block-bg-color);
209
210
  margin: 0 0 var(--spacing-sm);
210
211
 
@@ -55,6 +55,7 @@ const CodeBlockContainerComponent = styled.pre<{
55
55
  max-height: ${({ $maxHeight }) =>
56
56
  $maxHeight ? $maxHeight : 'var(--code-block-max-height, 600px);'};
57
57
  word-break: var(--code-block-word-break, initial);
58
+ border-radius: var(--border-radius-xl);
58
59
 
59
60
  pre,
60
61
  code {