@conscience-technology/ctds 0.1.12 → 0.1.13
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.
|
@@ -8,34 +8,49 @@
|
|
|
8
8
|
|
|
9
9
|
export type Rgb = [number, number, number];
|
|
10
10
|
|
|
11
|
+
/** oklch(L C H) → sRGB [r,g,b] 0~1. L은 0~1, C는 0~0.4, H는 degree.
|
|
12
|
+
* CTDS 토큰이 전부 oklch라 브라우저 Canvas 미지원을 우회하기 위해 수동 변환. */
|
|
13
|
+
function oklchToRgb(L: number, C: number, Hdeg: number): Rgb {
|
|
14
|
+
const H = (Hdeg * Math.PI) / 180;
|
|
15
|
+
const a = C * Math.cos(H);
|
|
16
|
+
const b = C * Math.sin(H);
|
|
17
|
+
// OKLab → linear sRGB (Björn Ottosson)
|
|
18
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
19
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
20
|
+
const s_ = L - 0.0894841775 * a - 1.2914855480 * b;
|
|
21
|
+
const l = l_ * l_ * l_;
|
|
22
|
+
const m = m_ * m_ * m_;
|
|
23
|
+
const s = s_ * s_ * s_;
|
|
24
|
+
const r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
|
|
25
|
+
const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
|
|
26
|
+
const bl = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s;
|
|
27
|
+
// linear → sRGB gamma
|
|
28
|
+
const toSrgb = (x: number) => {
|
|
29
|
+
const c = Math.max(0, Math.min(1, x));
|
|
30
|
+
return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
31
|
+
};
|
|
32
|
+
return [toSrgb(r), toSrgb(g), toSrgb(bl)];
|
|
33
|
+
}
|
|
34
|
+
|
|
11
35
|
/** CSS 색 문자열 → [r,g,b] 0~1 정규화. 서버에서는 null 반환.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* rgb() 폴백 파싱. */
|
|
36
|
+
* oklch()는 수동 변환(브라우저 Canvas가 oklch 입력을 받지 못하는 경우가 많음).
|
|
37
|
+
* rgb()/rgba()/#hex는 그대로 파싱. */
|
|
15
38
|
export function parseCssColor(css: string): Rgb | null {
|
|
16
39
|
if (typeof document === "undefined") return null;
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
const normalized = ctx.fillStyle as string;
|
|
29
|
-
const hex = /^#([0-9a-f]{6})$/i.exec(normalized);
|
|
30
|
-
if (hex) {
|
|
31
|
-
const n = parseInt(hex[1], 16);
|
|
32
|
-
return [((n >> 16) & 0xff) / 255, ((n >> 8) & 0xff) / 255, (n & 0xff) / 255];
|
|
33
|
-
}
|
|
34
|
-
// Canvas가 못 받으면 rgba()/rgb() 문자열일 수 있음 → 숫자 파싱
|
|
35
|
-
const m = normalized.match(/-?\d+(\.\d+)?/g);
|
|
36
|
-
if (m && m.length >= 3 && !normalized.startsWith("oklch") && !normalized.startsWith("color(")) {
|
|
37
|
-
return [+m[0] / 255, +m[1] / 255, +m[2] / 255];
|
|
40
|
+
const trimmed = css.trim();
|
|
41
|
+
// oklch(L C H) 또는 oklch(L C H / A) — 수동 변환
|
|
42
|
+
const oklchMatch = /^oklch\(\s*([^\s,/)]+)[\s,]+([^\s,/)]+)[\s,]+([^\s,/)]+)/i.exec(trimmed);
|
|
43
|
+
if (oklchMatch) {
|
|
44
|
+
const parsePart = (s: string, scale: number) =>
|
|
45
|
+
s.endsWith("%") ? (parseFloat(s) / 100) * scale : parseFloat(s);
|
|
46
|
+
const L = parsePart(oklchMatch[1], 1);
|
|
47
|
+
const C = parsePart(oklchMatch[2], 0.4);
|
|
48
|
+
const H = parseFloat(oklchMatch[3]);
|
|
49
|
+
if ([L, C, H].every((v) => Number.isFinite(v))) return oklchToRgb(L, C, H);
|
|
38
50
|
}
|
|
51
|
+
// rgb() / rgba() / #hex — 숫자 파싱 (CSS Typed OM 없이 간단히)
|
|
52
|
+
const m = trimmed.match(/-?\d+(\.\d+)?/g);
|
|
53
|
+
if (m && m.length >= 3) return [+m[0] / 255, +m[1] / 255, +m[2] / 255];
|
|
39
54
|
return null;
|
|
40
55
|
}
|
|
41
56
|
|