Files
portifolio-evandrodevbr/app/components/animations/LazyRevealImage.tsx
T

64 lines
1.6 KiB
TypeScript

"use client";
import { motion } from "framer-motion";
import Image, { type StaticImageData } from "next/image";
import { useState } from "react";
import { useReducedMotion } from "@/app/hooks/useReducedMotion";
interface LazyRevealImageProps {
src: string | StaticImageData;
alt: string;
className?: string;
imageClassName?: string;
sizes?: string;
}
export function LazyRevealImage({
src,
alt,
className = "",
imageClassName = "object-cover",
sizes = "(max-width: 1024px) 100vw, 50vw",
}: Readonly<LazyRevealImageProps>) {
const shouldReduceMotion = useReducedMotion();
const [loaded, setLoaded] = useState(false);
return (
<motion.div
className={`relative ${className}`.trim()}
initial={
shouldReduceMotion
? { opacity: 0 }
: { opacity: 0, y: 20, scale: 1.02 }
}
animate={
loaded
? shouldReduceMotion
? { opacity: 1 }
: { opacity: 1, y: 0, scale: 1 }
: shouldReduceMotion
? { opacity: 0 }
: { opacity: 0, y: 20, scale: 1.02 }
}
transition={{
duration: shouldReduceMotion ? 0.25 : 0.75,
ease: [0.16, 1, 0.3, 1],
}}
style={{
willChange: !shouldReduceMotion ? "transform, opacity" : undefined,
}}
>
<Image
src={src}
alt={alt}
fill
loading="lazy"
sizes={sizes}
placeholder={typeof src === "string" ? "empty" : "blur"}
onLoad={() => setLoaded(true)}
className={imageClassName}
/>
</motion.div>
);
}