UNPKG

@gravityforms/components

Version:

UI components for use in Gravity Forms development. Both React and vanilla js flavors.

277 lines (261 loc) 8.24 kB
import { React, PropTypes, classnames } from '@gravityforms/libraries'; import { spacerClasses } from '@gravityforms/utils'; const { forwardRef } = React; const possiblePositions = [ 'center', 'top', 'bottom', 'left', 'right', 'top left', 'top center', 'top right', 'center left', 'center center', 'center right', 'bottom left', 'bottom center', 'bottom right', ]; /** * @module Image * @description An image component in react. * * @since 1.1.15 * * @param {object} props Component props. * @param {string} props.altText The alt text for the image. * @param {boolean} props.asBg Whether the image is a background image or not. * @param {number} props.aspectRatio The aspect ratio of the image, as width / height. This only applies to background images. * @param {JSX.Element|string} props.caption The caption for the image. This only applies if the image is a background image. * @param {object} props.captionAttributes Attributes for the image caption element. * @param {object} props.customAttributes Custom attributes for the component. * @param {string|Array|object} props.customClasses Custom classes for the component. * @param {number} props.height The height of the image, in px. This only applies if the image is a background image. * @param {object} props.imageAttributes Attributes for the image element. * @param {string} props.imagePosition The position of the image, if it is a background image. * @param {boolean} props.lazyload Whether to lazyload the image or not. * @param {string|number|Array|object} props.spacing The spacing for the component, as a string, number, array, or object. * @param {string} props.url The url of the image. * @param {number} props.width The width of the image, in px. * @param {object|null} ref Ref to the component. * * @return {JSX.Element} Return the function image component in React. * * @example * import Image from '@gravityforms/components/react/admin/elements/Image'; * * return ( * <Image * asBg={ true } * aspectRatio={ 1.5 } * url="https://path.to.image/" * /> * ); * */ const Image = forwardRef( ( { altText = '', asBg = false, aspectRatio = 0, caption = null, captionAttributes = {}, customAttributes = {}, customClasses = [], height = 0, imageAttributes = {}, imagePosition = 'center', lazyload = false, spacing = '', url = '', width = 0, }, ref ) => { /** * @function getBackgroundPosition * @description Get the background position for the background image. * * @param {string} position The background image position. * * @return {string} The position of the background image. */ const getBackgroundPosition = ( position ) => { if ( ! possiblePositions.includes( position ) ) { return ''; } return position; }; /** * @function getBackgroundImage * @description Get the markup in react for a background image. * * @since 1.1.15 * * @param {object} props Props for the background image. * @param {object} props.attributes The attributes for the image wrapper. * @param {object} props.imageAttributes The attributes for the background image. * * @return {JSX.Element} The background image. */ const getBackgroundImage = ( { attributes, imageAttributes: bgImageAttributes, } ) => { return ( <div { ...attributes }> <div { ...bgImageAttributes } /> </div> ); }; /** * @function getImageCaption * @description Get the markup in react for a caption for the image component. * * @since 1.1.15 * * @param {object} props Props for the caption. * @param {JSX.Element|string} props.children React element children. * @param {object} props.customAttributes Custom attributes for the caption. * @param {string|Array|object} props.customClasses Custom classes for the caption. * * @return {JSX.Element} The caption for the image component. */ const getImageCaption = ( { children = null, customAttributes: captionCustomAttributes = {}, customClasses: captionCustomClasses = [], } ) => { const captionAttrs = { className: classnames( { 'gform-image__caption': true, }, captionCustomClasses ), ...captionCustomAttributes, }; return ( <figcaption { ...captionAttrs }> { children } </figcaption> ); }; /** * @function getImageWithCaption * @description Get the markup in react for an image with caption. * * @since 1.1.15 * * @param {object} props Props for the image with caption. * @param {object} props.attributes The attributes for the image wrapper. * @param {JSX.Element|string} props.caption The caption for the image, can be a string or react children. * @param {object} props.captionAttributes The attributes for the caption element. * @param {object} props.imageAttributes The attributes for the image. * * @return {JSX.Element} The image with caption. */ const getImageWithCaption = ( { attributes, caption: captionElement, captionAttributes: captionElementAttributes, imageAttributes: imgAttributes, } ) => { return ( <figure { ...attributes }> <img { ...imgAttributes } />{ /* eslint-disable-line jsx-a11y/alt-text */ } { captionElement && getImageCaption( { ...captionElementAttributes, children: captionElement, } ) } </figure> ); }; const attrs = { className: classnames( { 'gform-image': true, 'gform-image--bg': asBg, ...spacerClasses( spacing ), }, customClasses ), ref, ...customAttributes, }; const { customClasses: imageCustomClasses, ...restImageAttributes } = imageAttributes; const imageAttrs = { ...restImageAttributes, className: classnames( { 'gform-image__image': true, }, imageCustomClasses || [] ), }; if ( asBg ) { // Background image. imageAttrs.style = { backgroundImage: `url('${ url }')`, backgroundSize: 'cover', backgroundRepeat: 'no-repeat', backgroundPosition: getBackgroundPosition( imagePosition ), // Use the function to ensure it's a valid position ...( imageAttributes.style || {} ), }; if ( aspectRatio ) { const padding = Math.round( ( 10000 / aspectRatio ) ) / 100; // Round to nearest 2 decimals. imageAttrs.style.paddingBottom = `${ padding }%`; } if ( width ) { attrs.style = { ...( customAttributes.style || {} ), width: `${ width }px`, }; } imageAttrs.role = 'img'; imageAttrs[ 'aria-label' ] = altText; } else { // Normal image. const imageStyles = {}; imageAttrs.src = url; imageAttrs.alt = altText; if ( width ) { imageStyles.width = `${ width }px`; } if ( height ) { imageStyles.height = `${ height }px`; } if ( 'lazy' === lazyload ) { imageAttrs.lazyload = 'lazy'; } imageAttrs.style = { ...( imageAttributes.style || {} ), ...imageStyles, }; } return asBg ? getBackgroundImage( { attributes: attrs, imageAttributes: imageAttrs, } ) : ( getImageWithCaption( { attributes: attrs, imageAttributes: imageAttrs, caption, captionAttributes, } ) ); } ); Image.propTypes = { altText: PropTypes.string, asBg: PropTypes.bool, aspectRatio: PropTypes.number, caption: PropTypes.node, captionAttributes: PropTypes.object, customAttributes: PropTypes.object, customClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), height: PropTypes.number, imageAttributes: PropTypes.object, imagePosition: PropTypes.string, lazyload: PropTypes.bool, spacing: PropTypes.oneOfType( [ PropTypes.string, PropTypes.number, PropTypes.array, PropTypes.object, ] ), url: PropTypes.string, width: PropTypes.number, }; Image.displayName = 'Image'; export default Image;