diff --git a/packages/block-editor/src/components/contrast-checker/README.md b/packages/block-editor/src/components/contrast-checker/README.md index b663b63fac514..6f3b41ecb7d0c 100644 --- a/packages/block-editor/src/components/contrast-checker/README.md +++ b/packages/block-editor/src/components/contrast-checker/README.md @@ -1,6 +1,8 @@ # ContrastChecker -ContrastChecker component determines if contrast for text styles is sufficient (WCAG 2.0 AA) when used with a given background color. ContrastCheker also accounts for background color transparency (alpha) as well as font sizes. +ContrastChecker component determines if contrast for text styles is sufficient (WCAG 2.0 AA) when used with a given background color. + +ContrastChecker also accounts for font sizes. A notice will be rendered if the color combination of text and background colors are low. diff --git a/packages/block-editor/src/components/contrast-checker/index.js b/packages/block-editor/src/components/contrast-checker/index.js index e50c3d4622996..afb60b5f42fda 100644 --- a/packages/block-editor/src/components/contrast-checker/index.js +++ b/packages/block-editor/src/components/contrast-checker/index.js @@ -20,22 +20,31 @@ function ContrastCheckerMessage( { colordTextColor, backgroundColor, textColor, + shouldShowTransparencyWarning, } ) { - const msg = - colordBackgroundColor.brightness() < colordTextColor.brightness() - ? __( - 'This color combination may be hard for people to read. Try using a darker background color and/or a brighter text color.' - ) - : __( - 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' - ); + let msg = ''; + if ( shouldShowTransparencyWarning ) { + msg = __( 'Transparent text may be hard for people to read.' ); + } else { + msg = + colordBackgroundColor.brightness() < colordTextColor.brightness() + ? __( + 'This color combination may be hard for people to read. Try using a darker background color and/or a brighter text color.' + ) + : __( + 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' + ); + } // Note: The `Notice` component can speak messages via its `spokenMessage` // prop, but the contrast checker requires granular control over when the // announcements are made. Notably, the message will be re-announced if a // new color combination is selected and the contrast is still insufficient. useEffect( () => { - speak( __( 'This color combination may be hard for people to read.' ) ); + const speakMsg = shouldShowTransparencyWarning + ? __( 'Transparent text may be hard for people to read.' ) + : __( 'This color combination may be hard for people to read.' ); + speak( speakMsg ); }, [ backgroundColor, textColor ] ); return ( @@ -58,6 +67,7 @@ function ContrastChecker( { fontSize, // font size value in pixels isLargeText, textColor, + enableAlphaChecker = false, } ) { if ( ! ( backgroundColor || fallbackBackgroundColor ) || @@ -69,28 +79,46 @@ function ContrastChecker( { backgroundColor || fallbackBackgroundColor ); const colordTextColor = colord( textColor || fallbackTextColor ); + const textColorHasTransparency = colordTextColor.alpha() < 1; + const backgroundColorHasTransparency = colordBackgroundColor.alpha() < 1; const hasTransparency = - colordBackgroundColor.alpha() !== 1 || colordTextColor.alpha() !== 1; + textColorHasTransparency || backgroundColorHasTransparency; + const isReadable = colordTextColor.isReadable( colordBackgroundColor, { + level: 'AA', + size: + isLargeText || ( isLargeText !== false && fontSize >= 24 ) + ? 'large' + : 'small', + } ); - if ( - hasTransparency || - colordTextColor.isReadable( colordBackgroundColor, { - level: 'AA', - size: - isLargeText || ( isLargeText !== false && fontSize >= 24 ) - ? 'large' - : 'small', - } ) - ) { + // Don't show the message if the text is readable AND there's no transparency. + // This is the default. + if ( isReadable && ! hasTransparency ) { return null; } + if ( hasTransparency ) { + if ( + // If there's transparency, don't show the message if the alpha checker is disabled. + ! enableAlphaChecker || + // If the alpha checker is enabled, we only show the warning if the text has transparency. + ( isReadable && ! textColorHasTransparency ) + ) { + return null; + } + } + return ( ); } diff --git a/packages/block-editor/src/components/contrast-checker/test/index.js b/packages/block-editor/src/components/contrast-checker/test/index.js index 0a9bf363f1625..d916e12439cff 100644 --- a/packages/block-editor/src/components/contrast-checker/test/index.js +++ b/packages/block-editor/src/components/contrast-checker/test/index.js @@ -50,6 +50,20 @@ describe( 'ContrastChecker', () => { expect( wrapper.html() ).toBeNull(); } ); + test( 'should render null when the colors meet AA WCAG guidelines and alpha checker enabled.', () => { + const wrapper = mount( + + ); + + expect( speak ).not.toHaveBeenCalled(); + expect( wrapper.html() ).toBeNull(); + } ); + test( 'should render component when the colors do not meet AA WCAG guidelines.', () => { const wrapper = mount( { expect( speak ).toHaveBeenCalledTimes( 2 ); } ); + + // enableAlphaChecker tests + test( 'should render component when the colors meet AA WCAG guidelines but the text color only has alpha transparency with alpha checker enabled.', () => { + const wrapper = mount( + + ); + + expect( speak ).toHaveBeenCalledWith( + 'Transparent text may be hard for people to read.' + ); + expect( wrapper.find( Notice ).children().text() ).toBe( + 'Transparent text may be hard for people to read.' + ); + } ); + + test( 'should render null when the colors meet AA WCAG guidelines but the background color only has alpha transparency with alpha checker enabled.', () => { + const wrapper = mount( + + ); + + expect( speak ).not.toHaveBeenCalled(); + expect( wrapper.html() ).toBeNull(); + } ); + + test( 'should render component when the colors meet AA WCAG guidelines but all colors have alpha transparency with alpha checker enabled.', () => { + const wrapper = mount( + + ); + + expect( speak ).toHaveBeenCalledWith( + 'Transparent text may be hard for people to read.' + ); + expect( wrapper.find( Notice ).children().text() ).toBe( + 'Transparent text may be hard for people to read.' + ); + } ); } ); diff --git a/packages/block-editor/src/hooks/color-panel.js b/packages/block-editor/src/hooks/color-panel.js index 9c018f6c649c4..72ec01fd326ce 100644 --- a/packages/block-editor/src/hooks/color-panel.js +++ b/packages/block-editor/src/hooks/color-panel.js @@ -17,6 +17,7 @@ function getComputedStyle( node ) { } export default function ColorPanel( { + enableAlpha = false, settings, clientId, enableContrastChecking = true, @@ -60,6 +61,7 @@ export default function ColorPanel( { initialOpen={ false } settings={ settings } showTitle={ showTitle } + enableAlpha={ enableAlpha } __experimentalHasMultipleOrigins __experimentalIsRenderedInSidebar > @@ -67,6 +69,7 @@ export default function ColorPanel( { ) } diff --git a/packages/block-editor/src/hooks/color.js b/packages/block-editor/src/hooks/color.js index bb648bac9f212..5d92c321daf1a 100644 --- a/packages/block-editor/src/hooks/color.js +++ b/packages/block-editor/src/hooks/color.js @@ -371,13 +371,14 @@ export function ColorEdit( props ) { props.setAttributes( { style: newStyle } ); }; + const enableContrastChecking = + Platform.OS === 'web' && ! gradient && ! style?.color?.gradient; + return (