color-value-tools 1.1.12 → 1.2.0
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/dist/cjs/index.js +48 -7
- package/dist/cli/src/index.js +48 -7
- package/dist/esm/index.js +48 -7
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -130,15 +130,24 @@ const NAMED_COLORS = {
|
|
|
130
130
|
springgreen: '#00ff7f', steelblue: '#4682b4', tan: '#d2b48c', teal: '#008080', thistle: '#d8bfd8',
|
|
131
131
|
tomato: '#ff6347', turquoise: '#40e0d0', violet: '#ee82ee', wheat: '#f5deb3', white: '#ffffff',
|
|
132
132
|
whitesmoke: '#f5f5f5', yellow: '#ffff00', yellowgreen: '#9acd32',
|
|
133
|
-
//
|
|
134
|
-
|
|
133
|
+
// 'transparent' is the only CSS-wide keyword with an actual fixed color (fully
|
|
134
|
+
// transparent black) — normalizeColor() special-cases it before ever reaching
|
|
135
|
+
// this table (see the `str === 'transparent'` check), so this entry only
|
|
136
|
+
// matters for getColorType()/toNearestNamedColor(), which read the table
|
|
137
|
+
// directly. 'currentcolor'/'inherit'/'initial'/'unset' are deliberately NOT
|
|
138
|
+
// listed here: none of them has a color value of their own (they only resolve
|
|
139
|
+
// to one given surrounding DOM/CSSOM context this library never has access
|
|
140
|
+
// to), so treating them as resolvable named colors would mean fabricating an
|
|
141
|
+
// arbitrary RGB value with no way for a caller to tell it apart from a real
|
|
142
|
+
// one — see normalizeColor()'s `type: 'unknown'` fallback for these instead.
|
|
143
|
+
transparent: 'transparent',
|
|
135
144
|
};
|
|
136
145
|
function isCssVariable(value) {
|
|
137
146
|
return value.trim().startsWith('var(--');
|
|
138
147
|
}
|
|
139
148
|
function isHexColor(value) {
|
|
140
149
|
const trimmed = value.trim();
|
|
141
|
-
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6})$/.test(trimmed);
|
|
150
|
+
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(trimmed);
|
|
142
151
|
}
|
|
143
152
|
function isOklchColor(value) {
|
|
144
153
|
return /^\s*oklcha?\s*\(/i.test(value.trim());
|
|
@@ -479,11 +488,18 @@ function rgbaStringToRgba(str) {
|
|
|
479
488
|
const parts = m[1].split(/,\s*/).map(p => p.trim());
|
|
480
489
|
if (parts.length < 3)
|
|
481
490
|
return null;
|
|
482
|
-
|
|
491
|
+
// Clamp channels to a valid byte and alpha to [0,1] — an out-of-range input
|
|
492
|
+
// like "rgb(300, -20, 0)" or "rgba(0,0,0,2)" is invalid CSS, but previously
|
|
493
|
+
// passed straight through unclamped, which could even corrupt downstream hex
|
|
494
|
+
// output (a negative channel stringifies with a leading "-" via toString(16)).
|
|
495
|
+
const parseChannel = (v) => {
|
|
496
|
+
const n = v.endsWith('%') ? parseFloat(v) * 2.55 : parseFloat(v);
|
|
497
|
+
return Math.round(Math.max(0, Math.min(255, n)));
|
|
498
|
+
};
|
|
483
499
|
const r = parseChannel(parts[0]);
|
|
484
500
|
const g = parseChannel(parts[1]);
|
|
485
501
|
const b = parseChannel(parts[2]);
|
|
486
|
-
const a = parts[3] !== undefined ? parseFloat(parts[3]) : 1;
|
|
502
|
+
const a = parts[3] !== undefined ? Math.max(0, Math.min(1, parseFloat(parts[3]))) : 1;
|
|
487
503
|
return { r, g, b, a };
|
|
488
504
|
}
|
|
489
505
|
function rgbToHsl({ r, g, b }) {
|
|
@@ -740,6 +756,16 @@ function normalizeColor(input) {
|
|
|
740
756
|
g = srgb.g;
|
|
741
757
|
b = srgb.b;
|
|
742
758
|
}
|
|
759
|
+
else if (parsed.space === 'srgb-linear') {
|
|
760
|
+
// srgb-linear components are linear-light, not gamma-encoded — unlike
|
|
761
|
+
// plain srgb below, they need the linear-to-sRGB transfer function
|
|
762
|
+
// applied before scaling to a 0-255 byte. Without this, only the 0/1
|
|
763
|
+
// extremes happened to come out correct; any mid-range value (e.g. 0.5)
|
|
764
|
+
// converted as if it were already gamma-encoded, which is wrong.
|
|
765
|
+
r = Math.round(linearChanToSrgb(p3r) * 255);
|
|
766
|
+
g = Math.round(linearChanToSrgb(p3g) * 255);
|
|
767
|
+
b = Math.round(linearChanToSrgb(p3b) * 255);
|
|
768
|
+
}
|
|
743
769
|
else {
|
|
744
770
|
r = Math.round(Math.max(0, Math.min(255, p3r * 255)));
|
|
745
771
|
g = Math.round(Math.max(0, Math.min(255, p3g * 255)));
|
|
@@ -778,10 +804,16 @@ function tetradic(color) {
|
|
|
778
804
|
return [hex, rotateHue(hex, 90), rotateHue(hex, 180), rotateHue(hex, 270)];
|
|
779
805
|
}
|
|
780
806
|
function colorShades(color, steps = 9) {
|
|
781
|
-
var _a, _b;
|
|
807
|
+
var _a, _b, _c;
|
|
782
808
|
const n = normalizeColor(color);
|
|
783
809
|
const h = (_a = n.h) !== null && _a !== void 0 ? _a : 0;
|
|
784
810
|
const s = (_b = n.s) !== null && _b !== void 0 ? _b : 0;
|
|
811
|
+
// steps - 1 === 0 below would otherwise divide by zero (NaN lightness, then
|
|
812
|
+
// a literal "#NaNNaNNaN" hex string) — a single shade is just the color's
|
|
813
|
+
// own lightness, same idea as interpolateColors() returning the midpoint
|
|
814
|
+
// for a 2-color, 1-step request.
|
|
815
|
+
if (steps <= 1)
|
|
816
|
+
return steps === 1 ? [hslToHex(h, s, (_c = n.l) !== null && _c !== void 0 ? _c : 50)] : [];
|
|
785
817
|
const result = [];
|
|
786
818
|
for (let i = 0; i < steps; i++) {
|
|
787
819
|
const l = Math.round(100 - (i / (steps - 1)) * 100);
|
|
@@ -790,10 +822,13 @@ function colorShades(color, steps = 9) {
|
|
|
790
822
|
return result;
|
|
791
823
|
}
|
|
792
824
|
function monochromatic(color, steps = 5) {
|
|
793
|
-
var _a, _b;
|
|
825
|
+
var _a, _b, _c;
|
|
794
826
|
const n = normalizeColor(color);
|
|
795
827
|
const h = (_a = n.h) !== null && _a !== void 0 ? _a : 0;
|
|
796
828
|
const l = (_b = n.l) !== null && _b !== void 0 ? _b : 50;
|
|
829
|
+
// Same steps === 1 divide-by-zero guard as colorShades() above.
|
|
830
|
+
if (steps <= 1)
|
|
831
|
+
return steps === 1 ? [hslToHex(h, (_c = n.s) !== null && _c !== void 0 ? _c : 0, l)] : [];
|
|
797
832
|
const result = [];
|
|
798
833
|
for (let i = 0; i < steps; i++) {
|
|
799
834
|
const s = Math.round((i / (steps - 1)) * 100);
|
|
@@ -1215,6 +1250,12 @@ function toNearestNamedColor(color) {
|
|
|
1215
1250
|
let bestName = 'black';
|
|
1216
1251
|
let bestDist = Infinity;
|
|
1217
1252
|
for (const [name, hex] of Object.entries(NAMED_COLORS)) {
|
|
1253
|
+
// Skip any non-hex entry (currently just a defensive guard — 'transparent'
|
|
1254
|
+
// is the only such value left in the table, and it has no real RGB to
|
|
1255
|
+
// compare against; hexToRgb() would otherwise silently fall back to
|
|
1256
|
+
// normalizeHex()'s placeholder color for it).
|
|
1257
|
+
if (hex[0] !== '#')
|
|
1258
|
+
continue;
|
|
1218
1259
|
const [nr, ng, nb] = hexToRgb(hex);
|
|
1219
1260
|
const dist = Math.sqrt(Math.pow(r - nr, 2) + Math.pow(g - ng, 2) + Math.pow(b - nb, 2));
|
|
1220
1261
|
if (dist < bestDist) {
|
package/dist/cli/src/index.js
CHANGED
|
@@ -130,15 +130,24 @@ const NAMED_COLORS = {
|
|
|
130
130
|
springgreen: '#00ff7f', steelblue: '#4682b4', tan: '#d2b48c', teal: '#008080', thistle: '#d8bfd8',
|
|
131
131
|
tomato: '#ff6347', turquoise: '#40e0d0', violet: '#ee82ee', wheat: '#f5deb3', white: '#ffffff',
|
|
132
132
|
whitesmoke: '#f5f5f5', yellow: '#ffff00', yellowgreen: '#9acd32',
|
|
133
|
-
//
|
|
134
|
-
|
|
133
|
+
// 'transparent' is the only CSS-wide keyword with an actual fixed color (fully
|
|
134
|
+
// transparent black) — normalizeColor() special-cases it before ever reaching
|
|
135
|
+
// this table (see the `str === 'transparent'` check), so this entry only
|
|
136
|
+
// matters for getColorType()/toNearestNamedColor(), which read the table
|
|
137
|
+
// directly. 'currentcolor'/'inherit'/'initial'/'unset' are deliberately NOT
|
|
138
|
+
// listed here: none of them has a color value of their own (they only resolve
|
|
139
|
+
// to one given surrounding DOM/CSSOM context this library never has access
|
|
140
|
+
// to), so treating them as resolvable named colors would mean fabricating an
|
|
141
|
+
// arbitrary RGB value with no way for a caller to tell it apart from a real
|
|
142
|
+
// one — see normalizeColor()'s `type: 'unknown'` fallback for these instead.
|
|
143
|
+
transparent: 'transparent',
|
|
135
144
|
};
|
|
136
145
|
function isCssVariable(value) {
|
|
137
146
|
return value.trim().startsWith('var(--');
|
|
138
147
|
}
|
|
139
148
|
function isHexColor(value) {
|
|
140
149
|
const trimmed = value.trim();
|
|
141
|
-
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6})$/.test(trimmed);
|
|
150
|
+
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(trimmed);
|
|
142
151
|
}
|
|
143
152
|
function isOklchColor(value) {
|
|
144
153
|
return /^\s*oklcha?\s*\(/i.test(value.trim());
|
|
@@ -479,11 +488,18 @@ function rgbaStringToRgba(str) {
|
|
|
479
488
|
const parts = m[1].split(/,\s*/).map(p => p.trim());
|
|
480
489
|
if (parts.length < 3)
|
|
481
490
|
return null;
|
|
482
|
-
|
|
491
|
+
// Clamp channels to a valid byte and alpha to [0,1] — an out-of-range input
|
|
492
|
+
// like "rgb(300, -20, 0)" or "rgba(0,0,0,2)" is invalid CSS, but previously
|
|
493
|
+
// passed straight through unclamped, which could even corrupt downstream hex
|
|
494
|
+
// output (a negative channel stringifies with a leading "-" via toString(16)).
|
|
495
|
+
const parseChannel = (v) => {
|
|
496
|
+
const n = v.endsWith('%') ? parseFloat(v) * 2.55 : parseFloat(v);
|
|
497
|
+
return Math.round(Math.max(0, Math.min(255, n)));
|
|
498
|
+
};
|
|
483
499
|
const r = parseChannel(parts[0]);
|
|
484
500
|
const g = parseChannel(parts[1]);
|
|
485
501
|
const b = parseChannel(parts[2]);
|
|
486
|
-
const a = parts[3] !== undefined ? parseFloat(parts[3]) : 1;
|
|
502
|
+
const a = parts[3] !== undefined ? Math.max(0, Math.min(1, parseFloat(parts[3]))) : 1;
|
|
487
503
|
return { r, g, b, a };
|
|
488
504
|
}
|
|
489
505
|
function rgbToHsl({ r, g, b }) {
|
|
@@ -740,6 +756,16 @@ function normalizeColor(input) {
|
|
|
740
756
|
g = srgb.g;
|
|
741
757
|
b = srgb.b;
|
|
742
758
|
}
|
|
759
|
+
else if (parsed.space === 'srgb-linear') {
|
|
760
|
+
// srgb-linear components are linear-light, not gamma-encoded — unlike
|
|
761
|
+
// plain srgb below, they need the linear-to-sRGB transfer function
|
|
762
|
+
// applied before scaling to a 0-255 byte. Without this, only the 0/1
|
|
763
|
+
// extremes happened to come out correct; any mid-range value (e.g. 0.5)
|
|
764
|
+
// converted as if it were already gamma-encoded, which is wrong.
|
|
765
|
+
r = Math.round(linearChanToSrgb(p3r) * 255);
|
|
766
|
+
g = Math.round(linearChanToSrgb(p3g) * 255);
|
|
767
|
+
b = Math.round(linearChanToSrgb(p3b) * 255);
|
|
768
|
+
}
|
|
743
769
|
else {
|
|
744
770
|
r = Math.round(Math.max(0, Math.min(255, p3r * 255)));
|
|
745
771
|
g = Math.round(Math.max(0, Math.min(255, p3g * 255)));
|
|
@@ -778,10 +804,16 @@ function tetradic(color) {
|
|
|
778
804
|
return [hex, rotateHue(hex, 90), rotateHue(hex, 180), rotateHue(hex, 270)];
|
|
779
805
|
}
|
|
780
806
|
function colorShades(color, steps = 9) {
|
|
781
|
-
var _a, _b;
|
|
807
|
+
var _a, _b, _c;
|
|
782
808
|
const n = normalizeColor(color);
|
|
783
809
|
const h = (_a = n.h) !== null && _a !== void 0 ? _a : 0;
|
|
784
810
|
const s = (_b = n.s) !== null && _b !== void 0 ? _b : 0;
|
|
811
|
+
// steps - 1 === 0 below would otherwise divide by zero (NaN lightness, then
|
|
812
|
+
// a literal "#NaNNaNNaN" hex string) — a single shade is just the color's
|
|
813
|
+
// own lightness, same idea as interpolateColors() returning the midpoint
|
|
814
|
+
// for a 2-color, 1-step request.
|
|
815
|
+
if (steps <= 1)
|
|
816
|
+
return steps === 1 ? [hslToHex(h, s, (_c = n.l) !== null && _c !== void 0 ? _c : 50)] : [];
|
|
785
817
|
const result = [];
|
|
786
818
|
for (let i = 0; i < steps; i++) {
|
|
787
819
|
const l = Math.round(100 - (i / (steps - 1)) * 100);
|
|
@@ -790,10 +822,13 @@ function colorShades(color, steps = 9) {
|
|
|
790
822
|
return result;
|
|
791
823
|
}
|
|
792
824
|
function monochromatic(color, steps = 5) {
|
|
793
|
-
var _a, _b;
|
|
825
|
+
var _a, _b, _c;
|
|
794
826
|
const n = normalizeColor(color);
|
|
795
827
|
const h = (_a = n.h) !== null && _a !== void 0 ? _a : 0;
|
|
796
828
|
const l = (_b = n.l) !== null && _b !== void 0 ? _b : 50;
|
|
829
|
+
// Same steps === 1 divide-by-zero guard as colorShades() above.
|
|
830
|
+
if (steps <= 1)
|
|
831
|
+
return steps === 1 ? [hslToHex(h, (_c = n.s) !== null && _c !== void 0 ? _c : 0, l)] : [];
|
|
797
832
|
const result = [];
|
|
798
833
|
for (let i = 0; i < steps; i++) {
|
|
799
834
|
const s = Math.round((i / (steps - 1)) * 100);
|
|
@@ -1215,6 +1250,12 @@ function toNearestNamedColor(color) {
|
|
|
1215
1250
|
let bestName = 'black';
|
|
1216
1251
|
let bestDist = Infinity;
|
|
1217
1252
|
for (const [name, hex] of Object.entries(NAMED_COLORS)) {
|
|
1253
|
+
// Skip any non-hex entry (currently just a defensive guard — 'transparent'
|
|
1254
|
+
// is the only such value left in the table, and it has no real RGB to
|
|
1255
|
+
// compare against; hexToRgb() would otherwise silently fall back to
|
|
1256
|
+
// normalizeHex()'s placeholder color for it).
|
|
1257
|
+
if (hex[0] !== '#')
|
|
1258
|
+
continue;
|
|
1218
1259
|
const [nr, ng, nb] = hexToRgb(hex);
|
|
1219
1260
|
const dist = Math.sqrt(Math.pow(r - nr, 2) + Math.pow(g - ng, 2) + Math.pow(b - nb, 2));
|
|
1220
1261
|
if (dist < bestDist) {
|
package/dist/esm/index.js
CHANGED
|
@@ -30,15 +30,24 @@ const NAMED_COLORS = {
|
|
|
30
30
|
springgreen: '#00ff7f', steelblue: '#4682b4', tan: '#d2b48c', teal: '#008080', thistle: '#d8bfd8',
|
|
31
31
|
tomato: '#ff6347', turquoise: '#40e0d0', violet: '#ee82ee', wheat: '#f5deb3', white: '#ffffff',
|
|
32
32
|
whitesmoke: '#f5f5f5', yellow: '#ffff00', yellowgreen: '#9acd32',
|
|
33
|
-
//
|
|
34
|
-
|
|
33
|
+
// 'transparent' is the only CSS-wide keyword with an actual fixed color (fully
|
|
34
|
+
// transparent black) — normalizeColor() special-cases it before ever reaching
|
|
35
|
+
// this table (see the `str === 'transparent'` check), so this entry only
|
|
36
|
+
// matters for getColorType()/toNearestNamedColor(), which read the table
|
|
37
|
+
// directly. 'currentcolor'/'inherit'/'initial'/'unset' are deliberately NOT
|
|
38
|
+
// listed here: none of them has a color value of their own (they only resolve
|
|
39
|
+
// to one given surrounding DOM/CSSOM context this library never has access
|
|
40
|
+
// to), so treating them as resolvable named colors would mean fabricating an
|
|
41
|
+
// arbitrary RGB value with no way for a caller to tell it apart from a real
|
|
42
|
+
// one — see normalizeColor()'s `type: 'unknown'` fallback for these instead.
|
|
43
|
+
transparent: 'transparent',
|
|
35
44
|
};
|
|
36
45
|
export function isCssVariable(value) {
|
|
37
46
|
return value.trim().startsWith('var(--');
|
|
38
47
|
}
|
|
39
48
|
export function isHexColor(value) {
|
|
40
49
|
const trimmed = value.trim();
|
|
41
|
-
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6})$/.test(trimmed);
|
|
50
|
+
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(trimmed);
|
|
42
51
|
}
|
|
43
52
|
export function isOklchColor(value) {
|
|
44
53
|
return /^\s*oklcha?\s*\(/i.test(value.trim());
|
|
@@ -379,11 +388,18 @@ export function rgbaStringToRgba(str) {
|
|
|
379
388
|
const parts = m[1].split(/,\s*/).map(p => p.trim());
|
|
380
389
|
if (parts.length < 3)
|
|
381
390
|
return null;
|
|
382
|
-
|
|
391
|
+
// Clamp channels to a valid byte and alpha to [0,1] — an out-of-range input
|
|
392
|
+
// like "rgb(300, -20, 0)" or "rgba(0,0,0,2)" is invalid CSS, but previously
|
|
393
|
+
// passed straight through unclamped, which could even corrupt downstream hex
|
|
394
|
+
// output (a negative channel stringifies with a leading "-" via toString(16)).
|
|
395
|
+
const parseChannel = (v) => {
|
|
396
|
+
const n = v.endsWith('%') ? parseFloat(v) * 2.55 : parseFloat(v);
|
|
397
|
+
return Math.round(Math.max(0, Math.min(255, n)));
|
|
398
|
+
};
|
|
383
399
|
const r = parseChannel(parts[0]);
|
|
384
400
|
const g = parseChannel(parts[1]);
|
|
385
401
|
const b = parseChannel(parts[2]);
|
|
386
|
-
const a = parts[3] !== undefined ? parseFloat(parts[3]) : 1;
|
|
402
|
+
const a = parts[3] !== undefined ? Math.max(0, Math.min(1, parseFloat(parts[3]))) : 1;
|
|
387
403
|
return { r, g, b, a };
|
|
388
404
|
}
|
|
389
405
|
export function rgbToHsl({ r, g, b }) {
|
|
@@ -640,6 +656,16 @@ export function normalizeColor(input) {
|
|
|
640
656
|
g = srgb.g;
|
|
641
657
|
b = srgb.b;
|
|
642
658
|
}
|
|
659
|
+
else if (parsed.space === 'srgb-linear') {
|
|
660
|
+
// srgb-linear components are linear-light, not gamma-encoded — unlike
|
|
661
|
+
// plain srgb below, they need the linear-to-sRGB transfer function
|
|
662
|
+
// applied before scaling to a 0-255 byte. Without this, only the 0/1
|
|
663
|
+
// extremes happened to come out correct; any mid-range value (e.g. 0.5)
|
|
664
|
+
// converted as if it were already gamma-encoded, which is wrong.
|
|
665
|
+
r = Math.round(linearChanToSrgb(p3r) * 255);
|
|
666
|
+
g = Math.round(linearChanToSrgb(p3g) * 255);
|
|
667
|
+
b = Math.round(linearChanToSrgb(p3b) * 255);
|
|
668
|
+
}
|
|
643
669
|
else {
|
|
644
670
|
r = Math.round(Math.max(0, Math.min(255, p3r * 255)));
|
|
645
671
|
g = Math.round(Math.max(0, Math.min(255, p3g * 255)));
|
|
@@ -678,10 +704,16 @@ export function tetradic(color) {
|
|
|
678
704
|
return [hex, rotateHue(hex, 90), rotateHue(hex, 180), rotateHue(hex, 270)];
|
|
679
705
|
}
|
|
680
706
|
export function colorShades(color, steps = 9) {
|
|
681
|
-
var _a, _b;
|
|
707
|
+
var _a, _b, _c;
|
|
682
708
|
const n = normalizeColor(color);
|
|
683
709
|
const h = (_a = n.h) !== null && _a !== void 0 ? _a : 0;
|
|
684
710
|
const s = (_b = n.s) !== null && _b !== void 0 ? _b : 0;
|
|
711
|
+
// steps - 1 === 0 below would otherwise divide by zero (NaN lightness, then
|
|
712
|
+
// a literal "#NaNNaNNaN" hex string) — a single shade is just the color's
|
|
713
|
+
// own lightness, same idea as interpolateColors() returning the midpoint
|
|
714
|
+
// for a 2-color, 1-step request.
|
|
715
|
+
if (steps <= 1)
|
|
716
|
+
return steps === 1 ? [hslToHex(h, s, (_c = n.l) !== null && _c !== void 0 ? _c : 50)] : [];
|
|
685
717
|
const result = [];
|
|
686
718
|
for (let i = 0; i < steps; i++) {
|
|
687
719
|
const l = Math.round(100 - (i / (steps - 1)) * 100);
|
|
@@ -690,10 +722,13 @@ export function colorShades(color, steps = 9) {
|
|
|
690
722
|
return result;
|
|
691
723
|
}
|
|
692
724
|
export function monochromatic(color, steps = 5) {
|
|
693
|
-
var _a, _b;
|
|
725
|
+
var _a, _b, _c;
|
|
694
726
|
const n = normalizeColor(color);
|
|
695
727
|
const h = (_a = n.h) !== null && _a !== void 0 ? _a : 0;
|
|
696
728
|
const l = (_b = n.l) !== null && _b !== void 0 ? _b : 50;
|
|
729
|
+
// Same steps === 1 divide-by-zero guard as colorShades() above.
|
|
730
|
+
if (steps <= 1)
|
|
731
|
+
return steps === 1 ? [hslToHex(h, (_c = n.s) !== null && _c !== void 0 ? _c : 0, l)] : [];
|
|
697
732
|
const result = [];
|
|
698
733
|
for (let i = 0; i < steps; i++) {
|
|
699
734
|
const s = Math.round((i / (steps - 1)) * 100);
|
|
@@ -1115,6 +1150,12 @@ export function toNearestNamedColor(color) {
|
|
|
1115
1150
|
let bestName = 'black';
|
|
1116
1151
|
let bestDist = Infinity;
|
|
1117
1152
|
for (const [name, hex] of Object.entries(NAMED_COLORS)) {
|
|
1153
|
+
// Skip any non-hex entry (currently just a defensive guard — 'transparent'
|
|
1154
|
+
// is the only such value left in the table, and it has no real RGB to
|
|
1155
|
+
// compare against; hexToRgb() would otherwise silently fall back to
|
|
1156
|
+
// normalizeHex()'s placeholder color for it).
|
|
1157
|
+
if (hex[0] !== '#')
|
|
1158
|
+
continue;
|
|
1118
1159
|
const [nr, ng, nb] = hexToRgb(hex);
|
|
1119
1160
|
const dist = Math.sqrt(Math.pow(r - nr, 2) + Math.pow(g - ng, 2) + Math.pow(b - nb, 2));
|
|
1120
1161
|
if (dist < bestDist) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "color-value-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Parse, convert and manipulate colors across hex, RGB, HSL, Lab, LCH, OKLCH and CMYK, with WCAG contrast checks and CSS variables. Zero dependencies.",
|
|
5
5
|
"author": "macrulez <macrulezru@gmail.com> (https://macrulez.ru/en)",
|
|
6
6
|
"license": "MIT",
|