59 lines
1.4 KiB
TypeScript
59 lines
1.4 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect } from "react";
|
|
import Image, { ImageProps } from "next/image";
|
|
import { blurHashToDataURL } from "@/lib/blurhash";
|
|
|
|
export interface BlurHashImageProps extends Omit<ImageProps, "blurDataURL" | "placeholder"> {
|
|
blurHash?: string | null;
|
|
fallbackSrc?: string;
|
|
}
|
|
|
|
export function BlurHashImage({
|
|
src,
|
|
blurHash,
|
|
alt,
|
|
fallbackSrc = "/placeholder.png",
|
|
className = "",
|
|
style,
|
|
...restProps
|
|
}: BlurHashImageProps) {
|
|
const [imgSrc, setImgSrc] = useState<string>(typeof src === "string" ? src : "");
|
|
const [blurDataUrl, setBlurDataUrl] = useState<string>(() => blurHashToDataURL(blurHash));
|
|
const [hasError, setHasError] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (typeof src === "string") {
|
|
setImgSrc(src);
|
|
}
|
|
}, [src]);
|
|
|
|
useEffect(() => {
|
|
setBlurDataUrl(blurHashToDataURL(blurHash));
|
|
}, [blurHash]);
|
|
|
|
const handleError = (e: React.SyntheticEvent<HTMLImageElement, Event>) => {
|
|
if (!hasError && fallbackSrc) {
|
|
setHasError(true);
|
|
setImgSrc(fallbackSrc);
|
|
}
|
|
if (restProps.onError) {
|
|
restProps.onError(e);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Image
|
|
{...restProps}
|
|
src={imgSrc || fallbackSrc}
|
|
alt={alt || "Image"}
|
|
placeholder="blur"
|
|
blurDataURL={blurDataUrl}
|
|
onError={handleError}
|
|
className={className}
|
|
style={style}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default BlurHashImage;
|