UNPKG

@fly4react/image

Version:

Image optimization and lazy loading utilities for React

194 lines (193 loc) 6.98 kB
import { Fragment, jsx } from "react/jsx-runtime"; import react, { useMemo } from "react"; import memo from "@fly4react/memo"; import observer from "@fly4react/observer"; const isServer = "undefined" == typeof window; const isBrowser = "undefined" != typeof window; let preload_preloadQueue = []; const getPreloadQueue = ()=>[ ...preload_preloadQueue ]; const clearPreloadQueue = ()=>{ preload_preloadQueue = []; }; const isImageInPreloadQueue = (src)=>preload_preloadQueue.some((item)=>item.src === src); const addToPreloadQueue = (options)=>{ if (isServer && false !== options.ssr) { if (!isImageInPreloadQueue(options.src)) preload_preloadQueue.push(options); } }; const generatePreloadHTML = ()=>{ if (0 === preload_preloadQueue.length) return ""; const links = preload_preloadQueue.map((options)=>{ const { src, type = "image", priority = "auto", sizes, media } = options; let link = `<link rel="preload" as="${type}" href="${src}"`; if ("auto" !== priority) link += ` importance="${priority}"`; if (sizes) link += ` sizes="${sizes}"`; if (media) link += ` media="${media}"`; link += ">"; return link; }); return links.join("\n"); }; const addImagesToPreloadQueue = (options)=>{ if (isServer) { for (const option of options)if (false !== option.ssr) addToPreloadQueue(option); } }; function useImagePreload(options) { const { src, type = "image", priority = "auto", ssr = true, sizes, media } = options; if ("undefined" == typeof window && ssr) addToPreloadQueue({ src, type, priority, ssr, sizes, media }); return { isAdded: "undefined" == typeof window && ssr }; } const useImagesPreload = (options)=>{ if ("undefined" == typeof window) { for (const option of options)if (false !== option.ssr) addToPreloadQueue(option); } return { isAdded: "undefined" == typeof window }; }; const BackgroundImage = /*#__PURE__*/ react.forwardRef(({ src, style, className, children, preload, transform }, ref)=>{ const transformedSrc = transform ? transform(src) : src; useImagePreload({ src: transformedSrc, priority: preload?.priority || "auto", type: preload?.type || "image", ssr: preload?.ssr ?? true, sizes: preload?.sizes, media: preload?.media }); const styles = useMemo(()=>({ ...style, backgroundImage: `url(${transformedSrc})`, backgroundSize: "cover", backgroundPosition: "center", backgroundRepeat: "no-repeat" }), [ transformedSrc, style ]); return /*#__PURE__*/ jsx("div", { ref: ref, className: className, style: styles, children: children }); }); BackgroundImage.displayName = "BackgroundImage"; const components_BackgroundImage = memo(BackgroundImage); const ContentImage_ContentImage = /*#__PURE__*/ react.forwardRef(({ src, lazyload, preload, transform, ...rest }, ref)=>{ const transformedSrc = transform ? transform(src) : src; useImagePreload({ src: transformedSrc, priority: preload?.priority || "auto", type: preload?.type || "image", ssr: preload?.ssr ?? true, sizes: preload?.sizes, media: preload?.media }); if (lazyload) return /*#__PURE__*/ jsx(observer, { children: /*#__PURE__*/ jsx("img", { ref: ref, src: transformedSrc, ...rest }) }); return /*#__PURE__*/ jsx("img", { ref: ref, src: transformedSrc, ...rest, loading: "eager" }); }); ContentImage_ContentImage.displayName = "ContentImage"; const ContentImage = memo(ContentImage_ContentImage); const ImageLoader_ImageLoader = /*#__PURE__*/ react.forwardRef((props, ref)=>{ if ("content" === props.type) { const { type, children, ...rest } = props; return /*#__PURE__*/ jsx(ContentImage, { ref: ref, ...rest }); } if ("background" === props.type) { const { type, ...rest } = props; return /*#__PURE__*/ jsx(components_BackgroundImage, { ref: ref, ...rest }); } return null; }); ImageLoader_ImageLoader.displayName = "ImageLoader"; const ImageLoader = /*#__PURE__*/ react.memo(ImageLoader_ImageLoader); const ImagePreloadConsumer = ({ ssr = false })=>{ if ("undefined" != typeof window || !ssr) return null; const preloadQueue = getPreloadQueue(); if (0 === preloadQueue.length) return null; return /*#__PURE__*/ jsx(Fragment, { children: preloadQueue.map((options)=>{ const { src, type = "image", priority = "auto", sizes, media } = options; return /*#__PURE__*/ jsx("link", { rel: "preload", as: type, href: src, ..."auto" !== priority && { importance: priority }, ...sizes && { sizes }, ...media && { media } }, `preload-${src}-${type}-${priority}`); }) }); }; const components_ImagePreloadConsumer = ImagePreloadConsumer; const generateImagePreloadHTML = ()=>generatePreloadHTML(); const getImagePreloadQueue = ()=>getPreloadQueue(); const clearImagePreloadQueue = ()=>{ clearPreloadQueue(); }; class ImagePreloadManager { queue = new Map(); addToPage(pageId, preloadOptions) { if (!this.queue.has(pageId)) this.queue.set(pageId, []); this.queue.get(pageId)?.push(...preloadOptions); } getPagePreloadHTML(pageId) { const pageQueue = this.queue.get(pageId) || []; if (0 === pageQueue.length) return ""; const links = pageQueue.map((options)=>{ const { src, type = "image", priority = "auto", sizes, media } = options; let link = `<link rel="preload" as="${type}" href="${src}"`; if ("auto" !== priority) link += ` importance="${priority}"`; if (sizes) link += ` sizes="${sizes}"`; if (media) link += ` media="${media}"`; link += ">"; return link; }); return links.join("\n"); } clearPage(pageId) { this.queue.delete(pageId); } clearAll() { this.queue.clear(); } } const imagePreloadManager = new ImagePreloadManager(); const src_0 = ImageLoader; export { ImageLoader, components_ImagePreloadConsumer as ImagePreloadConsumer, ImagePreloadManager, addImagesToPreloadQueue, addToPreloadQueue, clearImagePreloadQueue, clearPreloadQueue, src_0 as default, generateImagePreloadHTML, generatePreloadHTML, getImagePreloadQueue, getPreloadQueue, imagePreloadManager, isBrowser, isImageInPreloadQueue, isServer, useImagePreload, useImagesPreload };