Files
web/packages/design-system/lib/components/Lightbox/FullView/index.tsx
Rasmus Langvad d0546926a9 Merged in fix/3697-prettier-configs (pull request #3396)
fix(SW-3691): Setup one prettier config for whole repo

* Setup prettierrc in root and remove other configs


Approved-by: Joakim Jäderberg
Approved-by: Linus Flood
2026-01-07 12:45:50 +00:00

153 lines
3.6 KiB
TypeScript

"use client"
import { AnimatePresence, motion } from "motion/react"
import { useEffect, useState } from "react"
import { useIntl } from "react-intl"
import Image from "../../Image"
import { IconButton } from "../../IconButton"
import { Typography } from "../../Typography"
import { LightboxImage } from "../index"
import styles from "./fullView.module.css"
type FullViewProps = {
image: LightboxImage
onClose: () => void
onNext: () => void
onPrev: () => void
currentIndex: number
totalImages: number
hideLabel?: boolean
}
export default function FullView({
image,
onClose,
onNext,
onPrev,
currentIndex,
totalImages,
hideLabel,
}: FullViewProps) {
const intl = useIntl()
const [animateLeft, setAnimateLeft] = useState(true)
function handleSwipe(offset: number) {
if (offset > 30) {
setAnimateLeft(false)
onPrev()
}
if (offset < -30) {
setAnimateLeft(true)
onNext()
}
}
function handleNext() {
setAnimateLeft(true)
onNext()
}
function handlePrev() {
setAnimateLeft(false)
onPrev()
}
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "ArrowLeft") {
handlePrev()
} else if (e.key === "ArrowRight") {
handleNext()
}
}
useEffect(() => {
window.addEventListener("keydown", handleKeyDown)
return () => {
window.removeEventListener("keydown", handleKeyDown)
}
})
const variants = {
initial: (animateLeft: boolean) => ({
opacity: 0,
x: animateLeft ? 300 : -300,
}),
animate: { opacity: 1, x: 0 },
exit: (animateLeft: boolean) => ({
opacity: 0,
x: animateLeft ? -300 : 300,
}),
} as const
return (
<div className={styles.fullView}>
<IconButton
variant="Muted"
className={styles.closeButton}
onPress={onClose}
aria-label={intl.formatMessage({
id: "common.close",
defaultMessage: "Close",
})}
iconName="close"
/>
<div className={styles.header}>
<Typography variant="Tag/sm">
<span className={styles.imageCount}>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`${currentIndex + 1} / ${totalImages}`}
</span>
</Typography>
</div>
<div className={styles.content}>
<AnimatePresence initial={false} custom={animateLeft}>
<motion.div
key={image.src}
custom={animateLeft}
variants={variants}
initial="initial"
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className={styles.motionContainer}
drag="x"
onDragEnd={(_e, info) => handleSwipe(info.offset.x)}
>
<div className={styles.imageWrapper}>
<Image
alt={image.alt}
fill
sizes="90vw"
src={image.src}
className={styles.image}
/>
{image.caption && !hideLabel ? (
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.caption}>{image.caption}</p>
</Typography>
) : null}
</div>
</motion.div>
</AnimatePresence>
</div>
<IconButton
variant="Muted"
className={`${styles.navigationButton} ${styles.prev}`}
onPress={handlePrev}
iconName="arrow_back"
/>
<IconButton
variant="Muted"
className={`${styles.navigationButton} ${styles.next}`}
onPress={handleNext}
iconName="arrow_forward"
/>
</div>
)
}