diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 7113ae2796447d..4ae3a6352124d1 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -30,7 +30,7 @@ import { __experimentalImageEditor as ImageEditor, __experimentalImageEditingProvider as ImageEditingProvider, } from '@wordpress/block-editor'; -import { useEffect, useState, useRef } from '@wordpress/element'; +import { useEffect, useMemo, useState, useRef } from '@wordpress/element'; import { __, sprintf, isRTL } from '@wordpress/i18n'; import { getFilename } from '@wordpress/url'; import { createBlock, switchToBlockType } from '@wordpress/blocks'; @@ -142,6 +142,10 @@ export default function Image( { ); const isLargeViewport = useViewportMatch( 'medium' ); const isWideAligned = includes( [ 'wide', 'full' ], align ); + const [ + { loadedNaturalWidth, loadedNaturalHeight }, + setLoadedNaturalSize, + ] = useState( {} ); const [ isEditingImage, setIsEditingImage ] = useState( false ); const [ externalBlob, setExternalBlob ] = useState(); const clientWidth = useClientWidth( containerRef, [ align ] ); @@ -179,6 +183,23 @@ export default function Image( { } }, [ url, prevUrl ] ); + // 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 ] ); + function onResizeStart() { toggleSelection( false ); } @@ -290,6 +311,12 @@ export default function Image( { src={ temporaryURL || url } alt={ defaultedAlt } onError={ () => onImageError() } + onLoad={ ( event ) => { + setLoadedNaturalSize( { + loadedNaturalWidth: event.target?.naturalWidth, + loadedNaturalHeight: event.target?.naturalHeight, + } ); + } } ref={ imageRef } /> { temporaryURL && } @@ -297,12 +324,6 @@ export default function Image( { /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */ ); - let imageWidthWithinContainer; - let imageHeightWithinContainer; - - const naturalWidth = imageRef.current?.naturalWidth; - const naturalHeight = imageRef.current?.naturalHeight; - const canEditImage = id && naturalWidth && naturalHeight && imageEditing; const allowCrop = ! multiImageSelection && canEditImage && ! isEditingImage; @@ -423,6 +444,9 @@ export default function Image( { ); + let imageWidthWithinContainer; + let imageHeightWithinContainer; + if ( clientWidth && naturalWidth && naturalHeight ) { const exceedMaxWidth = naturalWidth > clientWidth; const ratio = naturalHeight / naturalWidth;