UNPKG

@shopgate/engage

Version:
179 lines (175 loc) 6.03 kB
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose"; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import isEqual from 'lodash/isEqual'; import classnames from 'classnames'; import { logger } from '@shopgate/pwa-core'; import appConfig, { themeConfig } from '@shopgate/pwa-common/helpers/config'; import Image from '@shopgate/pwa-common/components/Image'; import PlaceholderIcon from '@shopgate/pwa-ui-shared/icons/PlaceholderIcon'; import SurroundPortals from '@shopgate/pwa-common/components/SurroundPortals'; import { withWidgetSettings } from "../../../core/hocs/withWidgetSettings"; import { PORTAL_PRODUCT_IMAGE } from "../../../components/constants"; import ProductImagePlaceholder from "./ProductImagePlaceholder"; import styles from "./style"; import connect from "./connector"; import { jsx as _jsx } from "react/jsx-runtime"; const { colors } = themeConfig; /** * The product image component. * This component will behave like the core Image component with the additional * feature of showing a placeholder in case no src property has been passed * or the given source image cannot be loaded. */ let ProductImage = /*#__PURE__*/function (_Component) { /** * Component constructor * @param {Object} props The component properties */ function ProductImage(props) { var _this; _this = _Component.call(this, props) || this; /** * Triggered when the image could not be loaded for some reason. */ _this.imageLoadingFailed = () => { _this.setState({ showPlaceholder: true, imageLoadingFailed: true }); }; /** * Sets the image ratio based on width and height. * @return {number} The image ratio. */ _this.getImageRatio = () => { if (_this.props.ratio) { const [x, y] = _this.props.ratio; return (y / x).toFixed(3); } const { width, height } = _this.props.resolutions[_this.props.resolutions.length - 1]; return (height / width).toFixed(3); }; logger.assert(!props.srcmap, 'Use of srcmap prop is deprecated. Use resolutions instead'); const showPlaceholder = !props.src && (props.srcmap === null || props.srcmap.length === 0); _this.state = { showPlaceholder, imageLoadingFailed: false }; return _this; } /** * Called when the component props change. * @param {Object} nextProps The new component properties */ _inheritsLoose(ProductImage, _Component); var _proto = ProductImage.prototype; _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) { // Disable the placeholder to give the real image a new chance to load. // If we do not have a src property set then just show the placeholder instead. const showPlaceholder = !nextProps.src && (!nextProps.srcmap || nextProps.srcmap.length === 0); this.setState({ showPlaceholder }); } /** * Should component update given the new props? * @param {Object} nextProps The next component props. * @param {Object} nextState The next state. * @return {boolean} Update or not. */; _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState); }; /** * Renders the component. * @returns {JSX.Element} */ _proto.render = function render() { const { noBackground, className, placeholderSrc } = this.props; let { showInnerShadow } = this.props.widgetSettings; if (typeof showInnerShadow === 'undefined') { showInnerShadow = !appConfig.hideProductImageShadow; } if (this.state.imageLoadingFailed || this.state.showPlaceholder) { // Image is not present or could not be loaded, show a placeholder. return /*#__PURE__*/_jsx(SurroundPortals, { portalName: PORTAL_PRODUCT_IMAGE, children: /*#__PURE__*/_jsx("div", { className: classnames(styles.placeholderContainer(this.getImageRatio()), { [styles.innerShadow]: showInnerShadow, [className]: !!className }), children: placeholderSrc ? /*#__PURE__*/_jsx(ProductImagePlaceholder, { src: placeholderSrc, showInnerShadow: showInnerShadow, noBackground: noBackground }) : /*#__PURE__*/_jsx("div", { "aria-hidden": true, className: styles.placeholderContent, "data-test-id": "placeHolder", children: /*#__PURE__*/_jsx(PlaceholderIcon, { className: styles.placeholder }) }) }) }); } // Return the actual image. return /*#__PURE__*/_jsx(SurroundPortals, { portalName: PORTAL_PRODUCT_IMAGE, portalProps: { src: this.props.src, resolutions: this.props.resolutions }, children: /*#__PURE__*/_jsx("div", { className: `${className} engage__product__product-image`, children: /*#__PURE__*/_jsx(Image, { ...this.props, className: showInnerShadow ? styles.innerShadow : '', backgroundColor: noBackground ? 'transparent' : colors.light, onError: this.imageLoadingFailed, "aria-hidden": !this.props.alt }) }) }); }; return ProductImage; }(Component); /** * See Image component manual for detailed description about the component property types. */ ProductImage.defaultProps = { alt: null, animating: true, className: null, forcePlaceholder: false, highestResolutionLoaded: () => {}, noBackground: false, ratio: null, resolutions: [{ width: 50, height: 50, blur: 2 }, { width: 440, height: 440 }], src: null, srcmap: null, placeholderSrc: null, widgetSettings: {} }; export { ProductImage as UnwrappedProductImage }; export default connect(withWidgetSettings(ProductImage, '@shopgate/engage/product/ProductImage'));