@redocly/theme 0.63.0-next.3 → 0.63.0-next.5

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 (54) hide show
  1. package/lib/components/Buttons/CopyButton.d.ts +1 -1
  2. package/lib/components/Buttons/CopyButton.js +1 -1
  3. package/lib/components/Buttons/DownloadButton.d.ts +6 -0
  4. package/lib/components/Buttons/DownloadButton.js +20 -0
  5. package/lib/components/Buttons/EmailButton.js +6 -1
  6. package/lib/components/Buttons/NewTabButton.js +6 -1
  7. package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +2 -2
  8. package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem.js +6 -13
  9. package/lib/components/CodeBlock/CodeBlockControls.js +3 -3
  10. package/lib/components/Menu/MenuItem.js +1 -1
  11. package/lib/components/PageActions/PageActions.js +1 -1
  12. package/lib/components/Search/SearchDialog.js +1 -1
  13. package/lib/components/SidebarActions/SidebarActions.js +1 -1
  14. package/lib/components/SidebarActions/styled.d.ts +1 -1
  15. package/lib/components/Tooltip/AnchorTooltip.d.ts +7 -0
  16. package/lib/components/Tooltip/AnchorTooltip.js +233 -0
  17. package/lib/components/Tooltip/JsTooltip.d.ts +3 -0
  18. package/lib/components/Tooltip/JsTooltip.js +277 -0
  19. package/lib/components/Tooltip/Tooltip.d.ts +2 -13
  20. package/lib/components/Tooltip/Tooltip.js +14 -190
  21. package/lib/core/hooks/use-page-actions.js +9 -5
  22. package/lib/core/hooks/use-theme-hooks.js +1 -0
  23. package/lib/core/types/hooks.d.ts +4 -0
  24. package/lib/core/types/index.d.ts +1 -0
  25. package/lib/core/types/l10n.d.ts +1 -1
  26. package/lib/core/types/tooltip.d.ts +14 -0
  27. package/lib/core/types/tooltip.js +3 -0
  28. package/lib/core/utils/transform-revisions-to-version-history.js +13 -20
  29. package/lib/index.d.ts +1 -0
  30. package/lib/index.js +1 -0
  31. package/package.json +3 -3
  32. package/src/components/Buttons/CopyButton.tsx +2 -1
  33. package/src/components/Buttons/DownloadButton.tsx +41 -0
  34. package/src/components/Buttons/EmailButton.tsx +18 -8
  35. package/src/components/Buttons/NewTabButton.tsx +19 -8
  36. package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +2 -2
  37. package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem.tsx +5 -21
  38. package/src/components/CodeBlock/CodeBlockControls.tsx +3 -0
  39. package/src/components/Menu/MenuItem.tsx +1 -0
  40. package/src/components/PageActions/PageActions.tsx +6 -1
  41. package/src/components/Search/SearchDialog.tsx +1 -1
  42. package/src/components/SidebarActions/SidebarActions.tsx +1 -0
  43. package/src/components/Tooltip/AnchorTooltip.tsx +259 -0
  44. package/src/components/Tooltip/JsTooltip.tsx +296 -0
  45. package/src/components/Tooltip/Tooltip.tsx +18 -257
  46. package/src/core/hooks/__mocks__/use-theme-hooks.ts +3 -0
  47. package/src/core/hooks/use-page-actions.ts +5 -0
  48. package/src/core/hooks/use-theme-hooks.ts +1 -0
  49. package/src/core/types/hooks.ts +2 -1
  50. package/src/core/types/index.ts +1 -0
  51. package/src/core/types/l10n.ts +5 -0
  52. package/src/core/types/tooltip.ts +15 -0
  53. package/src/core/utils/transform-revisions-to-version-history.ts +13 -21
  54. package/src/index.ts +1 -0
