/
luv.ts
35 lines (30 loc) · 1.38 KB
/
luv.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { TInput, Irgba, TFormat, Iluva } from "../types";
import { adjustAlpha, clamp } from "../utils/numeric";
import { isLUVObject } from "../utils/typeGuards";
import { LUVtoRGB } from "../conversions/luv";
/**
* color(luv[a] <number | percentage>{3} [ / <alpha-value> ]? )
* @note For typical images, u and v range is ±100%. By definition, 0 ≤ L ≤ 100%.
* @see https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
*/
const LUVA_RE =
/color\s*\(\s*luva?\s*(\d*\.?\d+%?)\s*,?\s*([+-]?\d*\.?\d+%?)\s*,?\s*([+-]?\d*\.?\d+%?)\s*,?\s*\/?\s*?(\d*\.?\d+%?)?\s*\)/gi;
function createReturnArr({ l, u, v, a }: Iluva): [Irgba, TFormat] {
return [LUVtoRGB({ l: clamp(0, l, 100), u: clamp(-100, u, 100), v: clamp(-100, v, 100), a: adjustAlpha(a) }), "luv"];
}
export function luvaParser(color: TInput): [Irgba, TFormat] {
if (color.constructor.name.toLowerCase() === "object" && isLUVObject(color)) {
return createReturnArr(color as Iluva);
} else if (typeof color === "string") {
LUVA_RE.lastIndex = 0;
const matches = LUVA_RE.exec(color);
if (matches) {
const [l, u, v, a] = matches
.filter((val) => val !== undefined)
.slice(1)
.map((elem, i) => (elem.includes("%") ? +elem.slice(0, -1) * (i < 3 ? 1 : 0.01) : +elem));
return createReturnArr({ l, u, v, a });
}
}
return [{ r: 0, g: 0, b: 0, a: 1 }, "invalid"];
}