Skip to content
Draft
102 changes: 102 additions & 0 deletions src/editor/components/BBContrastChecker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

const BBContrastChecker = ( { background, foreground } ) => {
/**
* If either colour is not provided, don't render anything
*/
if ( ! background || ! foreground ) {
return;
}

/**
* Get the luminance of a colour
*
* @param {string} colour The colour to convert to luminance value
*
* @return {number} The luminance value
*/
const getLuminance = ( colour ) => {
const rgb = colour
.match( /\w\w/g )
.map( ( c ) => parseInt( c, 16 ) / 255 );
const [ r, g, b ] = rgb.map( ( c ) => {
return c <= 0.03928
? c / 12.92
: Math.pow( ( c + 0.055 ) / 1.055, 2.4 );
} );
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
};

/**
* Compare two colours and return their contrast ratio.
*
* @param {string} colour1 This is an example function/method parameter description.
* @param {string} colour2 This is a second example.
*
* @return {number} The contrast ratio between the colours
*/
const getContrastRatio = ( colour1, colour2 ) => {
const luminance1 = getLuminance( colour1 );
const luminance2 = getLuminance( colour2 );
return (
( Math.max( luminance1, luminance2 ) + 0.05 ) /
( Math.min( luminance1, luminance2 ) + 0.05 )
);
};

/**
* Determine the colour contrast ratio
*/
const contrastRatio = getContrastRatio( background, foreground );

/**
* Determine the message to output
*/
const displayMessage =
contrastRatio >= 4.5
? __(
'The selected colours do not meet the colour contrast ratio for AAA (7:1) accessibility standards',
'themer'
)
: __(
'The selected colours do not meet the colour contrast ratio for AA (4.5:1) accessibility standards',
'themer'
);

/**
* Set the notice display level based on the contrast ratio
*/
const displayMessageImportance = contrastRatio >= 4.5 ? 'info' : 'warning';

return (
<>
<div className="contrast-checker">
<p className="contrast-checker-title">
{ __( 'WCAG Check:', 'themer' ) }
</p>
<p className="contrast-checker-ratio">
{ contrastRatio.toFixed( 1 ) } : 1
</p>
<div className="contrast-checker-badges">
<p className={ contrastRatio >= 4.5 ? 'pass' : ' fail' }>
&#x2713; { __( 'AA', 'themer' ) }
</p>
<p className={ contrastRatio >= 7 ? 'pass' : ' fail' }>
&#x2713; { __( 'AAA ', 'themer' ) }
</p>
</div>
</div>
{ contrastRatio < 7 && (
<Notice
status={ displayMessageImportance }
isDismissible={ false }
>
{ displayMessage }
</Notice>
) }
</>
);
};

export default BBContrastChecker;
19 changes: 15 additions & 4 deletions src/editor/components/StylesColor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { set } from 'lodash';
import { set, debounce } from 'lodash';
import { __ } from '@wordpress/i18n';
import { useContext } from '@wordpress/element';
import { ColorPalette } from '@wordpress/components';
Expand All @@ -8,6 +8,7 @@ import getThemeOption from '../../utils/get-theme-option';
import EditorContext from '../context/EditorContext';
import StylesContext from '../context/StylesContext';
import Gradient from './StylesGradient';
import BBContrastChecker from './BBContrastChecker';

/**
* Reusable color control style component
Expand All @@ -24,22 +25,28 @@ const Color = ( { selector } ) => {
themeConfig
);

const onChange = ( newValue, key ) => {
/**
* Function to handle the colour palette changes
*
* @param {string} newValue The value of the setting
* @param {string} key The key of the setting
*/
const onChange = debounce( ( newValue, key ) => {
let config = structuredClone( userConfig );
config = set(
config,
[ selector, key ].join( '.' ),
hexToVar( newValue, themePalette ) ?? ''
);
setUserConfig( config );
};
}, 50 );

const colorPalettes = [ 'background', 'text' ].map( ( key ) => (
<div key={ key } className="themer--styles__item__column">
<span className="themer--styles__item__label">{ key }</span>
<ColorPalette
label={ __( 'Color', 'themer' ) }
colors={ themePalette }
label={ __( 'Color', 'themer' ) }
onChange={ ( value ) => onChange( value, key ) }
value={ varToHex( colorStyles[ key ], themePalette ) }
/>
Expand All @@ -51,6 +58,10 @@ const Color = ( { selector } ) => {
<span className="themer--styles__item__title">
{ __( 'Color', 'themer' ) }
</span>
<BBContrastChecker
background={ varToHex( colorStyles.background, themePalette ) }
foreground={ varToHex( colorStyles.text, themePalette ) }
/>
<div className="themer--styles__item__columns themer--styles__item__columns--2">
{ colorPalettes }
<Gradient selector={ `${ selector }.gradient` } />
Expand Down
82 changes: 82 additions & 0 deletions src/editor/styles/components/bb-contrast-checker.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
.themer--styles__item:has(.contrast-checker) {
container-type: inline-size;
container-name: contrast-checker-outer;
}

.contrast-checker {
align-items: center;
border: 1px solid green;
border-radius: 0.5rem;
display: flex;
gap: 1rem;
justify-content: flex-start;
padding: 0.5rem;

transition: border-color 0.25s ease-in-out;
}

.contrast-checker:has(p.fail) {
border-color: blue;
}

.contrast-checker:has(p.fail + p.fail) {
border-color: red;
}

.contrast-checker p {
margin-block: 0;
}

.contrast-checker-title {
font-size: 0.75rem;
font-weight: bold;
text-transform: uppercase;
}

.contrast-checker-ratio {
font-size: 1.25rem;
font-weight: bold;
margin-inline-start: auto;
}

.contrast-checker-badges {
align-items: center;
display: flex;
gap: 0.5rem;
}

.contrast-checker-badges > p {
background-color: green;
border-radius: 0.25rem;
color: #fff;
display: block;
padding: 0.25rem 0.5rem;

transition: background-color 0.25s ease-in-out,
color 0.25s ease-in-out;
}

.contrast-checker-badges > p.fail {
background-color: red;
color: #000;
}


@container contrast-checker-outer (max-width: 350px) {

.contrast-checker {
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
}

.contrast-checker-title {
text-align: center;
width: 100%;
}

.contrast-checker-ratio {
margin-inline-start: 0;
}

}
1 change: 1 addition & 0 deletions src/editor/styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
@import "./components/breadcrumbs";
@import "./components/nav-list";
@import "./components/fontPicker.scss";
@import "./components/bb-contrast-checker";