From 3a9178a0f07063b20d7a1e4344c6e29e8b5fd0ae Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 3 Aug 2023 10:06:59 -0600 Subject: [PATCH] Image block: Fix stretched images constrained by max-width (#53274) * Fix dragging to resize from stretching image in the frontend * Add image block v7 deprecation * Update deprecation comment * Prevent image losing its aspect ratio at smaller window dimensions * Revert "Prevent image losing its aspect ratio at smaller window dimensions" This reverts commit 8ac9f8c4469d5e6cdfd5aa06bc0c89a37771f7c5. --------- Co-authored-by: scruffian --- packages/block-library/src/image/block.json | 4 +- .../block-library/src/image/deprecated.js | 209 +++++++++++++++++- packages/block-library/src/image/image.js | 52 +++-- packages/block-library/src/image/save.js | 2 - ...ed-v2-add-is-resized-class.serialized.html | 2 +- ...cated-v3-add-align-wrapper.serialized.html | 2 +- ...ed-v4-remove-align-wrapper.serialized.html | 2 +- ...-v6-add-style-width-height.serialized.html | 2 +- ...ted-v7-string-width-height-attributes.html | 3 + ...ted-v7-string-width-height-attributes.json | 15 ++ ...string-width-height-attributes.parsed.json | 15 ++ ...ng-width-height-attributes.serialized.html | 3 + 12 files changed, 278 insertions(+), 33 deletions(-) create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 7c8b2c2715c99a..fad94a62e5a755 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -64,10 +64,10 @@ "__experimentalRole": "content" }, "width": { - "type": "number" + "type": "string" }, "height": { - "type": "number" + "type": "string" }, "aspectRatio": { "type": "string" diff --git a/packages/block-library/src/image/deprecated.js b/packages/block-library/src/image/deprecated.js index edbabd7fb2d835..d159009b173739 100644 --- a/packages/block-library/src/image/deprecated.js +++ b/packages/block-library/src/image/deprecated.js @@ -740,4 +740,211 @@ const v6 = { }, }; -export default [ v6, v5, v4, v3, v2, v1 ]; +/** + * Deprecation for converting to string width and height block attributes and + * removing the width and height img element attributes which are not needed + * as they get added by the TODO hook. + * + * @see https://github.com/WordPress/gutenberg/pull/53274 + */ +const v7 = { + attributes: { + align: { + type: 'string', + }, + url: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'src', + __experimentalRole: 'content', + }, + alt: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + __experimentalRole: 'content', + }, + caption: { + type: 'string', + source: 'html', + selector: 'figcaption', + __experimentalRole: 'content', + }, + title: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'title', + __experimentalRole: 'content', + }, + href: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'href', + __experimentalRole: 'content', + }, + rel: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'rel', + }, + linkClass: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'class', + }, + id: { + type: 'number', + __experimentalRole: 'content', + }, + width: { + type: 'number', + }, + height: { + type: 'number', + }, + aspectRatio: { + type: 'string', + }, + scale: { + type: 'string', + }, + sizeSlug: { + type: 'string', + }, + linkDestination: { + type: 'string', + }, + linkTarget: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'target', + }, + }, + supports: { + anchor: true, + behaviors: { + lightbox: true, + }, + color: { + text: false, + background: false, + }, + filter: { + duotone: true, + }, + __experimentalBorder: { + color: true, + radius: true, + width: true, + __experimentalSkipSerialization: true, + __experimentalDefaultControls: { + color: true, + radius: true, + width: true, + }, + }, + }, + migrate( { width, height, ...attributes } ) { + return { + ...attributes, + width: `${ width }px`, + height: `${ height }px`, + }; + }, + save( { attributes } ) { + const { + url, + alt, + caption, + align, + href, + rel, + linkClass, + width, + height, + aspectRatio, + scale, + id, + linkTarget, + sizeSlug, + title, + } = attributes; + + const newRel = ! rel ? undefined : rel; + const borderProps = getBorderClassesAndStyles( attributes ); + + const classes = classnames( { + [ `align${ align }` ]: align, + [ `size-${ sizeSlug }` ]: sizeSlug, + 'is-resized': width || height, + 'has-custom-border': + !! borderProps.className || + ( borderProps.style && + Object.keys( borderProps.style ).length > 0 ), + } ); + + const imageClasses = classnames( borderProps.className, { + [ `wp-image-${ id }` ]: !! id, + } ); + + const image = ( + { + ); + + const figure = ( + <> + { href ? ( + + { image } + + ) : ( + image + ) } + { ! RichText.isEmpty( caption ) && ( + + ) } + + ); + + return ( +
+ { figure } +
+ ); + }, +}; + +export default [ v7, v6, v5, v4, v3, v2, v1 ]; diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 5fe5c93f4199b4..a880c20ed59ab9 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -114,6 +114,11 @@ export default function Image( { linkTarget, sizeSlug, } = attributes; + + // The only supported unit is px, so we can parseInt to strip the px here. + const numericWidth = width ? parseInt( width, 10 ) : undefined; + const numericHeight = height ? parseInt( height, 10 ) : undefined; + const imageRef = useRef(); const prevCaption = usePrevious( caption ); const [ showCaption, setShowCaption ] = useState( !! caption ); @@ -473,23 +478,14 @@ export default function Image( { ) } { // Rebuilding the object forces setting `undefined` // for values that are removed since setAttributes // doesn't do anything with keys that aren't set. setAttributes( { - width: - newValue.width && - parseInt( newValue.width, 10 ), - height: - newValue.height && - parseInt( newValue.height, 10 ), + width: newValue.width, + height: newValue.height, scale: newValue.scale, aspectRatio: newValue.aspectRatio, } ); @@ -587,8 +583,8 @@ export default function Image( { { img }; } else { + const numericRatio = aspectRatio && evalAspectRatio( aspectRatio ); + const customRatio = numericWidth / numericHeight; const ratio = - ( aspectRatio && evalAspectRatio( aspectRatio ) ) || - ( width && height && width / height ) || - naturalWidth / naturalHeight || - 1; - - const currentWidth = ! width && height ? height * ratio : width; - const currentHeight = ! height && width ? width / ratio : height; + numericRatio || customRatio || naturalWidth / naturalHeight || 1; + const currentWidth = + ! numericWidth && numericHeight + ? numericHeight * ratio + : numericWidth; + const currentHeight = + ! numericHeight && numericWidth + ? numericWidth / ratio + : numericHeight; const minWidth = naturalWidth < naturalHeight ? MIN_SIZE : MIN_SIZE * ratio; @@ -687,10 +687,14 @@ export default function Image( { onResizeStart={ onResizeStart } onResizeStop={ ( event, direction, elt ) => { onResizeStop(); + // Since the aspect ratio is locked when resizing, we can + // use the width of the resized element to calculate the + // height in CSS to prevent stretching when the max-width + // is reached. setAttributes( { - width: elt.offsetWidth, - height: elt.offsetHeight, - aspectRatio: undefined, + width: `${ elt.offsetWidth }px`, + height: 'auto', + aspectRatio: `${ ratio }`, } ); } } resizeRatio={ align === 'center' ? 2 : 1 } diff --git a/packages/block-library/src/image/save.js b/packages/block-library/src/image/save.js index 6fa8c6b2342f32..81565af09ababf 100644 --- a/packages/block-library/src/image/save.js +++ b/packages/block-library/src/image/save.js @@ -61,8 +61,6 @@ export default function save( { attributes } ) { width, height, } } - width={ width } - height={ height } title={ title } /> ); diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html index 7ce56e11fa75e9..9a66da6c018989 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html index 7ce56e11fa75e9..9a66da6c018989 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html index cfdc52e3cbb6ea..99da2155bce88f 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html index ad70fe65f35827..807ba3abc9f9ce 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html new file mode 100644 index 00000000000000..7210aee3564b5f --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html @@ -0,0 +1,3 @@ + +
+ diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json new file mode 100644 index 00000000000000..b49c515f8e5ab6 --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json @@ -0,0 +1,15 @@ +[ + { + "name": "core/image", + "isValid": true, + "attributes": { + "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", + "alt": "", + "caption": "", + "sizeSlug": "large", + "width": "164px", + "height": "164px" + }, + "innerBlocks": [] + } +] diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json new file mode 100644 index 00000000000000..fbd8627807b3da --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json @@ -0,0 +1,15 @@ +[ + { + "blockName": "core/image", + "attrs": { + "width": 164, + "height": 164, + "sizeSlug": "large" + }, + "innerBlocks": [], + "innerHTML": "\n
\"\"
\n", + "innerContent": [ + "\n
\"\"
\n" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html new file mode 100644 index 00000000000000..5392d261af89d6 --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html @@ -0,0 +1,3 @@ + +
+