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

Move to ESM #69

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ jobs:
fail-fast: false
matrix:
node-version:
- 17
- 20
- 18
- 16
- 14
- 12
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
4 changes: 1 addition & 3 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
save-exact = true
package-lock = false
update-notifier = false
package-lock=false
35 changes: 16 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

## Install

With [npm](http://npmjs.org/):

```console
$ npm install color-string
```sh
npm install color-string
```

## Usage
Expand Down Expand Up @@ -44,19 +42,18 @@ colorString.get.rgb('invalid color string') // null
### Generation

```js
colorString.to.hex([255, 255, 255]) // "#FFFFFF"
colorString.to.hex([0, 0, 255, 0.4]) // "#0000FF66"
colorString.to.hex([0, 0, 255], 0.4) // "#0000FF66"
colorString.to.rgb([255, 255, 255]) // "rgb(255, 255, 255)"
colorString.to.rgb([0, 0, 255, 0.4]) // "rgba(0, 0, 255, 0.4)"
colorString.to.rgb([0, 0, 255], 0.4) // "rgba(0, 0, 255, 0.4)"
colorString.to.rgb.percent([0, 0, 255]) // "rgb(0%, 0%, 100%)"
colorString.to.keyword([255, 255, 0]) // "yellow"
colorString.to.hsl([360, 100, 100]) // "hsl(360, 100%, 100%)"
colorString.to.hwb([50, 3, 15]) // "hwb(50, 3%, 15%)"

// all functions also support swizzling
colorString.to.rgb(0, [0, 255], 0.4) // "rgba(0, 0, 255, 0.4)"
colorString.to.rgb([0, 0], [255], 0.4) // "rgba(0, 0, 255, 0.4)"
colorString.to.rgb([0], 0, [255, 0.4]) // "rgba(0, 0, 255, 0.4)"
colorString.to.hex(255, 255, 255) // "#FFFFFF"
colorString.to.hex(0, 0, 255, 0.4) // "#0000FF66"
colorString.to.hex(0, 0, 255, 0.4) // "#0000FF66"
colorString.to.rgb(255, 255, 255) // "rgb(255, 255, 255)"
colorString.to.rgb(0, 0, 255, 0.4) // "rgba(0, 0, 255, 0.4)"
colorString.to.rgb(0, 0, 255, 0.4) // "rgba(0, 0, 255, 0.4)"
colorString.to.rgb.percent(0, 0, 255) // "rgb(0%, 0%, 100%)"
colorString.to.keyword(255, 255, 0) // "yellow"
colorString.to.hsl(360, 100, 100) // "hsl(360, 100%, 100%)"
colorString.to.hwb(50, 3, 15) // "hwb(50, 3%, 15%)"
```

## License

MIT
23 changes: 23 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export type Model = 'rgb' | 'hsl' | 'hwb';

export type ColorString = {
get: {
(color: string): {model: Model; value: number[]} | undefined;
rgb: (color: string) => number[] | undefined;
hsl: (color: string) => number[] | undefined;
hwb: (color: string) => number[] | undefined;
};
to: {
hex: (r: number, g: number, b: number, a?: number) => string | undefined;
rgb: {
(r: number, g: number, b: number, a?: number): string | undefined;
percent: (r: number, g: number, b: number, a?: number) => string | undefined;
};
keyword: (r: number, g: number, b: number, a?: number) => string | undefined;
hsl: (h: number, s: number, l: number, a?: number) => string | undefined;
hwb: (h: number, w: number, b: number, a?: number) => string | undefined;
};
};

declare const colorString: ColorString;
export default colorString;
164 changes: 76 additions & 88 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,118 +1,112 @@
/* MIT license */
var colorNames = require('color-name');
var swizzle = require('simple-swizzle');
var hasOwnProperty = Object.hasOwnProperty;
import colorNames from 'color-name';

var reverseNames = Object.create(null);
const reverseNames = Object.create(null);

// create a list of reverse color names
for (var name in colorNames) {
if (hasOwnProperty.call(colorNames, name)) {
// Create a list of reverse color names
for (const name in colorNames) {
if (Object.hasOwnProperty.call(colorNames, name)) {
reverseNames[colorNames[name]] = name;
}
}

var cs = module.exports = {
const cs = {
to: {},
get: {}
get: {},
};

cs.get = function (string) {
var prefix = string.substring(0, 3).toLowerCase();
var val;
var model;
const prefix = string.slice(0, 3).toLowerCase();
let value;
let model;
switch (prefix) {
case 'hsl':
val = cs.get.hsl(string);
case 'hsl': {
value = cs.get.hsl(string);
model = 'hsl';
break;
case 'hwb':
val = cs.get.hwb(string);
}

case 'hwb': {
value = cs.get.hwb(string);
model = 'hwb';
break;
default:
val = cs.get.rgb(string);
}

default: {
value = cs.get.rgb(string);
model = 'rgb';
break;
}
}

if (!val) {
if (!value) {
return null;
}

return {model: model, value: val};
return {model, value};
};

cs.get.rgb = function (string) {
if (!string) {
return null;
}

var abbr = /^#([a-f0-9]{3,4})$/i;
var hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i;
var rgba = /^rgba?\(\s*([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/;
var per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/;
var keyword = /^(\w+)$/;
const abbr = /^#([a-f\d]{3,4})$/i;
const hex = /^#([a-f\d]{6})([a-f\d]{2})?$/i;
const rgba = /^rgba?\(\s*([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)\s*(?:[,|/]\s*([+-]?[\d.]+)(%?)\s*)?\)$/;
const per = /^rgba?\(\s*([+-]?[\d.]+)%\s*,?\s*([+-]?[\d.]+)%\s*,?\s*([+-]?[\d.]+)%\s*(?:[,|/]\s*([+-]?[\d.]+)(%?)\s*)?\)$/;
const keyword = /^(\w+)$/;

var rgb = [0, 0, 0, 1];
var match;
var i;
var hexAlpha;
let rgb = [0, 0, 0, 1];
let match;
let i;
let hexAlpha;

if (match = string.match(hex)) {
hexAlpha = match[2];
match = match[1];

for (i = 0; i < 3; i++) {
// https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19
var i2 = i * 2;
rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);
const i2 = i * 2;
rgb[i] = Number.parseInt(match.slice(i2, i2 + 2), 16);
}

if (hexAlpha) {
rgb[3] = parseInt(hexAlpha, 16) / 255;
rgb[3] = Number.parseInt(hexAlpha, 16) / 255;
}
} else if (match = string.match(abbr)) {
match = match[1];
hexAlpha = match[3];

for (i = 0; i < 3; i++) {
rgb[i] = parseInt(match[i] + match[i], 16);
rgb[i] = Number.parseInt(match[i] + match[i], 16);
}

if (hexAlpha) {
rgb[3] = parseInt(hexAlpha + hexAlpha, 16) / 255;
rgb[3] = Number.parseInt(hexAlpha + hexAlpha, 16) / 255;
}
} else if (match = string.match(rgba)) {
for (i = 0; i < 3; i++) {
rgb[i] = parseInt(match[i + 1], 0);
rgb[i] = Number.parseInt(match[i + 1], 10);
}

if (match[4]) {
if (match[5]) {
rgb[3] = parseFloat(match[4]) * 0.01;
} else {
rgb[3] = parseFloat(match[4]);
}
rgb[3] = match[5] ? Number.parseFloat(match[4]) * 0.01 : Number.parseFloat(match[4]);
}
} else if (match = string.match(per)) {
for (i = 0; i < 3; i++) {
rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
rgb[i] = Math.round(Number.parseFloat(match[i + 1]) * 2.55);
}

if (match[4]) {
if (match[5]) {
rgb[3] = parseFloat(match[4]) * 0.01;
} else {
rgb[3] = parseFloat(match[4]);
}
rgb[3] = match[5] ? Number.parseFloat(match[4]) * 0.01 : Number.parseFloat(match[4]);
}
} else if (match = string.match(keyword)) {
if (match[1] === 'transparent') {
return [0, 0, 0, 0];
}

if (!hasOwnProperty.call(colorNames, match[1])) {
if (!Object.hasOwnProperty.call(colorNames, match[1])) {
return null;
}

Expand All @@ -127,6 +121,7 @@ cs.get.rgb = function (string) {
for (i = 0; i < 3; i++) {
rgb[i] = clamp(rgb[i], 0, 255);
}

rgb[3] = clamp(rgb[3], 0, 1);

return rgb;
Expand All @@ -137,15 +132,15 @@ cs.get.hsl = function (string) {
return null;
}

var hsl = /^hsla?\(\s*([+-]?(?:\d{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d\.]+)%\s*,?\s*([+-]?[\d\.]+)%\s*(?:[,|\/]\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/;
var match = string.match(hsl);
const hsl = /^hsla?\(\s*([+-]?(?:\d{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d.]+)%\s*,?\s*([+-]?[\d.]+)%\s*(?:[,|/]\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/;
const match = string.match(hsl);

if (match) {
var alpha = parseFloat(match[4]);
var h = ((parseFloat(match[1]) % 360) + 360) % 360;
var s = clamp(parseFloat(match[2]), 0, 100);
var l = clamp(parseFloat(match[3]), 0, 100);
var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
const alpha = Number.parseFloat(match[4]);
const h = ((Number.parseFloat(match[1]) % 360) + 360) % 360;
const s = clamp(Number.parseFloat(match[2]), 0, 100);
const l = clamp(Number.parseFloat(match[3]), 0, 100);
const a = clamp(Number.isNaN(alpha) ? 1 : alpha, 0, 1);

return [h, s, l, a];
}
Expand All @@ -158,24 +153,22 @@ cs.get.hwb = function (string) {
return null;
}

var hwb = /^hwb\(\s*([+-]?\d{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/;
var match = string.match(hwb);
const hwb = /^hwb\(\s*([+-]?\d{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/;
const match = string.match(hwb);

if (match) {
var alpha = parseFloat(match[4]);
var h = ((parseFloat(match[1]) % 360) + 360) % 360;
var w = clamp(parseFloat(match[2]), 0, 100);
var b = clamp(parseFloat(match[3]), 0, 100);
var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
const alpha = Number.parseFloat(match[4]);
const h = ((Number.parseFloat(match[1]) % 360) + 360) % 360;
const w = clamp(Number.parseFloat(match[2]), 0, 100);
const b = clamp(Number.parseFloat(match[3]), 0, 100);
const a = clamp(Number.isNaN(alpha) ? 1 : alpha, 0, 1);
return [h, w, b, a];
}

return null;
};

cs.to.hex = function () {
var rgba = swizzle(arguments);

cs.to.hex = function (...rgba) {
return (
'#' +
hexDouble(rgba[0]) +
Expand All @@ -187,56 +180,51 @@ cs.to.hex = function () {
);
};

cs.to.rgb = function () {
var rgba = swizzle(arguments);

cs.to.rgb = function (...rgba) {
return rgba.length < 4 || rgba[3] === 1
? 'rgb(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ')'
: 'rgba(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ', ' + rgba[3] + ')';
};

cs.to.rgb.percent = function () {
var rgba = swizzle(arguments);

var r = Math.round(rgba[0] / 255 * 100);
var g = Math.round(rgba[1] / 255 * 100);
var b = Math.round(rgba[2] / 255 * 100);
cs.to.rgb.percent = function (...rgba) {
const r = Math.round(rgba[0] / 255 * 100);
const g = Math.round(rgba[1] / 255 * 100);
const b = Math.round(rgba[2] / 255 * 100);

return rgba.length < 4 || rgba[3] === 1
? 'rgb(' + r + '%, ' + g + '%, ' + b + '%)'
: 'rgba(' + r + '%, ' + g + '%, ' + b + '%, ' + rgba[3] + ')';
};

cs.to.hsl = function () {
var hsla = swizzle(arguments);
cs.to.hsl = function (...hsla) {
return hsla.length < 4 || hsla[3] === 1
? 'hsl(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%)'
: 'hsla(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%, ' + hsla[3] + ')';
};

// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
// Hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
// (hwb have alpha optional & 1 is default value)
cs.to.hwb = function () {
var hwba = swizzle(arguments);

var a = '';
cs.to.hwb = function (...hwba) {
let a = '';
if (hwba.length >= 4 && hwba[3] !== 1) {
a = ', ' + hwba[3];
}

return 'hwb(' + hwba[0] + ', ' + hwba[1] + '%, ' + hwba[2] + '%' + a + ')';
};

cs.to.keyword = function (rgb) {
cs.to.keyword = function (...rgb) {
return reverseNames[rgb.slice(0, 3)];
};

// helpers
function clamp(num, min, max) {
return Math.min(Math.max(min, num), max);
// Helpers
function clamp(number_, min, max) {
return Math.min(Math.max(min, number_), max);
}

function hexDouble(num) {
var str = Math.round(num).toString(16).toUpperCase();
return (str.length < 2) ? '0' + str : str;
function hexDouble(number_) {
const string_ = Math.round(number_).toString(16).toUpperCase();
return (string_.length < 2) ? '0' + string_ : string_;
}

export default cs;
Loading