diff --git a/components/Lightbox.tsx b/components/Lightbox.tsx index 6f9f7b63..03480181 100644 --- a/components/Lightbox.tsx +++ b/components/Lightbox.tsx @@ -1,7 +1,8 @@ 'use client'; -import React, { useEffect } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import Image from 'next/image'; +import { createPortal } from 'react-dom'; interface LightboxProps { isOpen: boolean; @@ -11,32 +12,51 @@ interface LightboxProps { } export default function Lightbox({ isOpen, images, initialIndex, onClose }: LightboxProps) { - const [currentIndex, setCurrentIndex] = React.useState(initialIndex); + const [currentIndex, setCurrentIndex] = useState(initialIndex); + const [mounted, setMounted] = useState(false); useEffect(() => { - if (isOpen) { - document.body.style.overflow = 'hidden'; - } else { - document.body.style.overflow = 'unset'; - } + setMounted(true); + return () => setMounted(false); + }, []); - return () => { - document.body.style.overflow = 'unset'; - }; - }, [isOpen]); - - if (!isOpen) return null; - - const prevImage = () => { + const prevImage = useCallback(() => { setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1)); - }; + }, [images.length]); - const nextImage = () => { + const nextImage = useCallback(() => { setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1)); - }; + }, [images.length]); - return ( -
+ useEffect(() => { + if (!isOpen) return; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose(); + if (e.key === 'ArrowLeft') prevImage(); + if (e.key === 'ArrowRight') nextImage(); + }; + + // Lock scroll + const originalStyle = window.getComputedStyle(document.body).overflow; + document.body.style.overflow = 'hidden'; + + window.addEventListener('keydown', handleKeyDown); + + return () => { + document.body.style.overflow = originalStyle; + window.removeEventListener('keydown', handleKeyDown); + }; + }, [isOpen, onClose, prevImage, nextImage]); + + if (!isOpen || !mounted) return null; + + return createPortal( +
- {/* Keyboard navigation */} - {isOpen && ( -
{ - if (e.key === 'Escape') onClose(); - if (e.key === 'ArrowLeft') prevImage(); - if (e.key === 'ArrowRight') nextImage(); - }} - onClick={onClose} - /> - )} -
+ {/* Backdrop click to close */} +
+
, + document.body ); } \ No newline at end of file