@bobfrankston/colorlib 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +5 -0
- package/package.json +13 -4
- package/convert.ts +0 -111
- package/index.ts +0 -3
- package/parse.ts +0 -95
- package/tsconfig.json +0 -20
- package/types.ts +0 -90
package/.gitattributes
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/colorlib",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Color conversion library for RGB, HSL, HSB, HSBK and Kelvin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -13,9 +13,18 @@
|
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc",
|
|
16
|
-
"watch": "tsc -w"
|
|
16
|
+
"watch": "tsc -w",
|
|
17
|
+
"preversion": "npm run build",
|
|
18
|
+
"postversion": "git push && git push --tags && npm publish",
|
|
19
|
+
"release": "git add -A && git diff-index --quiet HEAD || git commit -m 'Build for release' && npm version patch"
|
|
17
20
|
},
|
|
18
|
-
"keywords": [
|
|
21
|
+
"keywords": [
|
|
22
|
+
"color",
|
|
23
|
+
"hsl",
|
|
24
|
+
"hsb",
|
|
25
|
+
"rgb",
|
|
26
|
+
"kelvin"
|
|
27
|
+
],
|
|
19
28
|
"license": "MIT",
|
|
20
29
|
"repository": {
|
|
21
30
|
"type": "git",
|
|
@@ -26,6 +35,6 @@
|
|
|
26
35
|
},
|
|
27
36
|
"devDependencies": {
|
|
28
37
|
"@types/color-convert": "^2.0.4",
|
|
29
|
-
"@types/node": "
|
|
38
|
+
"@types/node": "^25.0.6"
|
|
30
39
|
}
|
|
31
40
|
}
|
package/convert.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import convert from 'color-convert';
|
|
2
|
-
import { RGB, HSL, HSB, HSBK, HSBK16 } from './types.js';
|
|
3
|
-
|
|
4
|
-
const DEFAULT_KELVIN = 3500;
|
|
5
|
-
const MIN_KELVIN = 1500;
|
|
6
|
-
const MAX_KELVIN = 9000;
|
|
7
|
-
|
|
8
|
-
/** Clamp value to range */
|
|
9
|
-
function clamp(v: number, min: number, max: number): number {
|
|
10
|
-
return Math.max(min, Math.min(max, v));
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** RGB to HSL */
|
|
14
|
-
export function rgbToHsl(rgb: RGB): HSL {
|
|
15
|
-
const [h, s, l] = convert.rgb.hsl([rgb.r, rgb.g, rgb.b]);
|
|
16
|
-
return { h, s, l };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** HSL to RGB */
|
|
20
|
-
export function hslToRgb(hsl: HSL): RGB {
|
|
21
|
-
const [r, g, b] = convert.hsl.rgb([hsl.h, hsl.s, hsl.l]);
|
|
22
|
-
return { r, g, b };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** RGB to HSB (HSV) */
|
|
26
|
-
export function rgbToHsb(rgb: RGB): HSB {
|
|
27
|
-
const [h, s, v] = convert.rgb.hsv([rgb.r, rgb.g, rgb.b]);
|
|
28
|
-
return { h, s, b: v };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** HSB (HSV) to RGB */
|
|
32
|
-
export function hsbToRgb(hsb: HSB): RGB {
|
|
33
|
-
const [r, g, b] = convert.hsv.rgb([hsb.h, hsb.s, hsb.b]);
|
|
34
|
-
return { r, g, b };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** HSL to HSB */
|
|
38
|
-
export function hslToHsb(hsl: HSL): HSB {
|
|
39
|
-
const rgb = hslToRgb(hsl);
|
|
40
|
-
return rgbToHsb(rgb);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** HSB to HSL */
|
|
44
|
-
export function hsbToHsl(hsb: HSB): HSL {
|
|
45
|
-
const rgb = hsbToRgb(hsb);
|
|
46
|
-
return rgbToHsl(rgb);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** HSB to HSBK with optional kelvin */
|
|
50
|
-
export function hsbToHsbk(hsb: HSB, kelvin: number = DEFAULT_KELVIN): HSBK {
|
|
51
|
-
return {
|
|
52
|
-
h: hsb.h,
|
|
53
|
-
s: hsb.s,
|
|
54
|
-
b: hsb.b,
|
|
55
|
-
k: clamp(kelvin, MIN_KELVIN, MAX_KELVIN)
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** RGB to HSBK */
|
|
60
|
-
export function rgbToHsbk(rgb: RGB, kelvin: number = DEFAULT_KELVIN): HSBK {
|
|
61
|
-
const hsb = rgbToHsb(rgb);
|
|
62
|
-
return hsbToHsbk(hsb, kelvin);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** HSL to HSBK */
|
|
66
|
-
export function hslToHsbk(hsl: HSL, kelvin: number = DEFAULT_KELVIN): HSBK {
|
|
67
|
-
const hsb = hslToHsb(hsl);
|
|
68
|
-
return hsbToHsbk(hsb, kelvin);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Approximate RGB for a color temperature (for white light preview) */
|
|
72
|
-
export function kelvinToRgb(kelvin: number): RGB {
|
|
73
|
-
const k = clamp(kelvin, 1000, 40000) / 100;
|
|
74
|
-
let r: number, g: number, b: number;
|
|
75
|
-
|
|
76
|
-
if (k <= 66) {
|
|
77
|
-
r = 255;
|
|
78
|
-
g = 99.4708025861 * Math.log(k) - 161.1195681661;
|
|
79
|
-
b = k <= 19 ? 0 : 138.5177312231 * Math.log(k - 10) - 305.0447927307;
|
|
80
|
-
} else {
|
|
81
|
-
r = 329.698727446 * Math.pow(k - 60, -0.1332047592);
|
|
82
|
-
g = 288.1221695283 * Math.pow(k - 60, -0.0755148492);
|
|
83
|
-
b = 255;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
r: Math.round(clamp(r, 0, 255)),
|
|
88
|
-
g: Math.round(clamp(g, 0, 255)),
|
|
89
|
-
b: Math.round(clamp(b, 0, 255))
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** HSBK to 16-bit scaled format */
|
|
94
|
-
export function hsbkTo16(hsbk: HSBK): HSBK16 {
|
|
95
|
-
return {
|
|
96
|
-
h: Math.round((hsbk.h / 360) * 0xFFFF),
|
|
97
|
-
s: Math.round((hsbk.s / 100) * 0xFFFF),
|
|
98
|
-
b: Math.round((hsbk.b / 100) * 0xFFFF),
|
|
99
|
-
k: clamp(Math.round(hsbk.k), MIN_KELVIN, MAX_KELVIN)
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** 16-bit scaled format to HSBK */
|
|
104
|
-
export function hsbk16ToHsbk(hsbk16: HSBK16): HSBK {
|
|
105
|
-
return {
|
|
106
|
-
h: (hsbk16.h / 0xFFFF) * 360,
|
|
107
|
-
s: (hsbk16.s / 0xFFFF) * 100,
|
|
108
|
-
b: (hsbk16.b / 0xFFFF) * 100,
|
|
109
|
-
k: hsbk16.k
|
|
110
|
-
};
|
|
111
|
-
}
|
package/index.ts
DELETED
package/parse.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import convert from 'color-convert';
|
|
2
|
-
import { RGB, HSL, HSB, HSBK, ColorInput, isRGB, isHSL, isHSB, isHSBK } from './types.js';
|
|
3
|
-
import { rgbToHsbk, hslToHsbk, hsbToHsbk } from './convert.js';
|
|
4
|
-
|
|
5
|
-
const DEFAULT_KELVIN = 3500;
|
|
6
|
-
const MIN_KELVIN = 1500;
|
|
7
|
-
const MAX_KELVIN = 9000;
|
|
8
|
-
|
|
9
|
-
/** Parse hex color string */
|
|
10
|
-
function parseHex(hex: string): RGB {
|
|
11
|
-
const clean = hex.replace(/^#/, '');
|
|
12
|
-
const expanded = clean.length === 3
|
|
13
|
-
? clean.split('').map(c => c + c).join('')
|
|
14
|
-
: clean;
|
|
15
|
-
const num = parseInt(expanded, 16);
|
|
16
|
-
return {
|
|
17
|
-
r: (num >> 16) & 255,
|
|
18
|
-
g: (num >> 8) & 255,
|
|
19
|
-
b: num & 255
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** Parse rgb(r, g, b) string */
|
|
24
|
-
function parseRgbString(str: string): RGB {
|
|
25
|
-
const match = str.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i);
|
|
26
|
-
if (!match) throw new Error(`Invalid rgb string: ${str}`);
|
|
27
|
-
return {
|
|
28
|
-
r: parseInt(match[1], 10),
|
|
29
|
-
g: parseInt(match[2], 10),
|
|
30
|
-
b: parseInt(match[3], 10)
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Parse hsl(h, s%, l%) string */
|
|
35
|
-
function parseHslString(str: string): HSL {
|
|
36
|
-
const match = str.match(/hsl\s*\(\s*(\d+)\s*,\s*(\d+)%?\s*,\s*(\d+)%?\s*\)/i);
|
|
37
|
-
if (!match) throw new Error(`Invalid hsl string: ${str}`);
|
|
38
|
-
return {
|
|
39
|
-
h: parseInt(match[1], 10),
|
|
40
|
-
s: parseInt(match[2], 10),
|
|
41
|
-
l: parseInt(match[3], 10)
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Parse named color using color-convert */
|
|
46
|
-
function parseNamed(name: string): RGB {
|
|
47
|
-
try {
|
|
48
|
-
const rgb = convert.keyword.rgb(name as any);
|
|
49
|
-
if (rgb) return { r: rgb[0], g: rgb[1], b: rgb[2] };
|
|
50
|
-
} catch (e: any) { }
|
|
51
|
-
throw new Error(`Unknown color name: ${name}`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Parse flexible color input to HSBK
|
|
56
|
-
* Auto-detects type from input:
|
|
57
|
-
* - string: "#ff0000", "rgb(255,0,0)", "hsl(0,100%,50%)", "red"
|
|
58
|
-
* - number: Kelvin temperature (1500-9000) -> white at that temp
|
|
59
|
-
* - {r,g,b}: RGB object
|
|
60
|
-
* - {h,s,l}: HSL object
|
|
61
|
-
* - {h,s,b}: HSB object
|
|
62
|
-
* - {h,s,b,k}: HSBK object (passthrough)
|
|
63
|
-
*/
|
|
64
|
-
export function parseColor(input: ColorInput, defaultKelvin: number = DEFAULT_KELVIN): HSBK {
|
|
65
|
-
if (typeof input === 'number') {
|
|
66
|
-
if (input >= MIN_KELVIN && input <= MAX_KELVIN) {
|
|
67
|
-
return { h: 0, s: 0, b: 100, k: input }; /** white at kelvin */
|
|
68
|
-
}
|
|
69
|
-
throw new Error(`Kelvin must be ${MIN_KELVIN}-${MAX_KELVIN}, got ${input}`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (typeof input === 'string') {
|
|
73
|
-
const str = input.trim().toLowerCase();
|
|
74
|
-
|
|
75
|
-
if (str.startsWith('#') || /^[0-9a-f]{3,6}$/i.test(str)) {
|
|
76
|
-
return rgbToHsbk(parseHex(str), defaultKelvin);
|
|
77
|
-
}
|
|
78
|
-
if (str.startsWith('rgb(')) {
|
|
79
|
-
return rgbToHsbk(parseRgbString(str), defaultKelvin);
|
|
80
|
-
}
|
|
81
|
-
if (str.startsWith('hsl(')) {
|
|
82
|
-
return hslToHsbk(parseHslString(str), defaultKelvin);
|
|
83
|
-
}
|
|
84
|
-
return rgbToHsbk(parseNamed(str), defaultKelvin);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (typeof input === 'object') {
|
|
88
|
-
if (isHSBK(input)) return input;
|
|
89
|
-
if (isHSB(input)) return hsbToHsbk(input, defaultKelvin);
|
|
90
|
-
if (isHSL(input)) return hslToHsbk(input, defaultKelvin);
|
|
91
|
-
if (isRGB(input)) return rgbToHsbk(input, defaultKelvin);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
throw new Error(`Cannot parse color: ${JSON.stringify(input)}`);
|
|
95
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "esnext",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"allowSyntheticDefaultImports": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"forceConsistentCasingInFileNames": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"declarationMap": true,
|
|
13
|
-
"sourceMap": true,
|
|
14
|
-
"strictNullChecks": false,
|
|
15
|
-
"noImplicitAny": true,
|
|
16
|
-
"noImplicitThis": true,
|
|
17
|
-
"newLine": "lf"
|
|
18
|
-
},
|
|
19
|
-
"exclude": ["node_modules", "cruft", ".git", "tests", "prev"]
|
|
20
|
-
}
|
package/types.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RGB color (0-255 per channel)
|
|
3
|
-
*/
|
|
4
|
-
export interface RGB {
|
|
5
|
-
/** Red channel (0-255) */
|
|
6
|
-
r: number;
|
|
7
|
-
/** Green channel (0-255) */
|
|
8
|
-
g: number;
|
|
9
|
-
/** Blue channel (0-255) */
|
|
10
|
-
b: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* HSL color (Hue, Saturation, Lightness)
|
|
15
|
-
*/
|
|
16
|
-
export interface HSL {
|
|
17
|
-
/** Hue (0-360 degrees) */
|
|
18
|
-
h: number;
|
|
19
|
-
/** Saturation (0-100%) */
|
|
20
|
-
s: number;
|
|
21
|
-
/** Lightness (0-100%) */
|
|
22
|
-
l: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* HSB/HSV color (Hue, Saturation, Brightness/Value)
|
|
27
|
-
*/
|
|
28
|
-
export interface HSB {
|
|
29
|
-
/** Hue (0-360 degrees) */
|
|
30
|
-
h: number;
|
|
31
|
-
/** Saturation (0-100%) */
|
|
32
|
-
s: number;
|
|
33
|
-
/** Brightness/Value (0-100%) */
|
|
34
|
-
b: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* HSBK color with Kelvin temperature (used by LIFX and similar)
|
|
39
|
-
*/
|
|
40
|
-
export interface HSBK {
|
|
41
|
-
/** Hue (0-360 degrees) */
|
|
42
|
-
h: number;
|
|
43
|
-
/** Saturation (0-100%) */
|
|
44
|
-
s: number;
|
|
45
|
-
/** Brightness (0-100%) */
|
|
46
|
-
b: number;
|
|
47
|
-
/** Color temperature in Kelvin (1500-9000, warm to cool) */
|
|
48
|
-
k: number;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 16-bit scaled HSBK for wire protocols.
|
|
53
|
-
* h/s/b are 0-0xFFFF, k remains 1500-9000.
|
|
54
|
-
*/
|
|
55
|
-
export interface HSBK16 {
|
|
56
|
-
/** Hue (0-0xFFFF maps to 0-360°) */
|
|
57
|
-
h: number;
|
|
58
|
-
/** Saturation (0-0xFFFF maps to 0-100%) */
|
|
59
|
-
s: number;
|
|
60
|
-
/** Brightness (0-0xFFFF maps to 0-100%) */
|
|
61
|
-
b: number;
|
|
62
|
-
/** Color temperature in Kelvin (1500-9000) */
|
|
63
|
-
k: number;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Flexible color input for parseColor().
|
|
68
|
-
* Accepts: "#ff0000", "rgb(255,0,0)", "red", {r,g,b}, {h,s,l}, {h,s,b}, {h,s,b,k}, or Kelvin number
|
|
69
|
-
*/
|
|
70
|
-
export type ColorInput = string | number | RGB | HSL | HSB | HSBK;
|
|
71
|
-
|
|
72
|
-
/** Type guard: check if object is RGB */
|
|
73
|
-
export function isRGB(c: object): c is RGB {
|
|
74
|
-
return 'r' in c && 'g' in c && 'b' in c && !('h' in c);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Type guard: check if object is HSL */
|
|
78
|
-
export function isHSL(c: object): c is HSL {
|
|
79
|
-
return 'h' in c && 's' in c && 'l' in c;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Type guard: check if object is HSB (without kelvin) */
|
|
83
|
-
export function isHSB(c: object): c is HSB {
|
|
84
|
-
return 'h' in c && 's' in c && 'b' in c && !('k' in c);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** Type guard: check if object is HSBK (with kelvin) */
|
|
88
|
-
export function isHSBK(c: object): c is HSBK {
|
|
89
|
-
return 'h' in c && 's' in c && 'b' in c && 'k' in c;
|
|
90
|
-
}
|