@shopgate/engage
Version:
Shopgate's ENGAGE library.
179 lines (175 loc) • 6.03 kB
JavaScript
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'));