Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support #rrggbbaa and #rgba #36

Merged
merged 4 commits into from Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 31 additions & 26 deletions lib/color.js
Expand Up @@ -2,24 +2,33 @@ var installedColorSpaces = [];
var undef = function (obj) {
return typeof obj === 'undefined';
};
var channelRegExp = /\s*(\.\d+|\d+(?:\.\d+)?)(%)?\s*/;
var channelRegExp = /\s*(\.\d+|\d+(?:\.\d+)?)(%|deg)?\s*/;
var percentageChannelRegExp = /\s*(\.\d+|100|\d?\d(?:\.\d+)?)%\s*/;
var alphaChannelRegExp = /\s*(\.\d+|\d+(?:\.\d+)?)\s*/;
var cssColorRegExp = new RegExp(
'^(rgb|hsl|hsv)a?' +
'\\(' +
channelRegExp.source +
',' +
'[, ]' +
channelRegExp.source +
',' +
'[, ]' +
channelRegExp.source +
'(?:[,/]' +
channelRegExp.source +
'(?:,' +
alphaChannelRegExp.source +
')?' +
'\\)$',
'i'
);

function divisor(unit, channelNumber, hasHue) {
if (unit === '%') {
return 100;
} else if (unit === 'deg' || (hasHue && channelNumber === 0)) {
return 360;
} else if (!unit) {
return 255;
}
}

function color(obj) {
if (Array.isArray(obj)) {
if (typeof obj[0] === 'string' && typeof color[obj[0]] === 'function') {
Expand All @@ -46,37 +55,38 @@ function color(obj) {
var matchCssSyntax = obj.match(cssColorRegExp);
if (matchCssSyntax) {
var colorSpaceName = matchCssSyntax[1].toUpperCase();
var alpha = undef(matchCssSyntax[8])
? matchCssSyntax[8]
: parseFloat(matchCssSyntax[8]);
var hasHue = colorSpaceName[0] === 'H';
var firstChannelDivisor = matchCssSyntax[3] ? 100 : hasHue ? 360 : 255;
var secondChannelDivisor = matchCssSyntax[5] || hasHue ? 100 : 255;
var thirdChannelDivisor = matchCssSyntax[7] || hasHue ? 100 : 255;
if (undef(color[colorSpaceName])) {
throw new Error('color.' + colorSpaceName + ' is not installed.');
}
return new color[colorSpaceName](
parseFloat(matchCssSyntax[2]) / firstChannelDivisor,
parseFloat(matchCssSyntax[4]) / secondChannelDivisor,
parseFloat(matchCssSyntax[6]) / thirdChannelDivisor,
alpha
parseFloat(matchCssSyntax[2]) / divisor(matchCssSyntax[3], 0, hasHue),
parseFloat(matchCssSyntax[4]) / divisor(matchCssSyntax[5], 1, hasHue),
parseFloat(matchCssSyntax[6]) / divisor(matchCssSyntax[7], 2, hasHue),
undef(matchCssSyntax[8])
? matchCssSyntax[8]
: parseFloat(matchCssSyntax[8]) / (matchCssSyntax[9] ? 100 : 255)
);
}
// Assume hex syntax
if (obj.length < 6) {
// Allow CSS shorthand
obj = obj.replace(/^#?([0-9a-f])([0-9a-f])([0-9a-f])$/i, '$1$1$2$2$3$3');
obj = obj.replace(
/^#?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i,
'$1$1$2$2$3$3$4$4'
);
}
// Split obj into red, green, and blue components
// Split obj into the red, green, blue, and optionally alpha component
var hexMatch = obj.match(
/^#?([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/i
/^#?([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])?$/i
);

if (hexMatch) {
return new color.RGB(
parseInt(hexMatch[1], 16) / 255,
parseInt(hexMatch[2], 16) / 255,
parseInt(hexMatch[3], 16) / 255
parseInt(hexMatch[3], 16) / 255,
hexMatch[4] ? parseInt(hexMatch[4], 16) / 255 : 1
);
}

Expand Down Expand Up @@ -316,12 +326,7 @@ color.installColorSpace('RGB', ['red', 'green', 'blue', 'alpha'], {

hexa: function () {
var alphaString = Math.round(this._alpha * 255).toString(16);
return (
'#' +
'00'.substr(0, 2 - alphaString.length) +
alphaString +
this.hex().substr(1, 6)
);
return this.hex() + '00'.substr(0, 2 - alphaString.length) + alphaString;
},

css: function () {
Expand Down
124 changes: 124 additions & 0 deletions test/parse.js
Expand Up @@ -53,4 +53,128 @@ describe('parsing', function () {
expect(color('cmyk(100,100%,100%)'), 'to be false');
});
});

describe('with #rrggbbaa', function () {
var instance = color('#00ff0080');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#00ff00');
});

it('should have its alpha channel set correctly', function () {
expect(instance.alpha().toFixed(2), 'to equal', '0.50');
});
});

describe('with #rgba', function () {
var instance = color('#0f08');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#00ff00');
});

it('should have its alpha channel set correctly', function () {
expect(instance.alpha().toFixed(2), 'to equal', '0.53');
});
});

describe('with rgb(r, g, b)', function () {
var instance = color('rgb(10, 20, 30)');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#0a141e');
});
});

describe('with rgb(r,g,b)', function () {
var instance = color('rgb(10,20,30)');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#0a141e');
});
});

describe('with rgb(r g b)', function () {
var instance = color('rgb(10 20 30)');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#0a141e');
});
});

describe('with rgba(r g b / a)', function () {
var instance = color('rgba(10 20 30 / 50%)');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#0a141e');
});

it('should have its alpha channel set correctly', function () {
expect(instance.alpha().toFixed(2), 'to equal', '0.50');
});
});

describe('with rgba(r g b/a)', function () {
var instance = color('rgba(10 20 30/50%)');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#0a141e');
});

it('should have its alpha channel set correctly', function () {
expect(instance.alpha().toFixed(2), 'to equal', '0.50');
});
});

describe('with hsl(h s l) and the hue given as a percentage', function () {
var instance = color('hsl(10% 20% 30%)');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#5c503d');
});
});

describe('with hsl(h s l) and the hue given as an angle', function () {
var instance = color('hsl(10deg 20% 30%)');

it('should return a color instance', function () {
expect(instance, 'to be a color instance');
});

it('should be green', function () {
expect(instance.hex(), 'to equal', '#5c423d');
});
});
});