/
a11y.js
134 lines (107 loc) · 3.23 KB
/
a11y.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const chroma = require('chroma-js');
const fs = require('fs');
const Task = require('data.task');
const colorSet = [];
const results = {};
const checks = [];
const minimumRatios = {
aa: 4.5,
aaLarge: 3,
aaa: 7,
aaaLarge: 4.5
};
const Box = x =>
({
map: f => Box(f(x)),
fold: f => f(x),
inspect: () => `Box(${x}))`
})
const Right = x =>
({
chain:f => f(x),
map: f => Right(f(x)),
fold: (f, g) => g(x),
inspect: () => 'Right(${x})',
})
const Left = x =>
({
chain: f => Left(x),
map: f => Left(x),
fold: (f, g) => f(x),
inspect: () => 'Left(${x})'
})
const fromNullable = x =>
x != null ? Right(x) : Left(null);
const tryCatch = f => {
try {
return Right(f());
} catch(e) {
return Left(e);
}
}
const writeFile = (filename, contents) =>
new Task((rej, res) =>
fs.writeFile(filename, contents, (err, success) => (err ? rej(err) : res(success))));
// THIS IS TOTALLY GOOD
const readFile = (filename) =>
tryCatch(() => fs.readFileSync( filename, 'utf8'))
.chain(r => tryCatch(() => JSON.parse(r)))
.fold(e => 3000,
r => r);
const colors = readFile("./colorPalette.json");
// THIS IS TOTALLY GOOD
// Given two numbers, return their contrast ratio. Pass in true to truncate values at 2 decimals
const getRatio = (hex1, hex2, round) =>
Box(chroma.contrast(hex1, hex2))
.fold( r => round ? Math.round(r * 100)/100 : r )
// Flatten json object into an array of objects with name and hex props
// THIS SHOULD BE CHECKING FOR NULL VALUES USING RIGHT/LEFT
const getColors = obj =>
Object.keys(obj).forEach(k => {
Object.keys(obj[k]).forEach((v, index) => {
const color = {
name: v,
hex: obj[k][v]
};
colorSet.push(color);
});
});
// Check color contrast ratio against WCAG guidelines and print as object
// # SHOULD THE PUSH REALLY BE IN THIS FUNC?
const getColorContrastRatioForPair = (color, bg) => {
const comparison = {};
comparison.hex = bg.hex;
comparison.name = bg.name;
comparison.contrast = getRatio(color, bg.hex, true);
comparison.a11y = {
aa: comparison.contrast >= minimumRatios.aa,
aaLarge: comparison.contrast >= minimumRatios.aaLarge,
aaa: comparison.contrast >= minimumRatios.aaa,
aaaLarge: comparison.contrast >= minimumRatios.aaaLarge
};
return Box(comparison);
}
// Check a given color against an array of colors
// If the comparison doesn't meet a minimum ratio, do not pass the set into the results
const checkColorAgainstSet = (primaryColor, colors) => {
const set = {};
set.hex = primaryColor.hex;
set.name = primaryColor.name;
set.combinations = [];
Object.keys(colors).forEach(c =>
getColorContrastRatioForPair(primaryColor.hex, colors[c])
.map(pair => pair.contrast > 4.5 ? set.combinations.push(pair) : false));
set.combinations.length > 0 ? checks.push(set) : false ;
}
const app = output => {
// Flatten json object into an array of objects with name and hex props
getColors(colors);
// check each object against all others in the set
colorSet.map(color => {
checkColorAgainstSet(color, colorSet);
});
writeFile(output, JSON.stringify(checks, null, 4) )
.fork(e => console.log(e),
s => console.log('Success'));
};
app('a11y.json');