diff --git a/packages/block-editor/src/components/colors/color-panel.js b/packages/block-editor/src/components/colors/color-panel.js
index 95784826eb302d..75fe0e26238e30 100644
--- a/packages/block-editor/src/components/colors/color-panel.js
+++ b/packages/block-editor/src/components/colors/color-panel.js
@@ -53,7 +53,11 @@ export default function ColorPanel( {
);
@@ -79,7 +83,11 @@ export default function ColorPanel( {
{ ...contrastCheckers }
key={ `${ backgroundColor }-${ textColor }` }
backgroundColor={ backgroundColor }
- textColor={ textColor }
+ textColors={ [
+ {
+ color: textColor,
+ },
+ ] }
/>
);
} ) ) }
diff --git a/packages/block-editor/src/components/contrast-checker/contrast-checker-message.js b/packages/block-editor/src/components/contrast-checker/contrast-checker-message.js
index 96ea04c7bfb3e9..317f361e822c52 100644
--- a/packages/block-editor/src/components/contrast-checker/contrast-checker-message.js
+++ b/packages/block-editor/src/components/contrast-checker/contrast-checker-message.js
@@ -1,49 +1,9 @@
/**
* WordPress dependencies
*/
-import { speak } from '@wordpress/a11y';
-import { __ } from '@wordpress/i18n';
import { Notice } from '@wordpress/components';
-import { useEffect } from '@wordpress/element';
-
-export default function ContrastCheckerMessage( {
- colordBackgroundColor,
- colordTextColor,
- colordLinkColor,
- backgroundColor,
- textColor,
- linkColor,
- shouldShowTransparencyWarning,
-} ) {
- let msg = '';
- if ( shouldShowTransparencyWarning ) {
- msg = __( 'Transparent text may be hard for people to read.' );
- } else {
- const backgroundColorBrightness = colordBackgroundColor.brightness();
- msg =
- ( colordTextColor &&
- backgroundColorBrightness < colordTextColor.brightness() ) ||
- ( colordLinkColor &&
- backgroundColorBrightness < colordLinkColor.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( () => {
- 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, linkColor ] );
+export default function ContrastCheckerMessage( { message } ) {
return (
- { msg }
+ { message }
);
diff --git a/packages/block-editor/src/components/contrast-checker/index.js b/packages/block-editor/src/components/contrast-checker/index.js
index aba4b586f9f524..0925aade73a64e 100644
--- a/packages/block-editor/src/components/contrast-checker/index.js
+++ b/packages/block-editor/src/components/contrast-checker/index.js
@@ -1,3 +1,8 @@
+/**
+ * WordPress dependencies
+ */
+import { __, sprintf } from '@wordpress/i18n';
+import { speak } from '@wordpress/a11y';
/**
* External dependencies
*/
@@ -15,50 +20,21 @@ extend( [ namesPlugin, a11yPlugin ] );
function ContrastChecker( {
backgroundColor,
fallbackBackgroundColor,
- fallbackTextColor,
- fallbackLinkColor,
fontSize, // font size value in pixels
isLargeText,
- textColor,
- linkColor,
+ textColors,
enableAlphaChecker = false,
} ) {
const currentBackgroundColor = backgroundColor || fallbackBackgroundColor;
- // Must have a background color.
- if ( ! currentBackgroundColor ) {
- return null;
- }
-
- const currentTextColor = textColor || fallbackTextColor;
- const currentLinkColor = linkColor || fallbackLinkColor;
-
- // Must have at least one text color.
- if ( ! currentTextColor && ! currentLinkColor ) {
+ // Must have a background color and some colours to iterate over.
+ if ( ! currentBackgroundColor || ! textColors || ! textColors.length ) {
return null;
}
const colordBackgroundColor = colord( currentBackgroundColor );
const backgroundColorHasTransparency = colordBackgroundColor.alpha() < 1;
-
- // If there's only one color passed, store in `singleTextColor`.
- const singleTextColor =
- currentTextColor && currentLinkColor
- ? null
- : currentTextColor || currentLinkColor;
-
- const colordTextColor = singleTextColor
- ? colord( singleTextColor )
- : colord( currentTextColor );
- const colordLinkColor = colord( currentLinkColor );
-
- // Transparency.
- const textColorHasTransparency =
- currentTextColor && colordTextColor.alpha() < 1;
- const linkColorHasTransparency =
- currentLinkColor && colordLinkColor.alpha() < 1;
-
- // Text size.
+ const backgroundColorBrightness = colordBackgroundColor.brightness();
const isReadableOptions = {
level: 'AA',
size:
@@ -67,63 +43,75 @@ function ContrastChecker( {
: 'small',
};
- // Readability.
- const isTextColorReadable =
- currentTextColor &&
- colordTextColor.isReadable( colordBackgroundColor, isReadableOptions );
-
- const isLinkColorReadable =
- currentLinkColor &&
- colordLinkColor.isReadable( colordBackgroundColor, isReadableOptions );
-
- // Flag to warn about transparency only if the text is otherwise readable according to colord
- // to ensure the readability warnings take precedence.
- let shouldShowTransparencyWarning = false;
-
- // Don't show the message if the text is readable AND there's no transparency.
- // This is the default.
- if ( ! textColorHasTransparency && ! linkColorHasTransparency ) {
- // If the background has transparency, don't show any contrast warnings.
- if (
- backgroundColorHasTransparency ||
- ( isTextColorReadable && isLinkColorReadable ) ||
- ( singleTextColor && isTextColorReadable )
- ) {
- return null;
+ let message = '';
+ let speakMessage = '';
+ for ( const item of textColors ) {
+ const currentTextColor = item.color || item.fallback;
+ // If there is no color, go no further.
+ if ( ! currentTextColor ) {
+ continue;
}
- } else {
- // If there's text transparency, don't show the message if the alpha checker is disabled.
- if ( ! enableAlphaChecker ) {
- return null;
+ const colordTextColor = colord( currentTextColor );
+ const isColordTextReadable = colordTextColor.isReadable(
+ colordBackgroundColor,
+ isReadableOptions
+ );
+ const textHasTransparency = colordTextColor.alpha() < 1;
+
+ // If the contrast is not readable.
+ if ( ! isColordTextReadable ) {
+ // Don't show the message if the background or text is transparent.
+ if ( backgroundColorHasTransparency || textHasTransparency ) {
+ continue;
+ }
+ const description = item.description || __( 'text color' );
+ message =
+ backgroundColorBrightness < colordTextColor.brightness()
+ ? sprintf(
+ // translators: %s is a type of text color, e.g., "text color" or "link color"
+ __(
+ 'This color combination may be hard for people to read. Try using a darker background color and/or a brighter %s.'
+ ),
+ description
+ )
+ : sprintf(
+ // translators: %s is a type of text color, e.g., "text color" or "link color"
+ __(
+ 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker %s.'
+ ),
+ description
+ );
+ speakMessage = __(
+ 'This color combination may be hard for people to read.'
+ );
+ // Break from the loop when we have a contrast warning.
+ // These messages take priority over the transparency warning.
+ break;
}
- // If the background has transparency, don't show any contrast warnings.
- // If both text colors are readable, but transparent show the warning.
- if (
- backgroundColorHasTransparency ||
- ( isTextColorReadable && isLinkColorReadable )
- ) {
- shouldShowTransparencyWarning = true;
+ // If the text color is readable, but transparent, show the transparent warning.
+ if ( textHasTransparency && true === enableAlphaChecker ) {
+ message = __( 'Transparent text may be hard for people to read.' );
+ speakMessage = __(
+ 'Transparent text may be hard for people to read.'
+ );
}
+ }
- // If there is only one text color (text or link) and the color is readable with no transparency.
- if ( singleTextColor && isTextColorReadable ) {
- if ( ! textColorHasTransparency ) {
- return null;
- }
- shouldShowTransparencyWarning = true;
- }
+ if ( ! message ) {
+ return null;
}
+ // 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.
+ speak( speakMessage );
+
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 6b5dc9b45eaad2..d4936944b0ee49 100644
--- a/packages/block-editor/src/components/contrast-checker/test/index.js
+++ b/packages/block-editor/src/components/contrast-checker/test/index.js
@@ -39,9 +39,18 @@ describe( 'ContrastChecker', () => {
test( 'should render null when no background or fallback background color is provided', () => {
const wrapper = mount(
);
@@ -53,11 +62,20 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -69,10 +87,15 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -88,11 +111,20 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -100,7 +132,7 @@ describe( 'ContrastChecker', () => {
'This color combination may be hard for people to read.'
);
expect( wrapper.find( Notice ).children().text() ).toBe(
- 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.'
+ 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker link color, Jack.'
);
} );
@@ -108,11 +140,19 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -128,11 +168,18 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -140,14 +187,18 @@ describe( 'ContrastChecker', () => {
expect( wrapper.html() ).toBeNull();
} );
- test( 'should render render null if text color contains a transparency', () => {
+ test( 'should render null if text color contains a transparency', () => {
const wrapper = mount(
);
@@ -159,11 +210,18 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -177,10 +235,15 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -196,8 +259,13 @@ describe( 'ContrastChecker', () => {
const wrapperSmallText = mount(
);
@@ -211,8 +279,13 @@ describe( 'ContrastChecker', () => {
const wrapperLargeText = mount(
);
@@ -223,7 +296,12 @@ describe( 'ContrastChecker', () => {
const wrapperSmallFontSize = mount(
);
@@ -238,7 +316,12 @@ describe( 'ContrastChecker', () => {
const wrapperLargeText = mount(
);
@@ -250,7 +333,12 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
@@ -262,7 +350,12 @@ describe( 'ContrastChecker', () => {
const wrapperNoLargeText = mount(
@@ -281,7 +374,12 @@ describe( 'ContrastChecker', () => {
);
@@ -292,8 +390,13 @@ describe( 'ContrastChecker', () => {
test( 'should render messages when the textColor is valid, but the fallback backgroundColor conflicts.', () => {
const wrapper = mount(
);
@@ -308,8 +411,13 @@ describe( 'ContrastChecker', () => {
test( 'should render messages when the linkColor is valid, but the fallback backgroundColor conflicts.', () => {
const wrapper = mount(
);
@@ -317,7 +425,7 @@ describe( 'ContrastChecker', () => {
'This color combination may be hard for people to read.'
);
expect( wrapper.find( Notice ).children().text() ).toBe(
- 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.'
+ 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker link color.'
);
} );
@@ -327,8 +435,13 @@ describe( 'ContrastChecker', () => {
act( () => {
render(
,
appRoot
);
@@ -337,7 +450,12 @@ describe( 'ContrastChecker', () => {
act( () => {
render(
,
appRoot
@@ -352,9 +470,14 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -366,10 +489,18 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -385,10 +516,18 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -404,10 +543,18 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -419,12 +566,20 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -436,12 +591,20 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -457,12 +620,19 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
@@ -470,7 +640,7 @@ describe( 'ContrastChecker', () => {
'This color combination may be hard for people to read.'
);
expect( wrapper.find( Notice ).children().text() ).toBe(
- 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.'
+ 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker link color.'
);
} );
@@ -478,10 +648,18 @@ describe( 'ContrastChecker', () => {
const wrapper = mount(
);
diff --git a/packages/block-editor/src/hooks/color-panel.js b/packages/block-editor/src/hooks/color-panel.js
index c360ed4e87c6cb..2775eebe66c0de 100644
--- a/packages/block-editor/src/hooks/color-panel.js
+++ b/packages/block-editor/src/hooks/color-panel.js
@@ -74,9 +74,17 @@ export default function ColorPanel( {
{ enableContrastChecking && (
) }
diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js
index 705a46845c1057..0667377f71f947 100644
--- a/packages/block-library/src/navigation/edit/index.js
+++ b/packages/block-library/src/navigation/edit/index.js
@@ -633,13 +633,23 @@ function Navigation( {
backgroundColor={
detectedBackgroundColor
}
- textColor={ detectedColor }
+ textColors={ [
+ {
+ color: detectedColor,
+ description: __( 'text color' ),
+ },
+ ] }
/>
>
) }
diff --git a/packages/block-library/src/social-links/edit.js b/packages/block-library/src/social-links/edit.js
index ee5425174c67af..dd05a199e6844a 100644
--- a/packages/block-library/src/social-links/edit.js
+++ b/packages/block-library/src/social-links/edit.js
@@ -208,11 +208,14 @@ export function SocialLinksEdit( props ) {
/>
{ ! logosOnly && (
) }