@redocly/theme 0.69.0-next.5 → 0.69.0-next.7

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 (180) 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/variables.js +1 -1
  38. package/lib/components/Navbar/variables.js +1 -1
  39. package/lib/components/PageActions/PageActions.js +4 -6
  40. package/lib/components/PageActions/PageActionsMenuItem.d.ts +4 -4
  41. package/lib/components/PageActions/PageActionsMenuItem.js +27 -43
  42. package/lib/components/Panel/variables.js +1 -1
  43. package/lib/components/Product/variables.js +2 -1
  44. package/lib/components/ReplayGate/ReplayGate.d.ts +1 -0
  45. package/lib/components/Search/SearchAiDialog.js +1 -1
  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 +2 -2
  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/constants/search.js +2 -2
  69. package/lib/core/hooks/use-control.js +3 -0
  70. package/lib/core/hooks/use-mcp-config.d.ts +2 -0
  71. package/lib/core/hooks/use-mcp-config.js +14 -4
  72. package/lib/core/styles/global.js +11 -11
  73. package/lib/core/styles/palette.js +2 -0
  74. package/lib/core/types/button-group.d.ts +2 -0
  75. package/lib/core/types/button-group.js +3 -0
  76. package/lib/core/types/catalog.d.ts +2 -6
  77. package/lib/core/types/common.d.ts +2 -0
  78. package/lib/core/types/hooks.d.ts +1 -0
  79. package/lib/core/types/index.d.ts +1 -0
  80. package/lib/core/types/l10n.d.ts +1 -1
  81. package/lib/core/utils/RenderWithLink.d.ts +2 -0
  82. package/lib/core/utils/RenderWithLink.js +20 -0
  83. package/lib/core/utils/index.d.ts +1 -0
  84. package/lib/core/utils/index.js +1 -0
  85. package/lib/icons/LinkIcon/LinkIcon.js +1 -1
  86. package/lib/index.d.ts +2 -0
  87. package/lib/index.js +2 -0
  88. package/lib/layouts/McpNotAllowed.js +5 -7
  89. package/lib/markdoc/components/Cards/variables.js +6 -4
  90. package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +1 -0
  91. package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +1 -1
  92. package/lib/markdoc/components/CodeWalkthrough/variables.js +2 -1
  93. package/lib/markdoc/components/Tabs/TabList.js +6 -2
  94. package/lib/markdoc/components/Tabs/Tabs.js +4 -2
  95. package/lib/markdoc/components/Tabs/variables.js +4 -4
  96. package/package.json +8 -8
  97. package/src/components/Accordion/variables.ts +1 -1
  98. package/src/components/Admonition/variables.ts +1 -1
  99. package/src/components/Banner/variables.dark.ts +2 -0
  100. package/src/components/Banner/variables.ts +3 -1
  101. package/src/components/Breadcrumbs/Breadcrumb.tsx +1 -1
  102. package/src/components/Breadcrumbs/variables.ts +1 -1
  103. package/src/components/Button/ButtonGroup.tsx +28 -10
  104. package/src/components/Button/variables.ts +27 -4
  105. package/src/components/Buttons/ConnectMCPButton.tsx +63 -150
  106. package/src/components/Buttons/CopyButton.tsx +14 -2
  107. package/src/components/Buttons/variables.ts +2 -44
  108. package/src/components/Catalog/CatalogEntity/CatalogEntityLinks.tsx +1 -1
  109. package/src/components/Catalog/CatalogEntity/CatalogEntityMetadata.tsx +1 -1
  110. package/src/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.tsx +1 -1
  111. package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +1 -1
  112. package/src/components/Catalog/CatalogFilter/CatalogFilterSelect.tsx +1 -0
  113. package/src/components/Catalog/variables.ts +5 -5
  114. package/src/components/CatalogClassic/variables.ts +2 -2
  115. package/src/components/CodeBlock/CodeBlock.tsx +2 -1
  116. package/src/components/CodeBlock/CodeBlockContainer.tsx +1 -0
  117. package/src/components/Dropdown/Dropdown.tsx +25 -4
  118. package/src/components/Dropdown/DropdownMenuItemContent.tsx +72 -0
  119. package/src/components/Dropdown/variables.ts +19 -2
  120. package/src/components/Feedback/Mood.tsx +22 -15
  121. package/src/components/Feedback/Rating.tsx +22 -14
  122. package/src/components/Feedback/Scale.tsx +40 -32
  123. package/src/components/Feedback/Sentiment.tsx +21 -14
  124. package/src/components/Filter/FilterSelect.tsx +1 -0
  125. package/src/components/Filter/variables.ts +2 -2
  126. package/src/components/Image/variables.ts +5 -3
  127. package/src/components/LanguagePicker/variables.ts +1 -1
  128. package/src/components/Markdown/variables.ts +1 -1
  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/SearchAiDialog.tsx +1 -1
  137. package/src/components/Search/SearchAiMessage.tsx +1 -1
  138. package/src/components/Search/SearchAiNegativeFeedbackForm.tsx +2 -2
  139. package/src/components/Search/SearchDialog.tsx +2 -2
  140. package/src/components/Search/SearchItem.tsx +1 -0
  141. package/src/components/Search/SearchRecent.tsx +1 -0
  142. package/src/components/Search/SearchSuggestedPages.tsx +1 -0
  143. package/src/components/Search/variables.ts +8 -5
  144. package/src/components/Segmented/Segmented.tsx +6 -3
  145. package/src/components/Select/Select.tsx +24 -16
  146. package/src/components/Select/variables.ts +3 -3
  147. package/src/components/SplitButton/SplitButton.tsx +95 -0
  148. package/src/components/Switch/variables.dark.ts +2 -2
  149. package/src/components/Switch/variables.ts +2 -2
  150. package/src/components/Tag/variables.ts +2 -2
  151. package/src/components/Tags/variables.ts +1 -1
  152. package/src/components/Toast/variables.ts +1 -1
  153. package/src/components/Tooltip/AnchorTooltip.tsx +2 -2
  154. package/src/components/Tooltip/JsTooltip.tsx +2 -2
  155. package/src/components/UserMenu/variables.ts +1 -1
  156. package/src/core/constants/mcp.ts +4 -0
  157. package/src/core/constants/search.ts +2 -2
  158. package/src/core/hooks/use-control.ts +5 -1
  159. package/src/core/hooks/use-mcp-config.ts +15 -4
  160. package/src/core/openapi/index.ts +1 -1
  161. package/src/core/styles/global.ts +12 -12
  162. package/src/core/styles/palette.ts +2 -0
  163. package/src/core/types/button-group.ts +2 -0
  164. package/src/core/types/catalog.ts +2 -7
  165. package/src/core/types/common.ts +3 -0
  166. package/src/core/types/hooks.ts +1 -0
  167. package/src/core/types/index.ts +1 -0
  168. package/src/core/types/l10n.ts +8 -1
  169. package/src/core/utils/RenderWithLink.tsx +19 -0
  170. package/src/core/utils/index.ts +1 -0
  171. package/src/icons/LinkIcon/LinkIcon.tsx +1 -1
  172. package/src/index.ts +2 -0
  173. package/src/layouts/McpNotAllowed.tsx +33 -9
  174. package/src/markdoc/components/Cards/variables.ts +6 -4
  175. package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +1 -0
  176. package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +1 -1
  177. package/src/markdoc/components/CodeWalkthrough/variables.ts +2 -1
  178. package/src/markdoc/components/Tabs/TabList.tsx +6 -2
  179. package/src/markdoc/components/Tabs/Tabs.tsx +4 -2
  180. package/src/markdoc/components/Tabs/variables.ts +4 -4
