@findify/react-components
Version:
Findify react UI components
69 lines (68 loc) • 2.91 kB
JSX
/**
* @module components/common/Image
*/
import React, { useRef, useState, useEffect, useMemo } from 'react';
import cx from 'classnames';
import styles from 'components/common/Image/styles.css';
var LazyStrategy;
(function (LazyStrategy) {
LazyStrategy[LazyStrategy["native"] = 0] = "native";
LazyStrategy[LazyStrategy["observer"] = 1] = "observer";
LazyStrategy[LazyStrategy["none"] = 2] = "none";
})(LazyStrategy || (LazyStrategy = {}));
const lazyStrategy = (() => {
if ('loading' in HTMLImageElement.prototype)
return LazyStrategy.native;
if ('IntersectionObserver' in global)
return LazyStrategy.observer;
return LazyStrategy.none;
})();
const useViewPort = (lazyOffset = 200) => {
const [ready, setReady] = useState(false);
const element = useRef(null);
useEffect(() => {
if (!element.current || ready)
return;
const handleIntersect = (entries, observer) => {
if (!element.current)
return;
entries.forEach((entry) => {
if (entry.isIntersecting) {
setReady(true);
observer.unobserve(entry.target);
}
});
};
const observer = new IntersectionObserver(handleIntersect, {
root: null,
rootMargin: `${lazyOffset}px`,
threshold: 0,
});
observer.observe(element.current);
return () => observer && observer.unobserve(element.current);
}, [element]);
return { ready, element };
};
const getSource = (src, fx) => useMemo(() => {
const res = (fx && fx(src, window?.innerWidth)) || src;
if (!res)
return [];
return (typeof res === 'string' ? [res] : res).filter((value, index, self) => value && self.indexOf(value) === index);
}, [src]);
const ImageView = ({ lazy, src, alt, aspectRatio, register, isReady = true }) => {
const aspect = aspectRatio > 0;
const _src = Array.isArray(src) ? src : [src];
return <div ref={register} style={{
paddingBottom: aspect ? `${aspectRatio * 100}%` : 'auto',
}} className={cx(styles.root, (aspect && styles.aspect) || styles.static, _src.length > 1 && styles.multiple)}>
{_src.map((src, index) => (<img src={src} key={src} alt={alt} decode="async" loading={lazy ? 'lazy' : undefined} className={cx(styles.image, index && styles.next)} display-if={isReady}/>))}
</div>;
};
export default ({ lazy, getSrc, src, lazyOffset, ...props }) => {
const _src = getSource(src, getSrc);
if (lazyStrategy === LazyStrategy.native || lazyStrategy === LazyStrategy.none || !lazy) {
return <ImageView src={_src} lazy={lazy && lazyStrategy === LazyStrategy.native} {...props}/>;
}
const { ready, element } = useViewPort(lazyOffset);
return <ImageView src={_src} lazy={true} register={element} isReady={ready} {...props}/>;
};