From 97956dbd8369cefb421bc83543060e36d7917d04 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 23 Feb 2024 14:03:00 +1100 Subject: [PATCH] Use rAF approach for PaddingVisualizer as well ResizeObserver doesn't work in the case where an element with a fixed width has its padding changed. --- packages/block-editor/src/hooks/padding.js | 58 +++++++++++++--------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/packages/block-editor/src/hooks/padding.js b/packages/block-editor/src/hooks/padding.js index f6d9b3a912f54..84883d416a80d 100644 --- a/packages/block-editor/src/hooks/padding.js +++ b/packages/block-editor/src/hooks/padding.js @@ -1,7 +1,12 @@ /** * WordPress dependencies */ -import { useState, useRef, useEffect } from '@wordpress/element'; +import { + useState, + useRef, + useLayoutEffect, + useEffect, +} from '@wordpress/element'; import isShallowEqual from '@wordpress/is-shallow-equal'; /** @@ -20,33 +25,40 @@ export function PaddingVisualizer( { clientId, value, forceShow } ) { const blockElement = useBlockElement( clientId ); const [ style, setStyle ] = useState(); - useEffect( () => { + const padding = value?.spacing?.padding; + + useLayoutEffect( () => { if ( ! blockElement ) { return; } // It's not sufficient to read the computed padding value when value.spacing.padding - // changes as useEffect may run before the browser recomputes CSS and paints. Instead, - // we use a ResizeObserver with the box option set to 'border-box' to listen out for - // changes to the padding. - const observer = new window.ResizeObserver( () => { - setStyle( { - borderTopWidth: getComputedCSS( blockElement, 'padding-top' ), - borderRightWidth: getComputedCSS( - blockElement, - 'padding-right' - ), - borderBottomWidth: getComputedCSS( - blockElement, - 'padding-bottom' - ), - borderLeftWidth: getComputedCSS( blockElement, 'padding-left' ), - } ); - } ); - observer.observe( blockElement, { box: 'border-box' } ); - return () => observer.disconnect(); - }, [ blockElement ] ); + // changes as useEffect may run before the browser recomputes CSS. We therefore combine + // useLayoutEffect and two rAF calls to ensure that we read the padding after the current + // paint but before the next paint. + window.requestAnimationFrame( () => + window.requestAnimationFrame( () => { + setStyle( { + borderTopWidth: getComputedCSS( + blockElement, + 'padding-top' + ), + borderRightWidth: getComputedCSS( + blockElement, + 'padding-right' + ), + borderBottomWidth: getComputedCSS( + blockElement, + 'padding-bottom' + ), + borderLeftWidth: getComputedCSS( + blockElement, + 'padding-left' + ), + } ); + } ) + ); + }, [ blockElement, padding ] ); - const padding = value?.spacing?.padding; const previousPadding = useRef( padding ); const [ isActive, setIsActive ] = useState( false );