@@ -7,13 +7,12 @@ import type { PageAction } from '@redocly/theme/core/types';
7
7
  import { PageActionsMenuItem } from '@redocly/theme/components/PageActions/PageActionsMenuItem';
8
8
  import { DropdownMenuItem } from '@redocly/theme/components/Dropdown/DropdownMenuItem';
9
9
  import { Link } from '@redocly/theme/components/Link/Link';
10
- import { ButtonGroup } from '@redocly/theme/components/Button/ButtonGroup';
11
10
  import { Button } from '@redocly/theme/components/Button/Button';
12
- import { Dropdown } from '@redocly/theme/components/Dropdown/Dropdown';
11
+ import { SplitButton } from '@redocly/theme/components/SplitButton/SplitButton';
13
12
  import { DropdownMenu } from '@redocly/theme/components/Dropdown/DropdownMenu';
14
13
  import { Spinner } from '@redocly/theme/icons/Spinner/Spinner';
15
14
  import { CheckmarkFilledIcon } from '@redocly/theme/icons/CheckmarkFilledIcon/CheckmarkFilledIcon';
16
- import { PageActionType, usePageActions } from '@redocly/theme/core/hooks';
15
+ import { PageActionType, usePageActions, useThemeHooks } from '@redocly/theme/core/hooks';
17
16
 
18
17
  type ActionState = 'idle' | 'processing' | 'done';
19
18
 
