UNPKG

@grafana/ui

Version:
197 lines (194 loc) • 5.78 kB
import { jsx, jsxs } from 'react/jsx-runtime'; import { cx, css } from '@emotion/css'; import { useState, useEffect } from 'react'; import '@grafana/data'; import { useStyles2 } from '../../themes/ThemeContext.mjs'; import 'micro-memoize'; import '@emotion/react'; import 'tinycolor2'; import '../../utils/skeleton.mjs'; import { t } from '../../utils/i18n.mjs'; import { Alert } from '../Alert/Alert.mjs'; import { IconButton } from '../IconButton/IconButton.mjs'; const Carousel = ({ images }) => { const [selectedIndex, setSelectedIndex] = useState(null); const [imageErrors, setImageErrors] = useState({}); const [validImages, setValidImages] = useState(images); const styles = useStyles2(getStyles()); const handleImageError = (path) => { setImageErrors((prev) => ({ ...prev, [path]: true })); }; useEffect(() => { const filteredImages = images.filter((image) => !imageErrors[image.path]); setValidImages(filteredImages); }, [imageErrors, images]); const openPreview = (index) => { setSelectedIndex(index); }; const closePreview = () => { setSelectedIndex(null); }; const goToNext = () => { if (selectedIndex !== null && validImages.length > 0) { setSelectedIndex((selectedIndex + 1) % validImages.length); } }; const goToPrevious = () => { if (selectedIndex !== null && validImages.length > 0) { setSelectedIndex((selectedIndex - 1 + validImages.length) % validImages.length); } }; const handleKeyDown = (event) => { if (selectedIndex === null) { return; } switch (event.key) { case "ArrowRight": goToNext(); break; case "ArrowLeft": goToPrevious(); break; case "Escape": closePreview(); break; } }; if (validImages.length === 0) { return /* @__PURE__ */ jsx( Alert, { title: t("carousel.error", "Something went wrong loading images"), severity: "warning", "data-testid": "alert-warning" } ); } return /* @__PURE__ */ jsxs("div", { onKeyDown: handleKeyDown, tabIndex: 0, children: [ /* @__PURE__ */ jsx("div", { className: cx(styles.imageGrid), children: validImages.map((image, index) => /* @__PURE__ */ jsxs("div", { onClick: () => openPreview(index), style: { cursor: "pointer" }, children: [ /* @__PURE__ */ jsx("img", { src: image.path, alt: image.name, onError: () => handleImageError(image.path) }), /* @__PURE__ */ jsx("p", { children: image.name }) ] }, image.path)) }), selectedIndex !== null && /* @__PURE__ */ jsxs("div", { className: cx(styles.fullScreenDiv), onClick: closePreview, "data-testid": "carousel-full-screen", children: [ /* @__PURE__ */ jsx( IconButton, { name: "times", "aria-label": t("carousel.close", "Close"), size: "xl", onClick: closePreview, className: cx(styles.closeButton) } ), /* @__PURE__ */ jsx( IconButton, { size: "xl", name: "angle-left", "aria-label": t("carousel.previous", "Previous"), onClick: (e) => { e.stopPropagation(); goToPrevious(); }, className: cx(styles.navigationButton, styles.previousButton), "data-testid": "previous-button" } ), /* @__PURE__ */ jsx( "div", { style: { position: "relative", maxWidth: "90%", maxHeight: "90%" }, onClick: (e) => e.stopPropagation(), "data-testid": "carousel-full-image", children: /* @__PURE__ */ jsx( "img", { src: validImages[selectedIndex].path, alt: validImages[selectedIndex].name, onError: () => handleImageError(validImages[selectedIndex].path) } ) } ), /* @__PURE__ */ jsx( IconButton, { size: "xl", name: "angle-right", "aria-label": t("carousel.next", "Next"), onClick: (e) => { e.stopPropagation(); goToNext(); }, className: cx(styles.navigationButton, styles.nextButton), "data-testid": "next-button" } ) ] }) ] }); }; const getStyles = () => (theme) => ({ imageGrid: css({ display: "grid", gridTemplateColumns: `repeat(auto-fill, minmax(200px, 1fr))`, gap: "16px", marginBottom: "20px", "& img": { width: "100%", height: "150px", objectFit: "cover", border: theme.colors.border.strong, borderRadius: theme.shape.radius.default, boxShadow: theme.shadows.z1 }, "& p": { margin: "4px 0", fontWeight: theme.typography.fontWeightMedium, color: theme.colors.text.primary } }), fullScreenDiv: css({ position: "fixed", zIndex: theme.zIndex.modalBackdrop, top: 0, right: 0, bottom: 0, left: 0, backgroundColor: theme.components.overlay.background, alignItems: "center", justifyContent: "center", display: "flex", "& img": { maxWidth: "100%", maxHeight: "80vh", objectFit: "contain" } }), closeButton: css({ position: "absolute", top: "20px", right: "20px", backgroundColor: "transparent", color: theme.colors.text.primary }), navigationButton: css({ position: "absolute", backgroundColor: "transparent", color: theme.colors.text.primary, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }), nextButton: css({ right: "20px" }), previousButton: css({ left: "20px" }) }); export { Carousel }; //# sourceMappingURL=Carousel.mjs.map