@@ -0,0 +1,296 @@
1
+ import React, { useEffect, memo, useRef, useState, useCallback, useLayoutEffect } from 'react';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import type { JSX, PropsWithChildren } from 'react';
5
+ import type { TooltipProps } from '@redocly/theme/core/types';
6
+
7
+ import { useControl, useOutsideClick } from '@redocly/theme/core/hooks';
8
+ import { Portal } from '@redocly/theme/components/Portal/Portal';
9
+
10
+ function TooltipComponent({
11
+ children,
12
+ isOpen,
13
+ tip,
14
+ withArrow = true,
15
+ placement = 'top',
16
+ className = 'default',
17
+ width,
18
+ dataTestId,
19
+ disabled = false,
20
+ arrowPosition = 'center',
21
+ onClick,
22
+ }: PropsWithChildren<TooltipProps>): JSX.Element {
23
+ const ref = useRef<HTMLDivElement | null>(null);
24
+ const { isOpened, handleOpen, handleClose } = useControl(isOpen);
25
+ const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 });
26
+
27
+ useOutsideClick(ref, handleClose);
28
+
29
+ const isControlled = isOpen !== undefined;
30
+
31
+ const updateTooltipPosition = useCallback(() => {
32
+ if (isOpened && ref.current) {
33
+ const rect = ref.current.getBoundingClientRect();
34
+
35
+ let top = 0;
36
+ let left = 0;
37
+
38
+ switch (placement) {
39
+ case 'top':
40
+ top = rect.top;
41
+ if (arrowPosition === 'left') {
42
+ left = rect.left - 24;
43
+ } else if (arrowPosition === 'right') {
44
+ left = rect.right + 24;
45
+ } else {
46
+ left = rect.left + rect.width / 2;
47
+ }
48
+ break;
49
+ case 'bottom':
50
+ top = rect.bottom;
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 'left':
60
+ top = rect.top + rect.height / 2;
61
+ left = rect.left;
62
+ break;
63
+ case 'right':
64
+ top = rect.top + rect.height / 2;
65
+ left = rect.right;
66
+ break;
67
+ }
68
+
69
+ setTooltipPosition({ top, left });
70
+ }
71
+ }, [isOpened, placement, arrowPosition]);
72
+
73
+ useLayoutEffect(() => {
74
+ if (isOpened && ref.current) {
75
+ updateTooltipPosition();
76
+
77
+ const handleScroll = () => updateTooltipPosition();
78
+ const handleResize = () => updateTooltipPosition();
79
+
80
+ window.addEventListener('scroll', handleScroll, true);
81
+ window.addEventListener('resize', handleResize);
82
+
83
+ return () => {
84
+ window.removeEventListener('scroll', handleScroll, true);
85
+ window.removeEventListener('resize', handleResize);
86
+ };
87
+ }
88
+ }, [isOpened, placement, updateTooltipPosition]);
89
+
90
+ useEffect(() => {
91
+ if (isOpen && !disabled) {
92
+ handleOpen();
93
+ } else {
94
+ handleClose();
95
+ }
96
+ }, [isOpen, handleOpen, handleClose, disabled]);
97
+
98
+ const controllers = !isControlled &&
99
+ !disabled && {
100
+ onMouseEnter: handleOpen,
101
+ onMouseLeave: handleClose,
102
+ onClick: (e: React.MouseEvent<HTMLDivElement>) => {
103
+ onClick?.(e);
104
+ handleClose();
105
+ },
106
+ onFocus: handleOpen,
107
+ onBlur: handleClose,
108
+ };
109
+
110
+ return (
111
+ <TooltipWrapper
112
+ ref={ref}
113
+ {...controllers}
114
+ className={`tooltip-${className}`}
115
+ data-component-name="Tooltip/Tooltip"
116
+ >
117
+ {children}
118
+ {isOpened && !disabled && (
119
+ <Portal>
120
+ <TooltipBody
121
+ data-testid={dataTestId || (typeof tip === 'string' ? tip : '')}
122
+ placement={placement}
123
+ width={width}
124
+ withArrow={withArrow}
125
+ arrowPosition={arrowPosition}
126
+ style={{
127
+ position: 'fixed',
128
+ top: tooltipPosition.top,
129
+ left: tooltipPosition.left,
130
+ }}
131
+ >
132
+ {tip}
133
+ </TooltipBody>
134
+ </Portal>
135
+ )}
136
+ </TooltipWrapper>
137
+ );
138
+ }
139
+
140
+ export const Tooltip = memo<PropsWithChildren<TooltipProps>>(TooltipComponent);
141
+
142
+ const PLACEMENTS = {
143
+ top: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
144
+ ${({ withArrow, arrowPosition }) =>
145
+ withArrow && arrowPosition === 'left'
146
+ ? css`
147
+ transform: translate(0, -100%);
148
+ margin-top: -10px;
149
+ `
150
+ : arrowPosition === 'right'
151
+ ? css`
152
+ transform: translate(-100%, -100%);
153
+ margin-top: -10px;
154
+ `
155
+ : css`
156
+ transform: translate(-50%, -100%);
157
+ margin-top: -10px;
158
+ `}
159
+
160
+ ${({ withArrow, arrowPosition }) =>
161
+ withArrow &&
162
+ css`
163
+ &::after {
164
+ border-left: 14px solid transparent;
165
+ border-right: 14px solid transparent;
166
+ border-top-width: 8px;
167
+ border-top-style: solid;
168
+ border-radius: 2px;
169
+ bottom: 0;
170
+ ${arrowPosition === 'left' && 'left: 16px; transform: translateY(99%);'}
171
+ ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, 99%);'}
172
+ ${arrowPosition === 'right' && 'right: 16px; transform: translateY(99%);'}
173
+ }
174
+ `}
175
+ `,
176
+ bottom: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
177
+ ${({ withArrow, arrowPosition }) =>
178
+ withArrow && arrowPosition === 'left'
179
+ ? css`
180
+ transform: translate(0, 10px);
181
+ margin-top: 0;
182
+ `
183
+ : arrowPosition === 'right'
184
+ ? css`
185
+ transform: translate(-100%, 10px);
186
+ margin-top: 0;
187
+ `
188
+ : css`
189
+ transform: translate(-50%, 10px);
190
+ margin-top: 0;
191
+ `}
192
+
193
+ ${({ withArrow, arrowPosition }) =>
194
+ withArrow &&
195
+ css`
196
+ &::after {
197
+ border-left: 14px solid transparent;
198
+ border-right: 14px solid transparent;
199
+ border-bottom-width: 8px;
200
+ border-bottom-style: solid;
201
+ border-radius: 0 0 2px 2px;
202
+ top: 0;
203
+ ${arrowPosition === 'left' && 'left: 16px; transform: translateY(-99%);'}
204
+ ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, -99%);'}
205
+ ${arrowPosition === 'right' && 'right: 16px; transform: translateY(-99%);'}
206
+ }
207
+ `}
208
+ `,
209
+ left: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
210
+ transform: translate(-100%, -50%);
211
+ margin-left: -10px;
212
+
213
+ ${({ withArrow, arrowPosition }) =>
214
+ withArrow &&
215
+ css`
216
+ &::after {
217
+ border-top: 14px solid transparent;
218
+ border-bottom: 14px solid transparent;
219
+ border-left-width: 8px;
220
+ border-left-style: solid;
221
+ border-radius: 2px 0 0 2px;
222
+ top: 50%;
223
+ right: 0;
224
+ ${arrowPosition === 'top' && 'top: 16px; transform: translateX(99%);'}
225
+ ${arrowPosition === 'center' && 'top: 50%; transform: translate(99%, -50%);'}
226
+ ${arrowPosition === 'bottom' && 'bottom: 16px; transform: translateX(99%);'}
227
+ }
228
+ `}
229
+ `,
230
+ right: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
231
+ transform: translate(0, -50%);
232
+ margin-left: 10px;
233
+
234
+ ${({ withArrow, arrowPosition }) =>
235
+ withArrow &&
236
+ css`
237
+ &::after {
238
+ border-top: 14px solid transparent;
239
+ border-bottom: 14px solid transparent;
240
+ border-right-width: 8px;
241
+ border-right-style: solid;
242
+ border-radius: 0 2px 2px 0;
243
+ top: 50%;
244
+ left: 0;
245
+ ${arrowPosition === 'top' && 'top: 16px; transform: translateX(-99%);'}
246
+ ${arrowPosition === 'center' && 'top: 50%; transform: translate(-99%, -50%);'}
247
+ ${arrowPosition === 'bottom' && 'bottom: 16px; transform: translateX(-99%);'}
248
+ }
249
+ `}
250
+ `,
251
+ };
252
+
253
+ const TooltipWrapper = styled.div`
254
+ position: relative;
255
+ display: flex;
256
+ `;
257
+ const TooltipBody = styled.span<
258
+ Pick<Required<TooltipProps>, 'placement' | 'withArrow' | 'arrowPosition'> & { width?: string }
259
+ >`
260
+ display: inline-block;
261
+
262
+ padding: var(--tooltip-padding);
263
+ max-width: ${({ width }) => width || 'var(--tooltip-max-width)'};
264
+ white-space: normal;
265
+ word-break: normal;
266
+ overflow-wrap: break-word;
267
+
268
+ border-radius: var(--border-radius-md);
269
+ transition: opacity 0.3s ease-out;
270
+
271
+ font-size: var(--font-size-base);
272
+ line-height: var(--line-height-base);
273
+
274
+ z-index: var(--z-index-overlay);
275
+
276
+ &::after {
277
+ position: absolute;
278
+
279
+ content: ' ';
280
+ display: inline-block;
281
+ width: 0;
282
+ height: 0;
283
+ border-color: var(--tooltip-arrow-color, var(--tooltip-bg-color));
284
+ }
285
+
286
+ background: var(--tooltip-bg-color);
287
+ color: var(--tooltip-text-color);
288
+ border: var(--tooltip-border-width, 0) var(--tooltip-border-style, solid)
289
+ var(--tooltip-border-color, transparent);
290
+ box-shadow: var(--bg-raised-shadow);
291
+
292
+ width: ${({ width }) => width || 'auto'};
293
+ ${({ placement }) => css`
294
+ ${PLACEMENTS[placement]};
295
+ `}
296
+ `;
@@ -1,264 +1,25 @@
1
- import React, { memo, useEffect, useRef, useId } from 'react';
2
- import styled, { css } from 'styled-components';
1
+ import React, { memo } from 'react';
3
2
 