@@ -28,6 +27,8 @@ const ACTION_DONE_DISPLAY_DURATION = 1000;
28
27
  export function PageActions(props: PageActionProps): JSX.Element | null {
29
28
  const { pageSlug, mcpUrl } = props;
30
29
 
30
+ const { useTranslate } = useThemeHooks();
31
+ const { translate } = useTranslate();
31
32
  const actions = usePageActions(pageSlug || '/', mcpUrl, props.actions);
32
33
 
33
34
  const [actionState, setActionState] = useState<ActionState>('idle');
@@ -73,27 +74,25 @@ export function PageActions(props: PageActionProps): JSX.Element | null {
73
74
 
74
75
  return (
75
76
  <PageActionsWrapper data-component-name="PageActions/PageActions">
76
- <ButtonGroup variant="outlined" size="medium">
77
- <Button
78
- icon={renderIcon(buttonAction, actionState)}
79
- to={'link' in buttonAction ? buttonAction.link : undefined}
80
- external
81
- onClick={() => handleActionClick(buttonAction)}
82
- >
83
- {buttonAction.buttonText}
84
- </Button>
85
- {actions.length > 1 ? (
86
- <Dropdown
87
- withArrow
88
- portalled
89
- trigger={<Button aria-label="More actions" />}
90
- placement="bottom"
91
- alignment="end"
77
+ <SplitButton
78
+ portalled
79
+ variant="outlined"
80
+ size="medium"
81
+ toggleAriaLabel={translate('page.actions.moreActions', 'More actions')}
82
+ button={
83
+ <Button
84
+ variant="outlined"
85
+ icon={renderIcon(buttonAction, actionState)}
86
+ to={'link' in buttonAction ? buttonAction.link : undefined}
87
+ external
88
+ onClick={() => handleActionClick(buttonAction)}
92
89
  >
93
- <StyledDropdownMenu>{menuItems}</StyledDropdownMenu>
94
- </Dropdown>
95
- ) : null}
96
- </ButtonGroup>
90
+ {buttonAction.buttonText}
91
+ </Button>
92
+ }
93
+ >
94
+ {actions.length > 1 ? <StyledDropdownMenu>{menuItems}</StyledDropdownMenu> : null}
95
+ </SplitButton>
97
96
  </PageActionsWrapper>
98
97
  );
99
98
  }
@@ -1,73 +1,59 @@
1
1
  import React from 'react';
2
2
  import styled from 'styled-components';
3
3
 
4
+ import type { JSX } from 'react';
4
5
  import type { PageAction } from '@redocly/theme/core/types';
5
6
 
7
+ import { DropdownMenuItemContent } from '@redocly/theme/components/Dropdown/DropdownMenuItemContent';
6
8
  import { LaunchIcon } from '@redocly/theme/icons/LaunchIcon/LaunchIcon';
7
9
 
8
- type PageActionsMenuItemProps = {
10
+ export type PageActionsMenuItemProps = {
9
11
  pageAction: PageAction;
12
+ className?: string;
10
13
  };
11
14
 
12
- export function PageActionsMenuItem(props: PageActionsMenuItemProps) {
13
- const { pageAction } = props;
15
+ export function PageActionsMenuItem(props: PageActionsMenuItemProps): JSX.Element {
16
+ const { pageAction, className } = props;
14
17
 
15
18
  return (
16
- <MenuItemWrapper data-component-name="PageActions/PageActionsMenuItem">
17
- <IconWrapper>
18
- <pageAction.iconComponent />
19
- </IconWrapper>
20
- <ContentWrapper>
21
- <Title>
22
- {pageAction.title}
23
- {'link' in pageAction ? (
24
- <LaunchIcon color="var(--page-actions-menu-item-title-icon-color)" size="14px" />
25
- ) : null}
26
- </Title>
27
- <Description>{pageAction.description}</Description>
28
- </ContentWrapper>
19
+ <MenuItemWrapper data-component-name="PageActions/PageActionsMenuItem" className={className}>
20
+ <DropdownMenuItemContent
21
+ icon={<pageAction.iconComponent />}
22
+ title={
23
+ <>
24
+ {pageAction.title}
25
+ {'link' in pageAction ? (
26
+ <LaunchIcon color="var(--page-actions-menu-item-title-icon-color)" size="14px" />
27
+ ) : null}
28
+ </>
29
+ }
30
+ description={pageAction.description}
31
+ />
29
32
  </MenuItemWrapper>
30
33
  );
31
34
  }
32
35
 
33
36
  const MenuItemWrapper = styled.div`
34
- padding: var(--page-actions-menu-item-padding);
35
- display: flex;
36
- flex-direction: row;
37
- align-items: center;
38
- gap: var(--page-actions-menu-item-gap);
39
- `;
40
-
41
- const IconWrapper = styled.div`
42
- color: var(--page-actions-menu-item-icon-color);
43
- border: 1px solid var(--page-actions-menu-item-icon-border-color);
44
- border-radius: var(--page-actions-menu-item-icon-border-radius);
45
- width: var(--page-actions-menu-item-icon-wrapper-size);
46
- height: var(--page-actions-menu-item-icon-wrapper-size);
47
- display: flex;
48
- align-items: center;
49
- justify-content: center;
50
- `;
51
-
52
- const ContentWrapper = styled.div`
53
- display: flex;
54
- flex-direction: column;
55
- gap: var(--page-actions-menu-item-text-gap);
56
- `;
57
-
58
- const Title = styled.div`
59
- font-weight: var(--page-actions-menu-item-title-font-weight);
60
- font-size: var(--page-actions-menu-item-title-font-size);
61
- line-height: var(--page-actions-menu-item-title-line-height);
62
- color: var(--page-actions-menu-item-title-color);
63
- display: flex;
64
- align-items: center;
65
- gap: var(--page-actions-menu-item-title-icon-gap);
66
- `;
67
-
68
- const Description = styled.div`
69
- font-weight: var(--page-actions-menu-item-description-font-weight);
70
- font-size: var(--page-actions-menu-item-description-font-size);
71
- line-height: var(--page-actions-menu-item-description-line-height);
72
- color: var(--page-actions-menu-item-description-color);
37
+ --dropdown-menu-item-content-gap: var(--page-actions-menu-item-gap);
38
+ --dropdown-menu-item-content-padding: var(--page-actions-menu-item-padding);
39
+ --dropdown-menu-item-content-icon-size: var(--page-actions-menu-item-icon-wrapper-size);
40
+ --dropdown-menu-item-content-icon-color: var(--page-actions-menu-item-icon-color);
41
+ --dropdown-menu-item-content-icon-border: 1px solid var(--page-actions-menu-item-icon-border-color);
42
+ --dropdown-menu-item-content-icon-border-radius: var(--page-actions-menu-item-icon-border-radius);
43
+ --dropdown-menu-item-content-text-gap: var(--page-actions-menu-item-text-gap);
44
+ --dropdown-menu-item-content-title-icon-gap: var(--page-actions-menu-item-title-icon-gap);
45
+ --dropdown-menu-item-content-title-font-weight: var(--page-actions-menu-item-title-font-weight);
46
+ --dropdown-menu-item-content-title-font-size: var(--page-actions-menu-item-title-font-size);
47
+ --dropdown-menu-item-content-title-line-height: var(--page-actions-menu-item-title-line-height);
48
+ --dropdown-menu-item-content-title-color: var(--page-actions-menu-item-title-color);
49
+ --dropdown-menu-item-content-description-font-weight: var(
50
+ --page-actions-menu-item-description-font-weight
51
+ );
52
+ --dropdown-menu-item-content-description-font-size: var(
53
+ --page-actions-menu-item-description-font-size
54
+ );
55
+ --dropdown-menu-item-content-description-line-height: var(
56
+ --page-actions-menu-item-description-line-height
57
+ );
58
+ --dropdown-menu-item-content-description-color: var(--page-actions-menu-item-description-color);
73
59
  `;
@@ -178,7 +178,7 @@ export const apiReferencePanels = css`
178
178
  * @tokens Panel common
179
179
  */
180
180
 
181
- --panel-border-radius: var(--border-radius); // @presenter BorderRadius
181
+ --panel-border-radius: var(--border-radius-xl); // @presenter BorderRadius
182
182
  --panel-border: 1px solid var(--border-color-secondary); // @presenter Border
183
183
 
184
184
  --panel-line-height: var(--line-height-base); // @presenter LineHeight
@@ -25,7 +25,7 @@ export const productPicker = css`
25
25
  --product-picker-dropdown-item-padding-vertical: var(--dropdown-menu-item-padding-vertical); // @presenter Spacing
26
26
  --product-picker-dropdown-item-separator-padding-top: var(--dropdown-menu-item-separator-padding-top ); // @presenter Spacing
27
27
  --product-picker-dropdown-item-separator-padding-bottom: var(--dropdown-menu-item-separator-padding-bottom ); // @presenter Spacing
28
- --product-picker-dropdown-item-border-radius: var(--dropdown-menu-item-border-radius ); // @presenter BorderRadius
28
+ --product-picker-dropdown-item-border-radius: var(--dropdown-menu-item-border-radius); // @presenter BorderRadius
29
29
  --product-picker-dropdown-item-bg-color-active: var(--dropdown-menu-item-bg-color-active); // @presenter Color
30
30
  --product-picker-dropdown-item-bg-color-hover: var(--dropdown-menu-item-bg-color-hover); // @presenter Color
31
31
  --product-picker-dropdown-item-bg-color-disabled: var(--dropdown-menu-item-bg-color-disabled); // @presenter Color
@@ -36,4 +36,5 @@ export const productPicker = css`
36
36
  --product-picker-dropdown-item-color-hover: var(--dropdown-menu-item-color-hover);
37
37
  --product-picker-dropdown-item-border-color-focused: var(--dropdown-menu-item-border-color-focused);
38
38
 
39
+ // @tokens End
39
40
  `;
@@ -10,6 +10,9 @@ export type ReplayGateProps = {
10
10
  // The current OpenAPI description's id (from x-metadata), when known. Lets a custom
11
11
  // ReplayGate vary behavior per API in a multi-API catalog.
12
12
  apiId?: string;
13
+ // Closes the whole Replay overlay. A gate that denies access calls this instead of
14
+ // rendering `children`, so a dismissed gate doesn't leave Replay reachable.
15
+ onClose: () => void;
13
16
  children: React.ReactNode;
14
17
  };
15
18
 
@@ -176,7 +176,7 @@ export function SearchAiDialog({
176
176
  />
177
177
  {translate(
178
178
  'search.ai.welcomeText',
179
- 'Welcome to AI search! Feel free to ask me anything. How can I help you? ',
179
+ 'Welcome to AI assistant! Feel free to ask me anything. How can I help you? ',
180
180
  )}
181
181
  </WelcomeWrapper>
182
182
  )}
@@ -308,7 +308,7 @@ const MessageWrapper = styled.div<{ $role: string }>`
308
308
  $role === AiSearchConversationRole.USER
309
309
  ? 'var(--spacing-sm)'
310
310
  : 'var(--spacing-sm) var(--spacing-sm) var(--spacing-xs) var(--spacing-sm)'};
311
- border-radius: var(--border-radius-lg);
311
+ border-radius: var(--border-radius-xl);
312
312
  width: fit-content;
313
313
  max-width: 100%;
314
314
  word-wrap: break-word;
@@ -128,7 +128,7 @@ const FeedbackFormWrapper = styled.div`
128
128
  padding: var(--spacing-xs);
129
129
  background: var(--search-ai-feedback-form-bg-color);
130
130
  border: 1px solid var(--search-ai-feedback-form-border-color);
131
- border-radius: var(--border-radius-lg);
131
+ border-radius: var(--border-radius-xl);
132
132
  `;
133
133
 
134
134
  const FeedbackHeader = styled.div`
@@ -170,7 +170,7 @@ const FeedbackTextArea = styled.textarea`
170
170
  padding: var(--spacing-xs);
171
171
  padding-right: 3rem;
172
172
  border: 1px solid var(--border-color-primary);
173
- border-radius: var(--border-radius-md);
173
+ border-radius: var(--border-radius-lg);
174
174
  font-family: inherit;
175
175
  font-size: var(--font-size-base);
176
176
  line-height: var(--line-height-base);
@@ -493,7 +493,7 @@ export function SearchDialog({
493
493
  <AiDisclaimer>
494
494
  {translate(
495
495
  'search.ai.disclaimer',
496
- 'AI search might provide incomplete or incorrect results. Verify important information.',
496
+ 'AI assistant might provide incomplete or incorrect results. Verify important information.',
497
497
  )}
498
498
  </AiDisclaimer>
499
499
  ) : (
@@ -672,7 +672,6 @@ const SearchMessage = styled.div`
672
672
  `;
673
673
 
674
674
  const SearchProductTag = styled(Tag)`
675
- --tag-border-radius: var(--border-radius);
676
675
  border: none;
677
676
  margin: var(--spacing-xs) var(--spacing-sm) !important;
678
677
  `;
@@ -747,6 +746,7 @@ const SearchWithAI = styled.div`
747
746
  outline: none;
748
747
  border-top: 1px solid var(--search-item-border-color);
749
748
  border-bottom: 1px solid var(--search-item-border-color);
749
+ border-radius: var(--search-item-border-radius);
750
750
 
751
751
  transition: all 0.3s ease;
752
752
 
@@ -145,6 +145,7 @@ const SearchItemWrapper = styled(Link)`
145
145
  outline: none;
146
146
  border-top: 1px solid var(--search-item-border-color);
147
147
  border-bottom: 1px solid var(--search-item-border-color);
148
+ border-radius: var(--search-item-border-radius);
148
149
 
149
150
  ${ReturnKeyIcon} {
150
151
  align-self: center;
@@ -97,6 +97,7 @@ const SearchRecentItem = styled.div`
97
97
  font-weight: var(--search-recent-item-font-weight);
98
98
  line-height: var(--search-recent-item-line-height);
99
99
  padding: var(--search-recent-item-padding);
100
+ border-radius: var(--search-recent-item-border-radius);
100
101
  color: var(--search-recent-item-text-color);
101
102
  cursor: pointer;
102
103
 
@@ -81,6 +81,7 @@ const SearchSuggestedItem = styled(Link)`
81
81
  line-height: var(--search-suggested-item-line-height);
82
82
  color: var(--search-suggested-item-text-color);
83
83
  padding: var(--search-suggested-item-padding);
84
+ border-radius: var(--search-suggested-item-border-radius);
84
85
  cursor: pointer;
85
86
 
86
87
  &:hover {
@@ -10,7 +10,7 @@ export const search = css`
10
10
  --search-modal-min-height: 705px;
11
11
  --search-modal-bg-color: var(--modal-bg-color);
12
12
  --search-modal-box-shadow: var(--modal-box-shadow);
13
- --search-modal-border-radius: var(--border-radius-lg);
13
+ --search-modal-border-radius: var(--border-radius-xxl);
14
14
  --search-modal-border: 1px solid var(--border-color-secondary);
15
15
 
16
16
  --search-modal-header-bg-color: var(--bg-color-tonal); // @presenter Color
@@ -34,7 +34,7 @@ export const search = css`
34
34
  --search-input-gap: var(--spacing-sm);
35
35
  --search-input-height: 40px;
36
36
  --search-input-border: none;
37
- --search-input-border-radius: var(--border-radius); // @presenter BorderRadius
37
+ --search-input-border-radius: var(--border-radius-xl); // @presenter BorderRadius
38
38
 
39
39
  --search-group-title-padding: var(--spacing-sm);
40
40
  --search-group-title-bg-color: var(--bg-color-tonal); // @presenter Color
@@ -53,6 +53,7 @@ export const search = css`
53
53
  --search-item-bg-color-hover: var(--layer-color-ontonal-hover); // @presenter Color
54
54
  --search-item-border-color-focused: var(--color-blue-4); // @presenter Color
55
55
  --search-item-border-color: transparent; // @presenter Color
56
+ --search-item-border-radius: var(--border-radius-lg);
56
57
  --search-item-padding: var(--spacing-sm) var(--spacing-lg);
57
58
  --search-item-gap: var(--spacing-xxs);
58
59
  --search-item-product-icon-size: 16px;
@@ -71,6 +72,7 @@ export const search = css`
71
72
  --search-recent-item-title-padding: var(--spacing-md) var(--spacing-lg) var(--spacing-xxs) var(--spacing-lg); // @presenter Color
72
73
  --search-recent-item-bg-color-active: var(--layer-color); // @presenter Color
73
74
  --search-recent-item-border-color-focused: var(--color-blue-4); // @presenter Color
75
+ --search-recent-item-border-radius: var(--search-item-border-radius);
74
76
 
75
77
  --search-suggested-item-font-size: var(--font-size-base); // @presenter FontSize
76
78
  --search-suggested-item-font-weight: var(--font-weight-regular); // @presenter FontWeight
@@ -86,6 +88,7 @@ export const search = css`
86
88
  --search-suggested-item-title-padding: var(--spacing-md) var(--spacing-lg) var(--spacing-xxs) var(--spacing-lg); // @presenter Color
87
89
  --search-suggested-item-bg-color-active: var(--layer-color); // @presenter Color
88
90
  --search-suggested-item-border-color-focused: var(--color-blue-4); // @presenter Color
91
+ --search-suggested-item-border-radius: var(--search-item-border-radius);
89
92
 
90
93
  --search-shortcuts-gap: var(--spacing-xs);
91
94
 
@@ -133,7 +136,7 @@ export const search = css`
133
136
  --search-trigger-border-style: var(--border-style);
134
137
  --search-trigger-border-color: var(--input-border-color);
135
138
  --search-trigger-border-color-hover: var(--input-border-color-hover);
136
- --search-trigger-border-radius: var(--border-radius-md);
139
+ --search-trigger-border-radius: var(--border-radius-lg);
137
140
  --search-trigger-padding-vertical: var(--input-padding-vertical);
138
141
  --search-trigger-padding-horizontal: var(--input-padding-horizontal);
139
142
  --search-trigger-padding: var(--search-trigger-padding-vertical) var(--search-trigger-padding-horizontal);
@@ -244,7 +247,7 @@ export const search = css`
244
247
  --search-ai-conversation-input-bg-color-disabled: var(--color-warm-grey-1);
245
248
  --search-ai-conversation-input-padding: var(--spacing-sm) var(--spacing-md);
246
249
  --search-ai-conversation-input-border: 1px solid var(--border-color-secondary);
247
- --search-ai-conversation-input-border-radius: var(--border-radius-lg);
250
+ --search-ai-conversation-input-border-radius: var(--border-radius-xl);
248
251
  --search-ai-conversation-input-font-size: var(--font-size-base);
249
252
  --search-ai-conversation-input-placeholder-color: var(--search-input-placeholder-color);
250
253
  --search-ai-conversation-input-border-color-focus: var(--color-primary-base, var(--search-ai-conversation-input-border-color-focus-legacy));
@@ -252,7 +255,7 @@ export const search = css`
252
255
 
253
256
  --search-ai-conversation-input-send-button-right: 12px;
254
257
  --search-ai-conversation-input-send-button-padding: 5px;
255
- --search-ai-conversation-input-send-button-border-radius: var(--border-radius);
258
+ --search-ai-conversation-input-send-button-border-radius: var(--border-radius-md);
256
259
  --search-ai-conversation-input-send-button-border-disabled: 1px solid var(--button-border-color-disabled);
257
260
 
258
261
  --search-ai-conversation-input-min-height: 48px;
@@ -16,6 +16,7 @@ function SegmentedComponent<T>(
16
16
  data-component-name="Segmented/Segmented"
17
17
  className={`tag-grey ${size} ${className}`}
18
18
  role="tablist"
19
+ $size={size}
19
20
  >
20
21
  {options.map((opt, index) => (
21
22
  <React.Fragment key={index}>
@@ -40,12 +41,13 @@ export const Segmented = typedMemo(forwardRef(SegmentedComponent)) as <T>(
40
41
  props: SegmentedProps<T> & { ref?: ForwardedRef<HTMLDivElement> },
41
42
  ) => ReactElement;
42
43
 
43
- const SegmentedGroup = styled.div`
44
+ const SegmentedGroup = styled.div<{ $size: string }>`
44
45
  display: flex;
45
46
  background: var(--segmented-buttons-bg-color-main);
46
47
  padding: calc(var(--spacing-xxs) / 2);
47
48
  gap: calc(var(--spacing-xxs) / 2);
48
- border-radius: var(--border-radius-md);
49
+ border-radius: ${({ $size }) =>
50
+ $size === 'small' ? 'var(--border-radius-md)' : 'var(--border-radius-lg)'};
49
51
  max-width: 100%;
50
52
  width: fit-content;
51
53
  `;
@@ -75,7 +77,8 @@ const SegmentedItem = styled.button<{ $isActive: boolean; $size: string }>`
75
77
  cursor: pointer;
76
78
  `}
77
79
  line-height: var(--segmented-line-height);
78
- border-radius: var(--border-radius);
80
+ border-radius: ${({ $size }) =>
81
+ $size === 'small' ? 'var(--border-radius)' : 'var(--border-radius-md)'};
79
82
  padding: ${({ $size }) => ($size === 'small' ? 0 : '3px')} var(--spacing-sm);
80
83
  white-space: nowrap;
81
84
  text-overflow: ellipsis;
@@ -77,24 +77,32 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
77
77
  // eslint-disable-next-line react-hooks/exhaustive-deps
78
78
  }, [multiple, value]);
