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 = (
+
+ { contentResizeListener }
+
+ );
+
+ return [ maxWidthObserver, width ];
+}
+
+export { useMaxWidthObserver };