Skip to content

Commit

Permalink
Updated Colors component to Contrast checker
Browse files Browse the repository at this point in the history
  • Loading branch information
tjonx committed Sep 22, 2023
1 parent cf81817 commit aa73af3
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 30 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions polaris.shopify.com/public/images/icon-indeterminate.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,27 +1,122 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/fonts.scss';

.Colors {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: var(--p-space-4);
margin-bottom: var(--p-space-8);
font-size: var(--font-size-75);
grid-template-columns: repeat(16, 1fr);
font-size: 0.75rem;
font-weight: var(--p-font-weight-semibold);

@media (min-width: $breakpointTablet) {
grid-template-columns: repeat(10, 1fr);
grid-template-columns: repeat(16, 1fr);
}

h3 {
font-size: 0.75rem;
}

.ColorsSwatch {
position: relative;
overflow: hidden;
border-radius: var(--p-border-radius-2);
margin-bottom: var(--p-space-2);
display: flex;
align-items: center;
justify-content: center;
height: 2.5rem;
overflow: visible;
cursor: pointer;
}

&:before {
.ColorsSelected {
&:after {
content: '';
background: url(/images/icon-do.svg) black no-repeat;
background-position: center;
display: block;
padding-bottom: 75%;
width: var(--p-space-5);
height: var(--p-space-5);
top: var(--p-space-5);
border-radius: var(--p-border-radius-2);
}
}
}

.ColorsContainer {
border-radius: var(--p-border-radius-2);
overflow: hidden;
margin-bottom: var(--p-space-2);
}

.ColorsContrastContainer {
h3 {
font-weight: var(--p-font-weight-semibold);
}

span {
font-weight: var(--p-font-weight-bold);
font-size: var(--font-size-900);
}

.ColorBox {
display: flex;
gap: var(--p-space-2);
margin-top: var(--p-space-2);
align-items: center;

div {
height: var(--p-space-8);
width: var(--p-space-8);
border-radius: var(--p-border-radius-2);
border: 1px solid rgba(0, 0, 0, 0.2);
display: inline-block;
}

span {
font-size: var(--font-size-75);
font-weight: var(--p-font-weight-medium);
}
}
}

.ColorsWCAG {
display: inline-block;
background-color: var(--surface);
padding: var(--p-space-05) var(--p-space-2) var(--p-space-05) var(--p-space-5);
border-radius: var(--p-space-2);
font-size: var(--font-size-100);
font-weight: var(--font-weight-600);
line-height: 1rem;
position: relative;

&:after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
height: 20px;
width: 20px;
background-image: url(/images/icon-indeterminate.svg);
background-repeat: no-repeat;
background-position: left center;
background-size: cover;
z-index: 1;
transition: var(--p-ease-out) var(--p-duration-200) all;
}
}

.ColorsWCAGPass {
background-color: var(--fill-success);
color: var(--text-success-onfill);

&:after {
background-image: url(/images/icon-do.svg);
}
}

.ColorsWCAGFail {
background-color: var(--fill-critical);
color: var(--text-critical-onfill);

&:after {
background-image: url(/images/icon-dont.svg);
}
}
174 changes: 154 additions & 20 deletions polaris.shopify.com/src/components/Markdown/components/Colors/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as colorsObj from '../../../../../../polaris-tokens/dist/esm/src/colors.mjs';
import {Grid} from '@shopify/polaris';
import * as colorsObj from '../../../../../../polaris-tokens/dist/esm/src/colors-experimental.mjs';
import {capitalize} from '../../../../utils/various';
import {Card} from '../../../Card';
import styles from './Colors.module.scss';

type ColorScale = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
Expand All @@ -16,39 +18,171 @@ const colors = colorsObj as unknown as Colors;

