diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 660d99bc748ab0..16ec296554d743 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -23,7 +23,6 @@ import { useEffect, useRef, useState } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { image as icon, plugins as pluginsIcon } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; -import { useResizeObserver } from '@wordpress/compose'; /** * Internal dependencies @@ -32,6 +31,7 @@ import { unlock } from '../lock-unlock'; import { useUploadMediaFromBlobURL } from '../utils/hooks'; import Image from './image'; import { isValidFileType } from './utils'; +import { useMaxWidthObserver } from './use-max-width-observer'; /** * Module constants @@ -111,10 +111,15 @@ export function ImageEdit( { } = attributes; const [ temporaryURL, setTemporaryURL ] = useState( attributes.blob ); - const figureRef = useRef(); - const [ contentResizeListener, { width: containerWidth } ] = - useResizeObserver(); + const containerRef = useRef(); + // Only observe the max width from the parent container when the parent layout is not flex nor grid. + // This won't work for them because the container width changes with the image. + // TODO: Find a way to observe the container width for flex and grid layouts. + const isMaxWidthContainerWidth = + ! parentLayout || + ( parentLayout.type !== 'flex' && parentLayout.type !== 'grid' ); + const [ maxWidthObserver, maxContentWidth ] = useMaxWidthObserver(); const [ placeholderResizeListener, { width: placeholderWidth } ] = useResizeObserver(); @@ -166,7 +171,7 @@ export function ImageEdit( { } function onSelectImagesList( images ) { - const win = figureRef.current?.ownerDocument.defaultView; + const win = containerRef.current?.ownerDocument.defaultView; if ( images.every( ( file ) => file instanceof win.File ) ) { /** @type {File[]} */ @@ -354,7 +359,10 @@ export function ImageEdit( { Object.keys( borderProps.style ).length > 0 ), } ); - const blockProps = useBlockProps( { ref: figureRef, className: classes } ); + const blockProps = useBlockProps( { + ref: containerRef, + className: classes, + } ); // Much of this description is duplicated from MediaPlaceholder. const { lockUrlControls = false, lockUrlControlsMessage } = useSelect( @@ -445,7 +453,7 @@ export function ImageEdit( { clientId={ clientId } blockEditingMode={ blockEditingMode } parentLayoutType={ parentLayout?.type } - containerWidth={ containerWidth } + maxContentWidth={ maxContentWidth } /> } @@ -464,7 +472,7 @@ export function ImageEdit( { { // The listener cannot be placed as the first element as it will break the in-between inserter. // See https://github.com/WordPress/gutenberg/blob/71134165868298fc15e22896d0c28b41b3755ff7/packages/block-editor/src/components/block-list/use-in-between-inserter.js#L120 - contentResizeListener + isSingleSelected && isMaxWidthContainerWidth && maxWidthObserver } ); diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss index d143e6604d1e73..34f65d690d3d74 100644 --- a/packages/block-library/src/image/editor.scss +++ b/packages/block-library/src/image/editor.scss @@ -113,6 +113,11 @@ figure.wp-block-image:not(.wp-block) { text-align: center; } +// Relatively position the alignment container to support the content resizer. +.wp-block[data-align]:has(> .wp-block-image) { + position: relative; +} + .wp-block-image__crop-area { position: relative; max-width: 100%; diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index f79f078b1eef82..60d83f89129070 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -108,7 +108,7 @@ export default function Image( { clientId, blockEditingMode, parentLayoutType, - containerWidth, + maxContentWidth, } ) { const { url = '', @@ -938,7 +938,7 @@ export default function Image( { // @todo It would be good to revisit this once a content-width variable // becomes available. const maxWidthBuffer = maxWidth * 2.5; - const maxContentWidth = containerWidth || maxWidthBuffer; + const maxResizeWidth = maxContentWidth || maxWidthBuffer; let showRightHandle = false; let showLeftHandle = false; @@ -984,9 +984,9 @@ export default function Image( { } } showHandle={ isSingleSelected } minWidth={ minWidth } - maxWidth={ maxContentWidth } + maxWidth={ maxResizeWidth } minHeight={ minHeight } - maxHeight={ maxContentWidth / ratio } + maxHeight={ maxResizeWidth / ratio } lockAspectRatio={ ratio } enable={ { top: false, @@ -1000,6 +1000,7 @@ export default function Image( { // Clear hardcoded width if the resized width is close to the max-content width. if ( + maxContentWidth && // Only do this if the image is bigger than the container to prevent it from being squished. // TODO: Remove this check if the image support setting 100% width. naturalWidth >= maxContentWidth && diff --git a/packages/block-library/src/image/use-max-width-observer.js b/packages/block-library/src/image/use-max-width-observer.js new file mode 100644 index 00000000000000..684392537fac7a --- /dev/null +++ b/packages/block-library/src/image/use-max-width-observer.js @@ -0,0 +1,32 @@ +/** + * WordPress dependencies + */ +import { useRef } from '@wordpress/element'; +import { useResizeObserver } from '@wordpress/compose'; + +function useMaxWidthObserver() { + const [ contentResizeListener, { width } ] = useResizeObserver(); + const observerRef = useRef(); + + const maxWidthObserver = ( + + ); + + return [ maxWidthObserver, width ]; +} + +export { useMaxWidthObserver };