79
79
 
80
- useEffect(() => {
80
+ const changeSearchValue = (newSearchValue: string | null) => {
81
+ if (newSearchValue === searchValue) {
82
+ return;
83
+ }
84
+
85
+ setSearchValue(newSearchValue);
86
+
81
87
  if (onSearch) {
82
- onSearch?.(searchValue as T);
83
- } else {
84
- if (typeof searchValue === 'string') {
85
- const filteredOptions = options.filter((option) => {
88
+ onSearch(newSearchValue as T);
89
+ return;
90
+ }
91
+
92
+ if (typeof newSearchValue === 'string') {
93
+ setFilteredOptions(
94
+ options.filter((option) => {
86
95
  const valueForSearch = String(option.label ?? option.value ?? '');
87
96
  return (
88
- !valueForSearch || valueForSearch.toLowerCase().indexOf(searchValue.toLowerCase()) > -1
97
+ !valueForSearch ||
98
+ valueForSearch.toLowerCase().indexOf(newSearchValue.toLowerCase()) > -1
89
99
  );
90
- });
91
- setFilteredOptions(filteredOptions);
92
- } else {
93
- setFilteredOptions(options);
94
- }
100
+ }),
101
+ );
102
+ } else {
103
+ setFilteredOptions(options);
95
104
  }
96
- // eslint-disable-next-line react-hooks/exhaustive-deps
97
- }, [searchValue]);
105
+ };
98
106
 
