color-value-tools 1.2.1 → 1.2.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.
Files changed (49) hide show
  1. package/README.md +18 -0
  2. package/dist/cjs/a11y.d.ts +40 -0
  3. package/dist/cjs/a11y.js +253 -0
  4. package/dist/cjs/cache.d.ts +9 -0
  5. package/dist/cjs/cache.js +38 -0
  6. package/dist/cjs/convert/format.d.ts +3 -0
  7. package/dist/cjs/convert/format.js +42 -0
  8. package/dist/cjs/convert/index.d.ts +2 -0
  9. package/dist/cjs/convert/index.js +18 -0
  10. package/dist/cjs/convert/spaces.d.ts +189 -0
  11. package/dist/cjs/convert/spaces.js +556 -0
  12. package/dist/cjs/index.d.ts +6 -397
  13. package/dist/cjs/index.js +20 -1466
  14. package/dist/cjs/internal/named-colors.d.ts +1 -0
  15. package/dist/cjs/internal/named-colors.js +165 -0
  16. package/dist/cjs/internal/transfer.d.ts +2 -0
  17. package/dist/cjs/internal/transfer.js +12 -0
  18. package/dist/cjs/manipulate.d.ts +15 -0
  19. package/dist/cjs/manipulate.js +223 -0
  20. package/dist/cjs/palette.d.ts +40 -0
  21. package/dist/cjs/palette.js +164 -0
  22. package/dist/cjs/parse.d.ts +102 -0
  23. package/dist/cjs/parse.js +257 -0
  24. package/dist/cli/{bin/cli.js → cli.js} +28 -26
  25. package/dist/esm/a11y.d.ts +40 -0
  26. package/dist/esm/a11y.js +237 -0
  27. package/dist/esm/cache.d.ts +9 -0
  28. package/dist/esm/cache.js +31 -0
  29. package/dist/esm/convert/format.d.ts +3 -0
  30. package/dist/esm/convert/format.js +37 -0
  31. package/dist/esm/convert/index.d.ts +2 -0
  32. package/dist/esm/convert/index.js +2 -0
  33. package/dist/esm/convert/spaces.d.ts +189 -0
  34. package/dist/esm/convert/spaces.js +520 -0
  35. package/dist/esm/index.d.ts +6 -0
  36. package/dist/esm/index.js +6 -1368
  37. package/dist/esm/internal/named-colors.d.ts +1 -0
  38. package/dist/esm/internal/named-colors.js +162 -0
  39. package/dist/esm/internal/transfer.d.ts +2 -0
  40. package/dist/esm/internal/transfer.js +8 -0
  41. package/dist/esm/manipulate.d.ts +15 -0
  42. package/dist/esm/manipulate.js +210 -0
  43. package/dist/esm/package.json +3 -1
  44. package/dist/esm/palette.d.ts +40 -0
  45. package/dist/esm/palette.js +145 -0
  46. package/dist/esm/parse.d.ts +102 -0
  47. package/dist/esm/parse.js +241 -0
  48. package/package.json +100 -8
  49. package/dist/cli/src/index.js +0 -1468
