// Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useMemo, useCallback, useState, useRef } from 'react'; import { computeBlurHashUrl } from '../util/computeBlurHashUrl.js'; export type Props = React.ImgHTMLAttributes & Readonly<{ blurHash?: string; alt: string; intrinsicWidth?: number; intrinsicHeight?: number; }>; export function ImageOrBlurhash({ src: imageSrc, blurHash, alt, intrinsicWidth, intrinsicHeight, ...rest }: Props): JSX.Element { const ref = useRef(null); const [isLoaded, setIsLoaded] = useState(false); const blurHashUrl = useMemo(() => { return blurHash ? computeBlurHashUrl(blurHash, intrinsicWidth, intrinsicHeight) : undefined; }, [blurHash, intrinsicWidth, intrinsicHeight]); const onLoad = useCallback(() => { // Don't let background blurhash be visible at the same time as the image // while React propagates the `isLoaded` change. if (ref.current) { ref.current.style.backgroundImage = 'none'; } setIsLoaded(true); }, [ref]); const src = imageSrc ?? blurHashUrl; return ( {alt} ); }