postcss-color-hexa
Version:
A postcss plugin that enables the use of hexa() to combine hex codes and opacity into rgba()
114 lines (86 loc) • 3.31 kB
JavaScript
// ----------------------------------------------------------------------------
// Dependencies
// ----------------------------------------------------------------------------
var helpers = require("postcss-message-helpers");
var postcss = require("postcss");
// ----------------------------------------------------------------------------
// Regex's
// ----------------------------------------------------------------------------
// Match the whole property. Test: http://regexr.com/3bep1
var HEX_ALPHA_RE = /hexa\(\s*#(?:[0-9a-f]{3}){1,2}\s*,[\s]{0,}[0-9]*\.?[0-9]+\s*\)/i;
// Match the hex color. Test: http://regexr.com/3beoo
var HEX_RE = /#(?:[0-9a-f]{3}){1,2}/i;
// Match the opacity number. Test: http://regexr.com/3beol
var OPACITY_RE = /[0-9]*(\.)?[0-9]+(?=[\s]*\))/;
// Match an invalid hex code (followed by a comma). Test: http://regexr.com/3beoi
var INV_HEX_RE = /#(?:[0-9a-f]{0,2}|[0-9a-f]{4,5}|[0-9a-f]{7,})(?=,)/i;
// Match an invalid opacity number. Test: http://regexr.com/3beof
var INV_OPACITY_RE = /[0-9]*\.?[0-9]*(?:\.[0-9]*){2,}/i;
// ----------------------------------------------------------------------------
// PostCSS Plugin
// ----------------------------------------------------------------------------
module.exports = postcss.plugin('postcss-color-hexa', function(opts) {
opts = opts || {};
return function(css) {
css.walkDecls(function transformDecl(decl) {
if (!decl.value || decl.value.indexOf('hexa') === -1) {
return;
}
decl.value = helpers.try(function transformHexAlphaValue() {
return transformHexAlpha(decl.value, decl.source, decl);
}, decl.source);
});
};
});
// ----------------------------------------------------------------------------
// Helper functions
// ----------------------------------------------------------------------------
function transformHexAlpha(string, source, decl) {
return recurse(string);
function recurse(input) {
var hexa_pos = input.indexOf('hexa');
var subs = input.substring(hexa_pos);
var h = HEX_RE.exec(subs);
var o = OPACITY_RE.exec(subs);
var i_h = INV_HEX_RE.exec(subs);
var i_o = INV_OPACITY_RE.exec(subs);
if(i_h !== null){
throw decl.error('Invalid hex color: ' + i_h[0], { plugin: 'postcss-color-hexa' });
}
if(i_o !== null){
throw decl.error('Invalid opacity: ' + i_o[0], { plugin: 'postcss-color-hexa' });
}
if (!h) {
return input;
}
var rgb = hexToRgb(h[0]);
var rgb_chars = [rgb.r, rgb.g, rgb.b];
var hexa = '';
if (o) {
rgb_chars.push(o[0]);
hexa = 'rgba(' + rgb_chars.join(', ') + ')';
} else {
hexa = 'rgb(' + rgb_chars.join(', ') + ')';
}
var result = input.replace(HEX_ALPHA_RE, hexa);
if (result.indexOf('hexa') === -1) {
return result;
} else {
return recurse(result);
}
}
}
// http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}