99
107
  const selectHandler = (selectedOption: SelectOption<T>) => {
100
108
  const newSelectedOptions = multiple
@@ -113,7 +121,7 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
113
121
 
114
122
  setSelectedOptions(newSelectedOptions);
115
123
  onChange?.(newSelectedValues);
116
- setSearchValue(null);
124
+ changeSearchValue(null);
117
125
  setDropdownActive(false);
118
126
 
119
127
  if (!multiple) {
@@ -125,7 +133,7 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
125
133
 
126
134
  const searchHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
127
135
  const targetValue = e.target.value;
128
- setSearchValue(targetValue);
136
+ changeSearchValue(targetValue);
129
137
  setDropdownActive(true);
130
138
  };
131
139
 
@@ -150,7 +158,7 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
150
158
  if (!e.relatedTarget || e.relatedTarget?.id !== inputId) {
151
159
  setDropdownActive(false);
152
160
  }
153
- setSearchValue(null);
161
+ changeSearchValue(null);
154
162
  setStickyInputValue('');
155
163
  }
156
164
  };
@@ -8,7 +8,7 @@ export const select = css`
8
8
  --select-font-weight: var(--font-weight-regular); // @presenter FontWeight
9
9
  --select-line-height: var(--line-height-base); // @presenter LineHeight
10
10
  --select-text-color: var(--text-color-secondary); // @presenter Color
11
- --select-border-radius: var(--border-radius); // @presenter BorderRadius
11
+ --select-border-radius: var(--border-radius-lg); // @presenter BorderRadius
12
12
  --select-border: var(--border-width) var(--border-style) var(--border-color-primary); // @presenter Border
13
13
 
14
14
  --select-input-padding-vertical: 6px; // @presenter Spacing
@@ -16,7 +16,7 @@ export const select = css`
16
16
  --select-input-padding: var(--select-input-padding-vertical) var(--select-input-padding-horizontal);
