UNPKG

@plone/volto

Version:
102 lines (89 loc) 3.15 kB
import PropTypes from 'prop-types'; import cx from 'classnames'; import { flattenToAppURL, flattenScales } from '@plone/volto/helpers/Url/Url'; /** * Image component * @param {object} item - Context item that has the image field (can also be a catalog brain or summary) * @param {string} imageField - Key of the image field inside the item, or inside the image_scales object of the item if it is a catalog brain or summary * @param {string} src - URL of the image to be used if the item field is not available * @param {string} alt - Alternative text for the image * @param {boolean} loading - (default: eager) set to `lazy` to lazy load the image * @param {boolean} responsive - (default: false) set to `true` to add the `responsive` class to the image * @param {string} className - Additional classes to add to the image */ export default function Image({ item, imageField, src, alt = '', loading = 'eager', responsive = false, className = '', ...imageProps }) { if (!item && !src) return null; // TypeScript hints for editor autocomplete :) /** @type {React.ImgHTMLAttributes<HTMLImageElement>} */ const attrs = {}; attrs.className = cx(className, { responsive }) || undefined; if (!item && src) { attrs.src = src; } else { const isFromRealObject = !item.image_scales; const imageFieldWithDefault = imageField || item.image_field || 'image'; const image = isFromRealObject ? flattenScales(item['@id'], item[imageFieldWithDefault]) : flattenScales( item['@id'], item.image_scales[imageFieldWithDefault]?.[0], ); if (!image) return null; const isSvg = image['content-type'] === 'image/svg+xml'; // In case `base_path` is present (`preview_image_link`) use it as base path const basePath = image.base_path || item['@id']; attrs.src = `${flattenToAppURL(basePath)}/${image.download}`; attrs.width = image.width; attrs.height = image.height; if (!isSvg && image.scales && Object.keys(image.scales).length > 0) { const sortedScales = Object.values({ ...image.scales, original: { download: `${image.download}`, width: image.width, height: image.height, }, }).sort((a, b) => { if (a.width > b.width) return 1; else if (a.width < b.width) return -1; else return 0; }); attrs.srcSet = sortedScales .map( (scale) => `${flattenToAppURL(basePath)}/${scale.download} ${scale.width}w`, ) .join(', '); } } if (loading === 'lazy') { attrs.loading = 'lazy'; attrs.decoding = 'async'; } else { attrs.fetchpriority = 'high'; } return <img {...attrs} alt={alt} {...imageProps} />; } Image.propTypes = { item: PropTypes.shape({ '@id': PropTypes.string, image_field: PropTypes.string, image_scales: PropTypes.object, image: PropTypes.object, }), imageField: PropTypes.string, src: PropTypes.string, alt: PropTypes.string.isRequired, loading: PropTypes.string, responsive: PropTypes.bool, className: PropTypes.string, };