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

Trunk: Zoom in/out to correct location #66977

Closed
wants to merge 8 commits into from
Closed
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
84 changes: 49 additions & 35 deletions packages/block-editor/src/components/iframe/content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,69 @@
}

.block-editor-iframe__html {
$frame-size: var(--wp-block-editor-iframe-zoom-out-frame-size);
$scale: var(--wp-block-editor-iframe-zoom-out-scale, 1);
scale: $scale;
transform-origin: top center;
// Add the top/bottom frame size. We use scaling to account for the left/right, as
// the padding left/right causes the contents to reflow, which breaks the 1:1 scaling
// of the content.
padding-top: calc(#{$frame-size} / #{$scale});
padding-bottom: calc(#{$frame-size} / #{$scale});

// 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.
@include editor-canvas-resize-animation(transform 0s, scale 0s, padding 0s);
@include editor-canvas-resize-animation( transform 0s, scale 0s, padding 0s, translate 0s);

&.zoom-out-animation {
// we only want to animate the scaling when entering zoom out. When sidebars
$scroll-top: var(--wp-block-editor-iframe-zoom-out-scroll-top, 0);
$scroll-top-next: var(--wp-block-editor-iframe-zoom-out-scroll-top-next, 0);

position: fixed;
left: 0;
right: 0;
top: calc(-1 * #{$scroll-top});
bottom: 0;
translate: 0 calc(#{$scroll-top} - #{$scroll-top-next});
// Force preserving a scrollbar gutter as scrollbar-gutter isn't supported in all browsers yet,
// and removing the scrollbar causes the content to shift.
overflow-y: scroll;

// 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.
@include editor-canvas-resize-animation(transform 0s);
@include editor-canvas-resize-animation( transform 0s, top 0s, bottom 0s, right 0s, left 0s );
}
}

.block-editor-iframe__html.is-zoomed-out {
$scale: var(--wp-block-editor-iframe-zoom-out-scale);
$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);
$scale-container-width: var(--wp-block-editor-iframe-zoom-out-scale-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((#{$scale-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,
// so we need to adjust the height of the content to match the scale by using negative margins.
$extra-content-height: calc(#{$content-height} * (1 - #{$scale}));
$total-frame-height: calc(2 * #{$frame-size} / #{$scale});
$total-height: calc(#{$extra-content-height} + #{$total-frame-height} + 2px);
margin-bottom: calc(-1 * #{$total-height});
// Add the top/bottom frame size. We use scaling to account for the left/right, as
// the padding left/right causes the contents to reflow, which breaks the 1:1 scaling
// of the content.
padding-top: calc(#{$frame-size} / #{$scale});
padding-bottom: calc(#{$frame-size} / #{$scale});
&.is-zoomed-out {
$inner-height: var(--wp-block-editor-iframe-zoom-out-inner-height);
$content-height: var(--wp-block-editor-iframe-zoom-out-content-height);
$scale-container-width: var(--wp-block-editor-iframe-zoom-out-scale-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((#{$scale-container-width} - #{$container-width}) / 2 / #{$scale}));
background-color: $gray-300;

body {
min-height: calc((#{$inner-height} - #{$total-frame-height}) / #{$scale});
// Chrome seems to respect that transform scale shouldn't affect the layout size of the element,
// so we need to adjust the height of the content to match the scale by using negative margins.
$extra-content-height: calc(#{$content-height} * (1 - #{$scale}));
$total-frame-height: calc(2 * #{$frame-size} / #{$scale});
$total-height: calc(#{$extra-content-height} + #{$total-frame-height} + 2px);
margin-bottom: calc(-1 * #{$total-height});

> .is-root-container:not(.wp-block-post-content) {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
body {
min-height: calc((#{$inner-height} - #{$total-frame-height}) / #{$scale});

> main {
> .is-root-container:not(.wp-block-post-content) {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;

> main {
flex: 1;
}
}
}
}
Expand Down
166 changes: 19 additions & 147 deletions packages/block-editor/src/components/iframe/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { useSelect } from '@wordpress/data';
import { useBlockSelectionClearer } from '../block-selection-clearer';
import { useWritingFlow } from '../writing-flow';
import { getCompatibilityStyles } from './get-compatibility-styles';
import { useScaleCanvas } from './use-scale-canvas';
import { store as blockEditorStore } from '../../store';

function bubbleEvent( event, Constructor, frame ) {
Expand Down Expand Up @@ -225,36 +226,6 @@ function Iframe( {
};
}, [] );

const [ iframeWindowInnerHeight, setIframeWindowInnerHeight ] = useState();

const iframeResizeRef = useRefEffect( ( node ) => {
const nodeWindow = node.ownerDocument.defaultView;

setIframeWindowInnerHeight( nodeWindow.innerHeight );
const onResize = () => {
setIframeWindowInnerHeight( nodeWindow.innerHeight );
};
nodeWindow.addEventListener( 'resize', onResize );
return () => {
nodeWindow.removeEventListener( 'resize', onResize );
};
}, [] );

const [ windowInnerWidth, setWindowInnerWidth ] = useState();

const windowResizeRef = useRefEffect( ( node ) => {
const nodeWindow = node.ownerDocument.defaultView;

setWindowInnerWidth( nodeWindow.innerWidth );
const onResize = () => {
setWindowInnerWidth( nodeWindow.innerWidth );
};
nodeWindow.addEventListener( 'resize', onResize );
return () => {
nodeWindow.removeEventListener( 'resize', onResize );
};
}, [] );

const isZoomedOut = scale !== 1;

useEffect( () => {
Expand All @@ -268,17 +239,30 @@ function Iframe( {
containerWidth
);

const maxWidth = 750;

useScaleCanvas( {
scale:
scale === 'auto-scaled'
? ( Math.min( containerWidth, maxWidth ) -
parseInt( frameSize ) * 2 ) /
scaleContainerWidth
: scale,
frameSize: parseInt( frameSize ),
iframeDocument,
contentHeight,
containerWidth,
isZoomedOut,
scaleContainerWidth,
} );

const disabledRef = useDisabled( { isDisabled: ! readonly } );
const bodyRef = useMergeRefs( [
useBubbleEvents( iframeDocument ),
contentRef,
clearerRef,
writingFlowRef,
disabledRef,
// Avoid resize listeners when not needed, these will trigger
// unnecessary re-renders when animating the iframe width, or when
// expanding preview iframes.
isZoomedOut ? iframeResizeRef : null,
] );

// Correct doctype is required to enable rendering in standards
Expand Down Expand Up @@ -320,118 +304,6 @@ function Iframe( {

useEffect( () => cleanup, [ cleanup ] );

const zoomOutAnimationClassnameRef = useRef( null );

// 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;
}

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
};

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 (sidebars open),
// initialContainerWidthRef 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
// but calc( 100px / 2px ) is not.
iframeDocument.documentElement.style.setProperty(
'--wp-block-editor-iframe-zoom-out-scale',
scale === 'auto-scaled'
? ( Math.min( containerWidth, maxWidth ) -
parseInt( frameSize ) * 2 ) /
scaleContainerWidth
: scale
);

// frameSize has to be a px value for the scaling and frame size to be computed correctly.
iframeDocument.documentElement.style.setProperty(
'--wp-block-editor-iframe-zoom-out-frame-size',
typeof frameSize === 'number' ? `${ frameSize }px` : frameSize
);
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',
`${ iframeWindowInnerHeight }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`
);

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'
);
};
}, [
scale,
frameSize,
iframeDocument,
iframeWindowInnerHeight,
contentHeight,
containerWidth,
windowInnerWidth,
isZoomedOut,
scaleContainerWidth,
] );

// Make sure to not render the before and after focusable div elements in view
// mode. They're only needed to capture focus in edit mode.
const shouldRenderFocusCaptureElements = tabIndex >= 0 && ! isPreviewMode;
Expand Down Expand Up @@ -511,7 +383,7 @@ function Iframe( {
);

return (
<div className="block-editor-iframe__container" ref={ windowResizeRef }>
<div className="block-editor-iframe__container">
{ containerResizeListener }
<div
className={ clsx(
Expand Down
Loading
Loading