4
- import type { JSX, PropsWithChildren, ReactNode } from 'react';
3
+ import { Tooltip as AnchorTooltip } from '@redocly/theme/components/Tooltip/AnchorTooltip';
4
+ import { Tooltip as JsTooltip } from '@redocly/theme/components/Tooltip/JsTooltip';
5
+ import { TooltipProps } from '@redocly/theme/core/types';
6
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
5
7
 
6
- import { useControl, useOutsideClick } from '@redocly/theme/core/hooks';
7
- import { Portal } from '@redocly/theme/components/Portal/Portal';
8
+ function TooltipComponent(props: TooltipProps): React.ReactElement {
9
+ const { useAnchorPositioning } = useThemeHooks();
10
+ const { isSupported } = useAnchorPositioning();
8
11
 
9
- export type TooltipProps = {
10
- tip: string | ReactNode;
11
- isOpen?: boolean;
12
- withArrow?: boolean;
13
- placement?: 'top' | 'bottom' | 'left' | 'right';
14
- className?: string;
15
- width?: string;
16
- dataTestId?: string;
17
- disabled?: boolean;
18
- arrowPosition?: 'left' | 'right' | 'center';
19
- };
20
-
21
- function TooltipComponent({
22
- children,
23
- isOpen,
24
- tip,
25
- withArrow = true,
26
- placement = 'top',
27
- className = 'default',
28
- width,
29
- dataTestId,
30
- disabled = false,
31
- arrowPosition = 'center',
32
- }: PropsWithChildren<TooltipProps>): JSX.Element {
33
- const tooltipWrapperRef = useRef<HTMLDivElement | null>(null);
34
- const tooltipBodyRef = useRef<HTMLDivElement | null>(null);
35
- const { isOpened, handleOpen, handleClose } = useControl(isOpen);
36
- const anchorName = `--tooltip${useId().replace(/:/g, '')}`;
37
-
38
- useOutsideClick(isOpened ? [tooltipWrapperRef, tooltipBodyRef] : tooltipWrapperRef, handleClose);
39
-
40
- const isControlled = isOpen !== undefined;
41
-
42
- useEffect(() => {
43
- if (!isControlled) return;
44
-
45
- if (isOpen && !disabled) {
46
- handleOpen();
47
- } else {
48
- handleClose();
49
- }
50
- }, [isOpen, disabled, isControlled, handleOpen, handleClose]);
51
-
52
- const controllers =
53
- !isControlled && !disabled
54
- ? {
55
- onMouseEnter: handleOpen,
56
- onMouseLeave: handleClose,
57
- onClick: handleClose,
58
- onFocus: handleOpen,
59
- onBlur: handleClose,
60
- }
61
- : {};
62
-
63
- return (
64
- <TooltipWrapper
65
- ref={tooltipWrapperRef}
66
- {...controllers}
67
- className={`tooltip-${className}`}
68
- data-component-name="Tooltip/Tooltip"
69
- anchorName={anchorName}
70
- >
71
- {children}
72
- {isOpened && !disabled && (
73
- <Portal>
74
- <TooltipBody
75
- ref={tooltipBodyRef}
76
- data-testid={dataTestId || (typeof tip === 'string' ? tip : '')}
77
- placement={placement}
78
- width={width}
79
- withArrow={withArrow}
80
- arrowPosition={arrowPosition}
81
- anchorName={anchorName}
82
- >
83
- {tip}
84
- </TooltipBody>
85
- </Portal>
86
- )}
87
- </TooltipWrapper>
88
- );
89
- }
90
-
91
- export const Tooltip = memo<PropsWithChildren<TooltipProps>>(TooltipComponent);
92
-
93
- const PLACEMENTS = {
94
- top: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
95
- bottom: anchor(top);
96
- ${({ withArrow, arrowPosition }) =>
97
- withArrow && arrowPosition === 'left'
98
- ? css`
99
- transform: translate(-32px, -6px);
100
- left: anchor(center);
101
- `
102
- : arrowPosition === 'right'
103
- ? css`
104
- transform: translate(32px, -6px);
105
- right: anchor(center);
106
- `
107
- : css`
108
- transform: translate(-50%, -6px);
109
- left: anchor(center);
110
- `}
111
-
112
- ${({ withArrow, arrowPosition }) =>
113
- withArrow &&
114
- css`
115
- &::after {
116
- border-left: 14px solid transparent;
117
- border-right: 14px solid transparent;
118
- border-top-width: 8px;
119
- border-top-style: solid;
120
- border-radius: 2px;
121
- bottom: 0;
122
- ${arrowPosition === 'left' && 'left: 16px; transform: translateY(100%);'}
123
- ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, 100%);'}
124
- ${arrowPosition === 'right' && 'right: 16px; transform: translateY(100%);'}
125
- }
126
- `}
127
- `,
128
- bottom: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
129
- top: anchor(bottom);
130
- ${({ withArrow, arrowPosition }) =>
131
- withArrow && arrowPosition === 'left'
132
- ? css`
133
- transform: translate(-32px, 6px);
134
- left: anchor(center);
135
- `
136
- : arrowPosition === 'right'
137
- ? css`
138
- transform: translate(32px, 6px);
139
- right: anchor(center);
140
- `
141
- : css`
142
- transform: translate(-50%, 6px);
143
- left: anchor(center);
144
- `}
145
-
146
- ${({ withArrow, arrowPosition }) =>
147
- withArrow &&
148
- css`
149
- &::after {
150
- border-left: 14px solid transparent;
151
- border-right: 14px solid transparent;
152
- border-bottom-width: 8px;
153
- border-bottom-style: solid;
154
- border-radius: 0 0 2px 2px;
155
- top: 0;
156
- ${arrowPosition === 'left' && 'left: 16px; transform: translateY(-100%);'}
157
- ${arrowPosition === 'center' && 'left: 50%; transform: translate(-50%, -100%);'}
158
- ${arrowPosition === 'right' && 'right: 16px; transform: translateY(-100%);'}
159
- }
160
- `}
161
- `,
162
- left: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
163
- transform: translate(-100%, -50%);
164
- margin-left: -7px;
165
- top: anchor(center);
166
- left: anchor(left);
167
-
168
- ${({ withArrow }) =>
169
- withArrow &&
170
- css`
171
- &::after {
172
- border-top: 14px solid transparent;
173
- border-bottom: 14px solid transparent;
174
- border-left-width: 8px;
175
- border-left-style: solid;
176
- border-radius: 2px 0 0 2px;
177
- right: -9px;
178
- top: 50%;
179
- transform: translateY(-50%);
180
- }
181
- `}
182
- `,
183
- right: css<Pick<TooltipProps, 'withArrow' | 'arrowPosition'>>`
184
- transform: translate(0, -50%);
185
- margin-left: 7px;
186
- top: anchor(center);
187
- left: anchor(right);
188
-
189
- ${({ withArrow }) =>
190
- withArrow &&
191
- css`
192
- &::after {
193
- border-top: 14px solid transparent;
194
- border-bottom: 14px solid transparent;
195
- border-right-width: 8px;
196
- border-right-style: solid;
197
- border-radius: 0 2px 2px 0;
198
- left: -9px;
199
- top: 50%;
200
- transform: translateY(-50%);
201
- }
202
- `}
203
- `,
204
- };
205
-
206
- const TooltipWrapper = styled.div.attrs<{ anchorName: string }>(({ anchorName }) => ({
207
- style: {
208
- anchorName: anchorName,
209
- } as React.CSSProperties,
210
- }))<{ anchorName: string }>`
211
- display: flex;
212
- `;
213
-
214
- const TooltipBody = styled.span.attrs<{ anchorName: string }>(({ anchorName }) => ({
215
- style: {
216
- positionAnchor: anchorName,
217
- } as React.CSSProperties,
218
- }))<
219
- Pick<Required<TooltipProps>, 'placement' | 'withArrow' | 'arrowPosition'> & {
220
- width?: string;
221
- anchorName: string;
12
+ if (isSupported) {
13
+ return <AnchorTooltip {...props} arrowPosition={prepareArrowPosition(props.arrowPosition)} />;
222
14
  }
223
- >`
224
- position: fixed;
225
- min-width: 64px;
226
- padding: var(--tooltip-padding);
227
- max-width: var(--tooltip-max-width);
228
- white-space: normal;
229
- word-break: normal;
230
- overflow-wrap: break-word;
231
- text-align: left;
232
-
233
- border-radius: var(--border-radius-md);
234
- transition: opacity 0.3s ease-out;
235
-
236
- font-size: var(--font-size-base);
237
- line-height: var(--line-height-base);
238
-
239
- z-index: var(--z-index-overlay);
15
+ return <JsTooltip {...props} />;
16
+ }
240
17
 
241
- &::after {
242
- position: absolute;
18
+ export const Tooltip = memo<TooltipProps>(TooltipComponent);
243
19
 
244
- content: ' ';
245
- display: inline-block;
246
- width: 0;
247
- height: 0;
248
- border-color: var(--tooltip-arrow-color, var(--tooltip-bg-color));
20
+ const prepareArrowPosition = (arrowPosition: TooltipProps['arrowPosition']) => {
21
+ if (arrowPosition === 'bottom' || arrowPosition === 'top') {
22
+ return 'center';
249
23
  }
250
-
251
- background: var(--tooltip-bg-color);
252
- color: var(--tooltip-text-color);
253
- border: var(--tooltip-border-width, 0) var(--tooltip-border-style, solid)
254
- var(--tooltip-border-color, transparent);
255
- box-shadow:
256
- 0px 8px 24px 8px #0000000a,
257
- 0px 4px 12px 0px #00000014;
258
-
259
- width: ${({ width }) => width || 'max-content'};
260
-
261
- ${({ placement }) => css`
262
- ${PLACEMENTS[placement]};
263
- `}
264
- `;
24
+ return arrowPosition;
25
+ };
@@ -3,6 +3,9 @@ import { vi, type MockedFunction } from 'vitest';
3
3
  import type { ThemeHooks } from '../../types/hooks';
4
4
 
5
5
  export const useThemeHooks = vi.fn(() => ({
6
+ useAnchorPositioning: vi.fn(() => ({
7
+ isSupported: true,
8
+ })),
6
9
  useTranslate: vi.fn(() => ({
7
10
  translate: vi.fn((key: string, defaultValue: string | { defaultValue: string }) =>
8
11
  defaultValue
@@ -290,6 +290,11 @@ function shouldHidePageActions(
290
290
  themeConfig: UiAccessibleConfig,
291
291
  openapiExcludeFromSearch?: boolean,
292
292
  ): boolean {
293
+ // Can't use any actions if search is globally disabled (markdown files are not generated)
294
+ if (themeConfig.search?.hide) {
295
+ return true;
296
+ }
297
+
293
298
  // Can't use any actions if no markdown files are generated for LLMs
294
299
  if (pageProps?.seo?.llmstxt?.hide) {
295
300
  return true;
@@ -6,6 +6,7 @@ import { ThemeDataContext } from '../contexts/ThemeDataContext';
6
6
  import { useTelemetryFallback } from './use-telemetry-fallback';
7
7
 
8
8
  const fallbacks = {
9
+ useAnchorPositioning: () => ({ isSupported: false }),
9
10
  useTranslate: () => ({
10
11
  translate: (value?: string, options?: { defaultValue: string } | string) =>
11
12
  (typeof options === 'string' ? options : options?.defaultValue) || value || '',
@@ -47,6 +47,7 @@ import {
47
47
  import { AiSearchError } from '../constants/search';
48
48
 
49
49
  export type ThemeHooks = {
50
+ useAnchorPositioning: () => { isSupported: boolean };
50
51
  useTranslate: () => { translate: TFunction };
51
52
  /**
52
53
  * @deprecated use `useL10n` instead
@@ -116,7 +117,7 @@ export type ThemeHooks = {
116
117
  advancedSearch?: boolean;
117
118
  askAi?: boolean;
118
119
  };
119
- useAiSearch: (options?: { filter?: SearchFilterItem[] }) => {
120
+ useAiSearch: (options?: { filter?: SearchFilterItem[]; product?: string }) => {
120
121
  askQuestion: (question: string, history?: AiSearchConversationItem[]) => void;
121
122
  isGeneratingResponse: boolean;
122
123
  question: string;
@@ -19,3 +19,4 @@ export type * from './code-walkthrough';
19
19
  export type * from './page-actions';
20
20
  export type * from './open-api-info';
21
21
  export type * from './segmented';
22
+ export type * from './tooltip';
@@ -275,6 +275,7 @@ export type TranslationKey =
275
275
  | 'openapi.actions.hide'
276
276
  | 'openapi.actions.more'
277
277
  | 'openapi.languages.title'
278
+ | 'openapi.languages.moreButton.tooltipText'
278
279
  | 'openapi.servers.title'
279
280
  | 'openapi.operations'
280
281
  | 'openapi.webhooks'
@@ -395,6 +396,10 @@ export type TranslationKey =
395
396
  | 'graphql.sample'
396
397
  | 'graphql.referenced'
397
398
  | 'graphql.content.fragment'
399
+ | 'button.copy.tooltipText'
400
+ | 'button.download.tooltipText'
401
+ | 'button.externalLink.tooltipText'
402
+ | 'button.email.tooltipText'
398
403
  | 'codeWalkthrough.download'
399
404
  | 'codeWalkthrough.preview'
400
405
  | 'time.justNow'
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export type TooltipProps = {
4
+ children?: ReactNode;
5
+ tip: string | ReactNode;
6
+ isOpen?: boolean;
7
+ withArrow?: boolean;
8
+ placement?: 'top' | 'bottom' | 'left' | 'right';
9
+ className?: string;
10
+ width?: string;
11
+ dataTestId?: string;
12
+ disabled?: boolean;
13
+ arrowPosition?: 'top' | 'bottom' | 'left' | 'right' | 'center';
14
+ onClick?: React.MouseEventHandler<HTMLDivElement>;
15
+ };