From 7f4b389a92e1cc435b3a4e82dc809073e1ae48b2 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Thu, 10 Oct 2024 16:09:53 -0500 Subject: [PATCH 01/11] Position scaled html within available container space --- packages/block-editor/src/components/iframe/content.scss | 6 +++--- packages/block-editor/src/components/iframe/style.scss | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/iframe/content.scss b/packages/block-editor/src/components/iframe/content.scss index 069274e66bdfd0..bbbe6dae5ab1fb 100644 --- a/packages/block-editor/src/components/iframe/content.scss +++ b/packages/block-editor/src/components/iframe/content.scss @@ -14,9 +14,9 @@ $inner-height: var(--wp-block-editor-iframe-zoom-out-inner-height); $content-height: var(--wp-block-editor-iframe-zoom-out-content-height); $prev-container-width: var(--wp-block-editor-iframe-zoom-out-prev-container-width); - - transform: scale(#{$scale}); - + $container-width: var(--wp-block-editor-iframe-zoom-out-container-width, 100vw); + // Apply an X translation to center the scaled content within the available space. + transform: scale(#{$scale}) translateX(calc(( #{$prev-container-width} - #{ $container-width }) / 2 / #{$scale})); background-color: $gray-300; // Chrome seems to respect that transform scale shouldn't affect the layout size of the element, diff --git a/packages/block-editor/src/components/iframe/style.scss b/packages/block-editor/src/components/iframe/style.scss index dcddcdf0950a45..bc16989dabf096 100644 --- a/packages/block-editor/src/components/iframe/style.scss +++ b/packages/block-editor/src/components/iframe/style.scss @@ -9,9 +9,10 @@ } .block-editor-iframe__scale-container.is-zoomed-out { - $container-width: var(--wp-block-editor-iframe-zoom-out-container-width, 100vw); $prev-container-width: var(--wp-block-editor-iframe-zoom-out-prev-container-width, 100vw); width: $prev-container-width; - // This is to offset the movement of the iframe when we open sidebars - margin-left: calc(-1 * (#{$prev-container-width} - #{$container-width}) / 2); + // Position the iframe so that it is always aligned with the right side so that + // the scrollbar is always visible on the right side + position: absolute; + right: 0; } From d09162128dfac68992975a4ba454766352a03f11 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 11 Oct 2024 09:30:11 -0500 Subject: [PATCH 02/11] Move scale to own css line --- packages/block-editor/src/components/iframe/content.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/iframe/content.scss b/packages/block-editor/src/components/iframe/content.scss index bbbe6dae5ab1fb..891b47720a65c4 100644 --- a/packages/block-editor/src/components/iframe/content.scss +++ b/packages/block-editor/src/components/iframe/content.scss @@ -16,7 +16,8 @@ $prev-container-width: var(--wp-block-editor-iframe-zoom-out-prev-container-width); $container-width: var(--wp-block-editor-iframe-zoom-out-container-width, 100vw); // Apply an X translation to center the scaled content within the available space. - transform: scale(#{$scale}) translateX(calc(( #{$prev-container-width} - #{ $container-width }) / 2 / #{$scale})); + transform: translateX(calc(( #{$prev-container-width} - #{ $container-width }) / 2 / #{$scale})); + scale: #{$scale}; background-color: $gray-300; // Chrome seems to respect that transform scale shouldn't affect the layout size of the element, From 374477ba4ea8efd5c6652dbab1d0978941452687 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 11 Oct 2024 10:34:20 -0500 Subject: [PATCH 03/11] Always have width of scale container be full width avaialable The scale container could be smaller than the available area if zoom out was initialized with a sidebar open, then closed. We were using prevContainerWidth in the CSS under the assumption it would always be the largest value, but that was not true. This renames prevContainerWidthRef to initialContainerWidth so it's clearer that this is the point when zoom out was initialized, then renames the CSS vars prev-container-width to outer-container-width, using the larger value of containerWidth or initialContainerWidth so it can be more consistently named. --- .../src/components/iframe/content.scss | 4 ++-- .../src/components/iframe/index.js | 20 +++++++++++-------- .../src/components/iframe/style.scss | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/block-editor/src/components/iframe/content.scss b/packages/block-editor/src/components/iframe/content.scss index 891b47720a65c4..2d2947f6981df7 100644 --- a/packages/block-editor/src/components/iframe/content.scss +++ b/packages/block-editor/src/components/iframe/content.scss @@ -13,10 +13,10 @@ $frame-size: var(--wp-block-editor-iframe-zoom-out-frame-size); $inner-height: var(--wp-block-editor-iframe-zoom-out-inner-height); $content-height: var(--wp-block-editor-iframe-zoom-out-content-height); - $prev-container-width: var(--wp-block-editor-iframe-zoom-out-prev-container-width); + $outer-container-width: var(--wp-block-editor-iframe-zoom-out-outer-container-width); $container-width: var(--wp-block-editor-iframe-zoom-out-container-width, 100vw); // Apply an X translation to center the scaled content within the available space. - transform: translateX(calc(( #{$prev-container-width} - #{ $container-width }) / 2 / #{$scale})); + transform: translateX(calc(( #{$outer-container-width} - #{ $container-width }) / 2 / #{$scale})); scale: #{$scale}; background-color: $gray-300; diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index d234339909a5c1..b2c1bc9d09b065 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -122,7 +122,7 @@ function Iframe( { }, [] ); const { styles = '', scripts = '' } = resolvedAssets; const [ iframeDocument, setIframeDocument ] = useState(); - const prevContainerWidthRef = useRef(); + const initialContainerWidth = useRef(); const [ bodyClasses, setBodyClasses ] = useState( [] ); const clearerRef = useBlockSelectionClearer(); const [ before, writingFlowRef, after ] = useWritingFlow(); @@ -243,7 +243,7 @@ function Iframe( { useEffect( () => { if ( ! isZoomedOut ) { - prevContainerWidthRef.current = containerWidth; + initialContainerWidth.current = containerWidth; } }, [ containerWidth, isZoomedOut ] ); @@ -314,7 +314,7 @@ function Iframe( { scale === 'default' ? ( Math.min( containerWidth, maxWidth ) - parseInt( frameSize ) * 2 ) / - prevContainerWidthRef.current + initialContainerWidth.current : scale ); @@ -336,8 +336,8 @@ function Iframe( { `${ containerWidth }px` ); iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-prev-container-width', - `${ prevContainerWidthRef.current }px` + '--wp-block-editor-iframe-zoom-out-outer-container-width', + `${ Math.max( initialContainerWidth.current, containerWidth ) }px` ); return () => { @@ -359,7 +359,7 @@ function Iframe( { '--wp-block-editor-iframe-zoom-out-container-width' ); iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-prev-container-width' + '--wp-block-editor-iframe-zoom-out-outer-container-width' ); }; }, [ @@ -462,8 +462,12 @@ function Iframe( { style={ { '--wp-block-editor-iframe-zoom-out-container-width': isZoomedOut && `${ containerWidth }px`, - '--wp-block-editor-iframe-zoom-out-prev-container-width': - isZoomedOut && `${ prevContainerWidthRef.current }px`, + '--wp-block-editor-iframe-zoom-out-outer-container-width': + isZoomedOut && + `${ Math.max( + initialContainerWidth.current, + containerWidth + ) }px`, } } > { iframe } diff --git a/packages/block-editor/src/components/iframe/style.scss b/packages/block-editor/src/components/iframe/style.scss index bc16989dabf096..d05be2f3977b9f 100644 --- a/packages/block-editor/src/components/iframe/style.scss +++ b/packages/block-editor/src/components/iframe/style.scss @@ -9,8 +9,8 @@ } .block-editor-iframe__scale-container.is-zoomed-out { - $prev-container-width: var(--wp-block-editor-iframe-zoom-out-prev-container-width, 100vw); - width: $prev-container-width; + $outer-container-width: var(--wp-block-editor-iframe-zoom-out-outer-container-width, 100vw); + width: $outer-container-width; // Position the iframe so that it is always aligned with the right side so that // the scrollbar is always visible on the right side position: absolute; From 3d252dac1ab1b32f746649c520151aec2fa6ad22 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 11 Oct 2024 10:56:02 -0500 Subject: [PATCH 04/11] Comment about bug --- packages/block-editor/src/components/iframe/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index b2c1bc9d09b065..17e9bf890ff8d1 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -306,6 +306,9 @@ function Iframe( { iframeDocument.documentElement.classList.add( 'is-zoomed-out' ); const maxWidth = 750; + // Note: When we initialize the zoom out when the canvas is smaller, + // reflow happens when the canvas area becomes larger + // This scaling calculation has to happen within the JS because CSS calc() can // only divide and multiply by a unitless value. I.e. calc( 100px / 2 ) is valid // but calc( 100px / 2px ) is not. From 9f58573f01b27d002668bf5c2812e4dc9beb1cd3 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Fri, 11 Oct 2024 11:31:20 -0500 Subject: [PATCH 05/11] Remove unused css var --- packages/block-editor/src/components/iframe/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 17e9bf890ff8d1..d3675a3922d5f2 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -463,8 +463,6 @@ function Iframe( { isZoomedOut && 'is-zoomed-out' ) } style={ { - '--wp-block-editor-iframe-zoom-out-container-width': - isZoomedOut && `${ containerWidth }px`, '--wp-block-editor-iframe-zoom-out-outer-container-width': isZoomedOut && `${ Math.max( From dc49dfa26b5df5f1932497203c242cd18ab1b769 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 11 Oct 2024 14:21:04 -0500 Subject: [PATCH 06/11] Force largest available window size to scale from If you started with a sidebar open, then entered zoom out, then closed the sidebar, your scaled canvas would be too large. It should match the same size as if you start with no sidebars open, then enter zoom out. --- packages/block-editor/src/components/iframe/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index d3675a3922d5f2..e65ad0c915034b 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -312,12 +312,17 @@ function Iframe( { // This scaling calculation has to happen within the JS because CSS calc() can // only divide and multiply by a unitless value. I.e. calc( 100px / 2 ) is valid // but calc( 100px / 2px ) is not. + // Use the max of the container width and intial container width to account for when we + // scale from a smaller container to a larger one. iframeDocument.documentElement.style.setProperty( '--wp-block-editor-iframe-zoom-out-scale', scale === 'default' ? ( Math.min( containerWidth, maxWidth ) - parseInt( frameSize ) * 2 ) / - initialContainerWidth.current + Math.max( + initialContainerWidth.current, + containerWidth + ) : scale ); From c5fc1e194594998b7e245dd591f7820660ff2745 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 11 Oct 2024 16:19:24 -0500 Subject: [PATCH 07/11] Improve animation by not transitioning the translateX --- packages/base-styles/_animations.scss | 5 ----- packages/block-editor/src/components/block-canvas/style.scss | 1 - packages/block-editor/src/components/iframe/content.scss | 3 ++- packages/block-editor/src/components/iframe/index.js | 5 +---- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/base-styles/_animations.scss b/packages/base-styles/_animations.scss index 87e5f035f46a6c..e5bbf863757356 100644 --- a/packages/base-styles/_animations.scss +++ b/packages/base-styles/_animations.scss @@ -36,11 +36,6 @@ @include reduce-motion("animation"); } -@mixin editor-canvas-resize-animation() { - transition: all 0.4s cubic-bezier(0.46, 0.03, 0.52, 0.96); - @include reduce-motion("transition"); -} - // Deprecated @mixin edit-post__fade-in-animation($speed: 0.08s, $delay: 0s) { @warn "The `edit-post__fade-in-animation` mixin is deprecated. Use `animation__fade-in` instead."; diff --git a/packages/block-editor/src/components/block-canvas/style.scss b/packages/block-editor/src/components/block-canvas/style.scss index 1395b5c0a437d3..9e924cb79bace1 100644 --- a/packages/block-editor/src/components/block-canvas/style.scss +++ b/packages/block-editor/src/components/block-canvas/style.scss @@ -4,5 +4,4 @@ iframe[name="editor-canvas"] { height: 100%; display: block; background-color: transparent; - @include editor-canvas-resize-animation; } diff --git a/packages/block-editor/src/components/iframe/content.scss b/packages/block-editor/src/components/iframe/content.scss index 2d2947f6981df7..e0b931e5e63483 100644 --- a/packages/block-editor/src/components/iframe/content.scss +++ b/packages/block-editor/src/components/iframe/content.scss @@ -5,7 +5,8 @@ .block-editor-iframe__html { transform-origin: top center; - @include editor-canvas-resize-animation; + transition: all 0.4s cubic-bezier(0.46, 0.03, 0.52, 0.96), transform 0s; + @include reduce-motion("transition"); } .block-editor-iframe__html.is-zoomed-out { diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index e65ad0c915034b..77c3308e041283 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -319,10 +319,7 @@ function Iframe( { scale === 'default' ? ( Math.min( containerWidth, maxWidth ) - parseInt( frameSize ) * 2 ) / - Math.max( - initialContainerWidth.current, - containerWidth - ) + initialContainerWidth.current : scale ); From 3cea81491e88cc888490efa1f62096a783d6c596 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 11 Oct 2024 16:21:08 -0500 Subject: [PATCH 08/11] Remove unused comment --- packages/block-editor/src/components/iframe/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 77c3308e041283..d3675a3922d5f2 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -312,8 +312,6 @@ function Iframe( { // This scaling calculation has to happen within the JS because CSS calc() can // only divide and multiply by a unitless value. I.e. calc( 100px / 2 ) is valid // but calc( 100px / 2px ) is not. - // Use the max of the container width and intial container width to account for when we - // scale from a smaller container to a larger one. iframeDocument.documentElement.style.setProperty( '--wp-block-editor-iframe-zoom-out-scale', scale === 'default' From ec7a584b04ea7a806680c067a6f1fb479b29c87d Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Mon, 14 Oct 2024 12:15:01 -0500 Subject: [PATCH 09/11] Only animate scaling on entry and exit of zoom out mode --- .../src/components/iframe/content.scss | 15 ++++++++- .../src/components/iframe/index.js | 32 +++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/iframe/content.scss b/packages/block-editor/src/components/iframe/content.scss index e0b931e5e63483..4a0e2d519f914b 100644 --- a/packages/block-editor/src/components/iframe/content.scss +++ b/packages/block-editor/src/components/iframe/content.scss @@ -5,8 +5,21 @@ .block-editor-iframe__html { transform-origin: top center; - transition: all 0.4s cubic-bezier(0.46, 0.03, 0.52, 0.96), transform 0s; + // 400ms should match the animation speed used in iframe/index.js + $zoomOutAnimation: all 400ms cubic-bezier(0.46, 0.03, 0.52, 0.96); + + // We don't want to animate the transform of the translateX because it is used + // to "center" the canvas. Leaving it on causes the canvas to slide around in + // odd ways. + transition: $zoomOutAnimation, transform 0s scale 0s; @include reduce-motion("transition"); + + &.zoom-out-animation { + // we only want to animate the scaling when entering zoom out. When sidebars + // are toggled, the resizing of the iframe handles scaling the canvas as well, + // and the doubled animations cause very odd animations. + transition: $zoomOutAnimation, transform 0s; + } } .block-editor-iframe__html.is-zoomed-out { diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index d3675a3922d5f2..3993211bdb7ed4 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -298,13 +298,43 @@ function Iframe( { useEffect( () => cleanup, [ cleanup ] ); + const zoomOutAnimationClassnameRef = useRef( null ); + const handleZoomOutAnimationClassname = () => { + clearTimeout( zoomOutAnimationClassnameRef.current ); + + iframeDocument.documentElement.classList.add( 'zoom-out-animation' ); + + zoomOutAnimationClassnameRef.current = setTimeout( () => { + iframeDocument.documentElement.classList.remove( + 'zoom-out-animation' + ); + }, 400 ); // 400ms should match the animation speed used in components/iframe/content.scss + }; + + // Toggle zoom out CSS Classes only when zoom out mode changes. We could add these into the useEffect + // that controls settings the CSS variables, but then we would need to do more work to ensure we're + // only toggling these when the zoom out mode changes, as that useEffect is also triggered by a large + // number of dependencies. useEffect( () => { if ( ! iframeDocument || ! isZoomedOut ) { return; } + handleZoomOutAnimationClassname(); iframeDocument.documentElement.classList.add( 'is-zoomed-out' ); + return () => { + handleZoomOutAnimationClassname(); + iframeDocument.documentElement.classList.remove( 'is-zoomed-out' ); + }; + }, [ iframeDocument, isZoomedOut ] ); + + // Calculate the scaling and CSS variables for the zoom out canvas + useEffect( () => { + if ( ! iframeDocument || ! isZoomedOut ) { + return; + } + const maxWidth = 750; // Note: When we initialize the zoom out when the canvas is smaller, // reflow happens when the canvas area becomes larger @@ -344,8 +374,6 @@ function Iframe( { ); return () => { - iframeDocument.documentElement.classList.remove( 'is-zoomed-out' ); - iframeDocument.documentElement.style.removeProperty( '--wp-block-editor-iframe-zoom-out-scale' ); From 581d4047d929acf5599e1cd413bd35b8c1898f64 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Mon, 14 Oct 2024 16:22:49 -0500 Subject: [PATCH 10/11] Use max of initialContainerWidth or containerWidth to avoid scaling canvas over 1 --- .../block-editor/src/components/iframe/index.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 3993211bdb7ed4..b72d86ef8e0f8f 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -336,8 +336,10 @@ function Iframe( { } const maxWidth = 750; - // Note: When we initialize the zoom out when the canvas is smaller, - // reflow happens when the canvas area becomes larger + // Note: When we initialize the zoom out when the canvas is smaller (sidebars open), + // initialContainerWidth will be smaller than the full page, and reflow will happen + // when the canvas area becomes larger due to sidebars closing. This is a known but + // minor divergence for now. // This scaling calculation has to happen within the JS because CSS calc() can // only divide and multiply by a unitless value. I.e. calc( 100px / 2 ) is valid @@ -347,7 +349,10 @@ function Iframe( { scale === 'default' ? ( Math.min( containerWidth, maxWidth ) - parseInt( frameSize ) * 2 ) / - initialContainerWidth.current + Math.max( + initialContainerWidth.current, + containerWidth + ) : scale ); @@ -373,6 +378,11 @@ function Iframe( { `${ Math.max( initialContainerWidth.current, containerWidth ) }px` ); + // iframeDocument.documentElement.style.setProperty( + // '--wp-block-editor-iframe-zoom-out-outer-container-width', + // `${ Math.max( initialContainerWidth.current, containerWidth ) }px` + // ); + return () => { iframeDocument.documentElement.style.removeProperty( '--wp-block-editor-iframe-zoom-out-scale' From caba47c216dbb5a49ec245c07a683b1097626ab9 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Tue, 15 Oct 2024 08:08:18 -0500 Subject: [PATCH 11/11] Allow zoom out scale e2e test to be more flexible --- test/e2e/specs/site-editor/zoom-out.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/site-editor/zoom-out.spec.js b/test/e2e/specs/site-editor/zoom-out.spec.js index 6ede9014d2a303..2aabee07d18785 100644 --- a/test/e2e/specs/site-editor/zoom-out.spec.js +++ b/test/e2e/specs/site-editor/zoom-out.spec.js @@ -27,8 +27,8 @@ test.describe( 'Zoom Out', () => { // Check that the html is scaled. await expect( html ).toHaveCSS( - 'transform', - 'matrix(0.67, 0, 0, 0.67, 0, 0)' + 'scale', + new RegExp( /0\.[5-8][0-9]*/, 'i' ) ); const iframeRect = await iframe.boundingBox(); const htmlRect = await html.boundingBox();