From b925ac6085bce05cf81a9230d227ed4bb59d269c Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Sat, 18 Jan 2025 14:03:21 +0400 Subject: [PATCH 1/3] Block Editor: Fix block color contrast checker --- .../src/hooks/contrast-checker.js | 80 +++++++++++++------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/packages/block-editor/src/hooks/contrast-checker.js b/packages/block-editor/src/hooks/contrast-checker.js index 368e2e75264858..7ed920587c12f6 100644 --- a/packages/block-editor/src/hooks/contrast-checker.js +++ b/packages/block-editor/src/hooks/contrast-checker.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useState, useEffect } from '@wordpress/element'; +import { useState, useLayoutEffect } from '@wordpress/element'; /** * Internal dependencies @@ -9,8 +9,47 @@ import { useState, useEffect } from '@wordpress/element'; import ContrastChecker from '../components/contrast-checker'; import { useBlockElement } from '../components/block-list/use-block-props/use-block-refs'; -function getComputedStyle( node ) { - return node.ownerDocument.defaultView.getComputedStyle( node ); +function getComputedValue( node, property ) { + return node.ownerDocument.defaultView + .getComputedStyle( node ) + .getPropertyValue( property ); +} + +function getBlockElementColors( blockEl ) { + if ( ! blockEl ) { + return {}; + } + + const firstLinkElement = blockEl.querySelector( 'a' ); + const linkColor = !! firstLinkElement?.innerText + ? getComputedValue( firstLinkElement, 'color' ) + : null; + + const textColor = getComputedValue( blockEl, 'color' ); + + let backgroundColorNode = blockEl; + let backgroundColor = getComputedValue( + backgroundColorNode, + 'background-color' + ); + while ( + backgroundColor === 'rgba(0, 0, 0, 0)' && + backgroundColorNode.parentNode && + backgroundColorNode.parentNode.nodeType === + backgroundColorNode.parentNode.ELEMENT_NODE + ) { + backgroundColorNode = backgroundColorNode.parentNode; + backgroundColor = getComputedValue( + backgroundColorNode, + 'background-color' + ); + } + + return { + textColor, + backgroundColor, + linkColor, + }; } export default function BlockColorContrastChecker( { clientId } ) { @@ -21,40 +60,31 @@ export default function BlockColorContrastChecker( { clientId } ) { // There are so many things that can change the color of a block // So we perform this check on every render. - useEffect( () => { + useLayoutEffect( () => { if ( ! blockEl ) { return; } - setDetectedColor( getComputedStyle( blockEl ).color ); - - const firstLinkElement = blockEl.querySelector( 'a' ); - if ( firstLinkElement && !! firstLinkElement.innerText ) { - setDetectedLinkColor( getComputedStyle( firstLinkElement ).color ); - } - let backgroundColorNode = blockEl; - let backgroundColor = - getComputedStyle( backgroundColorNode ).backgroundColor; - while ( - backgroundColor === 'rgba(0, 0, 0, 0)' && - backgroundColorNode.parentNode && - backgroundColorNode.parentNode.nodeType === - backgroundColorNode.parentNode.ELEMENT_NODE - ) { - backgroundColorNode = backgroundColorNode.parentNode; - backgroundColor = - getComputedStyle( backgroundColorNode ).backgroundColor; + function updateColors() { + const colors = getBlockElementColors( blockEl ); + setDetectedColor( colors.textColor ); + setDetectedBackgroundColor( colors.backgroundColor ); + if ( colors.linkColor ) { + setDetectedLinkColor( colors.linkColor ); + } } - setDetectedBackgroundColor( backgroundColor ); - }, [ blockEl ] ); + window.requestAnimationFrame( () => + window.requestAnimationFrame( updateColors ) + ); + } ); return ( ); } From 49286cf287ea866923fae7c7ddc515356078cf7e Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Sat, 18 Jan 2025 17:48:34 +0400 Subject: [PATCH 2/3] Use reducer hook --- .../src/hooks/contrast-checker.js | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/hooks/contrast-checker.js b/packages/block-editor/src/hooks/contrast-checker.js index 7ed920587c12f6..dd4aeda8277e1d 100644 --- a/packages/block-editor/src/hooks/contrast-checker.js +++ b/packages/block-editor/src/hooks/contrast-checker.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useState, useLayoutEffect } from '@wordpress/element'; +import { useLayoutEffect, useReducer } from '@wordpress/element'; /** * Internal dependencies @@ -23,7 +23,7 @@ function getBlockElementColors( blockEl ) { const firstLinkElement = blockEl.querySelector( 'a' ); const linkColor = !! firstLinkElement?.innerText ? getComputedValue( firstLinkElement, 'color' ) - : null; + : undefined; const textColor = getComputedValue( blockEl, 'color' ); @@ -52,11 +52,18 @@ function getBlockElementColors( blockEl ) { }; } +function reducer( prevColors, newColors ) { + const hasChanged = Object.keys( newColors ).some( + ( key ) => prevColors[ key ] !== newColors[ key ] + ); + + // Do not re-render if the colors have not changed. + return hasChanged ? newColors : prevColors; +} + export default function BlockColorContrastChecker( { clientId } ) { - const [ detectedBackgroundColor, setDetectedBackgroundColor ] = useState(); - const [ detectedColor, setDetectedColor ] = useState(); - const [ detectedLinkColor, setDetectedLinkColor ] = useState(); const blockEl = useBlockElement( clientId ); + const [ colors, setColors ] = useReducer( reducer, {} ); // There are so many things that can change the color of a block // So we perform this check on every render. @@ -66,12 +73,7 @@ export default function BlockColorContrastChecker( { clientId } ) { } function updateColors() { - const colors = getBlockElementColors( blockEl ); - setDetectedColor( colors.textColor ); - setDetectedBackgroundColor( colors.backgroundColor ); - if ( colors.linkColor ) { - setDetectedLinkColor( colors.linkColor ); - } + setColors( getBlockElementColors( blockEl ) ); } window.requestAnimationFrame( () => @@ -81,9 +83,9 @@ export default function BlockColorContrastChecker( { clientId } ) { return ( ); From 3662d7cd258fca37c20cece8132cf335ec923a3f Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Sat, 18 Jan 2025 17:53:13 +0400 Subject: [PATCH 3/3] Add comment --- packages/block-editor/src/hooks/contrast-checker.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/block-editor/src/hooks/contrast-checker.js b/packages/block-editor/src/hooks/contrast-checker.js index dd4aeda8277e1d..7cb231110401d4 100644 --- a/packages/block-editor/src/hooks/contrast-checker.js +++ b/packages/block-editor/src/hooks/contrast-checker.js @@ -76,6 +76,8 @@ export default function BlockColorContrastChecker( { clientId } ) { setColors( getBlockElementColors( blockEl ) ); } + // Combine `useLayoutEffect` and two rAF calls to ensure that values are read + // after the current paint but before the next paint. window.requestAnimationFrame( () => window.requestAnimationFrame( updateColors ) );