@redocly/theme 0.63.0-next.3 → 0.63.0-next.4
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.
- package/lib/components/Buttons/CopyButton.d.ts +1 -1
- package/lib/components/Buttons/CopyButton.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +2 -2
- package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem.js +6 -13
- package/lib/components/CodeBlock/CodeBlockControls.js +3 -3
- package/lib/components/PageActions/PageActions.js +1 -1
- package/lib/components/SidebarActions/styled.d.ts +1 -1
- package/lib/components/Tooltip/AnchorTooltip.d.ts +7 -0
- package/lib/components/Tooltip/AnchorTooltip.js +230 -0
- package/lib/components/Tooltip/JsTooltip.d.ts +3 -0
- package/lib/components/Tooltip/JsTooltip.js +274 -0
- package/lib/components/Tooltip/Tooltip.d.ts +2 -13
- package/lib/components/Tooltip/Tooltip.js +14 -190
- package/lib/core/hooks/use-page-actions.js +9 -5
- package/lib/core/hooks/use-theme-hooks.js +1 -0
- package/lib/core/types/hooks.d.ts +3 -0
- package/lib/core/types/index.d.ts +1 -0
- package/lib/core/types/tooltip.d.ts +13 -0
- package/lib/core/types/tooltip.js +3 -0
- package/lib/core/utils/transform-revisions-to-version-history.js +13 -20
- package/package.json +3 -3
- package/src/components/Buttons/CopyButton.tsx +2 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +2 -2
- package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem.tsx +5 -21
- package/src/components/CodeBlock/CodeBlockControls.tsx +3 -0
- package/src/components/PageActions/PageActions.tsx +6 -1
- package/src/components/Tooltip/AnchorTooltip.tsx +255 -0
- package/src/components/Tooltip/JsTooltip.tsx +292 -0
- package/src/components/Tooltip/Tooltip.tsx +18 -257
- package/src/core/hooks/__mocks__/use-theme-hooks.ts +3 -0
- package/src/core/hooks/use-page-actions.ts +5 -0
- package/src/core/hooks/use-theme-hooks.ts +1 -0
- package/src/core/types/hooks.ts +1 -0
- package/src/core/types/index.ts +1 -0
- package/src/core/types/tooltip.ts +14 -0
- package/src/core/utils/transform-revisions-to-version-history.ts +13 -21
|
@@ -1,264 +1,25 @@
|
|
|
1
|
-
import React, { memo
|
|
2
|
-
import styled, { css } from 'styled-components';
|
|
1
|
+
import React, { memo } from 'react';
|
|
3
2
|
|
|
4
|
-
import
|
|
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
|
-
|
|
7
|
-
|
|
8
|
+
function TooltipComponent(props: TooltipProps): React.ReactElement {
|
|
9
|
+
const { useAnchorPositioning } = useThemeHooks();
|
|
10
|
+
const { isSupported } = useAnchorPositioning();
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
242
|
-
position: absolute;
|
|
18
|
+
export const Tooltip = memo<TooltipProps>(TooltipComponent);
|
|
243
19
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
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 || '',
|
package/src/core/types/hooks.ts
CHANGED
package/src/core/types/index.ts
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
};
|
|
@@ -53,27 +53,19 @@ export function transformRevisionsToVersionHistory({
|
|
|
53
53
|
// Check if any revision in this version group is the default version
|
|
54
54
|
const isDefaultVersion = versionRevisions.some((rev) => rev.isDefaultVersion === true);
|
|
55
55
|
|
|
56
|
-
const revisions =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
name: `r.${versionRevisions.length - index}`,
|
|
70
|
-
date: toLocalizedShortDateTime(rev.revision, locale),
|
|
71
|
-
revisionDate: rev.revision,
|
|
72
|
-
isActive: isActiveRevision || isCurrentByDefault,
|
|
73
|
-
isCurrent: rev.isCurrent ?? false,
|
|
74
|
-
};
|
|
75
|
-
})
|
|
76
|
-
: undefined;
|
|
56
|
+
const revisions = versionRevisions.map((rev, index): CatalogEntityRevision => {
|
|
57
|
+
const revisionMatches = currentRevisionDate ? rev.revision === currentRevisionDate : false;
|
|
58
|
+
const isActiveRevision = revisionMatches && versionMatches;
|
|
59
|
+
const isCurrentByDefault =
|
|
60
|
+
!currentRevisionDate && normalizedCurrentVersion === undefined && index === 0 && isCurrent;
|
|
61
|
+
return {
|
|
62
|
+
name: `r.${versionRevisions.length - index}`,
|
|
63
|
+
date: toLocalizedShortDateTime(rev.revision, locale),
|
|
64
|
+
revisionDate: rev.revision,
|
|
65
|
+
isActive: isActiveRevision || isCurrentByDefault,
|
|
66
|
+
isCurrent: rev.isCurrent ?? false,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
77
69
|
|
|
78
70
|
return {
|
|
79
71
|
version,
|