UNPKG

@findify/react-components

Version:
69 lines (68 loc) 2.91 kB
/** * @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}/>; };