@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
- * getComputedStyle이 oklch()를 그대로 반환하는 브라우저가 많아, Canvas 2D fillStyle에
13
- * 던져 브라우저가 sRGB hex로 정규화해주는 트릭을 사용. Canvas가 못 받으면 "#000"이 유지되므로
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 canvas = document.createElement("canvas");
18
- canvas.width = canvas.height = 1;
19
- const ctx = canvas.getContext("2d");
20
- if (!ctx) return null;
21
- // 센티넬로 "#000"을 먼저 넣고 입력 시도 — Canvas가 입력을 못 받으면 "#000"이 그대로 유지됨.
22
- ctx.fillStyle = "#000";
23
- try {
24
- ctx.fillStyle = css;
25
- } catch {
26
- // 일부 브라우저는 invalid color 시 예외 throw
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conscience-technology/ctds",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "CTDS — 하이브리드 디자인 시스템 설치 · 온보딩 CLI",
5
5
  "type": "module",
6
6
  "bin": {