source: trip-planner-front/node_modules/csso/lib/replace/color.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 12.7 KB
Line 
1var lexer = require('css-tree').lexer;
2var packNumber = require('./Number').pack;
3
4// http://www.w3.org/TR/css3-color/#svg-color
5var NAME_TO_HEX = {
6 'aliceblue': 'f0f8ff',
7 'antiquewhite': 'faebd7',
8 'aqua': '0ff',
9 'aquamarine': '7fffd4',
10 'azure': 'f0ffff',
11 'beige': 'f5f5dc',
12 'bisque': 'ffe4c4',
13 'black': '000',
14 'blanchedalmond': 'ffebcd',
15 'blue': '00f',
16 'blueviolet': '8a2be2',
17 'brown': 'a52a2a',
18 'burlywood': 'deb887',
19 'cadetblue': '5f9ea0',
20 'chartreuse': '7fff00',
21 'chocolate': 'd2691e',
22 'coral': 'ff7f50',
23 'cornflowerblue': '6495ed',
24 'cornsilk': 'fff8dc',
25 'crimson': 'dc143c',
26 'cyan': '0ff',
27 'darkblue': '00008b',
28 'darkcyan': '008b8b',
29 'darkgoldenrod': 'b8860b',
30 'darkgray': 'a9a9a9',
31 'darkgrey': 'a9a9a9',
32 'darkgreen': '006400',
33 'darkkhaki': 'bdb76b',
34 'darkmagenta': '8b008b',
35 'darkolivegreen': '556b2f',
36 'darkorange': 'ff8c00',
37 'darkorchid': '9932cc',
38 'darkred': '8b0000',
39 'darksalmon': 'e9967a',
40 'darkseagreen': '8fbc8f',
41 'darkslateblue': '483d8b',
42 'darkslategray': '2f4f4f',
43 'darkslategrey': '2f4f4f',
44 'darkturquoise': '00ced1',
45 'darkviolet': '9400d3',
46 'deeppink': 'ff1493',
47 'deepskyblue': '00bfff',
48 'dimgray': '696969',
49 'dimgrey': '696969',
50 'dodgerblue': '1e90ff',
51 'firebrick': 'b22222',
52 'floralwhite': 'fffaf0',
53 'forestgreen': '228b22',
54 'fuchsia': 'f0f',
55 'gainsboro': 'dcdcdc',
56 'ghostwhite': 'f8f8ff',
57 'gold': 'ffd700',
58 'goldenrod': 'daa520',
59 'gray': '808080',
60 'grey': '808080',
61 'green': '008000',
62 'greenyellow': 'adff2f',
63 'honeydew': 'f0fff0',
64 'hotpink': 'ff69b4',
65 'indianred': 'cd5c5c',
66 'indigo': '4b0082',
67 'ivory': 'fffff0',
68 'khaki': 'f0e68c',
69 'lavender': 'e6e6fa',
70 'lavenderblush': 'fff0f5',
71 'lawngreen': '7cfc00',
72 'lemonchiffon': 'fffacd',
73 'lightblue': 'add8e6',
74 'lightcoral': 'f08080',
75 'lightcyan': 'e0ffff',
76 'lightgoldenrodyellow': 'fafad2',
77 'lightgray': 'd3d3d3',
78 'lightgrey': 'd3d3d3',
79 'lightgreen': '90ee90',
80 'lightpink': 'ffb6c1',
81 'lightsalmon': 'ffa07a',
82 'lightseagreen': '20b2aa',
83 'lightskyblue': '87cefa',
84 'lightslategray': '789',
85 'lightslategrey': '789',
86 'lightsteelblue': 'b0c4de',
87 'lightyellow': 'ffffe0',
88 'lime': '0f0',
89 'limegreen': '32cd32',
90 'linen': 'faf0e6',
91 'magenta': 'f0f',
92 'maroon': '800000',
93 'mediumaquamarine': '66cdaa',
94 'mediumblue': '0000cd',
95 'mediumorchid': 'ba55d3',
96 'mediumpurple': '9370db',
97 'mediumseagreen': '3cb371',
98 'mediumslateblue': '7b68ee',
99 'mediumspringgreen': '00fa9a',
100 'mediumturquoise': '48d1cc',
101 'mediumvioletred': 'c71585',
102 'midnightblue': '191970',
103 'mintcream': 'f5fffa',
104 'mistyrose': 'ffe4e1',
105 'moccasin': 'ffe4b5',
106 'navajowhite': 'ffdead',
107 'navy': '000080',
108 'oldlace': 'fdf5e6',
109 'olive': '808000',
110 'olivedrab': '6b8e23',
111 'orange': 'ffa500',
112 'orangered': 'ff4500',
113 'orchid': 'da70d6',
114 'palegoldenrod': 'eee8aa',
115 'palegreen': '98fb98',
116 'paleturquoise': 'afeeee',
117 'palevioletred': 'db7093',
118 'papayawhip': 'ffefd5',
119 'peachpuff': 'ffdab9',
120 'peru': 'cd853f',
121 'pink': 'ffc0cb',
122 'plum': 'dda0dd',
123 'powderblue': 'b0e0e6',
124 'purple': '800080',
125 'rebeccapurple': '639',
126 'red': 'f00',
127 'rosybrown': 'bc8f8f',
128 'royalblue': '4169e1',
129 'saddlebrown': '8b4513',
130 'salmon': 'fa8072',
131 'sandybrown': 'f4a460',
132 'seagreen': '2e8b57',
133 'seashell': 'fff5ee',
134 'sienna': 'a0522d',
135 'silver': 'c0c0c0',
136 'skyblue': '87ceeb',
137 'slateblue': '6a5acd',
138 'slategray': '708090',
139 'slategrey': '708090',
140 'snow': 'fffafa',
141 'springgreen': '00ff7f',
142 'steelblue': '4682b4',
143 'tan': 'd2b48c',
144 'teal': '008080',
145 'thistle': 'd8bfd8',
146 'tomato': 'ff6347',
147 'turquoise': '40e0d0',
148 'violet': 'ee82ee',
149 'wheat': 'f5deb3',
150 'white': 'fff',
151 'whitesmoke': 'f5f5f5',
152 'yellow': 'ff0',
153 'yellowgreen': '9acd32'
154};
155
156var HEX_TO_NAME = {
157 '800000': 'maroon',
158 '800080': 'purple',
159 '808000': 'olive',
160 '808080': 'gray',
161 '00ffff': 'cyan',
162 'f0ffff': 'azure',
163 'f5f5dc': 'beige',
164 'ffe4c4': 'bisque',
165 '000000': 'black',
166 '0000ff': 'blue',
167 'a52a2a': 'brown',
168 'ff7f50': 'coral',
169 'ffd700': 'gold',
170 '008000': 'green',
171 '4b0082': 'indigo',
172 'fffff0': 'ivory',
173 'f0e68c': 'khaki',
174 '00ff00': 'lime',
175 'faf0e6': 'linen',
176 '000080': 'navy',
177 'ffa500': 'orange',
178 'da70d6': 'orchid',
179 'cd853f': 'peru',
180 'ffc0cb': 'pink',
181 'dda0dd': 'plum',
182 'f00': 'red',
183 'ff0000': 'red',
184 'fa8072': 'salmon',
185 'a0522d': 'sienna',
186 'c0c0c0': 'silver',
187 'fffafa': 'snow',
188 'd2b48c': 'tan',
189 '008080': 'teal',
190 'ff6347': 'tomato',
191 'ee82ee': 'violet',
192 'f5deb3': 'wheat',
193 'ffffff': 'white',
194 'ffff00': 'yellow'
195};
196
197function hueToRgb(p, q, t) {
198 if (t < 0) {
199 t += 1;
200 }
201 if (t > 1) {
202 t -= 1;
203 }
204 if (t < 1 / 6) {
205 return p + (q - p) * 6 * t;
206 }
207 if (t < 1 / 2) {
208 return q;
209 }
210 if (t < 2 / 3) {
211 return p + (q - p) * (2 / 3 - t) * 6;
212 }
213 return p;
214}
215
216function hslToRgb(h, s, l, a) {
217 var r;
218 var g;
219 var b;
220
221 if (s === 0) {
222 r = g = b = l; // achromatic
223 } else {
224 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
225 var p = 2 * l - q;
226
227 r = hueToRgb(p, q, h + 1 / 3);
228 g = hueToRgb(p, q, h);
229 b = hueToRgb(p, q, h - 1 / 3);
230 }
231
232 return [
233 Math.round(r * 255),
234 Math.round(g * 255),
235 Math.round(b * 255),
236 a
237 ];
238}
239
240function toHex(value) {
241 value = value.toString(16);
242 return value.length === 1 ? '0' + value : value;
243}
244
245function parseFunctionArgs(functionArgs, count, rgb) {
246 var cursor = functionArgs.head;
247 var args = [];
248 var wasValue = false;
249
250 while (cursor !== null) {
251 var node = cursor.data;
252 var type = node.type;
253
254 switch (type) {
255 case 'Number':
256 case 'Percentage':
257 if (wasValue) {
258 return;
259 }
260
261 wasValue = true;
262 args.push({
263 type: type,
264 value: Number(node.value)
265 });
266 break;
267
268 case 'Operator':
269 if (node.value === ',') {
270 if (!wasValue) {
271 return;
272 }
273 wasValue = false;
274 } else if (wasValue || node.value !== '+') {
275 return;
276 }
277 break;
278
279 default:
280 // something we couldn't understand
281 return;
282 }
283
284 cursor = cursor.next;
285 }
286
287 if (args.length !== count) {
288 // invalid arguments count
289 // TODO: remove those tokens
290 return;
291 }
292
293 if (args.length === 4) {
294 if (args[3].type !== 'Number') {
295 // 4th argument should be a number
296 // TODO: remove those tokens
297 return;
298 }
299
300 args[3].type = 'Alpha';
301 }
302
303 if (rgb) {
304 if (args[0].type !== args[1].type || args[0].type !== args[2].type) {
305 // invalid color, numbers and percentage shouldn't be mixed
306 // TODO: remove those tokens
307 return;
308 }
309 } else {
310 if (args[0].type !== 'Number' ||
311 args[1].type !== 'Percentage' ||
312 args[2].type !== 'Percentage') {
313 // invalid color, for hsl values should be: number, percentage, percentage
314 // TODO: remove those tokens
315 return;
316 }
317
318 args[0].type = 'Angle';
319 }
320
321 return args.map(function(arg) {
322 var value = Math.max(0, arg.value);
323
324 switch (arg.type) {
325 case 'Number':
326 // fit value to [0..255] range
327 value = Math.min(value, 255);
328 break;
329
330 case 'Percentage':
331 // convert 0..100% to value in [0..255] range
332 value = Math.min(value, 100) / 100;
333
334 if (!rgb) {
335 return value;
336 }
337
338 value = 255 * value;
339 break;
340
341 case 'Angle':
342 // fit value to (-360..360) range
343 return (((value % 360) + 360) % 360) / 360;
344
345 case 'Alpha':
346 // fit value to [0..1] range
347 return Math.min(value, 1);
348 }
349
350 return Math.round(value);
351 });
352}
353
354function compressFunction(node, item, list) {
355 var functionName = node.name;
356 var args;
357
358 if (functionName === 'rgba' || functionName === 'hsla') {
359 args = parseFunctionArgs(node.children, 4, functionName === 'rgba');
360
361 if (!args) {
362 // something went wrong
363 return;
364 }
365
366 if (functionName === 'hsla') {
367 args = hslToRgb.apply(null, args);
368 node.name = 'rgba';
369 }
370
371 if (args[3] === 0) {
372 // try to replace `rgba(x, x, x, 0)` to `transparent`
373 // always replace `rgba(0, 0, 0, 0)` to `transparent`
374 // otherwise avoid replacement in gradients since it may break color transition
375 // http://stackoverflow.com/questions/11829410/css3-gradient-rendering-issues-from-transparent-to-white
376 var scopeFunctionName = this.function && this.function.name;
377 if ((args[0] === 0 && args[1] === 0 && args[2] === 0) ||
378 !/^(?:to|from|color-stop)$|gradient$/i.test(scopeFunctionName)) {
379
380 item.data = {
381 type: 'Identifier',
382 loc: node.loc,
383 name: 'transparent'
384 };
385
386 return;
387 }
388 }
389
390 if (args[3] !== 1) {
391 // replace argument values for normalized/interpolated
392 node.children.each(function(node, item, list) {
393 if (node.type === 'Operator') {
394 if (node.value !== ',') {
395 list.remove(item);
396 }
397 return;
398 }
399
400 item.data = {
401 type: 'Number',
402 loc: node.loc,
403 value: packNumber(args.shift(), null)
404 };
405 });
406
407 return;
408 }
409
410 // otherwise convert to rgb, i.e. rgba(255, 0, 0, 1) -> rgb(255, 0, 0)
411 functionName = 'rgb';
412 }
413
414 if (functionName === 'hsl') {
415 args = args || parseFunctionArgs(node.children, 3, false);
416
417 if (!args) {
418 // something went wrong
419 return;
420 }
421
422 // convert to rgb
423 args = hslToRgb.apply(null, args);
424 functionName = 'rgb';
425 }
426
427 if (functionName === 'rgb') {
428 args = args || parseFunctionArgs(node.children, 3, true);
429
430 if (!args) {
431 // something went wrong
432 return;
433 }
434
435 // check if color is not at the end and not followed by space
436 var next = item.next;
437 if (next && next.data.type !== 'WhiteSpace') {
438 list.insert(list.createItem({
439 type: 'WhiteSpace',
440 value: ' '
441 }), next);
442 }
443
444 item.data = {
445 type: 'Hash',
446 loc: node.loc,
447 value: toHex(args[0]) + toHex(args[1]) + toHex(args[2])
448 };
449
450 compressHex(item.data, item);
451 }
452}
453
454function compressIdent(node, item) {
455 if (this.declaration === null) {
456 return;
457 }
458
459 var color = node.name.toLowerCase();
460
461 if (NAME_TO_HEX.hasOwnProperty(color) &&
462 lexer.matchDeclaration(this.declaration).isType(node, 'color')) {
463 var hex = NAME_TO_HEX[color];
464
465 if (hex.length + 1 <= color.length) {
466 // replace for shorter hex value
467 item.data = {
468 type: 'Hash',
469 loc: node.loc,
470 value: hex
471 };
472 } else {
473 // special case for consistent colors
474 if (color === 'grey') {
475 color = 'gray';
476 }
477
478 // just replace value for lower cased name
479 node.name = color;
480 }
481 }
482}
483
484function compressHex(node, item) {
485 var color = node.value.toLowerCase();
486
487 // #112233 -> #123
488 if (color.length === 6 &&
489 color[0] === color[1] &&
490 color[2] === color[3] &&
491 color[4] === color[5]) {
492 color = color[0] + color[2] + color[4];
493 }
494
495 if (HEX_TO_NAME[color]) {
496 item.data = {
497 type: 'Identifier',
498 loc: node.loc,
499 name: HEX_TO_NAME[color]
500 };
501 } else {
502 node.value = color;
503 }
504}
505
506module.exports = {
507 compressFunction: compressFunction,
508 compressIdent: compressIdent,
509 compressHex: compressHex
510};
Note: See TracBrowser for help on using the repository browser.