export function Colors() {
const colorOrder = [
'gray',
'red',
'orange',
'yellow',
'lime',
'green',
'cyan',
'teal',
'azure',
'blue',
'purple',
'red',
'orange',
'yellow',
'magenta',
'rose',
];

let a11ySelectColorOne: boolean = false;
let a11yColorOne: object = {id: 'none'};
let a11yColorTwo: object = {id: 'none'};
let a11yRatio: number = 0;
const selectColor = (colorValue: string, colorName: string) => {
a11ySelectColorOne = !a11ySelectColorOne;
let rgbaArray = colorValue.replace(/[^\d,]+/g, '').split(',');

document.querySelectorAll('.' + styles.ColorsSwatch).forEach((element) => {
element.classList.remove(styles.ColorsSelected);
});

if (a11ySelectColorOne) {
a11yColorOne = {
r: rgbaArray[0],
g: rgbaArray[1],
b: rgbaArray[2],
a: rgbaArray[3],
id: colorName,
};

document.querySelector(
'#contrast-ratio-color-one-box',
).style.backgroundColor = colorValue;
} else {
a11yColorTwo = {
r: rgbaArray[0],
g: rgbaArray[1],
b: rgbaArray[2],
a: rgbaArray[3],
id: colorName,
};

document.querySelector(
'#contrast-ratio-color-two-box',
).style.backgroundColor = colorValue;
}
console.log(a11yColorOne);
console.log(colorName);

document
.querySelector('#' + a11yColorOne.id)
?.classList.add(styles.ColorsSelected);

document
.querySelector('#' + a11yColorTwo.id)
?.classList.add(styles.ColorsSelected);

if (!Number.isNaN(1 / a11yColorRatio(a11yColorOne, a11yColorTwo))) {
a11yRatio = 1 / a11yColorRatio(a11yColorOne, a11yColorTwo);
document.getElementById('contrast-ratio').innerHTML = a11yRatio
.toFixed(2)
.toString();

let crInteractive = document.querySelector('#contrast-ratio-interactive');
let crText = document.querySelector('#contrast-ratio-text');

crInteractive.classList.remove(styles.ColorsWCAGPass);
crInteractive.classList.remove(styles.ColorsWCAGFail);
crText.classList.remove(styles.ColorsWCAGPass);
crText.classList.remove(styles.ColorsWCAGFail);

a11yRatio > 2.99
? crInteractive.classList.add(styles.ColorsWCAGPass)
: crInteractive.classList.add(styles.ColorsWCAGFail);
a11yRatio > 4.49
? crText.classList.add(styles.ColorsWCAGPass)
: crText.classList.add(styles.ColorsWCAGFail);

document.getElementById('contrast-ratio-color-one').innerHTML =
capitalize(a11yColorOne.id.split(/(\d+)/).join(' '));
document.getElementById('contrast-ratio-color-two').innerHTML =
capitalize(a11yColorTwo.id.split(/(\d+)/).join(' '));
}
};

const a11yLuminance = (r: number, g: number, b: number) => {
var a = [r, g, b].map(function (v) {
v /= 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
};

const a11yColorRatio = (colorOne: any, colorTwo: any) => {
const colorOneL = a11yLuminance(colorOne.r, colorOne.g, colorOne.b);
const colorTwoL = a11yLuminance(colorTwo.r, colorTwo.g, colorTwo.b);

const ratio =
colorOneL > colorTwoL
? (colorTwoL + 0.05) / (colorOneL + 0.05)
: (colorOneL + 0.05) / (colorTwoL + 0.05);

return ratio;
};

const colorMap = colorOrder.map((color) => {
const shades: ColorValue = colors[color] ?? [];
const swatches = Object.entries(shades)
.sort(([prevShade], [nextShade]) =>
Number(prevShade) < Number(nextShade) ? 1 : -1,
)
.map(([shade, value]) => (
<div key={value}>
<div
className={styles.ColorsSwatch}
style={{backgroundColor: value}}
></div>
<div>{shade}</div>
</div>
));
const swatches = Object.entries(shades).map(([shade, value]) => (
<div key={value}>
<div
id={color + shade}
className={styles.ColorsSwatch}
style={{backgroundColor: value}}
onClick={() => selectColor(value, color + shade)}
></div>
</div>
));

return (
<>
<h3>{capitalize(color)}</h3>
<div className={styles.Colors}>{swatches}</div>
</>
);
});

return <>{colorMap}</>;
return (
<>
<div className={styles.ColorsContainer}>{colorMap}</div>
<div className={styles.ColorsContrastContainer}>
<Card>
<Grid>
<Grid.Cell columnSpan={{xs: 3, sm: 3, md: 3, lg: 4, xl: 4}}>
<h3>Colors</h3>
<div className={styles.ColorBox}>
<div id="contrast-ratio-color-one-box"></div>
<span id="contrast-ratio-color-one">Pick two colors</span>
</div>
<div className={styles.ColorBox}>
<div id="contrast-ratio-color-two-box"></div>
<span id="contrast-ratio-color-two">Pick two colors</span>
</div>
</Grid.Cell>
<Grid.Cell columnSpan={{xs: 3, sm: 3, md: 3, lg: 8, xl: 8}}>
<h3>Contrast ratio</h3>
<span id="contrast-ratio"></span>
<br />
<div id="contrast-ratio-text" className={styles.ColorsWCAG}>
AA Text
</div>
<br />
<div
id="contrast-ratio-interactive"
className={styles.ColorsWCAG}
>
AA Interactive
</div>
</Grid.Cell>
</Grid>
</Card>
</div>
</>
);
}

0 comments on commit aa73af3

Please sign in to comment.