@@ -0,0 +1,520 @@
1
+ // Pure numeric conversions between color spaces and hex/rgba strings.
2
+ import { linearChanToSrgb, srgbChanToLinear } from '../internal/transfer.js';
3
+ // ─── Display P3 ────────────────────────────────────────────────
4
+ export function rgbToDisplayP3(rgb) {
5
+ // Remove sRGB gamma (linearize)
6
+ const rl = srgbChanToLinear(rgb.r / 255);
7
+ const gl = srgbChanToLinear(rgb.g / 255);
8
+ const bl = srgbChanToLinear(rgb.b / 255);
9
+ // sRGB-linear → P3-linear matrix
10
+ const pr = 0.8226 * rl + 0.1774 * gl + 0.0 * bl;
11
+ const pg = 0.0332 * rl + 0.9669 * gl + 0.0 * bl;
12
+ const pb = 0.0171 * rl + 0.0724 * gl + 0.9103 * bl;
13
+ // Apply P3 gamma (same as sRGB)
14
+ return {
15
+ r: linearChanToSrgb(pr),
16
+ g: linearChanToSrgb(pg),
17
+ b: linearChanToSrgb(pb),
18
+ };
19
+ }
20
+ export function displayP3ToRgb(p3) {
21
+ // Remove P3 gamma
22
+ const rl = srgbChanToLinear(p3.r);
23
+ const gl = srgbChanToLinear(p3.g);
24
+ const bl = srgbChanToLinear(p3.b);
25
+ // P3-linear → sRGB-linear inverse matrix
26
+ const sr = 1.2247 * rl + -0.2247 * gl + 0.0 * bl;
27
+ const sg = -0.0421 * rl + 1.0432 * gl + 0.0 * bl;
28
+ const sb = -0.0197 * rl + -0.0786 * gl + 1.0983 * bl;
29
+ // Apply sRGB gamma and scale to 0-255
30
+ return {
31
+ r: Math.round(Math.max(0, Math.min(255, linearChanToSrgb(sr) * 255))),
32
+ g: Math.round(Math.max(0, Math.min(255, linearChanToSrgb(sg) * 255))),
33
+ b: Math.round(Math.max(0, Math.min(255, linearChanToSrgb(sb) * 255))),
34
+ };
35
+ }
36
+ // ─── Short RGBA hex #RGBA ──────────────────────────────────────
37
+ export function shortHexToRgba(hex) {
38
+ let h = hex.trim();
39
+ if (!h.startsWith('#'))
40
+ h = `#${h}`;
41
+ if (!/^#[0-9a-f]{4}$/i.test(h))
42
+ return null;
43
+ const r = parseInt(h[1] + h[1], 16);
44
+ const g = parseInt(h[2] + h[2], 16);
45
+ const b = parseInt(h[3] + h[3], 16);
46
+ const a = parseInt(h[4] + h[4], 16) / 255;
47
+ return { r, g, b, a };
48
+ }
49
+ export function normalizeHex(hex) {
50
+ let cleanHex = hex.trim();
51
+ if (!cleanHex.startsWith('#'))
52
+ cleanHex = `#${cleanHex}`;
53
+ if (cleanHex.length === 4) {
54
+ cleanHex = `#${cleanHex
55
+ .slice(1)
56
+ .split('')
57
+ .map((c) => c + c)
58
+ .join('')}`;
59
+ }
60
+ if (!/^#[0-9A-Fa-f]{6}$/.test(cleanHex)) {
61
+ return '#f5e477';
62
+ }
63
+ return cleanHex.toLowerCase();
64
+ }
65
+ export function hexToRgb(hex) {
66
+ const normalizedHex = normalizeHex(hex);
67
+ const r = parseInt(normalizedHex.slice(1, 3), 16);
68
+ const g = parseInt(normalizedHex.slice(3, 5), 16);
69
+ const b = parseInt(normalizedHex.slice(5, 7), 16);
70
+ return [r, g, b];
71
+ }
72
+ export function hexToRgba(hex, opacity = 1) {
73
+ const [r, g, b] = hexToRgb(hex);
74
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
75
+ }
76
+ export function hexToHsl(hex) {
77
+ const [r, g, b] = hexToRgb(hex);
78
+ const red = r / 255;
79
+ const green = g / 255;
80
+ const blue = b / 255;
81
+ const max = Math.max(red, green, blue);
82
+ const min = Math.min(red, green, blue);
83
+ let h = 0, s = 0;
84
+ const l = (max + min) / 2;
85
+ if (max !== min) {
86
+ const d = max - min;
87
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
88
+ switch (max) {
89
+ case red:
90
+ h = (green - blue) / d + (green < blue ? 6 : 0);
91
+ break;
92
+ case green:
93
+ h = (blue - red) / d + 2;
94
+ break;
95
+ case blue:
96
+ h = (red - green) / d + 4;
97
+ break;
98
+ }
99
+ h /= 6;
100
+ }
101
+ return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
102
+ }
103
+ export function hslToHex(h, s, l) {
104
+ h = ((h % 360) + 360) % 360;
105
+ s = Math.max(0, Math.min(100, s)) / 100;
106
+ l = Math.max(0, Math.min(100, l)) / 100;
107
+ const c = (1 - Math.abs(2 * l - 1)) * s;
108
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
109
+ const m = l - c / 2;
110
+ let r = 0, g = 0, b = 0;
111
+ if (h >= 0 && h < 60) {
112
+ r = c;
113
+ g = x;
114
+ b = 0;
115
+ }
116
+ else if (h >= 60 && h < 120) {
117
+ r = x;
118
+ g = c;
119
+ b = 0;
120
+ }
121
+ else if (h >= 120 && h < 180) {
122
+ r = 0;
123
+ g = c;
124
+ b = x;
125
+ }
126
+ else if (h >= 180 && h < 240) {
127
+ r = 0;
128
+ g = x;
129
+ b = c;
130
+ }
131
+ else if (h >= 240 && h < 300) {
132
+ r = x;
133
+ g = 0;
134
+ b = c;
135
+ }
136
+ else {
137
+ r = c;
138
+ g = 0;
139
+ b = x;
140
+ }
141
+ r = Math.round((r + m) * 255);
142
+ g = Math.round((g + m) * 255);
143
+ b = Math.round((b + m) * 255);
144
+ return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
145
+ }
146
+ function clamp01(v) {
147
+ return Math.max(0, Math.min(1, v));
148
+ }
149
+ function toHex2(n) {
150
+ return Math.round(n).toString(16).padStart(2, '0');
151
+ }
152
+ export function rgbToHex({ r, g, b }) {
153
+ return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}`.toLowerCase();
154
+ }
155
+ export function rgbaToHex({ r, g, b, a }) {
156
+ const aa = Math.round(clamp01(a) * 255);
157
+ return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}${toHex2(aa)}`.toLowerCase();
158
+ }
159
+ export function rgbToRgbaString({ r, g, b }, a) {
160
+ return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${+a.toFixed(3)})`;
161
+ }
162
+ export function rgbaStringToRgba(str) {
163
+ const s = str.trim().toLowerCase();
164
+ const m = s.match(/rgba?\(([^)]+)\)/);
165
+ if (!m)
166
+ return null;
167
+ const parts = m[1].split(/,\s*/).map((p) => p.trim());
168
+ if (parts.length < 3)
169
+ return null;
170
+ // Clamp channels to a valid byte and alpha to [0,1] — an out-of-range input
171
+ // like "rgb(300, -20, 0)" or "rgba(0,0,0,2)" is invalid CSS, but previously
172
+ // passed straight through unclamped, which could even corrupt downstream hex
173
+ // output (a negative channel stringifies with a leading "-" via toString(16)).
174
+ const parseChannel = (v) => {
175
+ const n = v.endsWith('%') ? parseFloat(v) * 2.55 : parseFloat(v);
176
+ return Math.round(Math.max(0, Math.min(255, n)));
177
+ };
178
+ const r = parseChannel(parts[0]);
179
+ const g = parseChannel(parts[1]);
180
+ const b = parseChannel(parts[2]);
181
+ const a = parts[3] !== undefined ? Math.max(0, Math.min(1, parseFloat(parts[3]))) : 1;
182
+ return { r, g, b, a };
183
+ }
184
+ export function rgbToHsl({ r, g, b, }) {
185
+ const rd = r / 255, gd = g / 255, bd = b / 255;
186
+ const max = Math.max(rd, gd, bd), min = Math.min(rd, gd, bd);
187
+ let h = 0, s = 0;
188
+ const l = (max + min) / 2;
189
+ if (max !== min) {
190
+ const d = max - min;
191
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
192
+ switch (max) {
193
+ case rd:
194
+ h = (gd - bd) / d + (gd < bd ? 6 : 0);
195
+ break;
196
+ case gd:
197
+ h = (bd - rd) / d + 2;
198
+ break;
199
+ case bd:
200
+ h = (rd - gd) / d + 4;
201
+ break;
202
+ }
203
+ h /= 6;
204
+ }
205
+ return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
206
+ }
207
+ export function hslToRgb(h, s, l) {
208
+ h = ((h % 360) + 360) % 360;
209
+ s = Math.max(0, Math.min(100, s)) / 100;
210
+ l = Math.max(0, Math.min(100, l)) / 100;
211
+ const c = (1 - Math.abs(2 * l - 1)) * s;
212
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
213
+ const m = l - c / 2;
214
+ let rd = 0, gd = 0, bd = 0;
215
+ if (h >= 0 && h < 60) {
216
+ rd = c;
217
+ gd = x;
218
+ bd = 0;
219
+ }
220
+ else if (h >= 60 && h < 120) {
221
+ rd = x;
222
+ gd = c;
223
+ bd = 0;
224
+ }
225
+ else if (h >= 120 && h < 180) {
226
+ rd = 0;
227
+ gd = c;
228
+ bd = x;
229
+ }
230
+ else if (h >= 180 && h < 240) {
231
+ rd = 0;
232
+ gd = x;
233
+ bd = c;
234
+ }
235
+ else if (h >= 240 && h < 300) {
236
+ rd = x;
237
+ gd = 0;
238
+ bd = c;
239
+ }
240
+ else {
241
+ rd = c;
242
+ gd = 0;
243
+ bd = x;
244
+ }
245
+ return {
246
+ r: Math.round((rd + m) * 255),
247
+ g: Math.round((gd + m) * 255),
248
+ b: Math.round((bd + m) * 255),
249
+ };
250
+ }
251
+ export function rgbToHsv({ r, g, b, }) {
252
+ const rd = r / 255, gd = g / 255, bd = b / 255;
253
+ const max = Math.max(rd, gd, bd), min = Math.min(rd, gd, bd);
254
+ const v = max;
255
+ const d = max - min;
256
+ const s = max === 0 ? 0 : d / max;
257
+ let h = 0;
258
+ if (d !== 0) {
259
+ switch (max) {
260
+ case rd:
261
+ h = (gd - bd) / d + (gd < bd ? 6 : 0);
262
+ break;
263
+ case gd:
264
+ h = (bd - rd) / d + 2;
265
+ break;
266
+ case bd:
267
+ h = (rd - gd) / d + 4;
268
+ break;
269
+ }
270
+ h /= 6;
271
+ }
272
+ return [Math.round(h * 360), Math.round(s * 100), Math.round(v * 100)];
273
+ }
274
+ export function hsvToRgb(h, s, v) {
275
+ h = ((h % 360) + 360) % 360;
276
+ s = Math.max(0, Math.min(100, s)) / 100;
277
+ v = Math.max(0, Math.min(100, v)) / 100;
278
+ const i = Math.floor(h / 60);
279
+ const f = h / 60 - i;
280
+ const p = v * (1 - s);
281
+ const q = v * (1 - f * s);
282
+ const t = v * (1 - (1 - f) * s);
283
+ let rd = 0, gd = 0, bd = 0;
284
+ switch (i) {
285
+ case 0:
286
+ rd = v;
287
+ gd = t;
288
+ bd = p;
289
+ break;
290
+ case 1:
291
+ rd = q;
292
+ gd = v;
293
+ bd = p;
294
+ break;
295
+ case 2:
296
+ rd = p;
297
+ gd = v;
298
+ bd = t;
299
+ break;
300
+ case 3:
301
+ rd = p;
302
+ gd = q;
303
+ bd = v;
304
+ break;
305
+ case 4:
306
+ rd = t;
307
+ gd = p;
308
+ bd = v;
309
+ break;
310
+ default:
311
+ rd = v;
312
+ gd = p;
313
+ bd = q;
314
+ break;
315
+ }
316
+ return { r: Math.round(rd * 255), g: Math.round(gd * 255), b: Math.round(bd * 255) };
317
+ }
318
+ export function hexToHsv(hex) {
319
+ const [r, g, b] = hexToRgb(hex);
320
+ return rgbToHsv({ r, g, b });
321
+ }
322
+ export function hsvToHex(h, s, v) {
323
+ const { r, g, b } = hsvToRgb(h, s, v);
324
+ return rgbToHex({ r, g, b });
325
+ }
326
+ export function hex8ToRgba(hex) {
327
+ let h = hex.trim();
328
+ if (!h.startsWith('#'))
329
+ h = `#${h}`;
330
+ if (h.length === 5) {
331
+ // #rgba shorthand
332
+ h = `#${h[1]}${h[1]}${h[2]}${h[2]}${h[3]}${h[3]}${h[4]}${h[4]}`;
333
+ }
334
+ if (h.length !== 9)
335
+ return null;
336
+ const r = parseInt(h.slice(1, 3), 16);
337
+ const g = parseInt(h.slice(3, 5), 16);
338
+ const b = parseInt(h.slice(5, 7), 16);
339
+ const a = parseInt(h.slice(7, 9), 16) / 255;
340
+ return { r, g, b, a };
341
+ }
342
+ export function rgbaToHex8({ r, g, b, a }) {
343
+ return rgbaToHex({ r, g, b, a });
344
+ }
345
+ export function rgbToCmyk({ r, g, b }) {
346
+ const rd = r / 255, gd = g / 255, bd = b / 255;
347
+ const k = 1 - Math.max(rd, gd, bd);
348
+ if (k === 1)
349
+ return { c: 0, m: 0, y: 0, k: 1 };
350
+ const c = (1 - rd - k) / (1 - k);
351
+ const m = (1 - gd - k) / (1 - k);
352
+ const y = (1 - bd - k) / (1 - k);
353
+ return { c, m, y, k };
354
+ }
355
+ export function cmykToRgb({ c, m, y, k }) {
356
+ const r = 255 * (1 - c) * (1 - k);
357
+ const g = 255 * (1 - m) * (1 - k);
358
+ const b = 255 * (1 - y) * (1 - k);
359
+ return { r: Math.round(r), g: Math.round(g), b: Math.round(b) };
360
+ }
361
+ function srgbToLinear(v) {
362
+ v = v / 255;
363
+ return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
364
+ }
365
+ function linearToSrgb(v) {
366
+ const t = v <= 0.0031308 ? 12.92 * v : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
367
+ return Math.round(Math.max(0, Math.min(1, t)) * 255);
368
+ }
369
+ function rgbToXyz({ r, g, b }) {
370
+ const R = srgbToLinear(r);
371
+ const G = srgbToLinear(g);
372
+ const B = srgbToLinear(b);
373
+ const X = R * 0.4124564 + G * 0.3575761 + B * 0.1804375;
374
+ const Y = R * 0.2126729 + G * 0.7151522 + B * 0.072175;
375
+ const Z = R * 0.0193339 + G * 0.119192 + B * 0.9503041;
376
+ return { X: X * 100, Y: Y * 100, Z: Z * 100 };
377
+ }
378
+ function xyzToRgb({ X, Y, Z }) {
379
+ X = X / 100;
380
+ Y = Y / 100;
381
+ Z = Z / 100;
382
+ let R = X * 3.2404542 + Y * -1.5371385 + Z * -0.4985314;
383
+ let G = X * -0.969266 + Y * 1.8760108 + Z * 0.041556;
384
+ let B = X * 0.0556434 + Y * -0.2040259 + Z * 1.0572252;
385
+ R = linearToSrgb(R);
386
+ G = linearToSrgb(G);
387
+ B = linearToSrgb(B);
388
+ return { r: R, g: G, b: B };
389
+ }
390
+ export function rgbToLab({ r, g, b }) {
391
+ const { X, Y, Z } = rgbToXyz({ r, g, b });
392
+ const refX = 95.047, refY = 100.0, refZ = 108.883;
393
+ const x = X / refX, y = Y / refY, z = Z / refZ;
394
+ const fx = x > 0.008856 ? Math.cbrt(x) : 7.787 * x + 16 / 116;
395
+ const fy = y > 0.008856 ? Math.cbrt(y) : 7.787 * y + 16 / 116;
396
+ const fz = z > 0.008856 ? Math.cbrt(z) : 7.787 * z + 16 / 116;
397
+ const L = 116 * fy - 16;
398
+ const a = 500 * (fx - fy);
399
+ const b2 = 200 * (fy - fz);
400
+ return { L, a, b: b2 };
401
+ }
402
+ export function labToRgb({ L, a, b }) {
403
+ const refX = 95.047, refY = 100.0, refZ = 108.883;
404
+ let fy = (L + 16) / 116;
405
+ let fx = a / 500 + fy;
406
+ let fz = fy - b / 200;
407
+ const fx3 = Math.pow(fx, 3);
408
+ const fz3 = Math.pow(fz, 3);
409
+ const fy3 = Math.pow(fy, 3);
410
+ const xr = fx3 > 0.008856 ? fx3 : (fx - 16 / 116) / 7.787;
411
+ const yr = L > 903.3 * 0.008856 ? fy3 : L / 903.3;
412
+ const zr = fz3 > 0.008856 ? fz3 : (fz - 16 / 116) / 7.787;
413
+ const X = xr * refX, Y = yr * refY, Z = zr * refZ;
414
+ return xyzToRgb({ X, Y, Z });
415
+ }
416
+ export function rgbToLch({ r, g, b }) {
417
+ const { L, a, b: bb } = rgbToLab({ r, g, b });
418
+ const C = Math.sqrt(a * a + bb * bb);
419
+ let H = Math.atan2(bb, a) * (180 / Math.PI);
420
+ if (H < 0)
421
+ H += 360;
422
+ return { L, C, H };
423
+ }
424
+ export function lchToRgb({ L, C, H }) {
425
+ const a = Math.cos((H * Math.PI) / 180) * C;
426
+ const b = Math.sin((H * Math.PI) / 180) * C;
427
+ return labToRgb({ L, a, b });
428
+ }
429
+ // ─── HWB ─────────────────────────────────────────────────────────────────────
430
+ export function rgbToHwb({ r, g, b, }) {
431
+ const rd = r / 255, gd = g / 255, bd = b / 255;
432
+ const max = Math.max(rd, gd, bd), min = Math.min(rd, gd, bd);
433
+ const w = min;
434
+ const bl = 1 - max;
435
+ let h = 0;
436
+ if (max !== min) {
437
+ const d = max - min;
438
+ switch (max) {
439
+ case rd:
440
+ h = (gd - bd) / d + (gd < bd ? 6 : 0);
441
+ break;
442
+ case gd:
443
+ h = (bd - rd) / d + 2;
444
+ break;
445
+ case bd:
446
+ h = (rd - gd) / d + 4;
447
+ break;
448
+ }
449
+ h /= 6;
450
+ }
451
+ return [Math.round(h * 360), Math.round(w * 100), Math.round(bl * 100)];
452
+ }
453
+ export function hwbToRgb(H, W, B) {
454
+ H = ((H % 360) + 360) % 360;
455
+ const w = W / 100, b = B / 100;
456
+ if (w + b >= 1) {
457
+ const gray = Math.round((w / (w + b)) * 255);
458
+ return { r: gray, g: gray, b: gray };
459
+ }
460
+ const { r, g, b: rb } = hslToRgb(H, 100, 50);
461
+ const factor = 1 - w - b;
462
+ return {
463
+ r: Math.round((r / 255) * factor * 255 + w * 255),
464
+ g: Math.round((g / 255) * factor * 255 + w * 255),
465
+ b: Math.round((rb / 255) * factor * 255 + w * 255),
466
+ };
467
+ }
468
+ export function toHwbString(H, W, B, alpha) {
469
+ if (alpha !== undefined)
470
+ return `hwb(${H} ${W}% ${B}% / ${+alpha.toFixed(3)})`;
471
+ return `hwb(${H} ${W}% ${B}%)`;
472
+ }
473
+ // ─── OKLCH / OKLAB ───────────────────────────────────────────────────────────
474
+ function srgbToOkLinear(v) {
475
+ v = v / 255;
476
+ return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
477
+ }
478
+ function okLinearToSrgb(v) {
479
+ const t = v <= 0.0031308 ? 12.92 * v : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
480
+ return Math.round(Math.max(0, Math.min(1, t)) * 255);
481
+ }
482
+ export function rgbToOklab({ r, g, b }) {
483
+ const R = srgbToOkLinear(r), G = srgbToOkLinear(g), B = srgbToOkLinear(b);
484
+ const l = Math.cbrt(0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B);
485
+ const m = Math.cbrt(0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B);
486
+ const s = Math.cbrt(0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B);
487
+ return {
488
+ L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
489
+ a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
490
+ b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
491
+ };
492
+ }
493
+ export function oklabToRgb({ L, a, b }) {
494
+ const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
495
+ const m = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
496
+ const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
497
+ const R = okLinearToSrgb(+4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s);
498
+ const G = okLinearToSrgb(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s);
499
+ const B = okLinearToSrgb(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s);
500
+ return { r: R, g: G, b: B };
501
+ }
502
+ export function rgbToOklch({ r, g, b }) {
503
+ const { L, a, b: bb } = rgbToOklab({ r, g, b });
504
+ const C = Math.sqrt(a * a + bb * bb);
505
+ let H = Math.atan2(bb, a) * (180 / Math.PI);
506
+ if (H < 0)
507
+ H += 360;
508
+ return { L, C, H };
509
+ }
510
+ export function oklchToRgb({ L, C, H }) {
511
+ const a = Math.cos((H * Math.PI) / 180) * C;
512
+ const b = Math.sin((H * Math.PI) / 180) * C;
513
+ return oklabToRgb({ L, a, b });
514
+ }
515
+ // ─── Utilities ───────────────────────────────────────────────────────────────
516
+ export function toHslString(h, s, l, alpha) {
517
+ if (alpha !== undefined)
518
+ return `hsla(${h}, ${s}%, ${l}%, ${+alpha.toFixed(3)})`;
519
+ return `hsl(${h}, ${s}%, ${l}%)`;
520
+ }
@@ -0,0 +1,6 @@
1
+ export * from './parse.js';
2
+ export * from './convert/index.js';
3
+ export * from './manipulate.js';
4
+ export * from './palette.js';
5
+ export * from './a11y.js';
6
+ export * from './cache.js';