@fly4react/image
Version:
Image optimization and lazy loading utilities for React
194 lines (193 loc) • 6.98 kB
JavaScript
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 };