{"version":3,"file":"Carousel.cjs","sources":["../../../../src/components/Carousel/Carousel.tsx"],"sourcesContent":["import { css, cx } from '@emotion/css';\nimport { useDialog } from '@react-aria/dialog';\nimport { FocusScope } from '@react-aria/focus';\nimport { OverlayContainer, useOverlay } from '@react-aria/overlays';\nimport { useState, useEffect, useRef, useId } from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { t } from '@grafana/i18n';\n\nimport { useStyles2 } from '../../themes/ThemeContext';\nimport { Alert } from '../Alert/Alert';\nimport { clearButtonStyles } from '../Button/Button';\nimport { IconButton } from '../IconButton/IconButton';\n\n// Define the image item interface\nexport interface CarouselImage {\n  path: string;\n  name: string;\n}\n\nexport interface CarouselProps {\n  images: CarouselImage[];\n}\n\n/**\n * The Carousel component displays a grid of image thumbnails that can be clicked to view full-sized images in a modal with navigation controls. It provides an elegant way to present collections of images or screenshots with fullscreen preview capabilities.\n *\n * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-carousel--docs\n */\nexport const Carousel: React.FC<CarouselProps> = ({ images }) => {\n  const [selectedIndex, setSelectedIndex] = useState<number | null>(null);\n  const [imageErrors, setImageErrors] = useState<Record<string, boolean>>({});\n  const [validImages, setValidImages] = useState<CarouselImage[]>(images);\n  const id = useId();\n\n  const styles = useStyles2(getStyles);\n  const resetButtonStyles = useStyles2(clearButtonStyles);\n\n  const handleImageError = (path: string) => {\n    setImageErrors((prev) => ({\n      ...prev,\n      [path]: true,\n    }));\n  };\n\n  useEffect(() => {\n    const filteredImages = images.filter((image) => !imageErrors[image.path]);\n    setValidImages(filteredImages);\n  }, [imageErrors, images]);\n\n  const openPreview = (index: number) => {\n    setSelectedIndex(index);\n  };\n\n  const closePreview = () => {\n    setSelectedIndex(null);\n  };\n\n  const goToNext = () => {\n    if (selectedIndex !== null && validImages.length > 0) {\n      setSelectedIndex((selectedIndex + 1) % validImages.length);\n    }\n  };\n\n  const goToPrevious = () => {\n    if (selectedIndex !== null && validImages.length > 0) {\n      setSelectedIndex((selectedIndex - 1 + validImages.length) % validImages.length);\n    }\n  };\n\n  const handleKeyDown = (event: React.KeyboardEvent) => {\n    if (selectedIndex === null) {\n      return;\n    }\n\n    switch (event.key) {\n      case 'ArrowRight':\n        goToNext();\n        break;\n      case 'ArrowLeft':\n        goToPrevious();\n        break;\n      case 'Escape':\n        closePreview();\n        break;\n      default:\n        break;\n    }\n  };\n\n  const ref = useRef<HTMLDivElement>(null);\n\n  const { overlayProps, underlayProps } = useOverlay({ isOpen: selectedIndex !== null, onClose: closePreview }, ref);\n  const { dialogProps } = useDialog({}, ref);\n\n  if (validImages.length === 0) {\n    return (\n      <Alert\n        title={t('carousel.error', 'Something went wrong loading images')}\n        severity=\"warning\"\n        data-testid=\"alert-warning\"\n      />\n    );\n  }\n\n  return (\n    <>\n      <div className={cx(styles.imageGrid)}>\n        {validImages.map((image, index) => {\n          const imageNameId = `${id}-carousel-image-${index}`;\n          return (\n            <button\n              aria-label={t('grafana-ui.carousel.aria-label-open-image', 'Open image preview')}\n              aria-describedby={imageNameId}\n              type=\"button\"\n              key={image.path}\n              onClick={() => openPreview(index)}\n              className={cx(resetButtonStyles, styles.imageButton)}\n            >\n              <img src={image.path} alt=\"\" onError={() => handleImageError(image.path)} />\n              <p id={imageNameId}>{image.name}</p>\n            </button>\n          );\n        })}\n      </div>\n\n      {selectedIndex !== null && (\n        <OverlayContainer>\n          <div role=\"presentation\" className={styles.underlay} onClick={closePreview} {...underlayProps} />\n          <FocusScope contain autoFocus restoreFocus>\n            {/* convenience method for keyboard users */}\n            {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}\n            <div\n              data-testid=\"carousel-full-screen\"\n              ref={ref}\n              {...overlayProps}\n              {...dialogProps}\n              onKeyDown={handleKeyDown}\n              className={styles.overlay}\n            >\n              <IconButton\n                name=\"times\"\n                aria-label={t('carousel.close', 'Close')}\n                size=\"xl\"\n                onClick={closePreview}\n                className={cx(styles.closeButton)}\n              />\n\n              <IconButton\n                size=\"xl\"\n                name=\"angle-left\"\n                aria-label={t('carousel.previous', 'Previous')}\n                onClick={goToPrevious}\n                data-testid=\"previous-button\"\n              />\n\n              <div className={styles.imageContainer} data-testid=\"carousel-full-image\">\n                <img\n                  className={styles.imagePreview}\n                  src={validImages[selectedIndex].path}\n                  alt={validImages[selectedIndex].name}\n                  onError={() => handleImageError(validImages[selectedIndex].path)}\n                />\n              </div>\n\n              <IconButton\n                size=\"xl\"\n                name=\"angle-right\"\n                aria-label={t('carousel.next', 'Next')}\n                onClick={goToNext}\n                data-testid=\"next-button\"\n              />\n            </div>\n          </FocusScope>\n        </OverlayContainer>\n      )}\n    </>\n  );\n};\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n  imageButton: css({\n    textAlign: 'left',\n  }),\n  imageContainer: css({\n    display: 'flex',\n    justifyContent: 'center',\n    flex: 1,\n  }),\n  imagePreview: css({\n    borderRadius: theme.shape.radius.lg,\n    maxWidth: '100%',\n    maxHeight: '80vh',\n    objectFit: 'contain',\n  }),\n  imageGrid: css({\n    display: 'grid',\n    gridTemplateColumns: `repeat(auto-fill, minmax(200px, 1fr))`,\n    gap: theme.spacing(2),\n    marginBottom: '20px',\n\n    '& img': {\n      width: '100%',\n      height: '150px',\n      objectFit: 'cover',\n      border: theme.colors.border.strong,\n      borderRadius: theme.shape.radius.default,\n      boxShadow: theme.shadows.z1,\n    },\n    '& p': {\n      margin: theme.spacing(0.5, 0),\n      fontWeight: theme.typography.fontWeightMedium,\n      color: theme.colors.text.primary,\n    },\n  }),\n  underlay: css({\n    position: 'fixed',\n    zIndex: theme.zIndex.modalBackdrop,\n    inset: 0,\n    backgroundColor: theme.components.overlay.background,\n  }),\n  overlay: css({\n    alignItems: 'center',\n    display: 'flex',\n    gap: theme.spacing(1),\n    height: 'fit-content',\n    marginBottom: 'auto',\n    marginTop: 'auto',\n    padding: theme.spacing(2),\n    position: 'fixed',\n    inset: 0,\n    zIndex: theme.zIndex.modal,\n  }),\n  closeButton: css({\n    color: theme.colors.text.primary,\n    position: 'fixed',\n    top: theme.spacing(2),\n    right: theme.spacing(2),\n  }),\n});\n"],"names":["useState","useId","useStyles2","clearButtonStyles","useEffect","useRef","useOverlay","useDialog","jsx","Alert","t","jsxs","Fragment","cx","OverlayContainer","FocusScope","IconButton","css"],"mappings":"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"}