import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from "@wordpress/element"; import { __, sprintf } from "@wordpress/i18n"; import classnames from "classnames"; import { usePhotos } from "../hooks/usePhotos"; import { areSimiliar } from "../lib/util"; import { useGlobalState } from "../state/global"; import type { ExternalImage, ImagePosition } from "../types"; import { ButtonNav } from "./ButtonNav"; import { MasonryItem } from "./MasonryItem"; type MondalContentProps = { setImage: (image: ExternalImage) => void; }; export const ModalContent = ({ setImage }: MondalContentProps) => { const { page, loading, currentTheme } = useGlobalState(); const { data: images, error, cacheId } = usePhotos({ per_page: 30, page }); const [gridWidth, setGridWidth] = useState(); const [columns, setColumns] = useState(3); const [imagePositions, setImagePositions] = useState([]); const [moving, setMoving] = useState(true); const [subpixelOffset, setSubpixelOffset] = useState(0); const [minHeight, setMinHeight] = useState(0); const gridRef = useRef(null); // Masonry items will report back their position // so that othe rmasonry items can read from the data const setPosition = useCallback( (index: number, incoming: ImagePosition) => { if (!imagePositions[index - 1] && index !== 0) return; // Check if the objects have the same values if (areSimiliar(imagePositions?.[index] ?? {}, incoming)) return; const newPositions = [...imagePositions]; newPositions[index] = incoming; if (newPositions?.length === images?.length) { setMoving(false); } setImagePositions(newPositions); }, [imagePositions, images], ); useLayoutEffect(() => { if (!images?.length) return; setImagePositions([]); }, [page, images]); // Find the height of all the images, and add some extra space useEffect(() => { if (!imagePositions?.length) return; const largestHeight = imagePositions .slice(-columns) .reduce((prev, next) => Math.max(prev, next.y + next.height), 0); setMinHeight(Math.floor(largestHeight) + 100); }, [moving, imagePositions, columns]); useLayoutEffect(() => { const events = ["resize", "focus"]; const handler = () => { setMoving(true); setImagePositions([]); }; events.forEach((e) => { window.addEventListener(e, handler, { passive: true }); }); return () => { events.forEach((e) => { window.removeEventListener(e, handler); }); }; }); useEffect(() => { // Update the grid stats to instruct the MasonryItems to re-render if (imagePositions?.length) return; if (!gridRef.current) return; const w = Math.ceil(gridRef.current.offsetWidth); const isMobile = window.innerWidth < 782; const columns = isMobile ? 1 : Math.max(Math.floor(w / 295), 2); setColumns(columns); // Fight subpixel rendering const realW = Math.floor(w / columns) * columns; setSubpixelOffset(w - realW); setGridWidth(realW); }, [imagePositions]); // Reset if we are fetching new data useEffect(() => { if (!loading) return; setImagePositions([]); }, [loading]); if (error || (!images?.length && typeof images !== "undefined" && !loading)) { return (
{error?.message ? (

{sprintf( __("Error: %s", "unlimited-photos"), error?.response?.message ?? sprintf( __("%s. Please wait or try again", "unlimited-photos"), error?.message, ), )}

) : images && images?.length > 0 ? null : (

{__("No photos found", "unlimited-photos")}

)}
); } if (loading) { return (
{__("Loading...", "unlimited-photos")}
); } return (
{images?.map((image, index) => ( ))}
); };