@redocly/theme 0.67.0-next.2 → 0.67.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/Breadcrumbs/BreadcrumbDropdown.d.ts +2 -1
- package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +7 -4
- package/lib/components/Breadcrumbs/Breadcrumbs.js +2 -4
- package/lib/components/Dropdown/Dropdown.d.ts +2 -0
- package/lib/components/Dropdown/Dropdown.js +8 -2
- package/lib/components/Image/Image.d.ts +3 -0
- package/lib/components/Image/Image.js +101 -13
- package/lib/components/Image/variables.d.ts +1 -0
- package/lib/components/Image/variables.js +59 -0
- package/lib/components/Search/SearchAiMessage.js +23 -5
- package/lib/core/styles/global.js +79 -77
- package/lib/core/types/search.d.ts +2 -1
- package/lib/core/types/search.js +1 -0
- package/lib/markdoc/tags/img.js +36 -2
- package/package.json +2 -2
- package/src/components/Breadcrumbs/BreadcrumbDropdown.tsx +16 -3
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +1 -2
- package/src/components/Dropdown/Dropdown.tsx +8 -1
- package/src/components/Image/Image.tsx +171 -34
- package/src/components/Image/variables.ts +56 -0
- package/src/components/Search/SearchAiMessage.tsx +25 -5
- package/src/core/styles/global.ts +2 -0
- package/src/core/types/search.ts +1 -0
- package/src/markdoc/tags/img.ts +36 -2
|
@@ -9,6 +9,7 @@ type BreadcrumbDropdownProps = {
|
|
|
9
9
|
})[];
|
|
10
10
|
onItemClick?: (item: BreadcrumbItem, index: number) => void;
|
|
11
11
|
className?: string;
|
|
12
|
+
withChevron?: boolean;
|
|
12
13
|
};
|
|
13
|
-
export declare function BreadcrumbDropdown({ children, label, items, onItemClick, className }: BreadcrumbDropdownProps): JSX.Element | null;
|
|
14
|
+
export declare function BreadcrumbDropdown({ children, label, items, onItemClick, className, withChevron }: BreadcrumbDropdownProps): JSX.Element | null;
|
|
14
15
|
export {};
|
|
@@ -47,19 +47,22 @@ const Tooltip_1 = require("../../components/Tooltip/Tooltip");
|
|
|
47
47
|
const GenericIcon_1 = require("../../icons/GenericIcon/GenericIcon");
|
|
48
48
|
const constants_1 = require("../../core/constants");
|
|
49
49
|
const BreadcrumbIcon_1 = require("../../components/Breadcrumbs/BreadcrumbIcon");
|
|
50
|
-
function BreadcrumbDropdown({ children, label, items, onItemClick, className, }) {
|
|
50
|
+
function BreadcrumbDropdown({ children, label, items, onItemClick, className, withChevron, }) {
|
|
51
51
|
const { useTelemetry, useTranslate } = (0, hooks_1.useThemeHooks)();
|
|
52
52
|
const telemetry = useTelemetry();
|
|
53
53
|
const { translate } = useTranslate();
|
|
54
|
+
const [isOpen, setIsOpen] = react_1.default.useState(false);
|
|
54
55
|
if (!items || items.length === 0) {
|
|
55
56
|
return null;
|
|
56
57
|
}
|
|
57
58
|
const isTruncated = label.length > constants_1.BREADCRUMB_MAX_LENGTH;
|
|
58
59
|
const triggerContent = isTruncated ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: label, placement: "bottom" },
|
|
59
60
|
react_1.default.createElement(TriggerContentWrapper, null, children))) : (children);
|
|
60
|
-
const trigger = react_1.default.createElement(StyledDropdownTrigger, null,
|
|
61
|
+
const trigger = (react_1.default.createElement(StyledDropdownTrigger, null,
|
|
62
|
+
triggerContent,
|
|
63
|
+
withChevron && react_1.default.createElement(GenericIcon_1.GenericIcon, { icon: isOpen ? 'chevron-up' : 'chevron-down' })));
|
|
61
64
|
return (react_1.default.createElement(BreadcrumbDropdownWrapper, { "data-component-name": "Breadcrumbs/BreadcrumbDropdown", className: className, "data-testid": "breadcrumb-dropdown" },
|
|
62
|
-
react_1.default.createElement(Dropdown_1.Dropdown, { trigger: trigger, closeOnClick: true },
|
|
65
|
+
react_1.default.createElement(Dropdown_1.Dropdown, { trigger: trigger, closeOnClick: true, onOpen: () => setIsOpen(true), onClose: () => setIsOpen(false) },
|
|
63
66
|
react_1.default.createElement(DropdownMenu_1.DropdownMenu, null, items.map((item, index) => {
|
|
64
67
|
const isActive = Boolean(item === null || item === void 0 ? void 0 : item.isActive);
|
|
65
68
|
const hasLink = Boolean(item.link);
|
|
@@ -101,7 +104,7 @@ const StyledDropdownTrigger = styled_components_1.default.button `
|
|
|
101
104
|
background-color: var(--breadcrumbs-background-color-hover);
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
&:focus {
|
|
107
|
+
&:focus-visible {
|
|
105
108
|
box-shadow: var(--breadcrumbs-box-shadow-focus);
|
|
106
109
|
outline: none;
|
|
107
110
|
}
|
|
@@ -12,7 +12,6 @@ const BreadcrumbDropdown_1 = require("../../components/Breadcrumbs/BreadcrumbDro
|
|
|
12
12
|
const BreadcrumbIcon_1 = require("../../components/Breadcrumbs/BreadcrumbIcon");
|
|
13
13
|
const utils_1 = require("../../core/utils");
|
|
14
14
|
const constants_1 = require("../../core/constants");
|
|
15
|
-
const GenericIcon_1 = require("../../icons/GenericIcon/GenericIcon");
|
|
16
15
|
function Breadcrumbs(props) {
|
|
17
16
|
const { useBreadcrumbs, useTelemetry, useTranslate } = (0, hooks_1.useThemeHooks)();
|
|
18
17
|
const { breadcrumbs: fileBreadcrumbs, currentItemSiblings } = useBreadcrumbs();
|
|
@@ -46,7 +45,7 @@ function Breadcrumbs(props) {
|
|
|
46
45
|
...currentItemSiblings,
|
|
47
46
|
];
|
|
48
47
|
const translatedLabel = translate(breadcrumb.labelTranslationKey, breadcrumb.label);
|
|
49
|
-
return (react_1.default.createElement(BreadcrumbDropdown_1.BreadcrumbDropdown, { label: translatedLabel, items: siblingsWithActive, onItemClick: (item, itemIdx) => telemetry.sendBreadcrumbClickedMessage([
|
|
48
|
+
return (react_1.default.createElement(BreadcrumbDropdown_1.BreadcrumbDropdown, { label: translatedLabel, items: siblingsWithActive, withChevron: true, onItemClick: (item, itemIdx) => telemetry.sendBreadcrumbClickedMessage([
|
|
50
49
|
{
|
|
51
50
|
object: 'breadcrumb',
|
|
52
51
|
link: item.link,
|
|
@@ -55,8 +54,7 @@ function Breadcrumbs(props) {
|
|
|
55
54
|
},
|
|
56
55
|
]) },
|
|
57
56
|
react_1.default.createElement(BreadcrumbIcon_1.BreadcrumbIcon, { icon: breadcrumb.icon }),
|
|
58
|
-
(0, utils_1.trimText)(translatedLabel, constants_1.BREADCRUMB_MAX_LENGTH)
|
|
59
|
-
react_1.default.createElement(GenericIcon_1.GenericIcon, { icon: "chevron-down" })));
|
|
57
|
+
(0, utils_1.trimText)(translatedLabel, constants_1.BREADCRUMB_MAX_LENGTH)));
|
|
60
58
|
}
|
|
61
59
|
return (react_1.default.createElement(Breadcrumb_1.Breadcrumb, { link: breadcrumb.link, label: translate(breadcrumb.labelTranslationKey, breadcrumb.label), isActive: isActive, icon: breadcrumb.icon, onClick: () => telemetry.sendBreadcrumbClickedMessage([
|
|
62
60
|
{
|
|
@@ -12,6 +12,7 @@ export type DropdownProps = PropsWithChildren<{
|
|
|
12
12
|
withArrow?: boolean;
|
|
13
13
|
onClick?: (event: React.UIEvent) => void;
|
|
14
14
|
onClose?: () => void;
|
|
15
|
+
onOpen?: () => void;
|
|
15
16
|
}>;
|
|
16
17
|
export declare const Dropdown: React.ForwardRefExoticComponent<{
|
|
17
18
|
trigger: React.ReactNode;
|
|
@@ -25,6 +26,7 @@ export declare const Dropdown: React.ForwardRefExoticComponent<{
|
|
|
25
26
|
withArrow?: boolean;
|
|
26
27
|
onClick?: (event: React.UIEvent) => void;
|
|
27
28
|
onClose?: () => void;
|
|
29
|
+
onOpen?: () => void;
|
|
28
30
|
} & {
|
|
29
31
|
children?: React.ReactNode | undefined;
|
|
30
32
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -42,11 +42,12 @@ const styled_components_1 = __importDefault(require("styled-components"));
|
|
|
42
42
|
const hooks_1 = require("../../core/hooks");
|
|
43
43
|
const ChevronDownIcon_1 = require("../../icons/ChevronDownIcon/ChevronDownIcon");
|
|
44
44
|
const ChevronUpIcon_1 = require("../../icons/ChevronUpIcon/ChevronUpIcon");
|
|
45
|
-
exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigger, triggerEvent = 'click', closeOnClick = true, withArrow, dataAttributes, placement, alignment, onClick, onClose, }, ref) => {
|
|
45
|
+
exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigger, triggerEvent = 'click', closeOnClick = true, withArrow, dataAttributes, placement, alignment, onClick, onClose, onOpen, }, ref) => {
|
|
46
46
|
const dropdownRef = (0, react_1.useRef)(null);
|
|
47
47
|
const [isOpen, setIsOpen] = (0, hooks_1.useControlledState)(false, active);
|
|
48
48
|
const handleOpen = () => {
|
|
49
49
|
setIsOpen(true);
|
|
50
|
+
onOpen === null || onOpen === void 0 ? void 0 : onOpen();
|
|
50
51
|
};
|
|
51
52
|
const handleClose = () => {
|
|
52
53
|
setIsOpen(false);
|
|
@@ -58,7 +59,12 @@ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigg
|
|
|
58
59
|
const handleToggle = (event) => {
|
|
59
60
|
event.stopPropagation();
|
|
60
61
|
event.preventDefault();
|
|
61
|
-
|
|
62
|
+
if (isOpen) {
|
|
63
|
+
handleClose();
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
handleOpen();
|
|
67
|
+
}
|
|
62
68
|
};
|
|
63
69
|
const handleKeyDown = (event) => {
|
|
64
70
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
@@ -3,11 +3,14 @@ import type { JSX } from 'react';
|
|
|
3
3
|
export type ImageProps = {
|
|
4
4
|
src?: string;
|
|
5
5
|
srcSet?: string;
|
|
6
|
+
images?: string[];
|
|
6
7
|
alt?: string;
|
|
7
8
|
className?: string;
|
|
8
9
|
width?: string | number;
|
|
9
10
|
height?: string | number;
|
|
10
11
|
border?: string;
|
|
12
|
+
caption?: string;
|
|
13
|
+
framed?: boolean;
|
|
11
14
|
withLightbox?: boolean;
|
|
12
15
|
lightboxStyle?: React.CSSProperties | string;
|
|
13
16
|
style?: React.CSSProperties | string;
|
|
@@ -32,17 +32,16 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.Image = Image;
|
|
40
37
|
const react_1 = __importStar(require("react"));
|
|
41
|
-
const styled_components_1 =
|
|
38
|
+
const styled_components_1 = __importStar(require("styled-components"));
|
|
42
39
|
const utils_1 = require("../../core/utils");
|
|
43
40
|
const hooks_1 = require("../../core/hooks");
|
|
41
|
+
const CloseIcon_1 = require("../../icons/CloseIcon/CloseIcon");
|
|
42
|
+
const Button_1 = require("../../components/Button/Button");
|
|
44
43
|
function Image(props) {
|
|
45
|
-
const { src, srcSet, alt, className, width, height, border, style, withLightbox, lightboxStyle } = props;
|
|
44
|
+
const { src, srcSet, images: galleryImages, alt, className, width, height, border, caption, framed, style, withLightbox, lightboxStyle, } = props;
|
|
46
45
|
const lightboxContainerRef = (0, react_1.useRef)(null);
|
|
47
46
|
const [lightboxImage, setLightboxImage] = (0, react_1.useState)(undefined);
|
|
48
47
|
const parsedSourceSetMap = (0, react_1.useMemo)(() => {
|
|
@@ -72,12 +71,73 @@ function Image(props) {
|
|
|
72
71
|
}, [lightboxImage]);
|
|
73
72
|
const combinedStyles = Object.assign(Object.assign(Object.assign({}, (withLightbox && { cursor: 'pointer' })), (border && { border })), (typeof style === 'string' ? (0, utils_1.parseStyleString)(style) : style));
|
|
74
73
|
const lightboxOverlayStyles = typeof lightboxStyle === 'string' ? (0, utils_1.parseStyleString)(lightboxStyle) : lightboxStyle;
|
|
74
|
+
const images = src ? (react_1.default.createElement("img", { src: src, alt: alt, className: className, width: width, height: height, style: combinedStyles, onClick: () => handleImageClick(src) })) : (Array.from(parsedSourceSetMap).map(([key, value]) => (react_1.default.createElement(ColorModeAwareImage, { key: key, $colorMode: key, src: value, alt: alt, className: className, width: width, height: height, $withLightbox: withLightbox, style: combinedStyles, onClick: () => handleImageClick(value) }))));
|
|
75
|
+
const hasGallery = Array.isArray(galleryImages) && galleryImages.length > 0;
|
|
76
|
+
const visibleGalleryImages = hasGallery ? galleryImages.slice(0, 3) : [];
|
|
77
|
+
const gallery = hasGallery ? (react_1.default.createElement(GalleryRow, null, visibleGalleryImages.map((galleryImageSrc, index) => (react_1.default.createElement("img", { key: `${galleryImageSrc}-${index}`, src: galleryImageSrc, alt: alt, style: withLightbox ? { cursor: 'pointer' } : undefined, onClick: () => handleImageClick(galleryImageSrc) }))))) : null;
|
|
78
|
+
const hasCaption = Boolean(caption);
|
|
79
|
+
const hasWrapper = Boolean(framed || hasCaption || hasGallery);
|
|
80
|
+
const wrapperContent = hasGallery ? gallery : images;
|
|
75
81
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
76
82
|
lightboxImage ? (react_1.default.createElement(LightboxContainer, { ref: lightboxContainerRef, onClick: handleCloseLightbox, onKeyDown: handleLightboxKeyDown, tabIndex: 0 },
|
|
77
83
|
react_1.default.createElement(Overlay, { style: lightboxOverlayStyles }),
|
|
78
|
-
react_1.default.createElement(
|
|
79
|
-
|
|
84
|
+
react_1.default.createElement(LightboxContent, null,
|
|
85
|
+
react_1.default.createElement(CloseButton, { variant: "secondary", "aria-label": "Close image", onClick: handleCloseLightbox },
|
|
86
|
+
react_1.default.createElement(CloseIcon_1.CloseIcon, null)),
|
|
87
|
+
react_1.default.createElement(Image, { src: lightboxImage, alt: alt })))) : null,
|
|
88
|
+
hasWrapper ? (react_1.default.createElement(ImageFrame, { "data-component-name": "Image/Image", $framed: framed, $gallery: hasGallery },
|
|
89
|
+
wrapperContent,
|
|
90
|
+
hasCaption ? react_1.default.createElement(ImageCaption, null, caption) : null)) : (images)));
|
|
80
91
|
}
|
|
92
|
+
const ImageFrame = styled_components_1.default.figure `
|
|
93
|
+
display: ${({ $gallery }) => ($gallery ? 'block' : 'inline-block')};
|
|
94
|
+
margin: 0;
|
|
95
|
+
${({ $gallery }) => ($gallery ? 'width: 100%;' : '')}
|
|
96
|
+
max-width: 100%;
|
|
97
|
+
|
|
98
|
+
${({ $framed }) => $framed &&
|
|
99
|
+
(0, styled_components_1.css) `
|
|
100
|
+
padding: var(--image-frame-padding);
|
|
101
|
+
border: var(--border-width) var(--border-style) var(--image-frame-border-color);
|
|
102
|
+
border-radius: var(--image-frame-border-radius);
|
|
103
|
+
background-color: var(--image-frame-bg-color);
|
|
104
|
+
`}
|
|
105
|
+
|
|
106
|
+
> img {
|
|
107
|
+
display: block;
|
|
108
|
+
max-width: 100%;
|
|
109
|
+
height: auto;
|
|
110
|
+
background: transparent center / cover no-repeat;
|
|
111
|
+
|
|
112
|
+
${({ $framed }) => $framed &&
|
|
113
|
+
(0, styled_components_1.css) `
|
|
114
|
+
border-radius: var(--image-frame-image-border-radius);
|
|
115
|
+
`}
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
const GalleryRow = styled_components_1.default.div `
|
|
119
|
+
display: flex;
|
|
120
|
+
align-items: stretch;
|
|
121
|
+
overflow: hidden;
|
|
122
|
+
border-radius: var(--image-gallery-border-radius);
|
|
123
|
+
|
|
124
|
+
img {
|
|
125
|
+
flex: 1 1 0;
|
|
126
|
+
min-width: 0;
|
|
127
|
+
width: 100%;
|
|
128
|
+
object-fit: cover;
|
|
129
|
+
border-radius: 0;
|
|
130
|
+
background: var(--image-gallery-image-bg-color) 50% / cover no-repeat;
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
const ImageCaption = styled_components_1.default.figcaption `
|
|
134
|
+
padding: var(--image-caption-padding);
|
|
135
|
+
color: var(--image-caption-text-color);
|
|
136
|
+
font-size: var(--image-caption-font-size);
|
|
137
|
+
line-height: var(--image-caption-line-height);
|
|
138
|
+
font-weight: var(--image-caption-font-weight);
|
|
139
|
+
text-align: center;
|
|
140
|
+
`;
|
|
81
141
|
const ColorModeAwareImage = styled_components_1.default.img `
|
|
82
142
|
html:not(.${(props) => props.$colorMode}) && {
|
|
83
143
|
display: none;
|
|
@@ -88,13 +148,38 @@ const ColorModeAwareImage = styled_components_1.default.img `
|
|
|
88
148
|
`}
|
|
89
149
|
`;
|
|
90
150
|
const Overlay = styled_components_1.default.div `
|
|
91
|
-
background-color: var(--bg-color
|
|
151
|
+
background-color: var(--image-lightbox-overlay-bg-color);
|
|
92
152
|
grid-column: 1 / 2;
|
|
93
153
|
grid-row: 1 / 2;
|
|
94
154
|
height: 100%;
|
|
95
155
|
width: 100%;
|
|
96
156
|
z-index: -1;
|
|
97
157
|
`;
|
|
158
|
+
const CloseButton = (0, styled_components_1.default)(Button_1.Button) `
|
|
159
|
+
position: absolute;
|
|
160
|
+
top: 0;
|
|
161
|
+
left: 100%;
|
|
162
|
+
margin-left: var(--image-lightbox-close-offset);
|
|
163
|
+
width: var(--image-lightbox-close-size);
|
|
164
|
+
height: var(--image-lightbox-close-size);
|
|
165
|
+
border-radius: var(--image-lightbox-close-border-radius);
|
|
166
|
+
z-index: 1;
|
|
167
|
+
|
|
168
|
+
svg {
|
|
169
|
+
width: var(--image-lightbox-close-icon-size);
|
|
170
|
+
height: var(--image-lightbox-close-icon-size);
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
const LightboxContent = styled_components_1.default.div `
|
|
174
|
+
position: relative;
|
|
175
|
+
grid-column: 1 / 2;
|
|
176
|
+
grid-row: 1 / 2;
|
|
177
|
+
margin: auto;
|
|
178
|
+
width: fit-content;
|
|
179
|
+
height: fit-content;
|
|
180
|
+
max-width: var(--image-lightbox-content-max-width);
|
|
181
|
+
max-height: var(--image-lightbox-content-max-height);
|
|
182
|
+
`;
|
|
98
183
|
const LightboxContainer = styled_components_1.default.div `
|
|
99
184
|
display: grid;
|
|
100
185
|
height: 100vh;
|
|
@@ -110,11 +195,14 @@ const LightboxContainer = styled_components_1.default.div `
|
|
|
110
195
|
|
|
111
196
|
img {
|
|
112
197
|
cursor: pointer;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
198
|
+
display: block;
|
|
199
|
+
max-width: var(--image-lightbox-image-max-width);
|
|
200
|
+
max-height: var(--image-lightbox-image-max-height);
|
|
201
|
+
border-radius: var(--image-lightbox-image-border-radius);
|
|
202
|
+
background:
|
|
203
|
+
var(--image-lightbox-image-bg-placeholder) center / cover no-repeat,
|
|
204
|
+
var(--image-frame-bg-color);
|
|
205
|
+
box-shadow: var(--image-lightbox-image-shadow);
|
|
118
206
|
}
|
|
119
207
|
`;
|
|
120
208
|
//# sourceMappingURL=Image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const image: import("styled-components").RuleSet<object>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.image = void 0;
|
|
4
|
+
const styled_components_1 = require("styled-components");
|
|
5
|
+
exports.image = (0, styled_components_1.css) `
|
|
6
|
+
/* === Image === */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @tokens Image frame
|
|
10
|
+
*/
|
|
11
|
+
--image-frame-padding: var(--spacing-xs);
|
|
12
|
+
--image-frame-border-color: var(--border-color-secondary);
|
|
13
|
+
--image-frame-border-radius: var(--border-radius-xxl);
|
|
14
|
+
--image-frame-bg-color: var(--bg-color-raised);
|
|
15
|
+
--image-frame-image-border-radius: var(--border-radius-lg);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @tokens Image caption
|
|
19
|
+
*/
|
|
20
|
+
--image-caption-padding: var(--spacing-sm) var(--spacing-lg) var(--spacing-xxs) var(--spacing-lg);
|
|
21
|
+
--image-caption-text-color: var(--text-color-primary);
|
|
22
|
+
--image-caption-font-size: var(--font-size-base);
|
|
23
|
+
--image-caption-line-height: var(--line-height-base);
|
|
24
|
+
--image-caption-font-weight: var(--font-weight-regular);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @tokens Image gallery
|
|
28
|
+
*/
|
|
29
|
+
--image-gallery-border-radius: var(--border-radius-lg);
|
|
30
|
+
--image-gallery-image-bg-color: var(--bg-color-tonal);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @tokens Image lightbox
|
|
34
|
+
*/
|
|
35
|
+
--image-lightbox-overlay-bg-color: var(--bg-color-modal-overlay);
|
|
36
|
+
--image-lightbox-content-max-width: 90%;
|
|
37
|
+
--image-lightbox-content-max-height: 90%;
|
|
38
|
+
|
|
39
|
+
--image-lightbox-image-max-width: min(
|
|
40
|
+
90vw,
|
|
41
|
+
calc(100vw - 2 * var(--image-lightbox-side-gutter))
|
|
42
|
+
);
|
|
43
|
+
--image-lightbox-image-max-height: 90vh;
|
|
44
|
+
--image-lightbox-image-border-radius: var(--border-radius-xl);
|
|
45
|
+
--image-lightbox-image-bg-placeholder: var(--bg-color-tonal);
|
|
46
|
+
--image-lightbox-image-shadow: var(--bg-raised-shadow);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @tokens Image lightbox close button
|
|
50
|
+
*/
|
|
51
|
+
--image-lightbox-close-size: 40px;
|
|
52
|
+
--image-lightbox-close-icon-size: 18px;
|
|
53
|
+
--image-lightbox-close-offset: var(--spacing-base);
|
|
54
|
+
--image-lightbox-close-border-radius: var(--border-radius-lg);
|
|
55
|
+
--image-lightbox-side-gutter: calc(
|
|
56
|
+
var(--image-lightbox-close-size) + var(--image-lightbox-close-offset) + var(--spacing-sm)
|
|
57
|
+
);
|
|
58
|
+
`;
|
|
59
|
+
//# sourceMappingURL=variables.js.map
|
|
@@ -41,6 +41,7 @@ const react_1 = __importStar(require("react"));
|
|
|
41
41
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
42
42
|
const types_1 = require("../../core/types");
|
|
43
43
|
const constants_1 = require("../../core/constants");
|
|
44
|
+
const types_2 = require("../../core/types");
|
|
44
45
|
const Link_1 = require("../../components/Link/Link");
|
|
45
46
|
const Tag_1 = require("../../components/Tag/Tag");
|
|
46
47
|
const constants_2 = require("../../core/constants");
|
|
@@ -56,11 +57,28 @@ function MarkdownSegment({ text }) {
|
|
|
56
57
|
const markdown = useMarkdownText(text);
|
|
57
58
|
return react_1.default.createElement(ResponseText, { as: "div", children: markdown, "data-testid": "response-text" });
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
+
// The codemode `execute` tool passes a human-readable `description` of what its code
|
|
61
|
+
// does; show that instead of a generic "Executing execute..." label.
|
|
62
|
+
function getExecuteDescription(args) {
|
|
63
|
+
if (args && typeof args === 'object' && 'description' in args) {
|
|
64
|
+
const { description } = args;
|
|
65
|
+
if (typeof description === 'string' && description.trim().length > 0) {
|
|
66
|
+
return description.trim();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
function getToolCallDisplayText(toolCall) {
|
|
60
72
|
var _a;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
if (toolCall.name === types_2.ToolCallName.Execute) {
|
|
74
|
+
const description = getExecuteDescription(toolCall.args);
|
|
75
|
+
if (description) {
|
|
76
|
+
return { inProgressText: description, completedText: description };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return ((_a = constants_1.TOOL_CALL_DISPLAY_TEXT[toolCall.name]) !== null && _a !== void 0 ? _a : {
|
|
80
|
+
inProgressText: `Executing ${toolCall.name}...`,
|
|
81
|
+
completedText: `${toolCall.name} executed`,
|
|
64
82
|
});
|
|
65
83
|
}
|
|
66
84
|
function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, toolCalls = [], contentSegments = [{ type: 'text', text: content }], }) {
|
|
@@ -111,7 +129,7 @@ function SearchAiMessageComponent({ role, content, isThinking, resources, classN
|
|
|
111
129
|
contentSegments.map((segment, index) => {
|
|
112
130
|
if (segment.type === 'tool') {
|
|
113
131
|
const toolCallCompleted = Boolean(segment.toolCall.result);
|
|
114
|
-
const { inProgressText, completedText } = getToolCallDisplayText(segment.toolCall
|
|
132
|
+
const { inProgressText, completedText } = getToolCallDisplayText(segment.toolCall);
|
|
115
133
|
const toolCallDisplayText = toolCallCompleted ? completedText : inProgressText;
|
|
116
134
|
return (react_1.default.createElement(ToolCallsInfoWrapper, { key: `tool-${index}`, "data-testid": "tool-calls-info" },
|
|
117
135
|
react_1.default.createElement(ToolCallInfoItem, null,
|
|
@@ -10,43 +10,44 @@ const variables_5 = require("../../components/Breadcrumbs/variables");
|
|
|
10
10
|
const variables_6 = require("../../components/Tag/variables");
|
|
11
11
|
const variables_7 = require("../../components/TableOfContent/variables");
|
|
12
12
|
const variables_8 = require("../../components/Catalog/variables");
|
|
13
|
-
const variables_9 = require("../../components/
|
|
14
|
-
const variables_10 = require("../../components/
|
|
15
|
-
const variables_11 = require("../../components/
|
|
16
|
-
const variables_12 = require("../../components/
|
|
17
|
-
const variables_13 = require("../../components/
|
|
18
|
-
const variables_14 = require("../../components/
|
|
19
|
-
const variables_15 = require("../../components/
|
|
20
|
-
const variables_16 = require("../../
|
|
21
|
-
const variables_17 = require("../../
|
|
22
|
-
const variables_18 = require("../../components/
|
|
23
|
-
const variables_19 = require("../../components/
|
|
24
|
-
const variables_20 = require("../../components/
|
|
25
|
-
const variables_21 = require("../../components/
|
|
26
|
-
const variables_22 = require("../../components/
|
|
27
|
-
const variables_23 = require("../../components/
|
|
28
|
-
const variables_24 = require("../../components/
|
|
29
|
-
const variables_25 = require("../../components/
|
|
30
|
-
const variables_26 = require("../../components/
|
|
31
|
-
const variables_27 = require("../../components/
|
|
32
|
-
const variables_28 = require("../../
|
|
33
|
-
const variables_29 = require("../../markdoc/components/
|
|
34
|
-
const variables_30 = require("../../components/
|
|
35
|
-
const variables_31 = require("../../components/
|
|
36
|
-
const variables_32 = require("../../components/
|
|
37
|
-
const variables_33 = require("../../components/
|
|
38
|
-
const variables_34 = require("../../components/
|
|
39
|
-
const variables_35 = require("../../components/
|
|
40
|
-
const variables_36 = require("../../components/
|
|
41
|
-
const variables_37 = require("../../components/
|
|
42
|
-
const variables_38 = require("../../components/
|
|
43
|
-
const variables_39 = require("../../
|
|
44
|
-
const variables_40 = require("../../markdoc/components/
|
|
45
|
-
const variables_41 = require("../../components/
|
|
46
|
-
const variables_42 = require("../../components/
|
|
47
|
-
const variables_43 = require("../../components/
|
|
48
|
-
const variables_44 = require("../../components/
|
|
49
|
-
const variables_45 = require("../../components/
|
|
13
|
+
const variables_9 = require("../../components/Image/variables");
|
|
14
|
+
const variables_10 = require("../../components/Filter/variables");
|
|
15
|
+
const variables_11 = require("../../components/CatalogClassic/variables");
|
|
16
|
+
const variables_12 = require("../../components/Panel/variables");
|
|
17
|
+
const variables_13 = require("../../components/Accordion/variables");
|
|
18
|
+
const variables_14 = require("../../components/Select/variables");
|
|
19
|
+
const variables_15 = require("../../components/Dropdown/variables");
|
|
20
|
+
const variables_16 = require("../../components/Tooltip/variables");
|
|
21
|
+
const variables_17 = require("../../icons/CheckboxIcon/variables");
|
|
22
|
+
const variables_18 = require("../../components/Admonition/variables");
|
|
23
|
+
const variables_19 = require("../../components/Footer/variables");
|
|
24
|
+
const variables_20 = require("../../components/Button/variables");
|
|
25
|
+
const variables_21 = require("../../components/Buttons/variables");
|
|
26
|
+
const variables_22 = require("../../components/Navbar/variables");
|
|
27
|
+
const variables_23 = require("../../components/Search/variables");
|
|
28
|
+
const variables_24 = require("../../components/Menu/variables");
|
|
29
|
+
const variables_25 = require("../../components/CodeBlock/variables");
|
|
30
|
+
const variables_26 = require("../../components/Product/variables");
|
|
31
|
+
const variables_27 = require("../../components/Markdown/variables");
|
|
32
|
+
const variables_28 = require("../../components/Banner/variables");
|
|
33
|
+
const variables_29 = require("../../markdoc/components/Tabs/variables");
|
|
34
|
+
const variables_30 = require("../../markdoc/components/Diagram/variables");
|
|
35
|
+
const variables_31 = require("../../components/LastUpdated/variables");
|
|
36
|
+
const variables_32 = require("../../components/Logo/variables");
|
|
37
|
+
const variables_33 = require("../../components/StatusCode/variables");
|
|
38
|
+
const variables_34 = require("../../components/Segmented/variables");
|
|
39
|
+
const variables_35 = require("../../components/UserMenu/variables");
|
|
40
|
+
const variables_36 = require("../../components/Tags/variables");
|
|
41
|
+
const variables_37 = require("../../components/VersionPicker/variables");
|
|
42
|
+
const variables_38 = require("../../components/DatePicker/variables");
|
|
43
|
+
const variables_39 = require("../../components/Switch/variables");
|
|
44
|
+
const variables_40 = require("../../markdoc/components/Cards/variables");
|
|
45
|
+
const variables_41 = require("../../markdoc/components/CodeWalkthrough/variables");
|
|
46
|
+
const variables_42 = require("../../components/SkipContent/variables");
|
|
47
|
+
const variables_43 = require("../../components/PageActions/variables");
|
|
48
|
+
const variables_44 = require("../../components/SvgViewer/variables");
|
|
49
|
+
const variables_45 = require("../../components/Toast/variables");
|
|
50
|
+
const variables_46 = require("../../components/PageNavigation/variables");
|
|
50
51
|
const palette_1 = require("./palette");
|
|
51
52
|
const dark_1 = require("./dark");
|
|
52
53
|
const themeColors = (0, styled_components_1.css) `
|
|
@@ -1255,47 +1256,48 @@ const replay = (0, styled_components_1.css) `
|
|
|
1255
1256
|
`;
|
|
1256
1257
|
exports.styles = (0, styled_components_1.css) `
|
|
1257
1258
|
:root {
|
|
1258
|
-
${
|
|
1259
|
-
${
|
|
1259
|
+
${variables_13.accordion}
|
|
1260
|
+
${variables_18.admonition}
|
|
1260
1261
|
${apiReferenceDocs}
|
|
1261
|
-
${
|
|
1262
|
+
${variables_12.apiReferencePanels}
|
|
1262
1263
|
${badges}
|
|
1263
|
-
${
|
|
1264
|
+
${variables_28.banner}
|
|
1264
1265
|
${borders}
|
|
1265
1266
|
${variables_5.breadcrumbs}
|
|
1266
|
-
${
|
|
1267
|
-
${
|
|
1268
|
-
${
|
|
1269
|
-
${
|
|
1267
|
+
${variables_20.button}
|
|
1268
|
+
${variables_21.aiAssistantButton}
|
|
1269
|
+
${variables_21.connectMCPButton}
|
|
1270
|
+
${variables_40.cards}
|
|
1270
1271
|
${variables_8.catalog}
|
|
1271
|
-
${
|
|
1272
|
-
${
|
|
1273
|
-
${
|
|
1272
|
+
${variables_11.catalogClassic}
|
|
1273
|
+
${variables_25.code}
|
|
1274
|
+
${variables_41.codeWalkthrough}
|
|
1274
1275
|
${docsDropdown}
|
|
1275
|
-
${
|
|
1276
|
+
${variables_15.dropdown}
|
|
1276
1277
|
${error}
|
|
1277
|
-
${
|
|
1278
|
-
${
|
|
1278
|
+
${variables_10.filter}
|
|
1279
|
+
${variables_19.footer}
|
|
1279
1280
|
${headingsTypography}
|
|
1280
|
-
${
|
|
1281
|
+
${variables_36.httpTag}
|
|
1282
|
+
${variables_9.image}
|
|
1281
1283
|
${inputs}
|
|
1282
1284
|
${variables_1.languagePicker}
|
|
1283
|
-
${
|
|
1285
|
+
${variables_31.lastUpdated}
|
|
1284
1286
|
${links}
|
|
1285
1287
|
${loadProgressBar}
|
|
1286
|
-
${
|
|
1287
|
-
${
|
|
1288
|
-
${
|
|
1289
|
-
${
|
|
1290
|
-
${
|
|
1291
|
-
${
|
|
1288
|
+
${variables_32.logo}
|
|
1289
|
+
${variables_27.markdown}
|
|
1290
|
+
${variables_29.markdownTabs}
|
|
1291
|
+
${variables_30.diagram}
|
|
1292
|
+
${variables_24.menu}
|
|
1293
|
+
${variables_24.mobileMenu}
|
|
1292
1294
|
${modal}
|
|
1293
|
-
${
|
|
1295
|
+
${variables_22.navbar}
|
|
1294
1296
|
${pages}
|
|
1295
|
-
${
|
|
1296
|
-
${
|
|
1297
|
-
${
|
|
1298
|
-
${
|
|
1297
|
+
${variables_26.productPicker}
|
|
1298
|
+
${variables_12.responsePanelColors}
|
|
1299
|
+
${variables_23.search}
|
|
1300
|
+
${variables_14.select}
|
|
1299
1301
|
${variables_4.sidebar}
|
|
1300
1302
|
${sizeAndSpace}
|
|
1301
1303
|
${variables_6.tag}
|
|
@@ -1303,28 +1305,28 @@ exports.styles = (0, styled_components_1.css) `
|
|
|
1303
1305
|
${palette_1.activeBrandPaletteLight}
|
|
1304
1306
|
${tile}
|
|
1305
1307
|
${variables_7.toc}
|
|
1306
|
-
${
|
|
1308
|
+
${variables_16.tooltip}
|
|
1307
1309
|
${typography}
|
|
1308
|
-
${
|
|
1309
|
-
${
|
|
1310
|
+
${variables_35.userMenu}
|
|
1311
|
+
${variables_37.versionPicker}
|
|
1310
1312
|
${zIndexDepth}
|
|
1311
1313
|
${scorecardColors}
|
|
1312
|
-
${
|
|
1314
|
+
${variables_33.statusCode}
|
|
1313
1315
|
${tab}
|
|
1314
1316
|
${icon}
|
|
1315
1317
|
${tree}
|
|
1316
|
-
${
|
|
1317
|
-
${
|
|
1318
|
-
${
|
|
1318
|
+
${variables_34.segmented}
|
|
1319
|
+
${variables_39.switcher}
|
|
1320
|
+
${variables_17.checkbox}
|
|
1319
1321
|
${variables_3.feedback}
|
|
1320
1322
|
${variables_2.scorecard}
|
|
1321
|
-
${
|
|
1323
|
+
${variables_38.datePicker}
|
|
1322
1324
|
${replay}
|
|
1323
|
-
${
|
|
1324
|
-
${
|
|
1325
|
-
${
|
|
1326
|
-
${
|
|
1327
|
-
${
|
|
1325
|
+
${variables_42.skipContent}
|
|
1326
|
+
${variables_43.pageActions}
|
|
1327
|
+
${variables_44.svgViewer}
|
|
1328
|
+
${variables_45.toast}
|
|
1329
|
+
${variables_46.pageNavigation}
|
|
1328
1330
|
|
|
1329
1331
|
background-color: var(--bg-color);
|
|
1330
1332
|
color: var(--text-color-primary);
|
|
@@ -124,5 +124,6 @@ export declare enum ToolCallName {
|
|
|
124
124
|
GetEndpoints = "get-endpoints",
|
|
125
125
|
GetEndpointInfo = "get-endpoint-info",
|
|
126
126
|
GetSecuritySchemes = "get-security-schemes",
|
|
127
|
-
GetFullApiDescription = "get-full-api-description"
|
|
127
|
+
GetFullApiDescription = "get-full-api-description",
|
|
128
|
+
Execute = "execute"
|
|
128
129
|
}
|
package/lib/core/types/search.js
CHANGED
|
@@ -14,5 +14,6 @@ var ToolCallName;
|
|
|
14
14
|
ToolCallName["GetEndpointInfo"] = "get-endpoint-info";
|
|
15
15
|
ToolCallName["GetSecuritySchemes"] = "get-security-schemes";
|
|
16
16
|
ToolCallName["GetFullApiDescription"] = "get-full-api-description";
|
|
17
|
+
ToolCallName["Execute"] = "execute";
|
|
17
18
|
})(ToolCallName || (exports.ToolCallName = ToolCallName = {}));
|
|
18
19
|
//# sourceMappingURL=search.js.map
|
package/lib/markdoc/tags/img.js
CHANGED
|
@@ -14,9 +14,20 @@ exports.img = {
|
|
|
14
14
|
type: String,
|
|
15
15
|
resolver: 'imageSrcSet',
|
|
16
16
|
},
|
|
17
|
+
images: {
|
|
18
|
+
type: Array,
|
|
19
|
+
resolver: 'imageGallery',
|
|
20
|
+
},
|
|
17
21
|
alt: {
|
|
18
22
|
type: String,
|
|
19
23
|
},
|
|
24
|
+
caption: {
|
|
25
|
+
type: String,
|
|
26
|
+
},
|
|
27
|
+
framed: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: false,
|
|
30
|
+
},
|
|
20
31
|
withLightbox: {
|
|
21
32
|
type: Boolean,
|
|
22
33
|
default: false,
|
|
@@ -45,8 +56,31 @@ exports.img = {
|
|
|
45
56
|
},
|
|
46
57
|
},
|
|
47
58
|
validate: (node) => {
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
const { src, srcSet, images } = node.attributes;
|
|
60
|
+
const hasGallery = Array.isArray(images) && images.length > 0;
|
|
61
|
+
if (!src && !srcSet && !hasGallery) {
|
|
62
|
+
return [{ id: '', message: 'src, srcSet, or images is required', level: 'error' }];
|
|
63
|
+
}
|
|
64
|
+
if (hasGallery && (src || srcSet)) {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
id: 'invalid-img-source-combination',
|
|
68
|
+
message: 'images cannot be used together with src or srcSet',
|
|
69
|
+
level: 'error',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
if (src && srcSet) {
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
id: 'invalid-img-source-combination',
|
|
77
|
+
message: 'src cannot be used together with srcSet',
|
|
78
|
+
level: 'error',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
if (Array.isArray(images) && images.length > 3) {
|
|
83
|
+
return [{ id: '', message: 'images supports a maximum of 3 items', level: 'error' }];
|
|
50
84
|
}
|
|
51
85
|
return [];
|
|
52
86
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/theme",
|
|
3
|
-
"version": "0.67.0-next.
|
|
3
|
+
"version": "0.67.0-next.4",
|
|
4
4
|
"description": "Shared UI components lib",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"theme",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"vitest": "4.1.8",
|
|
64
64
|
"vitest-when": "0.6.2",
|
|
65
65
|
"webpack": "5.105.2",
|
|
66
|
-
"@redocly/realm-asyncapi-sdk": "0.13.0-next.
|
|
66
|
+
"@redocly/realm-asyncapi-sdk": "0.13.0-next.3"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@tanstack/react-query": "5.62.3",
|
|
@@ -19,6 +19,7 @@ type BreadcrumbDropdownProps = {
|
|
|
19
19
|
items: (BreadcrumbItem & { isActive?: boolean })[];
|
|
20
20
|
onItemClick?: (item: BreadcrumbItem, index: number) => void;
|
|
21
21
|
className?: string;
|
|
22
|
+
withChevron?: boolean;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
export function BreadcrumbDropdown({
|
|
@@ -27,10 +28,12 @@ export function BreadcrumbDropdown({
|
|
|
27
28
|
items,
|
|
28
29
|
onItemClick,
|
|
29
30
|
className,
|
|
31
|
+
withChevron,
|
|
30
32
|
}: BreadcrumbDropdownProps): JSX.Element | null {
|
|
31
33
|
const { useTelemetry, useTranslate } = useThemeHooks();
|
|
32
34
|
const telemetry = useTelemetry();
|
|
33
35
|
const { translate } = useTranslate();
|
|
36
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
34
37
|
|
|
35
38
|
if (!items || items.length === 0) {
|
|
36
39
|
return null;
|
|
@@ -46,7 +49,12 @@ export function BreadcrumbDropdown({
|
|
|
46
49
|
children
|
|
47
50
|
);
|
|
48
51
|
|
|
49
|
-
const trigger =
|
|
52
|
+
const trigger = (
|
|
53
|
+
<StyledDropdownTrigger>
|
|
54
|
+
{triggerContent}
|
|
55
|
+
{withChevron && <GenericIcon icon={isOpen ? 'chevron-up' : 'chevron-down'} />}
|
|
56
|
+
</StyledDropdownTrigger>
|
|
57
|
+
);
|
|
50
58
|
|
|
51
59
|
return (
|
|
52
60
|
<BreadcrumbDropdownWrapper
|
|
@@ -54,7 +62,12 @@ export function BreadcrumbDropdown({
|
|
|
54
62
|
className={className}
|
|
55
63
|
data-testid="breadcrumb-dropdown"
|
|
56
64
|
>
|
|
57
|
-
<Dropdown
|
|
65
|
+
<Dropdown
|
|
66
|
+
trigger={trigger}
|
|
67
|
+
closeOnClick={true}
|
|
68
|
+
onOpen={() => setIsOpen(true)}
|
|
69
|
+
onClose={() => setIsOpen(false)}
|
|
70
|
+
>
|
|
58
71
|
<DropdownMenu>
|
|
59
72
|
{items.map((item, index) => {
|
|
60
73
|
const isActive = Boolean(item?.isActive);
|
|
@@ -117,7 +130,7 @@ const StyledDropdownTrigger = styled.button`
|
|
|
117
130
|
background-color: var(--breadcrumbs-background-color-hover);
|
|
118
131
|
}
|
|
119
132
|
|
|
120
|
-
&:focus {
|
|
133
|
+
&:focus-visible {
|
|
121
134
|
box-shadow: var(--breadcrumbs-box-shadow-focus);
|
|
122
135
|
outline: none;
|
|
123
136
|
}
|
|
@@ -10,7 +10,6 @@ import { BreadcrumbDropdown } from '@redocly/theme/components/Breadcrumbs/Breadc
|
|
|
10
10
|
import { BreadcrumbIcon } from '@redocly/theme/components/Breadcrumbs/BreadcrumbIcon';
|
|
11
11
|
import { trimText } from '@redocly/theme/core/utils';
|
|
12
12
|
import { BREADCRUMB_MAX_LENGTH } from '@redocly/theme/core/constants';
|
|
13
|
-
import { GenericIcon } from '@redocly/theme/icons/GenericIcon/GenericIcon';
|
|
14
13
|
|
|
15
14
|
export function Breadcrumbs(props: {
|
|
16
15
|
className?: string;
|
|
@@ -65,6 +64,7 @@ export function Breadcrumbs(props: {
|
|
|
65
64
|
<BreadcrumbDropdown
|
|
66
65
|
label={translatedLabel}
|
|
67
66
|
items={siblingsWithActive}
|
|
67
|
+
withChevron
|
|
68
68
|
onItemClick={(item, itemIdx) =>
|
|
69
69
|
telemetry.sendBreadcrumbClickedMessage([
|
|
70
70
|
{
|
|
@@ -78,7 +78,6 @@ export function Breadcrumbs(props: {
|
|
|
78
78
|
>
|
|
79
79
|
<BreadcrumbIcon icon={breadcrumb.icon} />
|
|
80
80
|
{trimText(translatedLabel, BREADCRUMB_MAX_LENGTH)}
|
|
81
|
-
<GenericIcon icon="chevron-down" />
|
|
82
81
|
</BreadcrumbDropdown>
|
|
83
82
|
);
|
|
84
83
|
}
|
|
@@ -30,6 +30,7 @@ export type DropdownProps = PropsWithChildren<{
|
|
|
30
30
|
|
|
31
31
|
onClick?: (event: React.UIEvent) => void;
|
|
32
32
|
onClose?: () => void;
|
|
33
|
+
onOpen?: () => void;
|
|
33
34
|
}>;
|
|
34
35
|
|
|
35
36
|
export const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(
|
|
@@ -47,6 +48,7 @@ export const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(
|
|
|
47
48
|
alignment,
|
|
48
49
|
onClick,
|
|
49
50
|
onClose,
|
|
51
|
+
onOpen,
|
|
50
52
|
},
|
|
51
53
|
ref,
|
|
52
54
|
) => {
|
|
@@ -55,6 +57,7 @@ export const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(
|
|
|
55
57
|
|
|
56
58
|
const handleOpen = () => {
|
|
57
59
|
setIsOpen(true);
|
|
60
|
+
onOpen?.();
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
const handleClose = () => {
|
|
@@ -69,7 +72,11 @@ export const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(
|
|
|
69
72
|
const handleToggle = (event: React.UIEvent) => {
|
|
70
73
|
event.stopPropagation();
|
|
71
74
|
event.preventDefault();
|
|
72
|
-
|
|
75
|
+
if (isOpen) {
|
|
76
|
+
handleClose();
|
|
77
|
+
} else {
|
|
78
|
+
handleOpen();
|
|
79
|
+
}
|
|
73
80
|
};
|
|
74
81
|
|
|
75
82
|
const handleKeyDown = (event: React.KeyboardEvent) => {
|
|
@@ -1,27 +1,45 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import styled from 'styled-components';
|
|
2
|
+
import styled, { css } from 'styled-components';
|
|
3
3
|
|
|
4
4
|
import type { KeyboardEvent, JSX } from 'react';
|
|
5
5
|
|
|
6
6
|
import { parseSrcSet, parseStyleString } from '@redocly/theme/core/utils';
|
|
7
7
|
import { useModalScrollLock } from '@redocly/theme/core/hooks';
|
|
8
|
+
import { CloseIcon } from '@redocly/theme/icons/CloseIcon/CloseIcon';
|
|
9
|
+
import { Button } from '@redocly/theme/components/Button/Button';
|
|
8
10
|
|
|
9
11
|
export type ImageProps = {
|
|
10
12
|
src?: string;
|
|
11
13
|
srcSet?: string;
|
|
14
|
+
images?: string[];
|
|
12
15
|
alt?: string;
|
|
13
16
|
className?: string;
|
|
14
17
|
width?: string | number;
|
|
15
18
|
height?: string | number;
|
|
16
19
|
border?: string;
|
|
20
|
+
caption?: string;
|
|
21
|
+
framed?: boolean;
|
|
17
22
|
withLightbox?: boolean;
|
|
18
23
|
lightboxStyle?: React.CSSProperties | string;
|
|
19
24
|
style?: React.CSSProperties | string;
|
|
20
25
|
};
|
|
21
26
|
|
|
22
27
|
export function Image(props: ImageProps): JSX.Element {
|
|
23
|
-
const {
|
|
24
|
-
|
|
28
|
+
const {
|
|
29
|
+
src,
|
|
30
|
+
srcSet,
|
|
31
|
+
images: galleryImages,
|
|
32
|
+
alt,
|
|
33
|
+
className,
|
|
34
|
+
width,
|
|
35
|
+
height,
|
|
36
|
+
border,
|
|
37
|
+
caption,
|
|
38
|
+
framed,
|
|
39
|
+
style,
|
|
40
|
+
withLightbox,
|
|
41
|
+
lightboxStyle,
|
|
42
|
+
} = props;
|
|
25
43
|
|
|
26
44
|
const lightboxContainerRef = useRef<HTMLDivElement>(null);
|
|
27
45
|
const [lightboxImage, setLightboxImage] = useState<string | undefined>(undefined);
|
|
@@ -66,6 +84,54 @@ export function Image(props: ImageProps): JSX.Element {
|
|
|
66
84
|
const lightboxOverlayStyles: React.CSSProperties | undefined =
|
|
67
85
|
typeof lightboxStyle === 'string' ? parseStyleString(lightboxStyle) : lightboxStyle;
|
|
68
86
|
|
|
87
|
+
const images = src ? (
|
|
88
|
+
<img
|
|
89
|
+
src={src}
|
|
90
|
+
alt={alt}
|
|
91
|
+
className={className}
|
|
92
|
+
width={width}
|
|
93
|
+
height={height}
|
|
94
|
+
style={combinedStyles}
|
|
95
|
+
onClick={() => handleImageClick(src)}
|
|
96
|
+
/>
|
|
97
|
+
) : (
|
|
98
|
+
Array.from(parsedSourceSetMap).map(([key, value]) => (
|
|
99
|
+
<ColorModeAwareImage
|
|
100
|
+
key={key}
|
|
101
|
+
$colorMode={key}
|
|
102
|
+
src={value}
|
|
103
|
+
alt={alt}
|
|
104
|
+
className={className}
|
|
105
|
+
width={width}
|
|
106
|
+
height={height}
|
|
107
|
+
$withLightbox={withLightbox}
|
|
108
|
+
style={combinedStyles}
|
|
109
|
+
onClick={() => handleImageClick(value)}
|
|
110
|
+
/>
|
|
111
|
+
))
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const hasGallery = Array.isArray(galleryImages) && galleryImages.length > 0;
|
|
115
|
+
const visibleGalleryImages = hasGallery ? galleryImages.slice(0, 3) : [];
|
|
116
|
+
|
|
117
|
+
const gallery = hasGallery ? (
|
|
118
|
+
<GalleryRow>
|
|
119
|
+
{visibleGalleryImages.map((galleryImageSrc, index) => (
|
|
120
|
+
<img
|
|
121
|
+
key={`${galleryImageSrc}-${index}`}
|
|
122
|
+
src={galleryImageSrc}
|
|
123
|
+
alt={alt}
|
|
124
|
+
style={withLightbox ? { cursor: 'pointer' } : undefined}
|
|
125
|
+
onClick={() => handleImageClick(galleryImageSrc)}
|
|
126
|
+
/>
|
|
127
|
+
))}
|
|
128
|
+
</GalleryRow>
|
|
129
|
+
) : null;
|
|
130
|
+
|
|
131
|
+
const hasCaption = Boolean(caption);
|
|
132
|
+
const hasWrapper = Boolean(framed || hasCaption || hasGallery);
|
|
133
|
+
const wrapperContent = hasGallery ? gallery : images;
|
|
134
|
+
|
|
69
135
|
return (
|
|
70
136
|
<>
|
|
71
137
|
{lightboxImage ? (
|
|
@@ -76,39 +142,80 @@ export function Image(props: ImageProps): JSX.Element {
|
|
|
76
142
|
tabIndex={0}
|
|
77
143
|
>
|
|
78
144
|
<Overlay style={lightboxOverlayStyles} />
|
|
79
|
-
<
|
|
145
|
+
<LightboxContent>
|
|
146
|
+
<CloseButton variant="secondary" aria-label="Close image" onClick={handleCloseLightbox}>
|
|
147
|
+
<CloseIcon />
|
|
148
|
+
</CloseButton>
|
|
149
|
+
<Image src={lightboxImage} alt={alt} />
|
|
150
|
+
</LightboxContent>
|
|
80
151
|
</LightboxContainer>
|
|
81
152
|
) : null}
|
|
82
|
-
{
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
width={width}
|
|
88
|
-
height={height}
|
|
89
|
-
style={combinedStyles}
|
|
90
|
-
onClick={() => handleImageClick(src)}
|
|
91
|
-
/>
|
|
153
|
+
{hasWrapper ? (
|
|
154
|
+
<ImageFrame data-component-name="Image/Image" $framed={framed} $gallery={hasGallery}>
|
|
155
|
+
{wrapperContent}
|
|
156
|
+
{hasCaption ? <ImageCaption>{caption}</ImageCaption> : null}
|
|
157
|
+
</ImageFrame>
|
|
92
158
|
) : (
|
|
93
|
-
|
|
94
|
-
<ColorModeAwareImage
|
|
95
|
-
key={key}
|
|
96
|
-
$colorMode={key}
|
|
97
|
-
src={value}
|
|
98
|
-
alt={alt}
|
|
99
|
-
className={className}
|
|
100
|
-
width={width}
|
|
101
|
-
height={height}
|
|
102
|
-
$withLightbox={withLightbox}
|
|
103
|
-
style={combinedStyles}
|
|
104
|
-
onClick={() => handleImageClick(value)}
|
|
105
|
-
/>
|
|
106
|
-
))
|
|
159
|
+
images
|
|
107
160
|
)}
|
|
108
161
|
</>
|
|
109
162
|
);
|
|
110
163
|
}
|
|
111
164
|
|
|
165
|
+
const ImageFrame = styled.figure<{ $framed?: boolean; $gallery?: boolean }>`
|
|
166
|
+
display: ${({ $gallery }) => ($gallery ? 'block' : 'inline-block')};
|
|
167
|
+
margin: 0;
|
|
168
|
+
${({ $gallery }) => ($gallery ? 'width: 100%;' : '')}
|
|
169
|
+
max-width: 100%;
|
|
170
|
+
|
|
171
|
+
${({ $framed }) =>
|
|
172
|
+
$framed &&
|
|
173
|
+
css`
|
|
174
|
+
padding: var(--image-frame-padding);
|
|
175
|
+
border: var(--border-width) var(--border-style) var(--image-frame-border-color);
|
|
176
|
+
border-radius: var(--image-frame-border-radius);
|
|
177
|
+
background-color: var(--image-frame-bg-color);
|
|
178
|
+
`}
|
|
179
|
+
|
|
180
|
+
> img {
|
|
181
|
+
display: block;
|
|
182
|
+
max-width: 100%;
|
|
183
|
+
height: auto;
|
|
184
|
+
background: transparent center / cover no-repeat;
|
|
185
|
+
|
|
186
|
+
${({ $framed }) =>
|
|
187
|
+
$framed &&
|
|
188
|
+
css`
|
|
189
|
+
border-radius: var(--image-frame-image-border-radius);
|
|
190
|
+
`}
|
|
191
|
+
}
|
|
192
|
+
`;
|
|
193
|
+
|
|
194
|
+
const GalleryRow = styled.div`
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: stretch;
|
|
197
|
+
overflow: hidden;
|
|
198
|
+
border-radius: var(--image-gallery-border-radius);
|
|
199
|
+
|
|
200
|
+
img {
|
|
201
|
+
flex: 1 1 0;
|
|
202
|
+
min-width: 0;
|
|
203
|
+
width: 100%;
|
|
204
|
+
object-fit: cover;
|
|
205
|
+
border-radius: 0;
|
|
206
|
+
background: var(--image-gallery-image-bg-color) 50% / cover no-repeat;
|
|
207
|
+
}
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
const ImageCaption = styled.figcaption`
|
|
211
|
+
padding: var(--image-caption-padding);
|
|
212
|
+
color: var(--image-caption-text-color);
|
|
213
|
+
font-size: var(--image-caption-font-size);
|
|
214
|
+
line-height: var(--image-caption-line-height);
|
|
215
|
+
font-weight: var(--image-caption-font-weight);
|
|
216
|
+
text-align: center;
|
|
217
|
+
`;
|
|
218
|
+
|
|
112
219
|
const ColorModeAwareImage = styled.img<{ $colorMode: string; $withLightbox?: boolean }>`
|
|
113
220
|
html:not(.${(props) => props.$colorMode}) && {
|
|
114
221
|
display: none;
|
|
@@ -121,7 +228,7 @@ const ColorModeAwareImage = styled.img<{ $colorMode: string; $withLightbox?: boo
|
|
|
121
228
|
`;
|
|
122
229
|
|
|
123
230
|
const Overlay = styled.div`
|
|
124
|
-
background-color: var(--bg-color
|
|
231
|
+
background-color: var(--image-lightbox-overlay-bg-color);
|
|
125
232
|
grid-column: 1 / 2;
|
|
126
233
|
grid-row: 1 / 2;
|
|
127
234
|
height: 100%;
|
|
@@ -129,6 +236,33 @@ const Overlay = styled.div`
|
|
|
129
236
|
z-index: -1;
|
|
130
237
|
`;
|
|
131
238
|
|
|
239
|
+
const CloseButton = styled(Button)`
|
|
240
|
+
position: absolute;
|
|
241
|
+
top: 0;
|
|
242
|
+
left: 100%;
|
|
243
|
+
margin-left: var(--image-lightbox-close-offset);
|
|
244
|
+
width: var(--image-lightbox-close-size);
|
|
245
|
+
height: var(--image-lightbox-close-size);
|
|
246
|
+
border-radius: var(--image-lightbox-close-border-radius);
|
|
247
|
+
z-index: 1;
|
|
248
|
+
|
|
249
|
+
svg {
|
|
250
|
+
width: var(--image-lightbox-close-icon-size);
|
|
251
|
+
height: var(--image-lightbox-close-icon-size);
|
|
252
|
+
}
|
|
253
|
+
`;
|
|
254
|
+
|
|
255
|
+
const LightboxContent = styled.div`
|
|
256
|
+
position: relative;
|
|
257
|
+
grid-column: 1 / 2;
|
|
258
|
+
grid-row: 1 / 2;
|
|
259
|
+
margin: auto;
|
|
260
|
+
width: fit-content;
|
|
261
|
+
height: fit-content;
|
|
262
|
+
max-width: var(--image-lightbox-content-max-width);
|
|
263
|
+
max-height: var(--image-lightbox-content-max-height);
|
|
264
|
+
`;
|
|
265
|
+
|
|
132
266
|
const LightboxContainer = styled.div`
|
|
133
267
|
display: grid;
|
|
134
268
|
height: 100vh;
|
|
@@ -144,10 +278,13 @@ const LightboxContainer = styled.div`
|
|
|
144
278
|
|
|
145
279
|
img {
|
|
146
280
|
cursor: pointer;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
281
|
+
display: block;
|
|
282
|
+
max-width: var(--image-lightbox-image-max-width);
|
|
283
|
+
max-height: var(--image-lightbox-image-max-height);
|
|
284
|
+
border-radius: var(--image-lightbox-image-border-radius);
|
|
285
|
+
background:
|
|
286
|
+
var(--image-lightbox-image-bg-placeholder) center / cover no-repeat,
|
|
287
|
+
var(--image-frame-bg-color);
|
|
288
|
+
box-shadow: var(--image-lightbox-image-shadow);
|
|
152
289
|
}
|
|
153
290
|
`;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { css } from 'styled-components';
|
|
2
|
+
|
|
3
|
+
export const image = css`
|
|
4
|
+
/* === Image === */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @tokens Image frame
|
|
8
|
+
*/
|
|
9
|
+
--image-frame-padding: var(--spacing-xs);
|
|
10
|
+
--image-frame-border-color: var(--border-color-secondary);
|
|
11
|
+
--image-frame-border-radius: var(--border-radius-xxl);
|
|
12
|
+
--image-frame-bg-color: var(--bg-color-raised);
|
|
13
|
+
--image-frame-image-border-radius: var(--border-radius-lg);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @tokens Image caption
|
|
17
|
+
*/
|
|
18
|
+
--image-caption-padding: var(--spacing-sm) var(--spacing-lg) var(--spacing-xxs) var(--spacing-lg);
|
|
19
|
+
--image-caption-text-color: var(--text-color-primary);
|
|
20
|
+
--image-caption-font-size: var(--font-size-base);
|
|
21
|
+
--image-caption-line-height: var(--line-height-base);
|
|
22
|
+
--image-caption-font-weight: var(--font-weight-regular);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @tokens Image gallery
|
|
26
|
+
*/
|
|
27
|
+
--image-gallery-border-radius: var(--border-radius-lg);
|
|
28
|
+
--image-gallery-image-bg-color: var(--bg-color-tonal);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @tokens Image lightbox
|
|
32
|
+
*/
|
|
33
|
+
--image-lightbox-overlay-bg-color: var(--bg-color-modal-overlay);
|
|
34
|
+
--image-lightbox-content-max-width: 90%;
|
|
35
|
+
--image-lightbox-content-max-height: 90%;
|
|
36
|
+
|
|
37
|
+
--image-lightbox-image-max-width: min(
|
|
38
|
+
90vw,
|
|
39
|
+
calc(100vw - 2 * var(--image-lightbox-side-gutter))
|
|
40
|
+
);
|
|
41
|
+
--image-lightbox-image-max-height: 90vh;
|
|
42
|
+
--image-lightbox-image-border-radius: var(--border-radius-xl);
|
|
43
|
+
--image-lightbox-image-bg-placeholder: var(--bg-color-tonal);
|
|
44
|
+
--image-lightbox-image-shadow: var(--bg-raised-shadow);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @tokens Image lightbox close button
|
|
48
|
+
*/
|
|
49
|
+
--image-lightbox-close-size: 40px;
|
|
50
|
+
--image-lightbox-close-icon-size: 18px;
|
|
51
|
+
--image-lightbox-close-offset: var(--spacing-base);
|
|
52
|
+
--image-lightbox-close-border-radius: var(--border-radius-lg);
|
|
53
|
+
--image-lightbox-side-gutter: calc(
|
|
54
|
+
var(--image-lightbox-close-size) + var(--image-lightbox-close-offset) + var(--spacing-sm)
|
|
55
|
+
);
|
|
56
|
+
`;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type ContentSegment,
|
|
11
11
|
} from '@redocly/theme/core/types';
|
|
12
12
|
import { TOOL_CALL_DISPLAY_TEXT } from '@redocly/theme/core/constants';
|
|
13
|
+
import { ToolCallName } from '@redocly/theme/core/types';
|
|
13
14
|
import { Link } from '@redocly/theme/components/Link/Link';
|
|
14
15
|
import { Tag } from '@redocly/theme/components/Tag/Tag';
|
|
15
16
|
import { AiSearchConversationRole } from '@redocly/theme/core/constants';
|
|
@@ -26,14 +27,33 @@ function MarkdownSegment({ text }: { text: string }): JSX.Element {
|
|
|
26
27
|
const markdown = useMarkdownText(text);
|
|
27
28
|
return <ResponseText as="div" children={markdown} data-testid="response-text" />;
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
+
// The codemode `execute` tool passes a human-readable `description` of what its code
|
|
31
|
+
// does; show that instead of a generic "Executing execute..." label.
|
|
32
|
+
function getExecuteDescription(args: unknown): string | undefined {
|
|
33
|
+
if (args && typeof args === 'object' && 'description' in args) {
|
|
34
|
+
const { description } = args as { description?: unknown };
|
|
35
|
+
if (typeof description === 'string' && description.trim().length > 0) {
|
|
36
|
+
return description.trim();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getToolCallDisplayText(toolCall: ToolCall): {
|
|
30
43
|
inProgressText: string;
|
|
31
44
|
completedText: string;
|
|
32
45
|
} {
|
|
46
|
+
if (toolCall.name === ToolCallName.Execute) {
|
|
47
|
+
const description = getExecuteDescription(toolCall.args);
|
|
48
|
+
if (description) {
|
|
49
|
+
return { inProgressText: description, completedText: description };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
33
53
|
return (
|
|
34
|
-
TOOL_CALL_DISPLAY_TEXT[
|
|
35
|
-
inProgressText: `Executing ${
|
|
36
|
-
completedText: `${
|
|
54
|
+
TOOL_CALL_DISPLAY_TEXT[toolCall.name] ?? {
|
|
55
|
+
inProgressText: `Executing ${toolCall.name}...`,
|
|
56
|
+
completedText: `${toolCall.name} executed`,
|
|
37
57
|
}
|
|
38
58
|
);
|
|
39
59
|
}
|
|
@@ -135,7 +155,7 @@ function SearchAiMessageComponent({
|
|
|
135
155
|
const toolCallCompleted = Boolean(segment.toolCall.result);
|
|
136
156
|
|
|
137
157
|
const { inProgressText, completedText } = getToolCallDisplayText(
|
|
138
|
-
segment.toolCall
|
|
158
|
+
segment.toolCall,
|
|
139
159
|
);
|
|
140
160
|
|
|
141
161
|
const toolCallDisplayText = toolCallCompleted ? completedText : inProgressText;
|
|
@@ -8,6 +8,7 @@ import { breadcrumbs } from '@redocly/theme/components/Breadcrumbs/variables';
|
|
|
8
8
|
import { tag } from '@redocly/theme/components/Tag/variables';
|
|
9
9
|
import { toc } from '@redocly/theme/components/TableOfContent/variables';
|
|
10
10
|
import { catalog } from '@redocly/theme/components/Catalog/variables';
|
|
11
|
+
import { image } from '@redocly/theme/components/Image/variables';
|
|
11
12
|
import { filter } from '@redocly/theme/components/Filter/variables';
|
|
12
13
|
import { catalogClassic } from '@redocly/theme/components/CatalogClassic/variables';
|
|
13
14
|
import { apiReferencePanels, responsePanelColors } from '@redocly/theme/components/Panel/variables';
|
|
@@ -1301,6 +1302,7 @@ export const styles = css<{ palette?: string }>`
|
|
|
1301
1302
|
${footer}
|
|
1302
1303
|
${headingsTypography}
|
|
1303
1304
|
${httpTag}
|
|
1305
|
+
${image}
|
|
1304
1306
|
${inputs}
|
|
1305
1307
|
${languagePicker}
|
|
1306
1308
|
${lastUpdated}
|
package/src/core/types/search.ts
CHANGED
package/src/markdoc/tags/img.ts
CHANGED
|
@@ -13,9 +13,20 @@ export const img: MarkdocSchemaWrapper = {
|
|
|
13
13
|
type: String,
|
|
14
14
|
resolver: 'imageSrcSet',
|
|
15
15
|
},
|
|
16
|
+
images: {
|
|
17
|
+
type: Array,
|
|
18
|
+
resolver: 'imageGallery',
|
|
19
|
+
},
|
|
16
20
|
alt: {
|
|
17
21
|
type: String,
|
|
18
22
|
},
|
|
23
|
+
caption: {
|
|
24
|
+
type: String,
|
|
25
|
+
},
|
|
26
|
+
framed: {
|
|
27
|
+
type: Boolean,
|
|
28
|
+
default: false,
|
|
29
|
+
},
|
|
19
30
|
withLightbox: {
|
|
20
31
|
type: Boolean,
|
|
21
32
|
default: false,
|
|
@@ -44,8 +55,31 @@ export const img: MarkdocSchemaWrapper = {
|
|
|
44
55
|
},
|
|
45
56
|
},
|
|
46
57
|
validate: (node) => {
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
const { src, srcSet, images } = node.attributes;
|
|
59
|
+
const hasGallery = Array.isArray(images) && images.length > 0;
|
|
60
|
+
if (!src && !srcSet && !hasGallery) {
|
|
61
|
+
return [{ id: '', message: 'src, srcSet, or images is required', level: 'error' }];
|
|
62
|
+
}
|
|
63
|
+
if (hasGallery && (src || srcSet)) {
|
|
64
|
+
return [
|
|
65
|
+
{
|
|
66
|
+
id: 'invalid-img-source-combination',
|
|
67
|
+
message: 'images cannot be used together with src or srcSet',
|
|
68
|
+
level: 'error',
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
if (src && srcSet) {
|
|
73
|
+
return [
|
|
74
|
+
{
|
|
75
|
+
id: 'invalid-img-source-combination',
|
|
76
|
+
message: 'src cannot be used together with srcSet',
|
|
77
|
+
level: 'error',
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
if (Array.isArray(images) && images.length > 3) {
|
|
82
|
+
return [{ id: '', message: 'images supports a maximum of 3 items', level: 'error' }];
|
|
49
83
|
}
|
|
50
84
|
return [];
|
|
51
85
|
},
|