17
17
  --select-input-gap: var(--spacing-xs); // @presenter Spacing
18
18
  --select-input-value-gap: var(--spacing-unit); // @presenter Spacing
19
- --select-input-border-radius: var(--border-radius); // @presenter BorderRadius
19
+ --select-input-border-radius: var(--border-radius-lg); // @presenter BorderRadius
20
20
  --select-input-font-size: var(--font-size-base); // @presenter FontSize
21
21
  --select-input-font-weight: var(--font-weight-regular); // @presenter FontWeight
22
22
  --select-input-line-height: var(--line-height-base); // @presenter LineHeight
@@ -35,7 +35,7 @@ export const select = css`
35
35
  --select-list-item-padding: var(--select-list-item-padding-vertical) var(--select-list-item-padding-horizontal);
36
36
 
37
37
  --select-list-item-gap: var(--spacing-xs); // @presenter Spacing
38
- --select-list-item-border-radius: var(--border-radius); // @presenter BorderRadius
38
+ --select-list-item-border-radius: var(--border-radius-md); // @presenter BorderRadius
39
39
  --select-list-item-bg-color-active: transparent; // @presenter Color
40
40
  --select-list-item-bg-color-hover: var(--menu-item-bg-color-hover); // @presenter Color
41
41
  --select-list-item-font-weight-active: var(--font-weight-medium); // @presenter Color
@@ -0,0 +1,95 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { ComponentProps, JSX } from 'react';
5
+ import type { ButtonProps } from '@redocly/theme/components/Button/Button';
6
+ import type { ButtonGroupSize, ButtonGroupVariant } from '@redocly/theme/core/types';
7
+
8
+ import { Button } from '@redocly/theme/components/Button/Button';
9
+ import { ButtonGroup } from '@redocly/theme/components/Button/ButtonGroup';
10
+ import { Dropdown } from '@redocly/theme/components/Dropdown/Dropdown';
11
+
12
+ export type SplitButtonProps = {
13
+ button: React.ReactElement<ButtonProps>;
14
+ children: ComponentProps<typeof Dropdown>['children'];
15
+ variant?: ButtonGroupVariant;
16
+ size?: ButtonGroupSize;
17
+ placement?: 'top' | 'bottom';
18
+ alignment?: 'start' | 'end';
19
+ portalled?: boolean;
20
+ closeOnSelect?: boolean;
21
+ disabled?: boolean;
22
+ toggleAriaLabel: string;
23
+ onOpen?: () => void;
24
+ onClose?: () => void;
25
+ className?: string;
26
+ };
27
+
28
+ export function SplitButton(props: SplitButtonProps): JSX.Element {
29
+ const {
30
+ button,
31
+ children,
32
+ variant,
33
+ size,
34
+ placement = 'bottom',
35
+ alignment = 'end',
36
+ portalled,
37
+ closeOnSelect = true,
38
+ disabled,
39
+ toggleAriaLabel,
40
+ onOpen,
41
+ onClose,
42
+ className,
43
+ } = props;
44
+
45
+ const hasMenu = typeof children === 'function' || React.Children.toArray(children).length > 0;
46
+
47
+ return (
48
+ <SplitButtonWrapper data-component-name="SplitButton/SplitButton" className={className}>
49
+ <ButtonGroup variant={variant} size={size}>
50
+ {button}
51
+ {hasMenu ? (
52
+ <ToggleDropdown
53
+ closeOnClick={closeOnSelect}
54
+ placement={placement}
55
+ alignment={alignment}
56
+ portalled={portalled}
57
+ withArrow
58
+ onOpen={onOpen}
59
+ onClose={onClose}
60
+ trigger={
61
+ <Button
62
+ aria-label={toggleAriaLabel}
63
+ aria-haspopup="menu"
64
+ variant={variant}
65
+ size={size}
66
+ disabled={disabled}
67
+ />
68
+ }
69
+ >
70
+ {children}
71
+ </ToggleDropdown>
72
+ ) : null}
73
+ </ButtonGroup>
74
+ </SplitButtonWrapper>
75
+ );
76
+ }
77
+
78
+ const SplitButtonWrapper = styled.div`
79
+ position: relative;
80
+ display: inline-flex;
81
+
82
+ /* Themed button margins must not split the group apart. Direct-child chains
83
+ keep the rule off buttons rendered inside the dropdown menu. */
84
+ > * > .button,
85
+ > * > * > .button {
86
+ margin: 0;
87
+ }
88
+ `;
89
+
90
+ /* The non-portalled menu is absolutely positioned against the nearest positioned
91
+ ancestor; keep the dropdown segment static so that ancestor is the whole
92
+ split button rather than the toggle segment. */
93
+ const ToggleDropdown = styled(Dropdown)`
94
+ position: static;
95
+ `;
@@ -14,7 +14,7 @@ export const switcherDarkMode = css`
14
14
  --switch-border-color-disabled: var(--color-warm-grey-5); // @presenter Color
