From 1ac96af13be38a6c1e76f29733c4fffe6d36cd82 Mon Sep 17 00:00:00 2001 From: Vlad Shilov Date: Thu, 20 May 2021 00:36:27 +0300 Subject: [PATCH] Output 4 and 8 digit hex colors --- .../postcss-colormin/src/__tests__/colours.js | 2 +- packages/postcss-colormin/src/colours.js | 50 +++++------------ packages/postcss-colormin/src/lib/color.js | 54 +++++++++++++++++++ .../src/lib/getShortestString.js | 16 ++++++ .../postcss-colormin/src/lib/toShorthand.js | 7 --- 5 files changed, 84 insertions(+), 45 deletions(-) create mode 100644 packages/postcss-colormin/src/lib/color.js create mode 100644 packages/postcss-colormin/src/lib/getShortestString.js delete mode 100644 packages/postcss-colormin/src/lib/toShorthand.js diff --git a/packages/postcss-colormin/src/__tests__/colours.js b/packages/postcss-colormin/src/__tests__/colours.js index 0a3dde304..a3c0c0411 100644 --- a/packages/postcss-colormin/src/__tests__/colours.js +++ b/packages/postcss-colormin/src/__tests__/colours.js @@ -20,7 +20,7 @@ test( test('should convert hsl to keyword', isEqual('hsl(0, 100%, 50%)', 'red')); test( - 'should convert fully oqaque hsl to keyword', + 'should convert fully opaque hsl to keyword', isEqual('hsla(0, 100%, 50%, 1)', 'red') ); diff --git a/packages/postcss-colormin/src/colours.js b/packages/postcss-colormin/src/colours.js index 3ee8bef91..2ec473295 100644 --- a/packages/postcss-colormin/src/colours.js +++ b/packages/postcss-colormin/src/colours.js @@ -1,11 +1,11 @@ -import { colord, extend, getFormat } from 'colord'; -import namesPlugin from 'colord/plugins/names'; -import toShorthand from './lib/toShorthand'; +import { process, getFormat } from './lib/color'; +import getShortestString from './lib/getShortestString'; -extend([namesPlugin]); +export default (input, isLegacy = false) => { + const colour = input.toLowerCase(); + const format = getFormat(colour); -export default (colour, isLegacy = false) => { - if (getFormat(colour) === 'rgb') { + if (format === 'rgb') { /* check that it is a valid CSS value https://www.w3.org/TR/css-color-4/#rgb-functions */ let percentCount = 0; @@ -20,37 +20,13 @@ export default (colour, isLegacy = false) => { } } - const parsed = colord(colour.toLowerCase()); - if (parsed.isValid()) { - const alpha = parsed.alpha(); - if (alpha === 1) { - const toHex = toShorthand(parsed.toHex()); - const toName = parsed.toName(); - if (toName && toName.length < toHex.length) { - return toName; - } else { - return toHex; - } - } else { - const rgb = parsed.toRgb(); - - if (!isLegacy && !rgb.r && !rgb.g && !rgb.b && !alpha) { - return 'transparent'; - } - - let hsla = parsed.toHslString(); - let rgba = parsed.toRgbString(); - - const shortestConversion = hsla.length < rgba.length ? hsla : rgba; - - let result; - if (colour.length < shortestConversion.length) { - result = colour; - } else { - result = shortestConversion; - } - return result; - } + if (format) { + // Try to shorten the string if it was successfully parsed + // Fall back to the original input if it's smaller or has equal length + return getShortestString([ + colour, + process(colour).toShortString({ isLegacy }), + ]); } else { // Possibly malformed, so pass through return colour; diff --git a/packages/postcss-colormin/src/lib/color.js b/packages/postcss-colormin/src/lib/color.js new file mode 100644 index 000000000..0d9241fef --- /dev/null +++ b/packages/postcss-colormin/src/lib/color.js @@ -0,0 +1,54 @@ +import { colord, extend, getFormat } from 'colord'; +import namesPlugin from 'colord/plugins/names'; +import getShortestString from './getShortestString'; + +let minifierPlugin = (Colord) => { + /** + * Shortens a color to 3 or 4 digit hexadecimal string if it's possible. + * Returns the original (6 or 8 digit) hex if the it can't be shortened. + */ + Colord.prototype.toShortHex = function () { + let hex = this.toHex(); + let [, r1, r2, g1, g2, b1, b2, a1, a2] = hex.split(''); + + // Check if the string can be shorten + if (r1 === r2 && g1 === g2 && b1 === b2) { + if (this.alpha() === 1) { + // Express as 3 digit hexadecimal string if the color doesn't have an alpha channel + return '#' + r1 + g1 + b1; + } else if (a1 === a2) { + // Format 4 digit hex + return '#' + r1 + g1 + b1 + a1; + } + } + + return hex; + }; + + /** + * Returns the shortest representation of a color. + */ + Colord.prototype.toShortString = function ({ isLegacy }) { + let { r, g, b, a } = this.toRgb(); + + // Hexadecimal, RGB[A] and HSL[A] notations + let options = [this.toShortHex(), this.toRgbString(), this.toHslString()]; + + // CSS keywords + if (!isLegacy && r === 0 && g === 0 && b === 0 && a === 0) { + options.push('transparent'); + } else if (a === 1) { + let name = this.toName(); + if (name) { + options.push(name); + } + } + + // Look for the shortest option + return getShortestString(options); + }; +}; + +extend([namesPlugin, minifierPlugin]); + +export { colord as process, getFormat }; diff --git a/packages/postcss-colormin/src/lib/getShortestString.js b/packages/postcss-colormin/src/lib/getShortestString.js new file mode 100644 index 000000000..819cf8820 --- /dev/null +++ b/packages/postcss-colormin/src/lib/getShortestString.js @@ -0,0 +1,16 @@ +/** + * Returns the shortest string in array + */ +const getShortestString = (strings) => { + let shortest = null; + + for (let string of strings) { + if (shortest === null || string.length < shortest.length) { + shortest = string; + } + } + + return shortest; +}; + +export default getShortestString; diff --git a/packages/postcss-colormin/src/lib/toShorthand.js b/packages/postcss-colormin/src/lib/toShorthand.js deleted file mode 100644 index 60f152814..000000000 --- a/packages/postcss-colormin/src/lib/toShorthand.js +++ /dev/null @@ -1,7 +0,0 @@ -export default (hex) => { - if (hex[1] === hex[2] && hex[3] === hex[4] && hex[5] === hex[6]) { - return '#' + hex[2] + hex[4] + hex[6]; - } - - return hex; -};