diff --git a/src/components/ui/Lightbox.jsx b/src/components/ui/Lightbox.jsx index 952df5a..c0eb8d2 100644 --- a/src/components/ui/Lightbox.jsx +++ b/src/components/ui/Lightbox.jsx @@ -4,13 +4,37 @@ import { X, ChevronLeft, ChevronRight } from "lucide-react"; const Lightbox = ({ images, currentIndex, onClose, onNavigate }) => { const touchStartX = useRef(null); + const containerRef = useRef(null); + + const canGoPrev = currentIndex > 0; + const canGoNext = currentIndex < images.length - 1; + + useEffect(() => { + const enterFullscreen = async () => { + try { + if (document.fullscreenElement === null) { + await containerRef.current?.requestFullscreen(); + } + } catch { + // Fullscreen not supported or denied - continue without it + } + }; + + enterFullscreen(); + + return () => { + if (document.fullscreenElement) { + document.exitFullscreen().catch(() => {}); + } + }; + }, []); const navigate = useCallback( (direction) => { - if (direction === "prev") { - onNavigate(currentIndex > 0 ? currentIndex - 1 : images.length - 1); - } else { - onNavigate(currentIndex < images.length - 1 ? currentIndex + 1 : 0); + if (direction === "prev" && currentIndex > 0) { + onNavigate(currentIndex - 1); + } else if (direction === "next" && currentIndex < images.length - 1) { + onNavigate(currentIndex + 1); } }, [currentIndex, images.length, onNavigate] @@ -44,14 +68,17 @@ const Lightbox = ({ images, currentIndex, onClose, onNavigate }) => { }, [navigate, onClose]); return ( -
+
{/* Backdrop - semantic button element */} {/* Image container */} -
+
{
diff --git a/src/components/ui/Lightbox.test.jsx b/src/components/ui/Lightbox.test.jsx index 53d362f..bfd24b2 100644 --- a/src/components/ui/Lightbox.test.jsx +++ b/src/components/ui/Lightbox.test.jsx @@ -84,16 +84,32 @@ describe("Lightbox", () => { expect(onNavigateMock).toHaveBeenCalledWith(2); }); - it("wraps to last image when navigating prev from first image", () => { + it("does not navigate when at first image and prev is clicked", () => { renderLightbox(0); fireEvent.click(screen.getByLabelText("Foto anterior")); - expect(onNavigateMock).toHaveBeenCalledWith(2); // Last image index + expect(onNavigateMock).not.toHaveBeenCalled(); }); - it("wraps to first image when navigating next from last image", () => { + it("does not navigate when at last image and next is clicked", () => { renderLightbox(2); fireEvent.click(screen.getByLabelText("Próxima foto")); - expect(onNavigateMock).toHaveBeenCalledWith(0); // First image index + expect(onNavigateMock).not.toHaveBeenCalled(); + }); + + it("disables prev button at first image", () => { + renderLightbox(0); + expect(screen.getByLabelText("Foto anterior")).toBeDisabled(); + }); + + it("disables next button at last image", () => { + renderLightbox(2); + expect(screen.getByLabelText("Próxima foto")).toBeDisabled(); + }); + + it("enables both buttons in the middle", () => { + renderLightbox(1); + expect(screen.getByLabelText("Foto anterior")).not.toBeDisabled(); + expect(screen.getByLabelText("Próxima foto")).not.toBeDisabled(); }); describe("keyboard navigation", () => { @@ -115,6 +131,18 @@ describe("Lightbox", () => { expect(onNavigateMock).toHaveBeenCalledWith(2); }); + it("does not navigate prev on ArrowLeft at first image", () => { + renderLightbox(0); + fireEvent.keyDown(document, { key: "ArrowLeft" }); + expect(onNavigateMock).not.toHaveBeenCalled(); + }); + + it("does not navigate next on ArrowRight at last image", () => { + renderLightbox(2); + fireEvent.keyDown(document, { key: "ArrowRight" }); + expect(onNavigateMock).not.toHaveBeenCalled(); + }); + it("does not respond to other keys", () => { renderLightbox(); fireEvent.keyDown(document, { key: "Enter" }); @@ -180,7 +208,7 @@ describe("Lightbox", () => { }); it("stops propagation when clicking navigation buttons", () => { - renderLightbox(); + renderLightbox(1); // Use middle index so both buttons are enabled // Click prev button - should not trigger backdrop close fireEvent.click(screen.getByLabelText("Foto anterior"));