Skip to content

Commit

Permalink
StylesPreview: Fix endless loop of ratio calculations when on the thr…
Browse files Browse the repository at this point in the history
…eshold of a scrollbar (#57090)

* StylesPreview: Fix endless loop of ratio calculations when on the threshold of a scrollbar

* Revert stray line
  • Loading branch information
andrewserong authored Dec 17, 2023
1 parent 2c79c9e commit 1ac1d88
Showing 1 changed file with 55 additions and 3 deletions.
58 changes: 55 additions & 3 deletions packages/edit-site/src/components/global-styles/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import {
__experimentalHStack as HStack,
__experimentalVStack as VStack,
} from '@wordpress/components';
import { useReducedMotion, useResizeObserver } from '@wordpress/compose';
import { useState, useMemo } from '@wordpress/element';
import {
useThrottle,
useReducedMotion,
useResizeObserver,
} from '@wordpress/compose';
import { useLayoutEffect, useState, useMemo } from '@wordpress/element';

/**
* Internal dependencies
Expand Down Expand Up @@ -60,6 +64,13 @@ const normalizedHeight = 152;

const normalizedColorSwatchSize = 32;

// Throttle options for useThrottle. Must be defined outside of the component,
// so that the object reference is the same on each render.
const THROTTLE_OPTIONS = {
leading: true,
trailing: true,
};

const StylesPreview = ( { label, isFocused, withHoverView } ) => {
const [ fontWeight ] = useGlobalStyle( 'typography.fontWeight' );
const [ fontFamily = 'serif' ] = useGlobalStyle( 'typography.fontFamily' );
Expand All @@ -79,7 +90,47 @@ const StylesPreview = ( { label, isFocused, withHoverView } ) => {
const disableMotion = useReducedMotion();
const [ isHovered, setIsHovered ] = useState( false );
const [ containerResizeListener, { width } ] = useResizeObserver();
const ratio = width ? width / normalizedWidth : 1;
const [ throttledWidth, setThrottledWidthState ] = useState( width );
const [ ratioState, setRatioState ] = useState();

const setThrottledWidth = useThrottle(
setThrottledWidthState,
250,
THROTTLE_OPTIONS
);

// Must use useLayoutEffect to avoid a flash of the iframe at the wrong
// size before the width is set.
useLayoutEffect( () => {
if ( width ) {
setThrottledWidth( width );
}
}, [ width, setThrottledWidth ] );

// Must use useLayoutEffect to avoid a flash of the iframe at the wrong
// size before the width is set.
useLayoutEffect( () => {
const newRatio = throttledWidth ? throttledWidth / normalizedWidth : 1;
const ratioDiff = newRatio - ( ratioState || 0 );

// Only update the ratio state if the difference is big enough
// or if the ratio state is not yet set. This is to avoid an
// endless loop of updates at particular viewport heights when the
// presence of a scrollbar causes the width to change slightly.
const isRatioDiffBigEnough = Math.abs( ratioDiff ) > 0.1;

if ( isRatioDiffBigEnough || ! ratioState ) {
setRatioState( newRatio );
}
}, [ throttledWidth, ratioState ] );

// Set a fallbackRatio to use before the throttled ratio has been set.
const fallbackRatio = width ? width / normalizedWidth : 1;
// Use the throttled ratio if it has been calculated, otherwise
// use the fallback ratio. The throttled ratio is used to avoid
// an endless loop of updates at particular viewport heights.
// See: https://github.com/WordPress/gutenberg/issues/55112
const ratio = ratioState ? ratioState : fallbackRatio;

const { paletteColors, highlightedColors } = useStylesPreviewColors();

Expand Down Expand Up @@ -108,6 +159,7 @@ const StylesPreview = ( { label, isFocused, withHoverView } ) => {
<Iframe
className="edit-site-global-styles-preview__iframe"
style={ {
width: '100%',
height: normalizedHeight * ratio,
} }
onMouseEnter={ () => setIsHovered( true ) }
Expand Down

1 comment on commit 1ac1d88

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 1ac1d88.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/7241531239
📝 Reported issues:

Please sign in to comment.