@redocly/theme 0.57.0-next.5 → 0.57.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.
@@ -8,15 +8,21 @@ const react_1 = __importDefault(require("react"));
8
8
  const HorizontalViewIcon_1 = require("../../icons/HorizontalViewIcon/HorizontalViewIcon");
9
9
  const VerticalViewIcon_1 = require("../../icons/VerticalViewIcon/VerticalViewIcon");
10
10
  const SidebarActions_1 = require("../../components/SidebarActions/SidebarActions");
11
- const styled_1 = require("../../components/SidebarActions/styled");
12
11
  const hooks_1 = require("../../core/hooks");
12
+ const styled_1 = require("../../components/SidebarActions/styled");
13
13
  const ChangeViewButton = ({ layout, onClick, collapsedSidebar, }) => {
14
14
  const { useTranslate } = (0, hooks_1.useThemeHooks)();
15
15
  const { translate } = useTranslate();
16
- return (react_1.default.createElement(styled_1.StyledChangeViewButton, { title: translate('sidebar.actions.changeLayout', 'Change layout'), onClick: onClick, collapsedSidebar: collapsedSidebar },
17
- react_1.default.createElement(styled_1.StyledChangeViewButtonWrap, { active: layout === SidebarActions_1.LayoutVariant.STACKED },
16
+ const isStacked = layout === SidebarActions_1.LayoutVariant.STACKED;
17
+ const isThreePanel = layout === SidebarActions_1.LayoutVariant.THREE_PANEL;
18
+ return (react_1.default.createElement(styled_1.StyledChangeViewButton, { onClick: onClick, collapsedSidebar: collapsedSidebar },
19
+ react_1.default.createElement(styled_1.StyledChangeViewButtonWrap, { placement: collapsedSidebar ? 'right' : 'top', arrowPosition: collapsedSidebar ? 'center' : 'right', active: isStacked, tip: isStacked
20
+ ? translate('sidebar.actions.singleColumn', 'Single column')
21
+ : translate('sidebar.actions.changeToSingleColumn', 'Switch to single column') },
18
22
  react_1.default.createElement(HorizontalViewIcon_1.HorizontalViewIcon, { size: "14px", color: "--segmented-buttons-content-color" })),
19
- react_1.default.createElement(styled_1.StyledChangeViewButtonWrap, { active: layout === SidebarActions_1.LayoutVariant.THREE_PANEL },
23
+ react_1.default.createElement(styled_1.StyledChangeViewButtonWrap, { active: isThreePanel, placement: collapsedSidebar ? 'right' : 'top', arrowPosition: collapsedSidebar ? 'center' : 'right', tip: isThreePanel
24
+ ? translate('sidebar.actions.twoColumns', 'Two columns')
25
+ : translate('sidebar.actions.changeToTwoColumns', 'Switch to two columns') },
20
26
  react_1.default.createElement(VerticalViewIcon_1.VerticalViewIcon, { size: "14px", color: "--segmented-buttons-content-color" }))));
21
27
  };
22
28
  exports.ChangeViewButton = ChangeViewButton;
@@ -13,22 +13,24 @@ const Button_1 = require("../../components/Button/Button");
13
13
  const SidePanelCloseIcon_1 = require("../../icons/SidePanelCloseIcon/SidePanelCloseIcon");
14
14
  const SidePanelOpenIcon_1 = require("../../icons/SidePanelOpenIcon/SidePanelOpenIcon");
15
15
  const styled_1 = require("../../components/SidebarActions/styled");
16
+ const Tooltip_1 = require("../../components/Tooltip/Tooltip");
16
17
  const SidebarActions = ({ layout, hideCollapseSidebarButton = false, collapsedSidebar, isApiDocs, onChangeViewClick, onChangeCollapseSidebarClick, requestAccessButton, className, }) => {
17
18
  const { useTelemetry, useTranslate } = (0, hooks_1.useThemeHooks)();
18
19
  const { translate } = useTranslate();
19
20
  const telemetry = useTelemetry();
20
21
  return (react_1.default.createElement(styled_1.ControlsWrap, { className: className, isCollapsed: collapsedSidebar, "data-component-name": "Sidebar/SidebarActions" },
21
- !hideCollapseSidebarButton && (react_1.default.createElement(Button_1.Button, { onClick: () => {
22
- onChangeCollapseSidebarClick();
23
- if (collapsedSidebar) {
24
- telemetry.sendSidebarItemExpandedMessage();
25
- }
26
- else {
27
- telemetry.sendSidebarItemCollapsedMessage();
28
- }
29
- }, title: collapsedSidebar
22
+ !hideCollapseSidebarButton && (react_1.default.createElement(Tooltip_1.Tooltip, { placement: collapsedSidebar ? 'right' : 'top', tip: collapsedSidebar
30
23
  ? translate('sidebar.actions.show', 'Show sidebar')
31
- : translate('sidebar.actions.hide', 'Hide sidebar'), size: "small", variant: "outlined", icon: collapsedSidebar ? react_1.default.createElement(SidePanelOpenIcon_1.SidePanelOpenIcon, null) : react_1.default.createElement(SidePanelCloseIcon_1.SidePanelCloseIcon, null) })),
24
+ : translate('sidebar.actions.hide', 'Hide sidebar') },
25
+ react_1.default.createElement(Button_1.Button, { onClick: () => {
26
+ onChangeCollapseSidebarClick();
27
+ if (collapsedSidebar) {
28
+ telemetry.sendSidebarItemExpandedMessage();
29
+ }
30
+ else {
31
+ telemetry.sendSidebarItemCollapsedMessage();
32
+ }
33
+ }, size: "small", variant: "outlined", icon: collapsedSidebar ? react_1.default.createElement(SidePanelOpenIcon_1.SidePanelOpenIcon, null) : react_1.default.createElement(SidePanelCloseIcon_1.SidePanelCloseIcon, null) }))),
32
34
  isApiDocs && (react_1.default.createElement(styled_1.ControlsWrapChangeLayoutButtons, { isCollapsed: collapsedSidebar },
33
35
  react_1.default.createElement(ChangeViewButton_1.ChangeViewButton, { collapsedSidebar: collapsedSidebar, layout: layout, onClick: () => {
34
36
  onChangeViewClick();
@@ -1,7 +1,7 @@
1
1
  export declare const StyledChangeViewButton: import("styled-components").StyledComponent<"span", any, {
2
2
  collapsedSidebar?: boolean;
3
3
  }, never>;
4
- export declare const StyledChangeViewButtonWrap: import("styled-components").StyledComponent<"span", any, {
4
+ export declare const StyledChangeViewButtonWrap: import("styled-components").StyledComponent<import("react").NamedExoticComponent<import("react").PropsWithChildren<import("../../components/Tooltip/Tooltip").TooltipProps>>, any, {
5
5
  active?: boolean;
6
6
  }, never>;
7
7
  export declare const ControlsWrap: import("styled-components").StyledComponent<"span", any, {
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.ControlsWrapChangeLayoutButtons = exports.ControlsWrap = exports.StyledChangeViewButtonWrap = exports.StyledChangeViewButton = void 0;
27
27
  const styled_components_1 = __importStar(require("styled-components"));
28
28
  const utils_1 = require("../../core/utils");
29
+ const Tooltip_1 = require("../../components/Tooltip/Tooltip");
29
30
  exports.StyledChangeViewButton = styled_components_1.default.span `
30
31
  display: flex;
31
32
  position: relative;
@@ -38,7 +39,7 @@ exports.StyledChangeViewButton = styled_components_1.default.span `
38
39
  z-index: 1;
39
40
  padding: calc(var(--spacing-unit) / 2);
40
41
  `;
41
- exports.StyledChangeViewButtonWrap = styled_components_1.default.span `
42
+ exports.StyledChangeViewButtonWrap = (0, styled_components_1.default)(Tooltip_1.Tooltip) `
42
43
  width: 20px;
43
44
  height: 20px;
44
45
  border-radius: var(--border-radius);
@@ -9,6 +9,7 @@ export type TooltipProps = {
9
9
  width?: string;
10
10
  dataTestId?: string;
11
11
  disabled?: boolean;
12
+ arrowPosition?: 'top' | 'bottom' | 'left' | 'right' | 'center';
12
13
  };
13
- export declare function TooltipComponent({ children, isOpen, tip, withArrow, placement, className, width, dataTestId, disabled, }: PropsWithChildren<TooltipProps>): JSX.Element;
14
+ export declare function TooltipComponent({ children, isOpen, tip, withArrow, placement, className, width, dataTestId, disabled, arrowPosition, }: PropsWithChildren<TooltipProps>): JSX.Element;
14
15
  export declare const Tooltip: React.NamedExoticComponent<React.PropsWithChildren<TooltipProps>>;
@@ -28,11 +28,68 @@ exports.TooltipComponent = TooltipComponent;
28
28
  const react_1 = __importStar(require("react"));
29
29
  const styled_components_1 = __importStar(require("styled-components"));
30
30
  const hooks_1 = require("../../core/hooks");
31
- function TooltipComponent({ children, isOpen, tip, withArrow = true, placement = 'top', className = 'default', width, dataTestId, disabled = false, }) {
31
+ const Portal_1 = require("../../components/Portal/Portal");
32
+ function TooltipComponent({ children, isOpen, tip, withArrow = true, placement = 'top', className = 'default', width, dataTestId, disabled = false, arrowPosition = 'center', }) {
32
33
  const ref = (0, react_1.useRef)(null);
33
34
  const { isOpened, handleOpen, handleClose } = (0, hooks_1.useControl)(isOpen);
35
+ const [tooltipPosition, setTooltipPosition] = (0, react_1.useState)({ top: 0, left: 0 });
34
36
  (0, hooks_1.useOutsideClick)(ref, handleClose);
35
37
  const isControlled = isOpen !== undefined;
38
+ const updateTooltipPosition = (0, react_1.useCallback)(() => {
39
+ if (isOpened && ref.current) {
40
+ const rect = ref.current.getBoundingClientRect();
41
+ let top = 0;
42
+ let left = 0;
43
+ switch (placement) {
44
+ case 'top':
45
+ top = rect.top;
46
+ if (arrowPosition === 'left') {
47
+ left = rect.left - 24;
48
+ }
49
+ else if (arrowPosition === 'right') {
50
+ left = rect.right + 24;
51
+ }
52
+ else {
53
+ left = rect.left + rect.width / 2;
54
+ }
55
+ break;
56
+ case 'bottom':
57
+ top = rect.bottom;
58
+ if (arrowPosition === 'left') {
59
+ left = rect.left - 24;
60
+ }
61
+ else if (arrowPosition === 'right') {
62
+ left = rect.right + 24;
63
+ }
64
+ else {
65
+ left = rect.left + rect.width / 2;
66
+ }
67
+ break;
68
+ case 'left':
69
+ top = rect.top + rect.height / 2;
70
+ left = rect.left;
71
+ break;
72
+ case 'right':
73
+ top = rect.top + rect.height / 2;
74
+ left = rect.right;
75
+ break;
76
+ }
77
+ setTooltipPosition({ top, left });
78
+ }
79
+ }, [isOpened, placement, arrowPosition]);
80
+ (0, react_1.useEffect)(() => {
81
+ if (isOpened && ref.current) {
82
+ updateTooltipPosition();
83
+ const handleScroll = () => updateTooltipPosition();
84
+ const handleResize = () => updateTooltipPosition();
85
+ window.addEventListener('scroll', handleScroll, true);
86
+ window.addEventListener('resize', handleResize);
87
+ return () => {
88
+ window.removeEventListener('scroll', handleScroll, true);
89
+ window.removeEventListener('resize', handleResize);
90
+ };
91
+ }
92
+ }, [isOpened, placement, updateTooltipPosition]);
36
93
  (0, react_1.useEffect)(() => {
37
94
  if (isControlled && !disabled) {
38
95
  if (isOpen) {
@@ -51,87 +108,114 @@ function TooltipComponent({ children, isOpen, tip, withArrow = true, placement =
51
108
  };
52
109
  return (react_1.default.createElement(TooltipWrapper, Object.assign({ ref: ref }, controllers, { className: `tooltip-${className}`, "data-component-name": "Tooltip/Tooltip" }),
53
110
  children,
54
- isOpened && !disabled && (react_1.default.createElement(TooltipBody, { "data-testid": dataTestId || (typeof tip === 'string' ? tip : ''), placement: placement, width: width, withArrow: withArrow }, tip))));
111
+ isOpened && !disabled && (react_1.default.createElement(Portal_1.Portal, null,
112
+ react_1.default.createElement(TooltipBody, { "data-testid": dataTestId || (typeof tip === 'string' ? tip : ''), placement: placement, width: width, withArrow: withArrow, arrowPosition: arrowPosition, style: {
113
+ position: 'fixed',
114
+ top: tooltipPosition.top,
115
+ left: tooltipPosition.left,
116
+ } }, tip)))));
55
117
  }
56
118
  exports.Tooltip = (0, react_1.memo)(TooltipComponent);
57
119
  const PLACEMENTS = {
58
120
  top: (0, styled_components_1.css) `
59
- top: 0;
60
- left: 50%;
61
- transform: translate(-50%, -99%);
62
- margin-top: -10px;
121
+ ${({ withArrow, arrowPosition }) => withArrow && arrowPosition === 'left'
122
+ ? (0, styled_components_1.css) `
123
+ transform: translate(0, -100%);
124
+ margin-top: -10px;
125
+ `
126
+ : arrowPosition === 'right'
127
+ ? (0, styled_components_1.css) `
128
+ transform: translate(-100%, -100%);
129
+ margin-top: -10px;
130
+ `
131
+ : (0, styled_components_1.css) `
132
+ transform: translate(-50%, -100%);
133
+ margin-top: -10px;
134
+ `}
63
135
 
64
- ${({ withArrow }) => withArrow &&
136
+ ${({ withArrow, arrowPosition }) => withArrow &&
65
137
  (0, styled_components_1.css) `
66
138
  &::after {
67
- border-left: 6px solid transparent;
68
- border-right: 6px solid transparent;
139
+ border-left: 14px solid transparent;
140
+ border-right: 14px solid transparent;
69
141
  border-top-width: 8px;
70
142
  border-top-style: solid;
71
- border-radius: 2px 2px 0 0;
143
+ border-radius: 2px;
72
144
  bottom: 0;
73
- left: 50%;
74
- transform: translate(-50%, 99%);
145
+ ${arrowPosition === 'left' && 'left: 16px; transform: translateY(99%);'}
146
+ ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, 99%);'}
147
+ ${arrowPosition === 'right' && 'right: 16px; transform: translateY(99%);'}
75
148
  }
76
149
  `}
77
150
  `,
78
151
  bottom: (0, styled_components_1.css) `
79
- bottom: 0;
80
- left: 50%;
81
- transform: translate(-50%, 99%);
82
- margin-bottom: -10px;
152
+ ${({ withArrow, arrowPosition }) => withArrow && arrowPosition === 'left'
153
+ ? (0, styled_components_1.css) `
154
+ transform: translate(0, -100%);
155
+ margin-top: -10px;
156
+ `
157
+ : arrowPosition === 'right'
158
+ ? (0, styled_components_1.css) `
159
+ transform: translate(-100%, -100%);
160
+ margin-top: -10px;
161
+ `
162
+ : (0, styled_components_1.css) `
163
+ transform: translate(-50%, -100%);
164
+ margin-top: -10px;
165
+ `}
83
166
 
84
- ${({ withArrow }) => withArrow &&
167
+ ${({ withArrow, arrowPosition }) => withArrow &&
85
168
  (0, styled_components_1.css) `
86
169
  &::after {
87
- border-left: 6px solid transparent;
88
- border-right: 6px solid transparent;
170
+ border-left: 14px solid transparent;
171
+ border-right: 14px solid transparent;
89
172
  border-bottom-width: 8px;
90
173
  border-bottom-style: solid;
91
174
  border-radius: 0 0 2px 2px;
92
175
  top: 0;
93
- left: 50%;
94
- transform: translate(-50%, -99%);
176
+ ${arrowPosition === 'left' && 'left: 16px; transform: translateY(-99%);'}
177
+ ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, -99%);'}
178
+ ${arrowPosition === 'right' && 'right: 16px; transform: translateY(-99%);'}
95
179
  }
96
180
  `}
97
181
  `,
98
182
  left: (0, styled_components_1.css) `
99
- top: 50%;
100
- left: 0;
101
183
  transform: translate(-100%, -50%);
102
184
  margin-left: -10px;
103
185
 
104
- ${({ withArrow }) => withArrow &&
186
+ ${({ withArrow, arrowPosition }) => withArrow &&
105
187
  (0, styled_components_1.css) `
106
188
  &::after {
107
- border-top: 6px solid transparent;
108
- border-bottom: 6px solid transparent;
189
+ border-top: 14px solid transparent;
190
+ border-bottom: 14px solid transparent;
109
191
  border-left-width: 8px;
110
192
  border-left-style: solid;
111
193
  border-radius: 2px 0 0 2px;
112
194
  top: 50%;
113
195
  right: 0;
114
- transform: translate(99%, -50%);
196
+ ${arrowPosition === 'top' && 'top: 16px; transform: translateX(99%);'}
197
+ ${arrowPosition === 'center' && 'top: 50%; transform: translate(99%, -50%);'}
198
+ ${arrowPosition === 'bottom' && 'bottom: 16px; transform: translateX(99%);'}
115
199
  }
116
200
  `}
117
201
  `,
118
202
  right: (0, styled_components_1.css) `
119
- top: 50%;
120
- right: 0;
121
- transform: translate(100%, -50%);
122
- margin-right: -10px;
203
+ transform: translate(0, -50%);
204
+ margin-left: 10px;
123
205
 
124
- ${({ withArrow }) => withArrow &&
206
+ ${({ withArrow, arrowPosition }) => withArrow &&
125
207
  (0, styled_components_1.css) `
126
208
  &::after {
127
- border-top: 6px solid transparent;
128
- border-bottom: 6px solid transparent;
209
+ border-top: 14px solid transparent;
210
+ border-bottom: 14px solid transparent;
129
211
  border-right-width: 8px;
130
212
  border-right-style: solid;
131
213
  border-radius: 0 2px 2px 0;
132
214
  top: 50%;
133
215
  left: 0;
134
- transform: translate(-99%, -50%);
216
+ ${arrowPosition === 'top' && 'top: 16px; transform: translateX(-99%);'}
217
+ ${arrowPosition === 'center' && 'top: 50%; transform: translate(-99%, -50%);'}
218
+ ${arrowPosition === 'bottom' && 'bottom: 16px; transform: translateX(-99%);'}
135
219
  }
136
220
  `}
137
221
  `,
@@ -143,18 +227,17 @@ const TooltipWrapper = styled_components_1.default.div `
143
227
  const TooltipBody = styled_components_1.default.span `
144
228
  display: inline-block;
145
229
 
146
- position: absolute;
147
- text-align: center;
148
-
149
230
  padding: var(--tooltip-padding);
150
231
  max-width: var(--tooltip-max-width);
151
232
  white-space: normal;
233
+ word-break: normal;
152
234
  overflow-wrap: break-word;
153
235
 
154
236
  border-radius: var(--border-radius-md);
155
237
  transition: opacity 0.3s ease-out;
156
238
 
157
- font-size: 13px;
239
+ font-size: var(--font-size-base);
240
+ line-height: var(--line-height-base);
158
241
 
159
242
  z-index: var(--z-index-overlay);
160
243
 
@@ -172,9 +255,11 @@ const TooltipBody = styled_components_1.default.span `
172
255
  color: var(--tooltip-text-color);
173
256
  border: var(--tooltip-border-width, 0) var(--tooltip-border-style, solid)
174
257
  var(--tooltip-border-color, transparent);
175
- box-shadow: rgb(0 0 0 / 25%) 0 2px 4px;
258
+ box-shadow:
259
+ 0px 8px 24px 8px #0000000a,
260
+ 0px 4px 12px 0px #00000014;
176
261
 
177
- width: ${({ width }) => width || '120px'};
262
+ width: ${({ width }) => width || 'auto'};
178
263
  ${({ placement }) => (0, styled_components_1.css) `
179
264
  ${PLACEMENTS[placement]};
180
265
  `}
@@ -0,0 +1 @@
1
+ export declare const tooltipDarkMode: import("styled-components").FlattenSimpleInterpolation;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tooltipDarkMode = void 0;
4
+ const styled_components_1 = require("styled-components");
5
+ exports.tooltipDarkMode = (0, styled_components_1.css) `
6
+ --tooltip-bg-color: var(--color-warm-grey-4);
7
+ --tooltip-border-color: var(--color-warm-grey-5);
8
+ `;
9
+ //# sourceMappingURL=variables.dark.js.map
@@ -8,16 +8,16 @@ exports.tooltip = (0, styled_components_1.css) `
8
8
  * @presenter Color
9
9
  */
10
10
 
11
- --tooltip-text-color: var(--text-color-secondary);
12
- --tooltip-bg-color: var(--bg-color-raised);
13
- --tooltip-arrow-color: var(--tooltip-bg-color);
14
- --tooltip-border-width: 0;
11
+ --tooltip-text-color: var(--color-static-white);
12
+ --tooltip-bg-color: var(--color-warm-grey-10);
13
+ --tooltip-arrow-color: var(--tooltip-border-color);
14
+ --tooltip-border-width: 2px;
15
15
  --tooltip-border-style: solid;
16
- --tooltip-border-color: transparent;
17
- --tooltip-padding-vertical: var(--spacing-xs);
18
- --tooltip-padding-horizontal: var(--spacing-sm);
16
+ --tooltip-border-color: var(--color-warm-grey-8);
17
+ --tooltip-padding-vertical: var(--spacing-xxs);
18
+ --tooltip-padding-horizontal: var(--spacing-xs);
19
19
  --tooltip-padding: var(--tooltip-padding-vertical) var(--tooltip-padding-horizontal);
20
- --tooltip-max-width: 250px;
20
+ --tooltip-max-width: 400px;
21
21
 
22
22
  .tooltip-copy-button {
23
23
  --tooltip-text-color: var(--text-color-secondary);
@@ -14,6 +14,7 @@ const variables_dark_9 = require("../../components/Switch/variables.dark");
14
14
  const variables_dark_10 = require("../../markdoc/components/Cards/variables.dark");
15
15
  const variables_dark_11 = require("../../components/Catalog/variables.dark");
16
16
  const variables_dark_12 = require("../../components/PageActions/variables.dark");
17
+ const variables_dark_13 = require("../../components/Tooltip/variables.dark");
17
18
  const replayDarkMode = (0, styled_components_1.css) `
18
19
  /**
19
20
  * @tokens Replay Colors
@@ -318,6 +319,7 @@ exports.darkMode = (0, styled_components_1.css) `
318
319
  ${variables_dark_10.cardsDarkMode}
319
320
  ${variables_dark_11.catalogDarkMode}
320
321
  ${variables_dark_12.pageActionsDarkMode}
322
+ ${variables_dark_13.tooltipDarkMode}
321
323
 
322
324
  /**
323
325
  * @tokens Dark Theme Scrollbar Config
@@ -1,5 +1,5 @@
1
1
  import type { TOptions } from 'i18next';
2
- export type TranslationKey = 'dev.newApp' | 'dev.newApp.text' | 'dev.sidebar.header' | 'dev.sidebar.footer.text' | 'dev.create.app.dialog.appName.placeholder' | 'dev.create.app.dialog.appName.error' | 'dev.create.app.dialog.selectAPIs' | 'dev.create.app.dialog.description' | 'dev.create.app.dialog.description.placeholder' | 'dev.create.app.dialog.create' | 'dev.create.app.dialog.cancel' | 'dev.main.tab.appKeys' | 'dev.main.tab.logs' | 'dev.app.description.title' | 'dev.edit.description.dialog.title' | 'dev.edit.description.dialog.save' | 'dev.edit.description.dialog.cancel' | 'dev.edit.apis.dialog.selectedAPIs' | 'dev.app.key.create' | 'dev.create.key.dialog.title' | 'dev.create.key.dialog.create' | 'dev.create.key.dialog.cancel' | 'dev.app.edit' | 'dev.app.delete' | 'dev.edit.app.dialog.title' | 'dev.edit.app.dialog.save' | 'dev.edit.app.dialog.cancel' | 'dev.delete.app.dialog.title' | 'dev.delete.app.dialog.confirmation' | 'dev.delete.app.dialog.delete' | 'dev.delete.app.dialog.cancel' | 'dev.app.key.roll' | 'dev.roll.key.dialog.title' | 'dev.roll.key.dialog.apiKey' | 'dev.roll.key.dialog.expires' | 'dev.roll.key.dialog.confirmation' | 'dev.roll.key.dialog.cancel' | 'dev.roll.key.dialog.roll' | 'dev.update.key.dialog.title' | 'dev.update.key.dialog.update' | 'dev.update.key.dialog.cancel' | 'dev.app.key.api.name' | 'dev.app.key.api.status' | 'dev.app.key.api.edit' | 'dev.edit.apis.dialog.title' | 'dev.edit.apis.dialog.apiKey' | 'dev.edit.apis.dialog.save' | 'dev.edit.apis.dialog.cancel' | 'dev.select.placeholder' | 'dev.app.overview.status.pending' | 'dev.app.overview.status.approved' | 'dev.app.overview.status.revoked' | 'dev.app.overview.status' | 'dev.app.overview.non-production' | 'dev.app.overview.production' | 'dev.app.overview.clientId' | 'dev.app.overview.apiKey' | 'dev.app.key.revoke' | 'dev.revoke.key.dialog.title' | 'dev.revoke.key.dialog.apiKey' | 'dev.revoke.key.dialog.expires' | 'dev.revoke.key.dialog.confirmation' | 'dev.revoke.key.dialog.revoke' | 'dev.revoke.key.dialog.cancel' | 'dev.app.overview.expires' | 'dev.app.overview.created' | 'dev.app.overview.visibilityToggle.hide' | 'dev.app.overview.visibilityToggle.show' | 'search.loading' | 'search.noResults.title' | 'search.keys.navigate' | 'search.keys.select' | 'search.keys.exit' | 'search.label' | 'search.cancel' | 'search.recent' | 'search.navbar.label' | 'search.suggested' | 'search.showMore' | 'search.filter.title' | 'search.filter.reset' | 'search.filter.field.reset' | 'search.ai.welcomeText' | 'search.ai.newConversation' | 'search.ai.backToSearch' | 'search.ai.placeholder' | 'search.ai.generatingResponse' | 'search.ai.followUpQuestion' | 'search.ai.suggestionsTitle' | 'search.ai.thinkingText' | 'search.ai.resourcesFound' | 'search.ai.resourcesFound.basedOn' | 'search.ai.resourcesFound.resources' | 'search.ai.button' | 'search.ai.label' | 'search.ai.disclaimer' | 'search.ai.error.description' | 'search.ai.error.description.forbidden' | 'search.ai.error.description.unauthorized' | 'search.ai.error.header' | 'search.ai.error.header.forbidden' | 'search.ai.error.header.unauthorized' | 'toc.header' | 'footer.copyrightText' | 'page.homeButton' | 'page.forbidden.title' | 'page.notFound.title' | 'page.notFound.description' | 'page.lastUpdated.timeago' | 'page.lastUpdated.on' | 'catalog.filters.placeholder' | 'catalog.filters.title' | 'catalog.filters.add' | 'catalog.filters.clearAll' | 'catalog.filters.select.addFilter' | 'catalog.filters.select.all' | 'catalog.filters.done' | 'catalog.catalogs.all.title' | 'catalog.catalogs.all.description' | 'catalog.catalogs.all.switcherLabel' | 'catalog.catalogs.service.title' | 'catalog.catalogs.service.description' | 'catalog.catalogs.service.switcherLabel' | 'catalog.catalogs.user.title' | 'catalog.catalogs.user.description' | 'catalog.catalogs.user.switcherLabel' | 'catalog.catalogs.team.title' | 'catalog.catalogs.team.description' | 'catalog.catalogs.team.switcherLabel' | 'catalog.catalogs.domain.title' | 'catalog.catalogs.domain.description' | 'catalog.catalogs.domain.switcherLabel' | 'catalog.catalogs.apiDescription.title' | 'catalog.catalogs.apiDescription.description' | 'catalog.catalogs.apiDescription.switcherLabel' | 'catalog.catalogs.dataSchema.title' | 'catalog.catalogs.dataSchema.description' | 'catalog.catalogs.dataSchema.switcherLabel' | 'catalog.catalogs.apiOperation.title' | 'catalog.catalogs.apiOperation.description' | 'catalog.catalogs.apiOperation.switcherLabel' | 'catalog.entity.metadata.title' | 'catalog.entity.schema.title' | 'catalog.entity.properties.apiDescription.title' | 'sidebar.menu.backLabel' | 'sidebar.menu.backToLabel' | 'sidebar.actions.show' | 'sidebar.actions.hide' | 'sidebar.actions.changeLayout' | 'versionPicker.label' | 'versionPicker.unversioned' | 'codeSnippet.copy.buttonText' | 'codeSnippet.copy.tooltipText' | 'codeSnippet.copy.toasterText' | 'markdown.editPage.text' | 'feedback.settings.comment.submitText' | 'feedback.settings.comment.label' | 'feedback.settings.comment.send' | 'feedback.settings.comment.cancel' | 'feedback.settings.comment.satisfiedLabel' | 'feedback.settings.comment.neutralLabel' | 'feedback.settings.comment.dissatisfiedLabel' | 'feedback.settings.submitText' | 'feedback.settings.label' | 'feedback.settings.reasons.label' | 'feedback.submit' | 'feedback.cancel' | 'feedback.settings.comment.likeLabel' | 'feedback.settings.comment.dislikeLabel' | 'feedback.sentiment.thumbUp' | 'feedback.sentiment.thumbDown' | 'feedback.settings.leftScaleLabel' | 'feedback.settings.rightScaleLabel' | 'feedback.settings.optionalEmail.placeholder' | 'feedback.settings.optionalEmail.label' | 'codeSnippet.report.buttonText' | 'codeSnippet.report.tooltipText' | 'codeSnippet.report.label' | 'codeSnippet.expand.tooltipText' | 'codeSnippet.collapse.tooltipText' | 'userMenu.login' | 'userMenu.logout' | 'userMenu.devOnboardingLabel' | 'mobileMenu.mainMenu' | 'mobileMenu.previous' | 'mobileMenu.products' | 'mobileMenu.version' | 'navbar.products' | 'page.nextButton' | 'page.previousButton' | 'page.actions.copyButtonText' | 'page.actions.copyTitle' | 'page.actions.copyDescription' | 'page.actions.viewAsMdTitle' | 'page.actions.viewAsMdButtonText' | 'page.actions.viewAsMdDescription' | 'page.actions.chatGptTitle' | 'page.actions.chatGptButtonText' | 'page.actions.chatGptDescription' | 'page.actions.claudeTitle' | 'page.actions.claudeButtonText' | 'page.actions.claudeDescription' | 'openapi.download.description.title' | 'openapi.info.title' | 'openapi.info.contact.url' | 'openapi.info.contact.name' | 'openapi.info.license' | 'openapi.info.termsOfService' | 'openapi.info.metadata.title' | 'openapi.key' | 'openapi.value' | 'openapi.enum' | 'openapi.items' | 'openapi.default' | 'openapi.variable' | 'openapi.variables' | 'openapi.actions.show' | 'openapi.actions.hide' | 'openapi.actions.more' | 'openapi.languages.title' | 'openapi.servers.title' | 'openapi.operations' | 'openapi.webhooks' | 'openapi.description' | 'openapi.badges.deprecated' | 'openapi.badges.required' | 'openapi.badges.webhook' | 'openapi.request' | 'openapi.path' | 'openapi.query' | 'openapi.cookie' | 'openapi.header' | 'openapi.body' | 'openapi.responses' | 'openapi.response' | 'openapi.callbacks' | 'openapi.callbackRequest' | 'openapi.callbackResponse' | 'openapi.payload' | 'openapi.discriminator' | 'openapi.contentType' | 'openapi.tryIt' | 'openapi.loading' | 'openapi.example' | 'openapi.examples' | 'openapi.additionalProperties' | 'openapi.patternProperties' | 'openapi.required' | 'openapi.recursive' | 'openapi.complex' | 'openapi.hideExample' | 'openapi.showExample' | 'openapi.expandAll' | 'openapi.collapseAll' | 'openapi.viewSecurityDetails' | 'openapi.noResponseExample' | 'openapi.discriminator.searchPlaceholder' | 'openapi.discriminator.searchNoResults' | 'openapi.noResponseContent' | 'openapi.noRequestPayload' | 'openapi.hidePattern' | 'openapi.showPattern' | 'openapi.authorizationUrl' | 'openapi.tokenUrl' | 'openapi.refreshUrl' | 'openapi.showOptionalScopes' | 'openapi.hideOptionalScopes' | 'openapi.security' | 'openapi.httpAuthorizationScheme' | 'openapi.bearerFormat' | 'openapi.parameterName' | 'openapi.flowType' | 'openapi.connectUrl' | 'openapi.requiredScopes' | 'openapi.unsupportedLanguage' | 'openapi.failedToGenerateCodeSample' | 'asyncapi.download.description.title' | 'asyncapi.info.title' | 'graphql.queries' | 'graphql.mutations' | 'graphql.subscriptions' | 'graphql.directives' | 'graphql.objects' | 'graphql.interfaces' | 'graphql.unions' | 'graphql.enums' | 'graphql.inputs' | 'graphql.scalars' | 'graphql.arguments.label' | 'graphql.arguments.show' | 'graphql.arguments.hide' | 'graphql.arguments.here' | 'graphql.returnTypes.label' | 'graphql.returnTypes.show' | 'graphql.returnTypes.hide' | 'graphql.possibleTypes' | 'graphql.defaultValue' | 'graphql.deprecationReason' | 'graphql.implementedInterfaces' | 'graphql.nonNull' | 'graphql.required' | 'graphql.deprecated' | 'graphql.variables' | 'graphql.querySample' | 'graphql.mutationSample' | 'graphql.subscriptionSample' | 'graphql.responseSample' | 'graphql.locations' | 'graphql.sample' | 'graphql.referenced' | 'graphql.content.fragment' | 'codeWalkthrough.download' | 'codeWalkthrough.preview' | 'time.justNow' | 'time.past.second' | 'time.past.seconds' | 'time.past.minute' | 'time.past.minutes' | 'time.past.hour' | 'time.past.hours' | 'time.past.day' | 'time.past.days' | 'time.past.week' | 'time.past.weeks' | 'time.past.month' | 'time.past.months' | 'time.past.year' | 'time.past.years' | 'page.internalServerError.title' | 'page.internalServerError.description' | 'page.skipToContent.label';
2
+ export type TranslationKey = 'dev.newApp' | 'dev.newApp.text' | 'dev.sidebar.header' | 'dev.sidebar.footer.text' | 'dev.create.app.dialog.appName.placeholder' | 'dev.create.app.dialog.appName.error' | 'dev.create.app.dialog.selectAPIs' | 'dev.create.app.dialog.description' | 'dev.create.app.dialog.description.placeholder' | 'dev.create.app.dialog.create' | 'dev.create.app.dialog.cancel' | 'dev.main.tab.appKeys' | 'dev.main.tab.logs' | 'dev.app.description.title' | 'dev.edit.description.dialog.title' | 'dev.edit.description.dialog.save' | 'dev.edit.description.dialog.cancel' | 'dev.edit.apis.dialog.selectedAPIs' | 'dev.app.key.create' | 'dev.create.key.dialog.title' | 'dev.create.key.dialog.create' | 'dev.create.key.dialog.cancel' | 'dev.app.edit' | 'dev.app.delete' | 'dev.edit.app.dialog.title' | 'dev.edit.app.dialog.save' | 'dev.edit.app.dialog.cancel' | 'dev.delete.app.dialog.title' | 'dev.delete.app.dialog.confirmation' | 'dev.delete.app.dialog.delete' | 'dev.delete.app.dialog.cancel' | 'dev.app.key.roll' | 'dev.roll.key.dialog.title' | 'dev.roll.key.dialog.apiKey' | 'dev.roll.key.dialog.expires' | 'dev.roll.key.dialog.confirmation' | 'dev.roll.key.dialog.cancel' | 'dev.roll.key.dialog.roll' | 'dev.update.key.dialog.title' | 'dev.update.key.dialog.update' | 'dev.update.key.dialog.cancel' | 'dev.app.key.api.name' | 'dev.app.key.api.status' | 'dev.app.key.api.edit' | 'dev.edit.apis.dialog.title' | 'dev.edit.apis.dialog.apiKey' | 'dev.edit.apis.dialog.save' | 'dev.edit.apis.dialog.cancel' | 'dev.select.placeholder' | 'dev.app.overview.status.pending' | 'dev.app.overview.status.approved' | 'dev.app.overview.status.revoked' | 'dev.app.overview.status' | 'dev.app.overview.non-production' | 'dev.app.overview.production' | 'dev.app.overview.clientId' | 'dev.app.overview.apiKey' | 'dev.app.key.revoke' | 'dev.revoke.key.dialog.title' | 'dev.revoke.key.dialog.apiKey' | 'dev.revoke.key.dialog.expires' | 'dev.revoke.key.dialog.confirmation' | 'dev.revoke.key.dialog.revoke' | 'dev.revoke.key.dialog.cancel' | 'dev.app.overview.expires' | 'dev.app.overview.created' | 'dev.app.overview.visibilityToggle.hide' | 'dev.app.overview.visibilityToggle.show' | 'search.loading' | 'search.noResults.title' | 'search.keys.navigate' | 'search.keys.select' | 'search.keys.exit' | 'search.label' | 'search.cancel' | 'search.recent' | 'search.navbar.label' | 'search.suggested' | 'search.showMore' | 'search.filter.title' | 'search.filter.reset' | 'search.filter.field.reset' | 'search.ai.welcomeText' | 'search.ai.newConversation' | 'search.ai.backToSearch' | 'search.ai.placeholder' | 'search.ai.generatingResponse' | 'search.ai.followUpQuestion' | 'search.ai.suggestionsTitle' | 'search.ai.thinkingText' | 'search.ai.resourcesFound' | 'search.ai.resourcesFound.basedOn' | 'search.ai.resourcesFound.resources' | 'search.ai.button' | 'search.ai.label' | 'search.ai.disclaimer' | 'search.ai.error.description' | 'search.ai.error.description.forbidden' | 'search.ai.error.description.unauthorized' | 'search.ai.error.header' | 'search.ai.error.header.forbidden' | 'search.ai.error.header.unauthorized' | 'toc.header' | 'footer.copyrightText' | 'page.homeButton' | 'page.forbidden.title' | 'page.notFound.title' | 'page.notFound.description' | 'page.lastUpdated.timeago' | 'page.lastUpdated.on' | 'catalog.filters.placeholder' | 'catalog.filters.title' | 'catalog.filters.add' | 'catalog.filters.clearAll' | 'catalog.filters.select.addFilter' | 'catalog.filters.select.all' | 'catalog.filters.done' | 'catalog.catalogs.all.title' | 'catalog.catalogs.all.description' | 'catalog.catalogs.all.switcherLabel' | 'catalog.catalogs.service.title' | 'catalog.catalogs.service.description' | 'catalog.catalogs.service.switcherLabel' | 'catalog.catalogs.user.title' | 'catalog.catalogs.user.description' | 'catalog.catalogs.user.switcherLabel' | 'catalog.catalogs.team.title' | 'catalog.catalogs.team.description' | 'catalog.catalogs.team.switcherLabel' | 'catalog.catalogs.domain.title' | 'catalog.catalogs.domain.description' | 'catalog.catalogs.domain.switcherLabel' | 'catalog.catalogs.apiDescription.title' | 'catalog.catalogs.apiDescription.description' | 'catalog.catalogs.apiDescription.switcherLabel' | 'catalog.catalogs.dataSchema.title' | 'catalog.catalogs.dataSchema.description' | 'catalog.catalogs.dataSchema.switcherLabel' | 'catalog.catalogs.apiOperation.title' | 'catalog.catalogs.apiOperation.description' | 'catalog.catalogs.apiOperation.switcherLabel' | 'catalog.entity.metadata.title' | 'catalog.entity.schema.title' | 'catalog.entity.properties.apiDescription.title' | 'sidebar.menu.backLabel' | 'sidebar.menu.backToLabel' | 'sidebar.actions.show' | 'sidebar.actions.hide' | 'sidebar.actions.changeToSingleColumn' | 'sidebar.actions.changeToTwoColumns' | 'sidebar.actions.singleColumn' | 'sidebar.actions.twoColumns' | 'versionPicker.label' | 'versionPicker.unversioned' | 'codeSnippet.copy.buttonText' | 'codeSnippet.copy.tooltipText' | 'codeSnippet.copy.toasterText' | 'markdown.editPage.text' | 'feedback.settings.comment.submitText' | 'feedback.settings.comment.label' | 'feedback.settings.comment.send' | 'feedback.settings.comment.cancel' | 'feedback.settings.comment.satisfiedLabel' | 'feedback.settings.comment.neutralLabel' | 'feedback.settings.comment.dissatisfiedLabel' | 'feedback.settings.submitText' | 'feedback.settings.label' | 'feedback.settings.reasons.label' | 'feedback.submit' | 'feedback.cancel' | 'feedback.settings.comment.likeLabel' | 'feedback.settings.comment.dislikeLabel' | 'feedback.sentiment.thumbUp' | 'feedback.sentiment.thumbDown' | 'feedback.settings.leftScaleLabel' | 'feedback.settings.rightScaleLabel' | 'feedback.settings.optionalEmail.placeholder' | 'feedback.settings.optionalEmail.label' | 'codeSnippet.report.buttonText' | 'codeSnippet.report.tooltipText' | 'codeSnippet.report.label' | 'codeSnippet.expand.tooltipText' | 'codeSnippet.collapse.tooltipText' | 'userMenu.login' | 'userMenu.logout' | 'userMenu.devOnboardingLabel' | 'mobileMenu.mainMenu' | 'mobileMenu.previous' | 'mobileMenu.products' | 'mobileMenu.version' | 'navbar.products' | 'page.nextButton' | 'page.previousButton' | 'page.actions.copyButtonText' | 'page.actions.copyTitle' | 'page.actions.copyDescription' | 'page.actions.viewAsMdTitle' | 'page.actions.viewAsMdButtonText' | 'page.actions.viewAsMdDescription' | 'page.actions.chatGptTitle' | 'page.actions.chatGptButtonText' | 'page.actions.chatGptDescription' | 'page.actions.claudeTitle' | 'page.actions.claudeButtonText' | 'page.actions.claudeDescription' | 'openapi.download.description.title' | 'openapi.info.title' | 'openapi.info.contact.url' | 'openapi.info.contact.name' | 'openapi.info.license' | 'openapi.info.termsOfService' | 'openapi.info.metadata.title' | 'openapi.key' | 'openapi.value' | 'openapi.enum' | 'openapi.items' | 'openapi.default' | 'openapi.variable' | 'openapi.variables' | 'openapi.actions.show' | 'openapi.actions.hide' | 'openapi.actions.more' | 'openapi.languages.title' | 'openapi.servers.title' | 'openapi.operations' | 'openapi.webhooks' | 'openapi.description' | 'openapi.badges.deprecated' | 'openapi.badges.required' | 'openapi.badges.webhook' | 'openapi.request' | 'openapi.path' | 'openapi.query' | 'openapi.cookie' | 'openapi.header' | 'openapi.body' | 'openapi.responses' | 'openapi.response' | 'openapi.callbacks' | 'openapi.callbackRequest' | 'openapi.callbackResponse' | 'openapi.payload' | 'openapi.discriminator' | 'openapi.contentType' | 'openapi.tryIt' | 'openapi.loading' | 'openapi.example' | 'openapi.examples' | 'openapi.additionalProperties' | 'openapi.patternProperties' | 'openapi.required' | 'openapi.recursive' | 'openapi.complex' | 'openapi.hideExample' | 'openapi.showExample' | 'openapi.expandAll' | 'openapi.collapseAll' | 'openapi.viewSecurityDetails' | 'openapi.noResponseExample' | 'openapi.discriminator.searchPlaceholder' | 'openapi.discriminator.searchNoResults' | 'openapi.noResponseContent' | 'openapi.noRequestPayload' | 'openapi.hidePattern' | 'openapi.showPattern' | 'openapi.authorizationUrl' | 'openapi.tokenUrl' | 'openapi.refreshUrl' | 'openapi.showOptionalScopes' | 'openapi.hideOptionalScopes' | 'openapi.security' | 'openapi.httpAuthorizationScheme' | 'openapi.bearerFormat' | 'openapi.parameterName' | 'openapi.flowType' | 'openapi.connectUrl' | 'openapi.requiredScopes' | 'openapi.unsupportedLanguage' | 'openapi.failedToGenerateCodeSample' | 'asyncapi.download.description.title' | 'asyncapi.info.title' | 'graphql.queries' | 'graphql.mutations' | 'graphql.subscriptions' | 'graphql.directives' | 'graphql.objects' | 'graphql.interfaces' | 'graphql.unions' | 'graphql.enums' | 'graphql.inputs' | 'graphql.scalars' | 'graphql.arguments.label' | 'graphql.arguments.show' | 'graphql.arguments.hide' | 'graphql.arguments.here' | 'graphql.returnTypes.label' | 'graphql.returnTypes.show' | 'graphql.returnTypes.hide' | 'graphql.possibleTypes' | 'graphql.defaultValue' | 'graphql.deprecationReason' | 'graphql.requiredScopes' | 'graphql.viewSecurityDetails' | 'graphql.objectScopes' | 'graphql.fieldScopes' | 'graphql.implementedInterfaces' | 'graphql.nonNull' | 'graphql.required' | 'graphql.deprecated' | 'graphql.variables' | 'graphql.querySample' | 'graphql.mutationSample' | 'graphql.subscriptionSample' | 'graphql.responseSample' | 'graphql.locations' | 'graphql.sample' | 'graphql.referenced' | 'graphql.content.fragment' | 'codeWalkthrough.download' | 'codeWalkthrough.preview' | 'time.justNow' | 'time.past.second' | 'time.past.seconds' | 'time.past.minute' | 'time.past.minutes' | 'time.past.hour' | 'time.past.hours' | 'time.past.day' | 'time.past.days' | 'time.past.week' | 'time.past.weeks' | 'time.past.month' | 'time.past.months' | 'time.past.year' | 'time.past.years' | 'page.internalServerError.title' | 'page.internalServerError.description' | 'page.skipToContent.label';
3
3
  export type Locale = {
4
4
  code: string;
5
5
  name: string;
@@ -148,13 +148,12 @@ exports.codeWalkthrough = {
148
148
  };
149
149
  function collectStepsFromChildren(children, idx = 0) {
150
150
  return children.flatMap((child) => {
151
- if (child instanceof markdoc_1.default.Tag && child.name === 'CodeStep') {
151
+ const isTag = markdoc_1.default.Tag.isTag(child);
152
+ if (!isTag)
153
+ return [];
154
+ if (child.name === 'CodeStep')
152
155
  return [child];
153
- }
154
- if (child instanceof markdoc_1.default.Tag) {
155
- return collectStepsFromChildren(child.children, idx);
156
- }
157
- return [];
156
+ return collectStepsFromChildren(child.children, idx);
158
157
  });
159
158
  }
160
159
  function collectTogglesFromChildren(children, toggles = {}) {
@@ -174,7 +173,10 @@ function collectTogglesFromChildren(children, toggles = {}) {
174
173
  }
175
174
  function collectInputsFromChildren(children, inputs = {}) {
176
175
  for (const child of children) {
177
- if (child instanceof markdoc_1.default.Tag && child.name === 'Input') {
176
+ const isTag = markdoc_1.default.Tag.isTag(child);
177
+ if (!isTag)
178
+ continue;
179
+ if (child.name === 'Input') {
178
180
  const id = child.attributes.id;
179
181
  if (id) {
180
182
  inputs[id] = {
@@ -185,9 +187,7 @@ function collectInputsFromChildren(children, inputs = {}) {
185
187
  }
186
188
  continue;
187
189
  }
188
- if (child instanceof markdoc_1.default.Tag) {
189
- collectInputsFromChildren(child.children, inputs);
190
- }
190
+ collectInputsFromChildren(child.children, inputs);
191
191
  }
192
192
  return inputs;
193
193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.57.0-next.5",
3
+ "version": "0.57.0-next.6",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -5,11 +5,11 @@ import type { JSX } from 'react';
5
5
  import { HorizontalViewIcon } from '@redocly/theme/icons/HorizontalViewIcon/HorizontalViewIcon';
6
6
  import { VerticalViewIcon } from '@redocly/theme/icons/VerticalViewIcon/VerticalViewIcon';
7
7
  import { LayoutVariant } from '@redocly/theme/components/SidebarActions/SidebarActions';
8
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
8
9
  import {
9
10
  StyledChangeViewButton,
10
11
  StyledChangeViewButtonWrap,
11
12
  } from '@redocly/theme/components/SidebarActions/styled';
12
- import { useThemeHooks } from '@redocly/theme/core/hooks';
13
13
 
14
14
  export type ChangeViewButtonProps = {
15
15
  layout: LayoutVariant;
@@ -24,17 +24,33 @@ export const ChangeViewButton = ({
24
24
  }: ChangeViewButtonProps): JSX.Element | null => {
25
25
  const { useTranslate } = useThemeHooks();
26
26
  const { translate } = useTranslate();
27
+ const isStacked = layout === LayoutVariant.STACKED;
28
+ const isThreePanel = layout === LayoutVariant.THREE_PANEL;
27
29
 
28
30
  return (
29
- <StyledChangeViewButton
30
- title={translate('sidebar.actions.changeLayout', 'Change layout')}
31
- onClick={onClick}
32
- collapsedSidebar={collapsedSidebar}
33
- >
34
- <StyledChangeViewButtonWrap active={layout === LayoutVariant.STACKED}>
31
+ <StyledChangeViewButton onClick={onClick} collapsedSidebar={collapsedSidebar}>
32
+ <StyledChangeViewButtonWrap
33
+ placement={collapsedSidebar ? 'right' : 'top'}
34
+ arrowPosition={collapsedSidebar ? 'center' : 'right'}
35
+ active={isStacked}
36
+ tip={
37
+ isStacked
38
+ ? translate('sidebar.actions.singleColumn', 'Single column')
39
+ : translate('sidebar.actions.changeToSingleColumn', 'Switch to single column')
40
+ }
41
+ >
35
42
  <HorizontalViewIcon size="14px" color="--segmented-buttons-content-color" />
36
43
  </StyledChangeViewButtonWrap>
37
- <StyledChangeViewButtonWrap active={layout === LayoutVariant.THREE_PANEL}>
44
+ <StyledChangeViewButtonWrap
45
+ active={isThreePanel}
46
+ placement={collapsedSidebar ? 'right' : 'top'}
47
+ arrowPosition={collapsedSidebar ? 'center' : 'right'}
48
+ tip={
49
+ isThreePanel
50
+ ? translate('sidebar.actions.twoColumns', 'Two columns')
51
+ : translate('sidebar.actions.changeToTwoColumns', 'Switch to two columns')
52
+ }
53
+ >
38
54
  <VerticalViewIcon size="14px" color="--segmented-buttons-content-color" />
39
55
  </StyledChangeViewButtonWrap>
40
56
  </StyledChangeViewButton>
@@ -10,6 +10,7 @@ import {
10
10
  ControlsWrap,
11
11
  ControlsWrapChangeLayoutButtons,
12
12
  } from '@redocly/theme/components/SidebarActions/styled';
13
+ import { Tooltip } from '@redocly/theme/components/Tooltip/Tooltip';
13
14
 
14
15
  export { LayoutVariant };
15
16
 
@@ -44,24 +45,28 @@ export const SidebarActions = ({
44
45
  data-component-name="Sidebar/SidebarActions"
45
46
  >
46
47
  {!hideCollapseSidebarButton && (
47
- <Button
48
- onClick={() => {
49
- onChangeCollapseSidebarClick();
50
- if (collapsedSidebar) {
51
- telemetry.sendSidebarItemExpandedMessage();
52
- } else {
53
- telemetry.sendSidebarItemCollapsedMessage();
54
- }
55
- }}
56
- title={
48
+ <Tooltip
49
+ placement={collapsedSidebar ? 'right' : 'top'}
50
+ tip={
57
51
  collapsedSidebar
58
52
  ? translate('sidebar.actions.show', 'Show sidebar')
59
53
  : translate('sidebar.actions.hide', 'Hide sidebar')
60
54
  }
61
- size="small"
62
- variant="outlined"
63
- icon={collapsedSidebar ? <SidePanelOpenIcon /> : <SidePanelCloseIcon />}
64
- />
55
+ >
56
+ <Button
57
+ onClick={() => {
58
+ onChangeCollapseSidebarClick();
59
+ if (collapsedSidebar) {
60
+ telemetry.sendSidebarItemExpandedMessage();
61
+ } else {
62
+ telemetry.sendSidebarItemCollapsedMessage();
63
+ }
64
+ }}
65
+ size="small"
66
+ variant="outlined"
67
+ icon={collapsedSidebar ? <SidePanelOpenIcon /> : <SidePanelCloseIcon />}
68
+ />
69
+ </Tooltip>
65
70
  )}
66
71
  {isApiDocs && (
67
72
  <ControlsWrapChangeLayoutButtons isCollapsed={collapsedSidebar}>
@@ -1,6 +1,7 @@
1
1
  import styled, { css } from 'styled-components';
2
2
 
3
3
  import { breakpoints } from '@redocly/theme/core/utils';
4
+ import { Tooltip } from '@redocly/theme/components/Tooltip/Tooltip';
4
5
 
5
6
  export const StyledChangeViewButton = styled.span<{ collapsedSidebar?: boolean }>`
6
7
  display: flex;
@@ -15,7 +16,7 @@ export const StyledChangeViewButton = styled.span<{ collapsedSidebar?: boolean }
15
16
  padding: calc(var(--spacing-unit) / 2);
16
17
  `;
17
18
 
18
- export const StyledChangeViewButtonWrap = styled.span<{ active?: boolean }>`
19
+ export const StyledChangeViewButtonWrap = styled(Tooltip)<{ active?: boolean }>`
19
20
  width: 20px;
20
21
  height: 20px;
21
22
  border-radius: var(--border-radius);
@@ -1,9 +1,10 @@
1
- import React, { useEffect, memo, useRef } from 'react';
1
+ import React, { useEffect, memo, useRef, useState, useCallback } from 'react';
2
2
  import styled, { css } from 'styled-components';
3
3
 
4
4
  import type { JSX, PropsWithChildren, ReactNode } from 'react';
5
5
 
6
6
  import { useControl, useOutsideClick } from '@redocly/theme/core/hooks';
7
+ import { Portal } from '@redocly/theme/components/Portal/Portal';
7
8
 
8
9
  export type TooltipProps = {
9
10
  tip: string | ReactNode;
@@ -14,6 +15,7 @@ export type TooltipProps = {
14
15
  width?: string;
15
16
  dataTestId?: string;
16
17
  disabled?: boolean;
18
+ arrowPosition?: 'top' | 'bottom' | 'left' | 'right' | 'center';
17
19
  };
18
20
 
19
21
  export function TooltipComponent({
@@ -26,14 +28,75 @@ export function TooltipComponent({
26
28
  width,
27
29
  dataTestId,
28
30
  disabled = false,
31
+ arrowPosition = 'center',
29
32
  }: PropsWithChildren<TooltipProps>): JSX.Element {
30
33
  const ref = useRef<HTMLDivElement | null>(null);
31
34
  const { isOpened, handleOpen, handleClose } = useControl(isOpen);
35
+ const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 });
32
36
 
33
37
  useOutsideClick(ref, handleClose);
34
38
 
35
39
  const isControlled = isOpen !== undefined;
36
40
 
41
+ const updateTooltipPosition = useCallback(() => {
42
+ if (isOpened && ref.current) {
43
+ const rect = ref.current.getBoundingClientRect();
44
+
45
+ let top = 0;
46
+ let left = 0;
47
+
48
+ switch (placement) {
49
+ case 'top':
50
+ top = rect.top;
51
+ if (arrowPosition === 'left') {
52
+ left = rect.left - 24;
53
+ } else if (arrowPosition === 'right') {
54
+ left = rect.right + 24;
55
+ } else {
56
+ left = rect.left + rect.width / 2;
57
+ }
58
+ break;
59
+ case 'bottom':
60
+ top = rect.bottom;
61
+ if (arrowPosition === 'left') {
62
+ left = rect.left - 24;
63
+ } else if (arrowPosition === 'right') {
64
+ left = rect.right + 24;
65
+ } else {
66
+ left = rect.left + rect.width / 2;
67
+ }
68
+ break;
69
+ case 'left':
70
+ top = rect.top + rect.height / 2;
71
+ left = rect.left;
72
+ break;
73
+ case 'right':
74
+ top = rect.top + rect.height / 2;
75
+ left = rect.right;
76
+ break;
77
+ }
78
+
79
+ setTooltipPosition({ top, left });
80
+ }
81
+ }, [isOpened, placement, arrowPosition]);
82
+
83
+ useEffect(() => {
84
+ if (isOpened && ref.current) {
85
+ updateTooltipPosition();
86
+
87
+ const handleScroll = () => updateTooltipPosition();
88
+ const handleResize = () => updateTooltipPosition();
89
+
90
+ window.addEventListener('scroll', handleScroll, true);
91
+ window.addEventListener('resize', handleResize);
92
+
93
+ return () => {
94
+ window.removeEventListener('scroll', handleScroll, true);
95
+ window.removeEventListener('resize', handleResize);
96
+ };
97
+ }
98
+ }, [isOpened, placement, updateTooltipPosition]);
99
+
37
100
  useEffect(() => {
38
101
  if (isControlled && !disabled) {
39
102
  if (isOpen) {
@@ -60,14 +123,22 @@ export function TooltipComponent({
60
123
  >
61
124
  {children}
62
125
  {isOpened && !disabled && (
63
- <TooltipBody
64
- data-testid={dataTestId || (typeof tip === 'string' ? tip : '')}
65
- placement={placement}
66
- width={width}
67
- withArrow={withArrow}
68
- >
69
- {tip}
70
- </TooltipBody>
126
+ <Portal>
127
+ <TooltipBody
128
+ data-testid={dataTestId || (typeof tip === 'string' ? tip : '')}
129
+ placement={placement}
130
+ width={width}
131
+ withArrow={withArrow}
132
+ arrowPosition={arrowPosition}
133
+ style={{
134
+ position: 'fixed',
135
+ top: tooltipPosition.top,
136
+ left: tooltipPosition.left,
137
+ }}
138
+ >
139
+ {tip}
140
+ </TooltipBody>
141
+ </Portal>
71
142
  )}
72
143
  </TooltipWrapper>
73
144
  );
@@ -76,87 +147,111 @@ export function TooltipComponent({
76
147
  export const Tooltip = memo<PropsWithChildren<TooltipProps>>(TooltipComponent);
77
148
 
78
149
  const PLACEMENTS = {
79
- top: css<Pick<TooltipProps, 'withArrow'>>`
80
- top: 0;
81
- left: 50%;
82
- transform: translate(-50%, -99%);
83
- margin-top: -10px;
150
+ top: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
151
+ ${({ withArrow, arrowPosition }) =>
152
+ withArrow && arrowPosition === 'left'
153
+ ? css`
154
+ transform: translate(0, -100%);
155
+ margin-top: -10px;
156
+ `
157
+ : arrowPosition === 'right'
158
+ ? css`
159
+ transform: translate(-100%, -100%);
160
+ margin-top: -10px;
161
+ `
162
+ : css`
163
+ transform: translate(-50%, -100%);
164
+ margin-top: -10px;
165
+ `}
84
166
 
85
- ${({ withArrow }) =>
167
+ ${({ withArrow, arrowPosition }) =>
86
168
  withArrow &&
87
169
  css`
88
170
  &::after {
89
- border-left: 6px solid transparent;
90
- border-right: 6px solid transparent;
171
+ border-left: 14px solid transparent;
172
+ border-right: 14px solid transparent;
91
173
  border-top-width: 8px;
92
174
  border-top-style: solid;
93
- border-radius: 2px 2px 0 0;
175
+ border-radius: 2px;
94
176
  bottom: 0;
95
- left: 50%;
96
- transform: translate(-50%, 99%);
177
+ ${arrowPosition === 'left' && 'left: 16px; transform: translateY(99%);'}
178
+ ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, 99%);'}
179
+ ${arrowPosition === 'right' && 'right: 16px; transform: translateY(99%);'}
97
180
  }
98
181
  `}
99
182
  `,
100
- bottom: css<Pick<TooltipProps, 'withArrow'>>`
101
- bottom: 0;
102
- left: 50%;
103
- transform: translate(-50%, 99%);
104
- margin-bottom: -10px;
183
+ bottom: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
184
+ ${({ withArrow, arrowPosition }) =>
185
+ withArrow && arrowPosition === 'left'
186
+ ? css`
187
+ transform: translate(0, -100%);
188
+ margin-top: -10px;
189
+ `
190
+ : arrowPosition === 'right'
191
+ ? css`
192
+ transform: translate(-100%, -100%);
193
+ margin-top: -10px;
194
+ `
195
+ : css`
196
+ transform: translate(-50%, -100%);
197
+ margin-top: -10px;
198
+ `}
105
199
 
106
- ${({ withArrow }) =>
200
+ ${({ withArrow, arrowPosition }) =>
107
201
  withArrow &&
108
202
  css`
109
203
  &::after {
110
- border-left: 6px solid transparent;
111
- border-right: 6px solid transparent;
204
+ border-left: 14px solid transparent;
205
+ border-right: 14px solid transparent;
112
206
  border-bottom-width: 8px;
113
207
  border-bottom-style: solid;
114
208
  border-radius: 0 0 2px 2px;
115
209
  top: 0;
116
- left: 50%;
117
- transform: translate(-50%, -99%);
210
+ ${arrowPosition === 'left' && 'left: 16px; transform: translateY(-99%);'}
211
+ ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, -99%);'}
212
+ ${arrowPosition === 'right' && 'right: 16px; transform: translateY(-99%);'}
118
213
  }
119
214
  `}
120
215
  `,
121
- left: css<Pick<TooltipProps, 'withArrow'>>`
122
- top: 50%;
123
- left: 0;
216
+ left: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
124
217
  transform: translate(-100%, -50%);
125
218
  margin-left: -10px;
126
219
 
127
- ${({ withArrow }) =>
220
+ ${({ withArrow, arrowPosition }) =>
128
221
  withArrow &&
129
222
  css`
130
223
  &::after {
131
- border-top: 6px solid transparent;
132
- border-bottom: 6px solid transparent;
224
+ border-top: 14px solid transparent;
225
+ border-bottom: 14px solid transparent;
133
226
  border-left-width: 8px;
134
227
  border-left-style: solid;
135
228
  border-radius: 2px 0 0 2px;
136
229
  top: 50%;
137
230
  right: 0;
138
- transform: translate(99%, -50%);
231
+ ${arrowPosition === 'top' && 'top: 16px; transform: translateX(99%);'}
232
+ ${arrowPosition === 'center' && 'top: 50%; transform: translate(99%, -50%);'}
233
+ ${arrowPosition === 'bottom' && 'bottom: 16px; transform: translateX(99%);'}
139
234
  }
140
235
  `}
141
236
  `,
142
- right: css<Pick<TooltipProps, 'withArrow'>>`
143
- top: 50%;
144
- right: 0;
145
- transform: translate(100%, -50%);
146
- margin-right: -10px;
237
+ right: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
238
+ transform: translate(0, -50%);
239
+ margin-left: 10px;
147
240
 
148
- ${({ withArrow }) =>
241
+ ${({ withArrow, arrowPosition }) =>
149
242
  withArrow &&
150
243
  css`
151
244
  &::after {
152
- border-top: 6px solid transparent;
153
- border-bottom: 6px solid transparent;
245
+ border-top: 14px solid transparent;
246
+ border-bottom: 14px solid transparent;
154
247
  border-right-width: 8px;
155
248
  border-right-style: solid;
156
249
  border-radius: 0 2px 2px 0;
157
250
  top: 50%;
158
251
  left: 0;
159
- transform: translate(-99%, -50%);
252
+ ${arrowPosition === 'top' && 'top: 16px; transform: translateX(-99%);'}
253
+ ${arrowPosition === 'center' && 'top: 50%; transform: translate(-99%, -50%);'}
254
+ ${arrowPosition === 'bottom' && 'bottom: 16px; transform: translateX(-99%);'}
160
255
  }
161
256
  `}
162
257
  `,
@@ -168,22 +263,21 @@ const TooltipWrapper = styled.div`
168
263
  `;
169
264
 
170
265
  const TooltipBody = styled.span<
171
- Pick<Required<TooltipProps>, 'placement' | 'withArrow'> & { width?: string }
266
+ Pick<Required<TooltipProps>, 'placement' | 'withArrow' | 'arrowPosition'> & { width?: string }
172
267
  >`
173
268
  display: inline-block;
174
269
 
175
- position: absolute;
176
- text-align: center;
177
-
178
270
  padding: var(--tooltip-padding);
179
271
  max-width: var(--tooltip-max-width);
180
272
  white-space: normal;
273
+ word-break: normal;
181
274
  overflow-wrap: break-word;
182
275
 
183
276
  border-radius: var(--border-radius-md);
184
277
  transition: opacity 0.3s ease-out;
185
278
 
186
- font-size: 13px;
279
+ font-size: var(--font-size-base);
280
+ line-height: var(--line-height-base);
187
281
 
188
282
  z-index: var(--z-index-overlay);
189
283
 
@@ -201,9 +295,11 @@ const TooltipBody = styled.span<
201
295
  color: var(--tooltip-text-color);
202
296
  border: var(--tooltip-border-width, 0) var(--tooltip-border-style, solid)
203
297
  var(--tooltip-border-color, transparent);
204
- box-shadow: rgb(0 0 0 / 25%) 0 2px 4px;
298
+ box-shadow:
299
+ 0px 8px 24px 8px #0000000a,
300
+ 0px 4px 12px 0px #00000014;
205
301
 
206
- width: ${({ width }) => width || '120px'};
302
+ width: ${({ width }) => width || 'auto'};
207
303
  ${({ placement }) => css`
208
304
  ${PLACEMENTS[placement]};
209
305
  `}
@@ -0,0 +1,6 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const tooltipDarkMode = css`
4
+ --tooltip-bg-color: var(--color-warm-grey-4);
5
+ --tooltip-border-color: var(--color-warm-grey-5);
6
+ `;
@@ -6,16 +6,16 @@ export const tooltip = css`
6
6
  * @presenter Color
7
7
  */
8
8
 
9
- --tooltip-text-color: var(--text-color-secondary);
10
- --tooltip-bg-color: var(--bg-color-raised);
11
- --tooltip-arrow-color: var(--tooltip-bg-color);
12
- --tooltip-border-width: 0;
9
+ --tooltip-text-color: var(--color-static-white);
10
+ --tooltip-bg-color: var(--color-warm-grey-10);
11
+ --tooltip-arrow-color: var(--tooltip-border-color);
12
+ --tooltip-border-width: 2px;
13
13
  --tooltip-border-style: solid;
14
- --tooltip-border-color: transparent;
15
- --tooltip-padding-vertical: var(--spacing-xs);
16
- --tooltip-padding-horizontal: var(--spacing-sm);
14
+ --tooltip-border-color: var(--color-warm-grey-8);
15
+ --tooltip-padding-vertical: var(--spacing-xxs);
16
+ --tooltip-padding-horizontal: var(--spacing-xs);
17
17
  --tooltip-padding: var(--tooltip-padding-vertical) var(--tooltip-padding-horizontal);
18
- --tooltip-max-width: 250px;
18
+ --tooltip-max-width: 400px;
19
19
 
20
20
  .tooltip-copy-button {
21
21
  --tooltip-text-color: var(--text-color-secondary);
@@ -12,6 +12,7 @@ import { switcherDarkMode } from '@redocly/theme/components/Switch/variables.dar
12
12
  import { cardsDarkMode } from '@redocly/theme/markdoc/components/Cards/variables.dark';
13
13
  import { catalogDarkMode } from '@redocly/theme/components/Catalog/variables.dark';
14
14
  import { pageActionsDarkMode } from '@redocly/theme/components/PageActions/variables.dark';
15
+ import { tooltipDarkMode } from '@redocly/theme/components/Tooltip/variables.dark';
15
16
 
16
17
  const replayDarkMode = css`
17
18
  /**
@@ -319,6 +320,7 @@ export const darkMode = css`
319
320
  ${cardsDarkMode}
320
321
  ${catalogDarkMode}
321
322
  ${pageActionsDarkMode}
323
+ ${tooltipDarkMode}
322
324
 
323
325
  /**
324
326
  * @tokens Dark Theme Scrollbar Config
@@ -149,7 +149,10 @@ export type TranslationKey =
149
149
  | 'sidebar.menu.backToLabel'
150
150
  | 'sidebar.actions.show'
151
151
  | 'sidebar.actions.hide'
152
- | 'sidebar.actions.changeLayout'
152
+ | 'sidebar.actions.changeToSingleColumn'
153
+ | 'sidebar.actions.changeToTwoColumns'
154
+ | 'sidebar.actions.singleColumn'
155
+ | 'sidebar.actions.twoColumns'
153
156
  | 'versionPicker.label'
154
157
  | 'versionPicker.unversioned'
155
158
  | 'codeSnippet.copy.buttonText'
@@ -299,6 +302,10 @@ export type TranslationKey =
299
302
  | 'graphql.possibleTypes'
300
303
  | 'graphql.defaultValue'
301
304
  | 'graphql.deprecationReason'
305
+ | 'graphql.requiredScopes'
306
+ | 'graphql.viewSecurityDetails'
307
+ | 'graphql.objectScopes'
308
+ | 'graphql.fieldScopes'
302
309
  | 'graphql.implementedInterfaces'
303
310
  | 'graphql.nonNull'
304
311
  | 'graphql.required'
@@ -186,15 +186,12 @@ export function collectStepsFromChildren(
186
186
  idx = 0,
187
187
  ): RenderableTreeNode[] {
188
188
  return children.flatMap((child) => {
189
- if (child instanceof markdoc.Tag && child.name === 'CodeStep') {
190
- return [child];
191
- }
189
+ const isTag = markdoc.Tag.isTag(child);
192
190
 
193
- if (child instanceof markdoc.Tag) {
194
- return collectStepsFromChildren(child.children, idx);
195
- }
191
+ if (!isTag) return [];
192
+ if (child.name === 'CodeStep') return [child];
196
193
 
197
- return [];
194
+ return collectStepsFromChildren(child.children, idx);
198
195
  });
199
196
  }
200
197
 
@@ -224,7 +221,11 @@ export function collectInputsFromChildren(
224
221
  inputs: InputsMarkdocAttr = {},
225
222
  ): InputsMarkdocAttr {
226
223
  for (const child of children) {
227
- if (child instanceof markdoc.Tag && child.name === 'Input') {
224
+ const isTag = markdoc.Tag.isTag(child);
225
+
226
+ if (!isTag) continue;
227
+
228
+ if (child.name === 'Input') {
228
229
  const id = child.attributes.id as string;
229
230
  if (id) {
230
231
  inputs[id] = {
@@ -236,9 +237,7 @@ export function collectInputsFromChildren(
236
237
  continue;
237
238
  }
238
239
 
239
- if (child instanceof markdoc.Tag) {
240
- collectInputsFromChildren(child.children, inputs);
241
- }
240
+ collectInputsFromChildren(child.children, inputs);
242
241
  }
243
242
 
244
243
  return inputs;