Files
web/packages/design-system/lib/components/ImageGallery/index.tsx
Rasmus Langvad c65091b36a Merged in feat/SW-3644-storybook-v10 (pull request #3240)
feat(SW-3644): Storybook v10

* Auto update to Storybook v10

* Add scandic theme and logo

* Update yarn.lock

* Update formatting of package.json

* Update vitest config and playwright plugin

* Remove vitest 4 update

* Re-added comment

* Update the Typography component to explicitly return React.ReactNode

* Add an explicit type assertion to the export

* Add an explicit type assertion to the export for Checkbox

* Explicit return type assertion

* Add an explicit type assertion to the export

* Update @types/react and fix ts warnings

* Updated typings


Approved-by: Linus Flood
Approved-by: Matilda Landström
2025-11-28 08:05:40 +00:00

105 lines
2.5 KiB
TypeScript

'use client'
import { memo, useState } from 'react'
import { Button as ButtonRAC } from 'react-aria-components'
import { useIntl } from 'react-intl'
import { MaterialIcon } from '../Icons/MaterialIcon'
import Image from '../Image'
import ImageFallback from '../ImageFallback'
import Lightbox from '../Lightbox'
import { Typography } from '../Typography'
import styles from './imageGallery.module.css'
export interface GalleryImage {
src: string
alt: string
caption?: string | null
}
type ImageGalleryProps = {
images?: GalleryImage[]
title: string
fill?: boolean
width?: number
height?: number
sizes?: string
hideLabel?: boolean
imageCountPosition?: 'top' | 'bottom'
}
function ImageGallery({
images,
title,
fill,
height = 280,
sizes,
hideLabel,
imageCountPosition = 'bottom',
}: ImageGalleryProps) {
const intl = useIntl()
const [isOpen, setIsOpen] = useState(false)
const [imageError, setImageError] = useState(false)
const imageProps = fill
? {
fill,
sizes:
sizes ?? 'auto, (max-width: 400px) 100vw, (min-width: 401px) 500px',
}
: { height, width: height * 1.5 }
if (!images?.length || imageError) {
return <ImageFallback />
}
const firstImage = images[0]
return (
<>
<div className={styles.wrapper}>
<Image
className={styles.image}
src={firstImage.src}
alt={firstImage.alt}
onError={() => setImageError(true)}
{...imageProps}
/>
<Typography variant={'Body/Supporting text (caption)/smRegular'}>
<span
className={`${styles.imageCount} ${
imageCountPosition === 'top'
? styles.imageCountTop
: styles.imageCountBottom
}`}
>
<MaterialIcon icon="filter" color="Icon/Inverted" size={16} />
<span>{images.length}</span>
</span>
</Typography>
<ButtonRAC
className={styles.triggerArea}
onPress={() => setIsOpen(true)}
aria-label={intl.formatMessage({
id: 'imageGallery.openImageGallery',
defaultMessage: 'Open image gallery',
})}
/>
</div>
<Lightbox
images={images}
dialogTitle={title}
onClose={() => setIsOpen(false)}
isOpen={isOpen}
hideLabel={hideLabel}
/>
</>
)
}
const ImageGalleryComponent = memo(ImageGallery)
export default ImageGalleryComponent as React.MemoExoticComponent<
(props: ImageGalleryProps) => React.ReactElement
>