Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix resizing to max width in classic themes #64819

Merged
merged 4 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions packages/block-library/src/image/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -110,10 +110,15 @@ export function ImageEdit( {
metadata,
} = 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 altRef = useRef();
useEffect( () => {
Expand Down Expand Up @@ -160,7 +165,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[]} */
Expand Down Expand Up @@ -348,7 +353,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(
Expand Down Expand Up @@ -436,7 +444,7 @@ export function ImageEdit( {
clientId={ clientId }
blockEditingMode={ blockEditingMode }
parentLayoutType={ parentLayout?.type }
containerWidth={ containerWidth }
maxContentWidth={ maxContentWidth }
/>
<MediaPlaceholder
icon={ <BlockIcon icon={ icon } /> }
Expand All @@ -455,7 +463,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
}
</>
);
Expand Down
5 changes: 5 additions & 0 deletions packages/block-library/src/image/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,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%;
Expand Down
9 changes: 5 additions & 4 deletions packages/block-library/src/image/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export default function Image( {
clientId,
blockEditingMode,
parentLayoutType,
containerWidth,
maxContentWidth,
} ) {
const {
url = '',
Expand Down Expand Up @@ -934,7 +934,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;
Expand Down Expand Up @@ -980,9 +980,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,
Expand All @@ -996,6 +996,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 &&
Expand Down
32 changes: 32 additions & 0 deletions packages/block-library/src/image/use-max-width-observer.js
Original file line number Diff line number Diff line change
@@ -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 = (
<div
// Some themes set max-width on blocks.
className="wp-block"
aria-hidden="true"
style={ {
position: 'absolute',
inset: 0,
width: '100%',
height: 0,
margin: 0,
} }
ref={ observerRef }
>
{ contentResizeListener }
</div>
);

return [ maxWidthObserver, width ];
}

export { useMaxWidthObserver };
Loading