From 944ff083c716b6b1ee29f53524b7846bcdd2ff03 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Sun, 25 Feb 2024 09:17:28 +0100 Subject: [PATCH] Scale the zoom out mode to fit available space (#59342) * Scale zoom out mode frame based on available content width When there's a small area available to scale the editor, we want to have the editor larger. This implements a smooth sloped clamped scale to scale the zoomed out editor to better fit its available space. We moved the scale calculation inside of the iframe components so when this is used within the edit post and other packages, they won't need to implement their own scaling. * update variable name * Add an explanatory comment * Add shouldZoom prop to only use zooming if desired --------- Co-authored-by: scruffian Co-authored-by: jeryj Co-authored-by: scruffian --- .../src/components/iframe/index.js | 50 ++++++++++++++----- .../block-editor/src/utils/calculate-scale.js | 20 ++++++++ .../components/block-editor/editor-canvas.js | 15 +++--- 3 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 packages/block-editor/src/utils/calculate-scale.js diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 4c152d68d34d7..13ce1116336c9 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -30,7 +30,7 @@ import { useBlockSelectionClearer } from '../block-selection-clearer'; import { useWritingFlow } from '../writing-flow'; import { getCompatibilityStyles } from './get-compatibility-styles'; import { store as blockEditorStore } from '../../store'; - +import calculateScale from '../../utils/calculate-scale'; function bubbleEvent( event, Constructor, frame ) { const init = {}; @@ -104,26 +104,52 @@ function Iframe( { contentRef, children, tabIndex = 0, - scale = 1, - frameSize = 0, + shouldZoom = false, readonly, forwardedRef: ref, ...props } ) { - const { resolvedAssets, isPreviewMode } = useSelect( ( select ) => { - const settings = select( blockEditorStore ).getSettings(); - return { - resolvedAssets: settings.__unstableResolvedAssets, - isPreviewMode: settings.__unstableIsPreviewMode, - }; - }, [] ); + const { resolvedAssets, isPreviewMode, isZoomOutMode } = useSelect( + ( select ) => { + const { getSettings, __unstableGetEditorMode } = + select( blockEditorStore ); + const settings = getSettings(); + return { + resolvedAssets: settings.__unstableResolvedAssets, + isPreviewMode: settings.__unstableIsPreviewMode, + isZoomOutMode: __unstableGetEditorMode() === 'zoom-out', + }; + }, + [] + ); const { styles = '', scripts = '' } = resolvedAssets; const [ iframeDocument, setIframeDocument ] = useState(); const [ bodyClasses, setBodyClasses ] = useState( [] ); const clearerRef = useBlockSelectionClearer(); const [ before, writingFlowRef, after ] = useWritingFlow(); - const [ contentResizeListener, { height: contentHeight } ] = - useResizeObserver(); + const [ + contentResizeListener, + { height: contentHeight, width: contentWidth }, + ] = useResizeObserver(); + + // When zoom-out mode is enabled, the iframe is scaled down to fit the + // content within the viewport. + // At 1000px wide, the iframe is scaled to 45%. + // At 400px wide, the iframe is scaled to 90%. + const scale = + isZoomOutMode && shouldZoom + ? calculateScale( + { + maxWidth: 1000, + minWidth: 400, + maxScale: 0.45, + minScale: 0.9, + }, + contentWidth + ) + : 1; + const frameSize = isZoomOutMode ? 100 : 0; + const setRef = useRefEffect( ( node ) => { node._load = () => { setIframeDocument( node.contentDocument ); diff --git a/packages/block-editor/src/utils/calculate-scale.js b/packages/block-editor/src/utils/calculate-scale.js new file mode 100644 index 0000000000000..f07ba24ea341a --- /dev/null +++ b/packages/block-editor/src/utils/calculate-scale.js @@ -0,0 +1,20 @@ +const clamp = ( lowerlimit, width, upperlimit ) => { + if ( width < lowerlimit ) return lowerlimit; + if ( width > upperlimit ) return upperlimit; + return width; +}; + +export default function calculateScale( scaleConfig, width ) { + const scaleSlope = + ( scaleConfig.maxScale - scaleConfig.minScale ) / + ( scaleConfig.maxWidth - scaleConfig.minWidth ); + + const scaleIntercept = + scaleConfig.minScale - scaleSlope * scaleConfig.minWidth; + + return clamp( + scaleConfig.maxScale, + scaleSlope * width + scaleIntercept, + scaleConfig.minScale + ); +} diff --git a/packages/edit-site/src/components/block-editor/editor-canvas.js b/packages/edit-site/src/components/block-editor/editor-canvas.js index ceb0bd6be27d8..c3ee980515e6c 100644 --- a/packages/edit-site/src/components/block-editor/editor-canvas.js +++ b/packages/edit-site/src/components/block-editor/editor-canvas.js @@ -26,10 +26,9 @@ import { const { EditorCanvas: EditorCanvasRoot } = unlock( editorPrivateApis ); function EditorCanvas( { enableResizing, settings, children, ...props } ) { - const { hasBlocks, isFocusMode, templateType, canvasMode, isZoomOutMode } = - useSelect( ( select ) => { - const { getBlockCount, __unstableGetEditorMode } = - select( blockEditorStore ); + const { hasBlocks, isFocusMode, templateType, canvasMode } = useSelect( + ( select ) => { + const { getBlockCount } = select( blockEditorStore ); const { getEditedPostType, getCanvasMode } = unlock( select( editSiteStore ) ); @@ -38,11 +37,12 @@ function EditorCanvas( { enableResizing, settings, children, ...props } ) { return { templateType: _templateType, isFocusMode: FOCUSABLE_ENTITIES.includes( _templateType ), - isZoomOutMode: __unstableGetEditorMode() === 'zoom-out', canvasMode: getCanvasMode(), hasBlocks: !! getBlockCount(), }; - }, [] ); + }, + [] + ); const { setCanvasMode } = unlock( useDispatch( editSiteStore ) ); const [ isFocused, setIsFocused ] = useState( false ); @@ -107,8 +107,7 @@ function EditorCanvas( { enableResizing, settings, children, ...props } ) { renderAppender={ showBlockAppender } styles={ styles } iframeProps={ { - scale: isZoomOutMode ? 0.45 : undefined, - frameSize: isZoomOutMode ? 100 : undefined, + shouldZoom: true, className: classnames( 'edit-site-visual-editor__editor-canvas', {