UNPKG

ima-ui-atoms

Version:
232 lines (191 loc) 7.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _propTypes = _interopRequireDefault(require("prop-types")); var _react = _interopRequireDefault(require("react")); var _Loader = _interopRequireDefault(require("../loader/Loader")); var _Sizer = _interopRequireDefault(require("../sizer/Sizer")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } const MIN_EXTENDED_PADDING = 300; const TIME_TO_SHOW_LOADER = 3000; /** * Html image * * @namespace ima.ui.atom.image * @module ima.ui.atom */ class HtmlImage extends _react.default.PureComponent { static get contextTypes() { return { $Utils: _propTypes.default.object }; } static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.src !== prevState.src || nextProps.srcSet !== prevState.srcSet || nextProps.sizes !== prevState.sizes) { return { showLoader: prevState.showLoader || false, src: nextProps.src, srcSet: nextProps.srcSet, sizes: nextProps.sizes, noloading: nextProps.noloading || prevState.noloading || false }; } return null; } constructor(props, context) { super(props, context); this.state = {}; this._mounted = false; this._visibleInViewport = false; this._loadIndicatorTimer = null; this._registeredVisibilityId = null; this._onVisibilityWriter = this.onVisibilityWriter.bind(this); this._rootElement = _react.default.createRef(); this._helper = this.utils.$UIComponentHelper; this._settings = this.utils.$Settings; } get utils() { return this.context.$Utils || this.props.$Utils; } get useIntersectionObserver() { return this.props.useIntersectionObserver !== undefined ? this.props.useIntersectionObserver : this._settings.plugin.uiAtoms.useIntersectionObserver.images; } get disableNoScript() { return this.props.disableNoScript !== undefined ? this.props.disableNoScript : this._settings.plugin.uiAtoms.disableNoScript.images; } componentDidMount() { this._mounted = true; if (this.state.noloading === false) { this._registerToCheckingVisibility(); } } componentWillUnmount() { this._mounted = false; this._unregisterToCheckingVisibility(); } componentDidUpdate(prevProps) { if (this.props.src !== prevProps.src || this.props.srcSet !== prevProps.srcSet || this.props.sizes !== prevProps.sizes) { this._visibleInViewport = false; if ((prevProps.noloading || this.props.noloading) === false) { this._registerToCheckingVisibility(); } } } render() { return _react.default.createElement("div", _extends({ ref: this._rootElement, className: this._helper.cssClasses({ 'atm-image': true, 'atm-overflow': true, 'atm-placeholder': !this.state.noloading, 'atm-responsive': this.props.layout === 'responsive', 'atm-fill': this.props.layout === 'fill' }, this.props.className), style: this.props.layout === 'responsive' ? {} : { width: this.props.width || 'auto', height: this.props.height || 'auto' } }, this._helper.getDataProps(this.props)), this.props.layout === 'responsive' ? _react.default.createElement(_Sizer.default, { width: this.props.width, height: this.props.height, placeholder: !this.state.noloading }) : null, this.state.noloading ? _react.default.createElement("img", _extends({ src: this.props.src, srcSet: this.props.srcSet, sizes: this.props.sizes, alt: this.props.alt, onLoad: this.props.onLoad, onError: this.props.onError, className: this._helper.cssClasses({ 'atm-fill': true, 'atm-loaded': this.state.noloading && this._visibleInViewport }) }, this._helper.getAriaProps(this.props))) : null, this.state.showLoader && !this.state.noloading ? _react.default.createElement(_Loader.default, { mode: "small", layout: "center" }) : null, !this.disableNoScript && _react.default.createElement("noscript", { dangerouslySetInnerHTML: { __html: `<img src="${this.props.src || ''}" srcset="${this.props.srcSet || ''}" sizes="${this.props.sizes || ''}" alt="${this.props.alt || ''}" class="${this._helper.cssClasses('atm-fill atm-loaded')}" ${this._helper.serializeObjectToNoScript(this._helper.getAriaProps(this.props))}/>` } })); } onVisibilityWriter(visibility, observer) { if (this._visibleInViewport === false && visibility > 0) { observer && observer.disconnect(); this._visibleInViewport = true; this._unregisterToCheckingVisibility(); this._preLoadImage(); } } _unregisterToCheckingVisibility() { if (this._registeredVisibilityId) { this._helper.visibility.unregister(this._registeredVisibilityId); this._registeredVisibilityId = null; } } _registerToCheckingVisibility() { let extendedPadding = this.props.extendedPadding || Math.max(Math.round(this._helper.componentPositions.getWindowViewportRect().height), MIN_EXTENDED_PADDING); this._registeredVisibilityId = this._helper.visibility.register(this._helper.getVisibilityReader(this._rootElement.current, { extendedPadding, useIntersectionObserver: this.useIntersectionObserver, width: this.props.width, height: this.props.height }), this._helper.wrapVisibilityWriter(this._onVisibilityWriter)); } _preLoadImage() { this._loadIndicatorTimer = setTimeout(() => { this.setState({ showLoader: true }); }, TIME_TO_SHOW_LOADER); let image = new Image(); image.onload = () => { this._imageIsLoaded(); }; image.onerror = () => { this._imageIsLoaded(); }; let { src, srcSet, sizes } = this.props; if (srcSet && this._areResponsiveImagesSupported(image)) { if (sizes) { image.sizes = sizes; } image.srcset = srcSet; } else if (src) { image.src = src; } if (!srcSet && !src) { this._imageIsLoaded(); } } _imageIsLoaded() { if (!this._loadIndicatorTimer) { return; } clearTimeout(this._loadIndicatorTimer); this._loadIndicatorTimer = null; if (this._mounted) { this.setState({ noloading: true, showLoader: false }); } } _areResponsiveImagesSupported(image) { return 'srcset' in image && 'sizes' in image; } } exports.default = HtmlImage;