import { useEffect, useRef, useState, RefObject } from 'react'; import { IMedia } from '../types'; /** * Computes the width a media card should occupy so that the image/video is * displayed at its natural aspect ratio while filling the full container height, * capped at `maxWidthRatio` (default 0.8 = 80 %) of the container's width. * * If the natural width would exceed the cap the card stops growing and the * media is cropped by `overflow: hidden` + `objectFit: cover`. * * @param post - The currently displayed media. * @param maxWidthRatio - Maximum fraction of the container width (0–1). Defaults to 0.8. * @returns An object containing: * - `containerRef` – attach this to the container whose dimensions are used as the constraint. * - `cardWidth` – inline `width` value to apply to the media card (e.g. `"480px"` or `"auto"`). */ const useMediaCardWidth = ( post: IMedia, maxWidthRatio = 0.8, ): { containerRef: RefObject; cardWidth: string } => { const containerRef = useRef(null); const [cardWidth, setCardWidth] = useState('auto'); useEffect(() => { const imageUrl = post.image || post.thumbnail; if (!imageUrl || !containerRef.current) { setCardWidth('auto'); return; } const container = containerRef.current; const img = new window.Image(); img.onload = () => { const containerH = container.clientHeight; const containerW = container.clientWidth; if (!containerH || !containerW || !img.naturalWidth || !img.naturalHeight) { setCardWidth('auto'); return; } const ratio = img.naturalWidth / img.naturalHeight; const naturalCardWidth = containerH * ratio; const maxCardWidth = containerW * maxWidthRatio; setCardWidth(`${Math.round(Math.min(naturalCardWidth, maxCardWidth))}px`); }; img.onerror = () => setCardWidth('auto'); img.src = imageUrl; }, [post.id, post.image, post.thumbnail, maxWidthRatio]); return { containerRef, cardWidth }; }; export default useMediaCardWidth;