1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | const chroma = require('chroma-js');
|
14 |
|
15 | const {
|
16 | colorSpaces,
|
17 | convertColorValue,
|
18 | multiplyRatios,
|
19 | ratioName,
|
20 | round,
|
21 | searchColors,
|
22 | } = require('./utils');
|
23 |
|
24 | const { BackgroundColor } = require('./backgroundcolor');
|
25 |
|
26 | class Theme {
|
27 | constructor({ colors, backgroundColor, lightness, contrast = 1, output = 'HEX' }) {
|
28 | this._output = output;
|
29 | this._colors = colors;
|
30 | this._lightness = lightness;
|
31 |
|
32 | this._setBackgroundColor(backgroundColor);
|
33 | this._setBackgroundColorValue();
|
34 |
|
35 | this._contrast = contrast;
|
36 | if (!this._colors) {
|
37 | throw new Error('No colors are defined');
|
38 | }
|
39 | if (!this._backgroundColor) {
|
40 | throw new Error('Background color is undefined');
|
41 | }
|
42 | colors.forEach((color) => {
|
43 | if (!color.ratios) throw new Error(`Color ${color.name}'s ratios are undefined`);
|
44 | });
|
45 | if (!colorSpaces[this._output]) {
|
46 | throw new Error(`Output “${output}” not supported`);
|
47 | }
|
48 |
|
49 | this._modifiedColors = this._colors;
|
50 |
|
51 |
|
52 |
|
53 | this._findContrastColors();
|
54 | this._findContrastColorPairs();
|
55 | this._findContrastColorValues();
|
56 | }
|
57 |
|
58 | set contrast(contrast) {
|
59 | this._contrast = contrast;
|
60 |
|
61 | this._findContrastColors();
|
62 | }
|
63 |
|
64 | get contrast() {
|
65 | return this._contrast;
|
66 | }
|
67 |
|
68 | set lightness(lightness) {
|
69 | this._lightness = lightness;
|
70 | this._setBackgroundColor(this._backgroundColor);
|
71 | this._findContrastColors();
|
72 | }
|
73 |
|
74 | get lightness() {
|
75 | return this._lightness;
|
76 | }
|
77 |
|
78 | set backgroundColor(backgroundColor) {
|
79 | this._setBackgroundColor(backgroundColor);
|
80 | this._findContrastColors();
|
81 | }
|
82 |
|
83 | get backgroundColorValue() {
|
84 | return this._backgroundColorValue;
|
85 | }
|
86 |
|
87 | get backgroundColor() {
|
88 | return this._backgroundColor;
|
89 | }
|
90 |
|
91 |
|
92 | set colors(colors) {
|
93 | this._colors = colors;
|
94 | this._findContrastColors();
|
95 | }
|
96 |
|
97 | get colors() {
|
98 | return this._colors;
|
99 | }
|
100 |
|
101 | set output(output) {
|
102 | this._output = output;
|
103 | this._colors.forEach((element) => {
|
104 | element.output = this._output;
|
105 | });
|
106 | this._backgroundColor.output = this._output;
|
107 |
|
108 | this._findContrastColors();
|
109 | }
|
110 |
|
111 | get output() {
|
112 | return this._output;
|
113 | }
|
114 |
|
115 | get contrastColors() {
|
116 | return this._contrastColors;
|
117 | }
|
118 |
|
119 | get contrastColorPairs() {
|
120 | return this._contrastColorPairs;
|
121 | }
|
122 |
|
123 | get contrastColorValues() {
|
124 | return this._contrastColorValues;
|
125 | }
|
126 |
|
127 | _setBackgroundColor(backgroundColor) {
|
128 | if (typeof backgroundColor === 'string') {
|
129 |
|
130 | const newBackgroundColor = new BackgroundColor({ name: 'background', colorKeys: [backgroundColor], output: 'RGB' });
|
131 | const calcLightness = round(chroma(String(backgroundColor)).hsluv()[2]);
|
132 |
|
133 | this._backgroundColor = newBackgroundColor;
|
134 | this._lightness = calcLightness;
|
135 | this._backgroundColorValue = newBackgroundColor[this._lightness];
|
136 |
|
137 | } else {
|
138 |
|
139 | backgroundColor.output = 'RGB';
|
140 | const calcBackgroundColorValue = backgroundColor.backgroundColorScale[this._lightness];
|
141 |
|
142 |
|
143 | this._backgroundColor = backgroundColor;
|
144 | this._backgroundColorValue = calcBackgroundColorValue;
|
145 | }
|
146 | }
|
147 |
|
148 | _setBackgroundColorValue() {
|
149 | this._backgroundColorValue = this._backgroundColor.backgroundColorScale[this._lightness];
|
150 | }
|
151 |
|
152 | _findContrastColors() {
|
153 | const bgRgbArray = chroma(String(this._backgroundColorValue)).rgb();
|
154 | const baseV = this._lightness / 100;
|
155 | const convertedBackgroundColorValue = convertColorValue(this._backgroundColorValue, this._output);
|
156 | const baseObj = { background: convertedBackgroundColorValue };
|
157 |
|
158 | const returnColors = [];
|
159 | const returnColorValues = [];
|
160 | const returnColorPairs = {...baseObj};
|
161 | returnColors.push(baseObj);
|
162 |
|
163 | this._modifiedColors.map((color) => {
|
164 | if (color.ratios !== undefined) {
|
165 | let swatchNames;
|
166 | const newArr = [];
|
167 | const colorObj = {
|
168 | name: color.name,
|
169 | values: newArr,
|
170 | };
|
171 |
|
172 | let ratioValues;
|
173 |
|
174 | if (Array.isArray(color.ratios)) {
|
175 | ratioValues = color.ratios;
|
176 | } else if (!Array.isArray(color.ratios)) {
|
177 | swatchNames = Object.keys(color.ratios);
|
178 | ratioValues = Object.values(color.ratios);
|
179 | }
|
180 |
|
181 |
|
182 | ratioValues = ratioValues.map((ratio) => multiplyRatios(+ratio, this._contrast));
|
183 |
|
184 | const contrastColors = searchColors(color, bgRgbArray, baseV, ratioValues).map((clr) => convertColorValue(clr, this._output));
|
185 |
|
186 | for (let i = 0; i < contrastColors.length; i++) {
|
187 | let n;
|
188 | if (!swatchNames) {
|
189 | const rVal = ratioName(color.ratios)[i];
|
190 | n = color.name.concat(rVal);
|
191 | } else {
|
192 | n = swatchNames[i];
|
193 | }
|
194 |
|
195 | const obj = {
|
196 | name: n,
|
197 | contrast: ratioValues[i],
|
198 | value: contrastColors[i],
|
199 | };
|
200 | newArr.push(obj);
|
201 |
|
202 | returnColorPairs[n] = contrastColors[i];
|
203 |
|
204 | returnColorValues.push(contrastColors[i]);
|
205 | }
|
206 | returnColors.push(colorObj);
|
207 | }
|
208 | return null;
|
209 | });
|
210 | this._contrastColorValues = returnColorValues;
|
211 | this._contrastColorPairs = returnColorPairs;
|
212 | this._contrastColors = returnColors;
|
213 | return this._contrastColors;
|
214 | }
|
215 |
|
216 | _findContrastColorPairs() {
|
217 | return this._contrastColorPairs;
|
218 | }
|
219 |
|
220 | _findContrastColorValues() {
|
221 | return this._contrastColorValues;
|
222 | }
|
223 | }
|
224 |
|
225 | module.exports = { Theme };
|