15
15
  --switch-border-color-selected: var(--color-primary-base, var(--switch-border-color-selected-legacy)); // @presenter Color
16
16
  --switch-border-width: var(--border-width); // @presenter Border
17
- --switch-border-radius: var(--border-radius); // @presenter BorderRadius
17
+ --switch-border-radius: var(--border-radius-full); // @presenter BorderRadius
18
18
 
19
19
  --switch-width: 32px; // @presenter Width
20
20
  --switch-height: 18px; // @presenter Height
@@ -27,7 +27,7 @@ export const switcherDarkMode = css`
27
27
  --switch-knob-bg-color-selected: var(--color-static-white); // @presenter Color
28
28
  --switch-knob-bg-color-disabled: var(--color-warm-grey-6); // @presenter Color
29
29
 
30
- --switch-knob-border-radius: calc(var(--border-radius) / 2); // @presenter BorderRadius
30
+ --switch-knob-border-radius: var(--border-radius-full); // @presenter BorderRadius
31
31
  --switch-knob-height: 14px; // @presenter Height
32
32
  --switch-knob-width: 14px; // @presenter Width
33
33
  --switch-knob-transition: all 0.3s; // @presenter Transition
@@ -13,7 +13,7 @@ export const switcher = css`
13
13
  --switch-border-color-pressed: transparent; // @presenter Color
14
14
  --switch-border-color-disabled: transparent; // @presenter Color
15
15
  --switch-border-color-selected: transparent; // @presenter Color
16
- --switch-border-radius: var(--border-radius); // @presenter BorderRadius
16
+ --switch-border-radius: var(--border-radius-full); // @presenter BorderRadius
17
17
  --switch-border-width: var(--border-width); // @presenter Border
18
18
 
19
19
  --switch-width: 32px; // @presenter Width
@@ -27,7 +27,7 @@ export const switcher = css`
27
27
  --switch-knob-bg-color-selected: var(--color-white); // @presenter Color
28
28
  --switch-knob-bg-color-disabled: var(--color-warm-grey-1); // @presenter Color
29
29
 
30
- --switch-knob-border-radius: calc(var(--border-radius) / 2); // @presenter BorderRadius
30
+ --switch-knob-border-radius: var(--border-radius-full); // @presenter BorderRadius
31
31
  --switch-knob-height: 14px; // @presenter Height
32
32
  --switch-knob-width: 14px; // @presenter Width
33
33
  --switch-knob-transition: transform 0.3s; // @presenter Transition