import { useState, useMemo, useRef } from '@wordpress/element'; import { ImagePlaceholder } from './ImagePlaceholder.jsx'; import { useDispatch } from '@wordpress/data'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { isURL } from '@wordpress/url'; export function Image( { elementAttributes, temporaryURL, onSelectImage, onSelectURL, onUploadError, dynamicTagValue, isSelected, clientId, linkHtmlAttributes, attributes, } ) { const imageRef = useRef(); const [ { loadedNaturalWidth, loadedNaturalHeight }, setLoadedNaturalSize, ] = useState( {} ); const { selectBlock } = useDispatch( blockEditorStore ); // Get naturalWidth and naturalHeight from image ref, and fall back to loaded natural // width and height. This resolves an issue in Safari where the loaded natural // witdth and height is otherwise lost when switching between alignments. // See: https://github.com/WordPress/gutenberg/pull/37210. const { naturalWidth, naturalHeight } = useMemo( () => { return { naturalWidth: imageRef.current?.naturalWidth || loadedNaturalWidth || undefined, naturalHeight: imageRef.current?.naturalHeight || loadedNaturalHeight || undefined, }; }, [ loadedNaturalWidth, loadedNaturalHeight, imageRef.current?.complete, ] ); const imageSrc = useMemo( () => { if ( dynamicTagValue?.[ 0 ]?.replacement && isURL( dynamicTagValue?.[ 0 ]?.replacement ) ) { return dynamicTagValue?.[ 0 ]?.replacement; } if ( temporaryURL ) { return temporaryURL; } if ( elementAttributes?.src ) { if ( elementAttributes?.src.startsWith( '{{' ) ) { return generateblocksBlockMedia.squarePlaceholder; } return elementAttributes.src; } }, [ dynamicTagValue, temporaryURL, elementAttributes?.src ] ); /* eslint-disable jsx-a11y/alt-text */ // The alt tag below is added via elementAttributes. /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ // The img element below is interactive if it's not selected. // This allows us to not render the surrounding `<div>` with the `blockProps` // unless the image is selected. /* eslint-disable jsx-a11y/anchor-is-valid */ // We disable the anchor in the editor only. const image = ( <> <img width={ naturalWidth } height={ naturalHeight } { ...elementAttributes } src={ imageSrc } ref={ imageRef } onLoad={ ( event ) => { setLoadedNaturalSize( { loadedNaturalWidth: event.target?.naturalWidth, loadedNaturalHeight: event.target?.naturalHeight, } ); } } onClick={ () => { if ( isSelected ) { return; } selectBlock( clientId ); } } onKeyDown={ () => { if ( isSelected ) { return; } selectBlock( clientId ); } } role={ ! isSelected ? 'button' : undefined } tabIndex={ ! isSelected ? 0 : undefined } /> </> ); return ( <> { ( !! temporaryURL || !! elementAttributes?.src ) ? ( <> { linkHtmlAttributes.href ? ( <a { ...linkHtmlAttributes } href="#" > { image } </a> ) : ( image ) } </> ) : ( <ImagePlaceholder onSelectImage={ onSelectImage } onSelectURL={ onSelectURL } onUploadError={ onUploadError } uniqueId={ attributes?.uniqueId ?? '' } /> ) } </> ); /* eslint-enable jsx-a11y/alt-text */ /* eslint-enable jsx-a11y/no-noninteractive-element-interactions */ /* eslint-enable jsx-a11y/anchor-is-valid */ }