"use client"; import { useEffect, useRef, useState } from "react"; import type { ThirdwebClient } from "../../../../client/client.js"; import { resolveScheme } from "../../../../utils/ipfs.js"; import { radius, type Theme } from "../../../core/design-system/index.js"; import { Container } from "./basic.js"; import { Skeleton } from "./Skeleton.js"; /** * @internal */ export const Img: React.FC<{ width?: string; height?: string; src?: string; alt?: string; loading?: "eager" | "lazy"; className?: string; style?: React.CSSProperties; fallbackImage?: string; fallback?: React.ReactNode; client: ThirdwebClient; skeletonColor?: keyof Theme["colors"]; }> = (props) => { const [_status, setStatus] = useState<"pending" | "fallback" | "loaded">( "pending", ); const imgRef = useRef(null); const propSrc = props.src; const widthPx = `${props.width}px`; const heightPx = `${props.height || props.width}px`; const getSrc = () => { if (propSrc === undefined) { return undefined; } try { return resolveScheme({ client: props.client, uri: propSrc, }); } catch { return props.src; } }; const src = getSrc(); const status = src === undefined ? "pending" : src === "" ? "fallback" : _status; const isLoaded = status === "loaded"; useEffect(() => { const imgEl = imgRef.current; if (!imgEl) { return; } if (imgEl.complete) { setStatus("loaded"); } else { function handleLoad() { setStatus("loaded"); } imgEl.addEventListener("load", handleLoad); return () => { imgEl.removeEventListener("load", handleLoad); }; } return; }, []); return (
{status === "pending" && ( )} {status === "fallback" && (props.fallback || (
))} {props.alt { if ( props.fallbackImage && e.currentTarget.src !== props.fallbackImage ) { e.currentTarget.src = props.fallbackImage; } else { setStatus("fallback"); } }} onLoad={() => { setStatus("loaded"); }} src={src || undefined} style={{ height: !isLoaded ? 0 : props.height ? `${props.height}px` : undefined, objectFit: "contain", opacity: isLoaded ? 1 : 0, transition: "opacity 0.4s ease", userSelect: "none", visibility: isLoaded ? "visible" : "hidden", width: !isLoaded ? 0 : props.width ? `${props.width}px` : undefined, ...props.style, }} width={props.width} />
); };