UNPKG

react-lazy-img-observer

Version:

A React component for lazy loading images with Intersection Observer

80 lines (79 loc) 3.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ImageLazy = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const ImageLazy = ({ src, alt, srcSet, sizes, width, height, className, id, extraData, title, useTitleFromAlt = false, viewTransitionName, style, backgroundColor, animationDuration = "0.9s", blurAmount = "20px", fallbackSrc, threshold = 0.5, transitionType = "blur", onLoadComplete, visibleByDefault = false, loadingComponent, }) => { const imageRef = (0, react_1.useRef)(null); const [realSrc, setRealSrc] = (0, react_1.useState)(visibleByDefault ? src : null); const [loaded, setLoaded] = (0, react_1.useState)(false); const [hasError, setHasError] = (0, react_1.useState)(false); (0, react_1.useEffect)(() => { const isDev = typeof window !== "undefined" && window?.location?.hostname?.includes("localhost"); if (isDev) { if (!alt) { console.warn("[ImageLazy] ⚠️ Se recomienda definir el atributo 'alt' por accesibilidad."); } if (!src) { console.warn("[ImageLazy] ⚠️ La prop 'src' está vacía o nula. La imagen no se cargará."); } } }, [alt, src]); (0, react_1.useLayoutEffect)(() => { if (typeof window === "undefined" || visibleByDefault) return; if (typeof IntersectionObserver === "undefined" || !imageRef.current) return; const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setRealSrc(src); observer.unobserve(entry.target); } }); }, { root: null, rootMargin: "0px", threshold }); observer.observe(imageRef.current); return () => observer.disconnect(); }, [src, threshold, visibleByDefault]); const handleLoad = () => { setLoaded(true); onLoadComplete?.(); }; const handleError = () => { if (fallbackSrc && realSrc !== fallbackSrc) { setRealSrc(fallbackSrc); } else { setHasError(true); } }; const isCustom = transitionType === "custom"; const transitionStyles = isCustom ? {} : transitionType === "fade" ? { opacity: loaded ? 1 : 0, transition: `opacity ${animationDuration}`, } : transitionType === "scale" ? { transform: loaded ? "scale(1)" : "scale(1.05)", opacity: loaded ? 1 : 0, transition: `transform ${animationDuration}, opacity ${animationDuration}`, } : { filter: loaded ? "none" : `blur(${blurAmount})`, transition: `filter ${animationDuration}`, }; return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!loaded && loadingComponent, !hasError && ((0, jsx_runtime_1.jsx)("img", { ref: imageRef, src: realSrc ?? undefined, alt: alt, title: title ?? (useTitleFromAlt ? alt : undefined), className: className, width: width, height: height, loading: "lazy", id: id?.toString(), onLoad: handleLoad, onError: handleError, srcSet: realSrc ? srcSet : undefined, sizes: realSrc ? sizes : undefined, style: { backgroundColor: !loaded && backgroundColor ? backgroundColor : undefined, backgroundSize: "cover", backgroundPosition: "center", ...(viewTransitionName ? { viewTransitionName } : {}), ...transitionStyles, ...style, }, ...extraData }))] })); }; exports.ImageLazy = ImageLazy; exports.default = ImageLazy;