UNPKG

react-advanced-gallery

Version:

A customizable React image gallery component with Bootstrap styling, fullscreen mode, animations, and support for various media types

144 lines (143 loc) 5.67 kB
import { useState, useCallback, useEffect } from 'react'; export const useGallery = ({ initialImages, initialLayout = 'grid', initialAnimation = 'fade', initialThumbnailsPosition = 'bottom', initialEnableZoom = true }) => { const [images, setImages] = useState(initialImages); const [selectedImage, setSelectedImage] = useState(null); const [currentIndex, setCurrentIndex] = useState(0); const [isFullscreenOpen, setIsFullscreenOpen] = useState(false); const [zoomLevel, setZoomLevel] = useState(1); const [layout, setLayout] = useState(initialLayout); const [animation, setAnimation] = useState(initialAnimation); const [thumbnailsPosition, setThumbnailsPosition] = useState(initialThumbnailsPosition); const [enableZoom, setEnableZoom] = useState(initialEnableZoom); // Reset zoom level when closing fullscreen or changing images useEffect(() => { if (!isFullscreenOpen) { setZoomLevel(1); } }, [isFullscreenOpen, selectedImage]); const openFullscreen = useCallback((image) => { const index = images.findIndex(img => img.id === image.id); setSelectedImage(image); setCurrentIndex(index !== -1 ? index : 0); setIsFullscreenOpen(true); }, [images]); const closeFullscreen = useCallback(() => { setIsFullscreenOpen(false); setSelectedImage(null); }, []); const toggleFavorite = useCallback((image) => { setImages(prevImages => prevImages.map(img => img.id === image.id ? { ...img, isFavorite: !img.isFavorite } : img)); if (selectedImage && selectedImage.id === image.id) { setSelectedImage({ ...selectedImage, isFavorite: !selectedImage.isFavorite }); } }, [selectedImage]); const removeImage = useCallback((image) => { // Get the new array of images before setting state to use for navigation const newImages = images.filter(img => img.id !== image.id); if (isFullscreenOpen && selectedImage && selectedImage.id === image.id) { if (newImages.length > 0) { // If we're removing the last image, go to the previous one // Otherwise, stay at the same index (which will now show the next image) const newIndex = currentIndex >= newImages.length ? newImages.length - 1 : currentIndex; setCurrentIndex(newIndex); setSelectedImage(newImages[newIndex]); } else { closeFullscreen(); } } // Update the images state after handling navigation setImages(newImages); }, [isFullscreenOpen, selectedImage, images, currentIndex, closeFullscreen]); const navigateToImage = useCallback((index) => { if (index >= 0 && index < images.length) { setCurrentIndex(index); setSelectedImage(images[index]); } }, [images]); const navigatePrev = useCallback(() => { const newIndex = (currentIndex - 1 + images.length) % images.length; navigateToImage(newIndex); }, [currentIndex, images.length, navigateToImage]); const navigateNext = useCallback(() => { const newIndex = (currentIndex + 1) % images.length; navigateToImage(newIndex); }, [currentIndex, images.length, navigateToImage]); const zoomIn = useCallback(() => { setZoomLevel(prevZoom => Math.min(prevZoom + 0.5, 3)); }, []); const zoomOut = useCallback(() => { setZoomLevel(prevZoom => Math.max(prevZoom - 0.5, 0.5)); }, []); const resetZoom = useCallback(() => { setZoomLevel(1); }, []); const addImages = useCallback((newImages) => { setImages(prevImages => [...prevImages, ...newImages]); }, []); const updateConfig = useCallback((config) => { if (config.layout) setLayout(config.layout); if (config.animation) setAnimation(config.animation); if (config.thumbnailsPosition) setThumbnailsPosition(config.thumbnailsPosition); if (config.enableZoom !== undefined) setEnableZoom(config.enableZoom); }, []); useEffect(() => { const handleKeyDown = (e) => { if (!isFullscreenOpen) return; switch (e.key) { case 'Escape': closeFullscreen(); break; case 'ArrowLeft': navigatePrev(); break; case 'ArrowRight': navigateNext(); break; case '+': zoomIn(); break; case '-': zoomOut(); break; case '0': resetZoom(); break; default: break; } }; window.addEventListener('keydown', handleKeyDown); return () => { window.removeEventListener('keydown', handleKeyDown); }; }, [isFullscreenOpen, closeFullscreen, navigatePrev, navigateNext, zoomIn, zoomOut, resetZoom]); return { images, selectedImage, currentIndex, isFullscreenOpen, zoomLevel, layout, animation, thumbnailsPosition, enableZoom, openFullscreen, closeFullscreen, toggleFavorite, removeImage, navigateToImage, navigatePrev, navigateNext, zoomIn, zoomOut, resetZoom, addImages, updateConfig, }; };