From 9d0bbf5ef3c346f28a36aa32b3b81344f89496db Mon Sep 17 00:00:00 2001 From: Ella Date: Mon, 2 Dec 2024 18:35:24 +0100 Subject: [PATCH 1/4] Zoom out: fix for inserter --- .../src/components/iframe/use-scale-canvas.js | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/block-editor/src/components/iframe/use-scale-canvas.js b/packages/block-editor/src/components/iframe/use-scale-canvas.js index 2d8cb217a3255c..732fe583d46ac8 100644 --- a/packages/block-editor/src/components/iframe/use-scale-canvas.js +++ b/packages/block-editor/src/components/iframe/use-scale-canvas.js @@ -2,11 +2,7 @@ * WordPress dependencies */ import { useEffect, useRef, useCallback } from '@wordpress/element'; -import { - usePrevious, - useReducedMotion, - useResizeObserver, -} from '@wordpress/compose'; +import { useReducedMotion, useResizeObserver } from '@wordpress/compose'; /** * @typedef {Object} TransitionState @@ -284,7 +280,8 @@ export function useScaleCanvas( { transitionFromRef.current = transitionToRef.current; }, [ iframeDocument ] ); - const previousIsZoomedOut = usePrevious( isZoomedOut ); + const previousIsZoomedOut = useRef( false ); + /** * Runs when zoom out mode is toggled, and sets the startAnimation flag * so the animation will start when the next useEffect runs. We _only_ @@ -292,20 +289,26 @@ export function useScaleCanvas( { * changes due to the container resizing. */ useEffect( () => { - if ( ! iframeDocument || previousIsZoomedOut === isZoomedOut ) { - return; - } + const trigger = + iframeDocument && previousIsZoomedOut.current !== isZoomedOut; - if ( isZoomedOut ) { - iframeDocument.documentElement.classList.add( 'is-zoomed-out' ); + previousIsZoomedOut.current = isZoomedOut; + + if ( ! trigger ) { + return; } startAnimationRef.current = true; + if ( ! isZoomedOut ) { + return; + } + + iframeDocument.documentElement.classList.add( 'is-zoomed-out' ); return () => { iframeDocument.documentElement.classList.remove( 'is-zoomed-out' ); }; - }, [ iframeDocument, isZoomedOut, previousIsZoomedOut ] ); + }, [ iframeDocument, isZoomedOut ] ); /** * This handles: From 6b324b5bf9f8f064d4249c38a54efbc748df7150 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Mon, 2 Dec 2024 12:11:02 -0600 Subject: [PATCH 2/4] Rely on containerHeight resize listener instead of iframe.documentElement.clientHeight --- .../src/components/iframe/use-scale-canvas.js | 70 +++++++------------ 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/packages/block-editor/src/components/iframe/use-scale-canvas.js b/packages/block-editor/src/components/iframe/use-scale-canvas.js index 732fe583d46ac8..0c681210b87db8 100644 --- a/packages/block-editor/src/components/iframe/use-scale-canvas.js +++ b/packages/block-editor/src/components/iframe/use-scale-canvas.js @@ -6,11 +6,11 @@ import { useReducedMotion, useResizeObserver } from '@wordpress/compose'; /** * @typedef {Object} TransitionState - * @property {number} scaleValue Scale of the canvas. - * @property {number} frameSize Size of the frame/offset around the canvas. - * @property {number} clientHeight ClientHeight of the iframe. - * @property {number} scrollTop ScrollTop of the iframe. - * @property {number} scrollHeight ScrollHeight of the iframe. + * @property {number} scaleValue Scale of the canvas. + * @property {number} frameSize Size of the frame/offset around the canvas. + * @property {number} containerHeight containerHeight of the iframe. + * @property {number} scrollTop ScrollTop of the iframe. + * @property {number} scrollHeight ScrollHeight of the iframe. */ /** @@ -44,27 +44,28 @@ function calculateScale( { */ function computeScrollTopNext( transitionFrom, transitionTo ) { const { - clientHeight: prevClientHeight, + containerHeight: prevContainerHeight, frameSize: prevFrameSize, scaleValue: prevScale, scrollTop, scrollHeight, } = transitionFrom; - const { clientHeight, frameSize, scaleValue } = transitionTo; + const { containerHeight, frameSize, scaleValue } = transitionTo; // Step 0: Start with the current scrollTop. let scrollTopNext = scrollTop; // Step 1: Undo the effects of the previous scale and frame around the // midpoint of the visible area. scrollTopNext = - ( scrollTopNext + prevClientHeight / 2 - prevFrameSize ) / prevScale - - prevClientHeight / 2; + ( scrollTopNext + prevContainerHeight / 2 - prevFrameSize ) / + prevScale - + prevContainerHeight / 2; // Step 2: Apply the new scale and frame around the midpoint of the // visible area. scrollTopNext = - ( scrollTopNext + clientHeight / 2 ) * scaleValue + + ( scrollTopNext + containerHeight / 2 ) * scaleValue + frameSize - - clientHeight / 2; + containerHeight / 2; // Step 3: Handle an edge case so that you scroll to the top of the // iframe if the top of the iframe content is visible in the container. @@ -78,7 +79,7 @@ function computeScrollTopNext( transitionFrom, transitionTo ) { const maxScrollTop = scrollHeight * ( scaleValue / prevScale ) + frameSize * 2 - - clientHeight; + containerHeight; // Step 4: Clamp the scrollTopNext between the minimum and maximum // possible scrollTop positions. Round the value to avoid subpixel @@ -146,8 +147,10 @@ export function useScaleCanvas( { } ) { const [ contentResizeListener, { height: contentHeight } ] = useResizeObserver(); - const [ containerResizeListener, { width: containerWidth } ] = - useResizeObserver(); + const [ + containerResizeListener, + { width: containerWidth, height: containerHeight }, + ] = useResizeObserver(); const initialContainerWidthRef = useRef( 0 ); const isZoomedOut = scale !== 1; @@ -186,7 +189,7 @@ export function useScaleCanvas( { const transitionFromRef = useRef( { scaleValue, frameSize, - clientHeight: 0, + containerHeight: 0, scrollTop: 0, scrollHeight: 0, } ); @@ -198,7 +201,7 @@ export function useScaleCanvas( { const transitionToRef = useRef( { scaleValue, frameSize, - clientHeight: 0, + containerHeight: 0, scrollTop: 0, scrollHeight: 0, } ); @@ -353,10 +356,9 @@ export function useScaleCanvas( { `${ contentHeight }px` ); - const clientHeight = iframeDocument.documentElement.clientHeight; iframeDocument.documentElement.style.setProperty( '--wp-block-editor-iframe-zoom-out-inner-height', - `${ clientHeight }px` + `${ containerHeight }px` ); iframeDocument.documentElement.style.setProperty( @@ -404,9 +406,11 @@ export function useScaleCanvas( { // appenders may appear or disappear, so we need to get the height from // the iframe at this point when we're about to animate the zoom out. // The iframe scrollTop, scrollHeight, and clientHeight will all be - // the most accurate. - transitionFromRef.current.clientHeight = - transitionFromRef.current.clientHeight ?? clientHeight; + // the most accurate. clientHeight has a performance hit though, so we + // rely on containerHeight from the resize listener. + transitionFromRef.current.containerHeight = + transitionFromRef.current.containerHeight ?? + containerHeight; transitionFromRef.current.scrollTop = iframeDocument.documentElement.scrollTop; transitionFromRef.current.scrollHeight = @@ -415,7 +419,7 @@ export function useScaleCanvas( { transitionToRef.current = { scaleValue, frameSize, - clientHeight, + containerHeight, }; transitionToRef.current.scrollTop = computeScrollTopNext( transitionFromRef.current, @@ -432,27 +436,6 @@ export function useScaleCanvas( { } } } - - return () => { - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-scale' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-frame-size' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-content-height' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-inner-height' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-container-width' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-scale-container-width' - ); - }; }, [ startZoomOutAnimation, finishZoomOutAnimation, @@ -463,6 +446,7 @@ export function useScaleCanvas( { iframeDocument, contentHeight, containerWidth, + containerHeight, maxContainerWidth, scaleContainerWidth, ] ); From 39a27cdddd71e259ba766a5a30197770019e4129 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Mon, 2 Dec 2024 13:10:13 -0600 Subject: [PATCH 3/4] Use iframeDocument.document.containerHeight to get the latest value if container height has changed between renders --- .../src/components/iframe/use-scale-canvas.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/iframe/use-scale-canvas.js b/packages/block-editor/src/components/iframe/use-scale-canvas.js index 0c681210b87db8..d63b412a3d3f91 100644 --- a/packages/block-editor/src/components/iframe/use-scale-canvas.js +++ b/packages/block-editor/src/components/iframe/use-scale-canvas.js @@ -406,11 +406,10 @@ export function useScaleCanvas( { // appenders may appear or disappear, so we need to get the height from // the iframe at this point when we're about to animate the zoom out. // The iframe scrollTop, scrollHeight, and clientHeight will all be - // the most accurate. clientHeight has a performance hit though, so we - // rely on containerHeight from the resize listener. + // the most accurate. transitionFromRef.current.containerHeight = transitionFromRef.current.containerHeight ?? - containerHeight; + containerHeight; // Use containerHeight, as it's the previous container height value if none was set. transitionFromRef.current.scrollTop = iframeDocument.documentElement.scrollTop; transitionFromRef.current.scrollHeight = @@ -419,7 +418,8 @@ export function useScaleCanvas( { transitionToRef.current = { scaleValue, frameSize, - containerHeight, + containerHeight: + iframeDocument.documentElement.clientHeight, // use clientHeight to get the actual height of the new container, as it will be the most up-to-date. }; transitionToRef.current.scrollTop = computeScrollTopNext( transitionFromRef.current, From d0fcc4c19473585758a759c25762ad3d345b9bc4 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Mon, 2 Dec 2024 14:35:38 -0600 Subject: [PATCH 4/4] Only add CSS variables if we need them (is zoomed out) --- .../src/components/iframe/use-scale-canvas.js | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/packages/block-editor/src/components/iframe/use-scale-canvas.js b/packages/block-editor/src/components/iframe/use-scale-canvas.js index d63b412a3d3f91..0b2b8d3c137ffa 100644 --- a/packages/block-editor/src/components/iframe/use-scale-canvas.js +++ b/packages/block-editor/src/components/iframe/use-scale-canvas.js @@ -336,39 +336,41 @@ export function useScaleCanvas( { } ); } - // If we are not going to animate the transition, set the scale and frame size directly. - // If we are animating, these values will be set when the animation is finished. - // Example: Opening sidebars that reduce the scale of the canvas, but we don't want to - // animate the transition. - if ( ! startAnimationRef.current ) { + if ( scaleValue < 1 ) { + // If we are not going to animate the transition, set the scale and frame size directly. + // If we are animating, these values will be set when the animation is finished. + // Example: Opening sidebars that reduce the scale of the canvas, but we don't want to + // animate the transition. + if ( ! startAnimationRef.current ) { + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-scale', + scaleValue + ); + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-frame-size', + `${ frameSize }px` + ); + } + iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-scale', - scaleValue + '--wp-block-editor-iframe-zoom-out-content-height', + `${ contentHeight }px` ); + iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-frame-size', - `${ frameSize }px` + '--wp-block-editor-iframe-zoom-out-inner-height', + `${ containerHeight }px` ); - } - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-content-height', - `${ contentHeight }px` - ); - - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-inner-height', - `${ containerHeight }px` - ); - - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-container-width', - `${ containerWidth }px` - ); - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-scale-container-width', - `${ scaleContainerWidth }px` - ); + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-container-width', + `${ containerWidth }px` + ); + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-scale-container-width', + `${ scaleContainerWidth }px` + ); + } /** * Handle the zoom out animation: