@ariaui/color 0.1.3 → 0.1.4

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/index.cjs ADDED
@@ -0,0 +1,476 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
+ var __export = (target, all) => {
24
+ for (var name in all)
25
+ __defProp(target, name, { get: all[name], enumerable: true });
26
+ };
27
+ var __copyProps = (to, from, except, desc) => {
28
+ if (from && typeof from === "object" || typeof from === "function") {
29
+ for (let key of __getOwnPropNames(from))
30
+ if (!__hasOwnProp.call(to, key) && key !== except)
31
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
32
+ }
33
+ return to;
34
+ };
35
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
+
37
+ // index.ts
38
+ var index_exports = {};
39
+ __export(index_exports, {
40
+ adjustHue: () => adjustHue,
41
+ complement: () => complement,
42
+ contrastRatio: () => contrastRatio,
43
+ darken: () => darken,
44
+ desaturate: () => desaturate,
45
+ grayscale: () => grayscale,
46
+ hexToOklch: () => hexToOklch,
47
+ invert: () => invert,
48
+ lighten: () => lighten,
49
+ meetsAA: () => meetsAA,
50
+ meetsAAA: () => meetsAAA,
51
+ mix: () => mix,
52
+ oklabToOklch: () => oklabToOklch,
53
+ oklchToHex: () => oklchToHex,
54
+ oklchToOklab: () => oklchToOklab,
55
+ oklchToSrgb: () => oklchToSrgb,
56
+ parseHex: () => parseHex,
57
+ parseOklchChannels: () => parseOklchChannels,
58
+ parseOklchCss: () => parseOklchCss,
59
+ parseRgb: () => parseRgb,
60
+ saturate: () => saturate,
61
+ setAlpha: () => setAlpha,
62
+ srgbToHex: () => srgbToHex,
63
+ srgbToOklch: () => srgbToOklch,
64
+ suggestAccessible: () => suggestAccessible,
65
+ toCssChannels: () => toCssChannels,
66
+ toHexString: () => toHexString,
67
+ toOklchString: () => toOklchString,
68
+ toRgbString: () => toRgbString
69
+ });
70
+ module.exports = __toCommonJS(index_exports);
71
+
72
+ // src/parse.ts
73
+ function parseOklchChannels(channels) {
74
+ const normalised = channels.trim();
75
+ const [colorPart, alphaPart] = normalised.split("/").map((s) => s.trim());
76
+ const parts = colorPart.split(/\s+/);
77
+ if (parts.length !== 3) {
78
+ throw new Error(
79
+ `Invalid OKLCH channel string: expected "L C H", got "${channels}"`
80
+ );
81
+ }
82
+ const [rawL, rawC, rawH] = parts;
83
+ let l;
84
+ if (rawL.endsWith("%")) {
85
+ l = parseFloat(rawL) / 100;
86
+ } else {
87
+ l = parseFloat(rawL);
88
+ }
89
+ const c = parseFloat(rawC);
90
+ const h = parseFloat(rawH);
91
+ if (Number.isNaN(l) || Number.isNaN(c) || Number.isNaN(h)) {
92
+ throw new Error(
93
+ `Invalid OKLCH channel string: could not parse numbers from "${channels}"`
94
+ );
95
+ }
96
+ let alpha = 1;
97
+ if (alphaPart !== void 0) {
98
+ alpha = parseFloat(alphaPart);
99
+ if (Number.isNaN(alpha)) {
100
+ throw new Error(
101
+ `Invalid OKLCH alpha value: could not parse "${alphaPart}"`
102
+ );
103
+ }
104
+ }
105
+ return { l, c, h, alpha };
106
+ }
107
+ function parseOklchCss(css) {
108
+ const match = css.match(/oklch\(\s*(.+?)\s*\)/i);
109
+ if (!match) {
110
+ throw new Error(`Invalid oklch() CSS string: "${css}"`);
111
+ }
112
+ return parseOklchChannels(match[1]);
113
+ }
114
+ function parseHex(hex) {
115
+ let h = hex.startsWith("#") ? hex.slice(1) : hex;
116
+ if (h.length === 3) {
117
+ h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
118
+ } else if (h.length === 4) {
119
+ h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
120
+ }
121
+ if (h.length !== 6 && h.length !== 8) {
122
+ throw new Error(`Invalid hex color: "${hex}"`);
123
+ }
124
+ if (!/^[0-9a-fA-F]+$/.test(h)) {
125
+ throw new Error(`Invalid hex color: "${hex}"`);
126
+ }
127
+ const r = parseInt(h.slice(0, 2), 16) / 255;
128
+ const g = parseInt(h.slice(2, 4), 16) / 255;
129
+ const b = parseInt(h.slice(4, 6), 16) / 255;
130
+ const alpha = h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1;
131
+ return { r, g, b, alpha };
132
+ }
133
+ function parseRgb(css) {
134
+ const match = css.match(/rgba?\(\s*(.+?)\s*\)/i);
135
+ if (!match) {
136
+ throw new Error(`Invalid rgb()/rgba() CSS string: "${css}"`);
137
+ }
138
+ const inner = match[1];
139
+ if (inner.includes("/")) {
140
+ const [colorPart, alphaPart] = inner.split("/").map((s) => s.trim());
141
+ const [r, g, b] = colorPart.split(/\s+/).map(Number);
142
+ const alpha = parseFloat(alphaPart);
143
+ return { r: r / 255, g: g / 255, b: b / 255, alpha };
144
+ }
145
+ if (inner.includes(",")) {
146
+ const parts2 = inner.split(",").map((s) => parseFloat(s.trim()));
147
+ return {
148
+ r: parts2[0] / 255,
149
+ g: parts2[1] / 255,
150
+ b: parts2[2] / 255,
151
+ alpha: parts2.length === 4 ? parts2[3] : 1
152
+ };
153
+ }
154
+ const parts = inner.split(/\s+/).map(Number);
155
+ if (parts.length !== 3) {
156
+ throw new Error(`Invalid rgb() CSS string: "${css}"`);
157
+ }
158
+ return { r: parts[0] / 255, g: parts[1] / 255, b: parts[2] / 255, alpha: 1 };
159
+ }
160
+
161
+ // src/convert.ts
162
+ function oklchToOklab(c) {
163
+ const hRad = c.h * Math.PI / 180;
164
+ return {
165
+ L: c.l,
166
+ a: c.c * Math.cos(hRad),
167
+ b: c.c * Math.sin(hRad),
168
+ alpha: c.alpha
169
+ };
170
+ }
171
+ function oklabToOklch(lab) {
172
+ const c = Math.sqrt(lab.a * lab.a + lab.b * lab.b);
173
+ let h = Math.atan2(lab.b, lab.a) * 180 / Math.PI;
174
+ if (h < 0) h += 360;
175
+ if (c < 1e-8) h = 0;
176
+ return { l: lab.L, c, h, alpha: lab.alpha };
177
+ }
178
+ function oklabToLinearSrgb(lab) {
179
+ const l_ = lab.L + 0.3963377774 * lab.a + 0.2158037573 * lab.b;
180
+ const m_ = lab.L - 0.1055613458 * lab.a - 0.0638541728 * lab.b;
181
+ const s_ = lab.L - 0.0894841775 * lab.a - 1.291485548 * lab.b;
182
+ const l = l_ * l_ * l_;
183
+ const m = m_ * m_ * m_;
184
+ const s = s_ * s_ * s_;
185
+ const r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
186
+ const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
187
+ const b = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
188
+ return [r, g, b];
189
+ }
190
+ function linearSrgbToOklab(r, g, b) {
191
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
192
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
193
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
194
+ const l_ = Math.cbrt(l);
195
+ const m_ = Math.cbrt(m);
196
+ const s_ = Math.cbrt(s);
197
+ return {
198
+ L: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
199
+ a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
200
+ b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_,
201
+ alpha: 1
202
+ };
203
+ }
204
+ function linearToGamma(c) {
205
+ if (c <= 31308e-7) return 12.92 * c;
206
+ return 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
207
+ }
208
+ function gammaToLinear(c) {
209
+ if (c <= 0.04045) return c / 12.92;
210
+ return Math.pow((c + 0.055) / 1.055, 2.4);
211
+ }
212
+ var GAMUT_EPSILON = 1e-6;
213
+ var DELTA_E_TOLERANCE = 0.02;
214
+ var CHROMA_STEP = 0.01;
215
+ function deltaEOK(a, b) {
216
+ const dL = a.L - b.L;
217
+ const da = a.a - b.a;
218
+ const db = a.b - b.b;
219
+ return Math.sqrt(dL * dL + da * da + db * db);
220
+ }
221
+ function isInGamut(r, g, b) {
222
+ return r >= -GAMUT_EPSILON && r <= 1 + GAMUT_EPSILON && g >= -GAMUT_EPSILON && g <= 1 + GAMUT_EPSILON && b >= -GAMUT_EPSILON && b <= 1 + GAMUT_EPSILON;
223
+ }
224
+ function clampChannel(v) {
225
+ return Math.max(0, Math.min(1, v));
226
+ }
227
+ function gamutMapOklchToSrgb(color) {
228
+ if (color.l <= 0) return { r: 0, g: 0, b: 0, alpha: color.alpha };
229
+ if (color.l >= 1) return { r: 1, g: 1, b: 1, alpha: color.alpha };
230
+ const lab = oklchToOklab(color);
231
+ const [lr, lg, lb] = oklabToLinearSrgb(lab);
232
+ if (isInGamut(lr, lg, lb)) {
233
+ return {
234
+ r: linearToGamma(clampChannel(lr)),
235
+ g: linearToGamma(clampChannel(lg)),
236
+ b: linearToGamma(clampChannel(lb)),
237
+ alpha: color.alpha
238
+ };
239
+ }
240
+ let min = 0;
241
+ let max = color.c;
242
+ let mappedChroma = 0;
243
+ const zeroChromaLab = oklchToOklab(__spreadProps(__spreadValues({}, color), { c: 0 }));
244
+ const [zr, zg, zb] = oklabToLinearSrgb(zeroChromaLab);
245
+ if (!isInGamut(zr, zg, zb)) {
246
+ return {
247
+ r: linearToGamma(clampChannel(zr)),
248
+ g: linearToGamma(clampChannel(zg)),
249
+ b: linearToGamma(clampChannel(zb)),
250
+ alpha: color.alpha
251
+ };
252
+ }
253
+ while (max - min > CHROMA_STEP) {
254
+ const mid = (min + max) / 2;
255
+ const testColor = __spreadProps(__spreadValues({}, color), { c: mid });
256
+ const testLab = oklchToOklab(testColor);
257
+ const [tr, tg, tb] = oklabToLinearSrgb(testLab);
258
+ if (isInGamut(tr, tg, tb)) {
259
+ min = mid;
260
+ mappedChroma = mid;
261
+ } else {
262
+ const clampedR = clampChannel(tr);
263
+ const clampedG = clampChannel(tg);
264
+ const clampedB = clampChannel(tb);
265
+ const clampedLab = linearSrgbToOklab(clampedR, clampedG, clampedB);
266
+ const dE = deltaEOK(testLab, clampedLab);
267
+ if (dE <= DELTA_E_TOLERANCE) {
268
+ min = mid;
269
+ mappedChroma = mid;
270
+ } else {
271
+ max = mid;
272
+ }
273
+ }
274
+ }
275
+ const finalLab = oklchToOklab(__spreadProps(__spreadValues({}, color), { c: mappedChroma }));
276
+ const [fr, fg, fb] = oklabToLinearSrgb(finalLab);
277
+ return {
278
+ r: linearToGamma(clampChannel(fr)),
279
+ g: linearToGamma(clampChannel(fg)),
280
+ b: linearToGamma(clampChannel(fb)),
281
+ alpha: color.alpha
282
+ };
283
+ }
284
+ function oklchToSrgb(color) {
285
+ return gamutMapOklchToSrgb(color);
286
+ }
287
+ function srgbToOklch(color) {
288
+ const lr = gammaToLinear(color.r);
289
+ const lg = gammaToLinear(color.g);
290
+ const lb = gammaToLinear(color.b);
291
+ const lab = linearSrgbToOklab(lr, lg, lb);
292
+ return __spreadValues({}, oklabToOklch(__spreadProps(__spreadValues({}, lab), { alpha: color.alpha })));
293
+ }
294
+ function srgbToHex(color) {
295
+ const r = Math.round(clampChannel(color.r) * 255);
296
+ const g = Math.round(clampChannel(color.g) * 255);
297
+ const b = Math.round(clampChannel(color.b) * 255);
298
+ const hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
299
+ if (color.alpha < 1) {
300
+ const a = Math.round(clampChannel(color.alpha) * 255);
301
+ return `${hex}${a.toString(16).padStart(2, "0")}`;
302
+ }
303
+ return hex;
304
+ }
305
+ function oklchToHex(color) {
306
+ return srgbToHex(oklchToSrgb(color));
307
+ }
308
+ function hexToOklch(hex) {
309
+ return srgbToOklch(parseHex(hex));
310
+ }
311
+
312
+ // src/manipulate.ts
313
+ function clamp(value, min, max) {
314
+ return Math.max(min, Math.min(max, value));
315
+ }
316
+ function normaliseHue(h) {
317
+ return (h % 360 + 360) % 360;
318
+ }
319
+ function lighten(color, amount) {
320
+ return __spreadProps(__spreadValues({}, color), { l: clamp(color.l + amount, 0, 1) });
321
+ }
322
+ function darken(color, amount) {
323
+ return __spreadProps(__spreadValues({}, color), { l: clamp(color.l - amount, 0, 1) });
324
+ }
325
+ function saturate(color, amount) {
326
+ return __spreadProps(__spreadValues({}, color), { c: Math.max(0, color.c + amount) });
327
+ }
328
+ function desaturate(color, amount) {
329
+ return __spreadProps(__spreadValues({}, color), { c: Math.max(0, color.c - amount) });
330
+ }
331
+ function setAlpha(color, alpha) {
332
+ return __spreadProps(__spreadValues({}, color), { alpha: clamp(alpha, 0, 1) });
333
+ }
334
+ function adjustHue(color, degrees) {
335
+ return __spreadProps(__spreadValues({}, color), { h: normaliseHue(color.h + degrees) });
336
+ }
337
+ function mix(color1, color2, ratio = 0.5) {
338
+ const t = clamp(ratio, 0, 1);
339
+ const l = color1.l + (color2.l - color1.l) * t;
340
+ const c = color1.c + (color2.c - color1.c) * t;
341
+ const alpha = color1.alpha + (color2.alpha - color1.alpha) * t;
342
+ let h1 = normaliseHue(color1.h);
343
+ let h2 = normaliseHue(color2.h);
344
+ let dh = h2 - h1;
345
+ if (dh > 180) dh -= 360;
346
+ if (dh < -180) dh += 360;
347
+ const h = normaliseHue(h1 + dh * t);
348
+ return { l, c, h, alpha };
349
+ }
350
+ function complement(color) {
351
+ return adjustHue(color, 180);
352
+ }
353
+ function invert(color) {
354
+ return __spreadProps(__spreadValues({}, color), { l: 1 - color.l });
355
+ }
356
+ function grayscale(color) {
357
+ return __spreadProps(__spreadValues({}, color), { c: 0, h: 0 });
358
+ }
359
+
360
+ // src/contrast.ts
361
+ function relativeLuminance(color) {
362
+ const toLinear = (c) => c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
363
+ const r = toLinear(color.r);
364
+ const g = toLinear(color.g);
365
+ const b = toLinear(color.b);
366
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
367
+ }
368
+ function contrastRatio(fg, bg) {
369
+ const fgSrgb = "l" in fg ? oklchToSrgb(fg) : fg;
370
+ const bgSrgb = "l" in bg ? oklchToSrgb(bg) : bg;
371
+ const l1 = relativeLuminance(fgSrgb);
372
+ const l2 = relativeLuminance(bgSrgb);
373
+ const lighter = Math.max(l1, l2);
374
+ const darker = Math.min(l1, l2);
375
+ return (lighter + 0.05) / (darker + 0.05);
376
+ }
377
+ function meetsAA(fg, bg, size = "normal") {
378
+ const ratio = contrastRatio(fg, bg);
379
+ return size === "large" ? ratio >= 3 : ratio >= 4.5;
380
+ }
381
+ function meetsAAA(fg, bg, size = "normal") {
382
+ const ratio = contrastRatio(fg, bg);
383
+ return size === "large" ? ratio >= 4.5 : ratio >= 7;
384
+ }
385
+ function suggestAccessible(fg, bg, target = "AA", size = "normal") {
386
+ const checker = target === "AAA" ? meetsAAA : meetsAA;
387
+ if (checker(fg, bg, size)) return fg;
388
+ const bgSrgb = "l" in bg ? oklchToSrgb(bg) : bg;
389
+ const bgLum = relativeLuminance(bgSrgb);
390
+ const directions = bgLum > 0.5 ? [(l, s) => l - s, (l, s) => l + s] : [(l, s) => l + s, (l, s) => l - s];
391
+ const step = 5e-3;
392
+ for (const adjust of directions) {
393
+ let testL = fg.l;
394
+ for (let i = 0; i < 220; i++) {
395
+ testL = adjust(testL, step);
396
+ if (testL < 0 || testL > 1) break;
397
+ testL = Math.max(0, Math.min(1, testL));
398
+ const candidate = __spreadProps(__spreadValues({}, fg), { l: testL });
399
+ if (checker(candidate, bg, size)) {
400
+ return candidate;
401
+ }
402
+ }
403
+ }
404
+ const blackRatio = contrastRatio({ l: 0, c: 0, h: 0, alpha: 1 }, bg);
405
+ const whiteRatio = contrastRatio({ l: 1, c: 0, h: 0, alpha: 1 }, bg);
406
+ return blackRatio > whiteRatio ? __spreadProps(__spreadValues({}, fg), { l: 0, c: 0 }) : __spreadProps(__spreadValues({}, fg), { l: 1, c: 0 });
407
+ }
408
+
409
+ // src/format.ts
410
+ function toOklchString(color) {
411
+ const l = `${roundTo(color.l * 100, 2)}%`;
412
+ const c = roundTo(color.c, 4);
413
+ const h = roundTo(color.h, 2);
414
+ if (color.alpha < 1) {
415
+ return `oklch(${l} ${c} ${h} / ${roundTo(color.alpha, 3)})`;
416
+ }
417
+ return `oklch(${l} ${c} ${h})`;
418
+ }
419
+ function toRgbString(color) {
420
+ const r = Math.round(clamp01(color.r) * 255);
421
+ const g = Math.round(clamp01(color.g) * 255);
422
+ const b = Math.round(clamp01(color.b) * 255);
423
+ if (color.alpha < 1) {
424
+ return `rgb(${r} ${g} ${b} / ${roundTo(color.alpha, 3)})`;
425
+ }
426
+ return `rgb(${r} ${g} ${b})`;
427
+ }
428
+ function toHexString(color) {
429
+ const srgb = "l" in color ? oklchToSrgb(color) : color;
430
+ return srgbToHex(srgb);
431
+ }
432
+ function toCssChannels(color) {
433
+ const l = `${roundTo(color.l * 100, 2)}%`;
434
+ const c = roundTo(color.c, 4);
435
+ const h = roundTo(color.h, 2);
436
+ return `${l} ${c} ${h}`;
437
+ }
438
+ function roundTo(value, decimals) {
439
+ const factor = Math.pow(10, decimals);
440
+ return Math.round(value * factor) / factor;
441
+ }
442
+ function clamp01(v) {
443
+ return Math.max(0, Math.min(1, v));
444
+ }
445
+ // Annotate the CommonJS export names for ESM import in node:
446
+ 0 && (module.exports = {
447
+ adjustHue,
448
+ complement,
449
+ contrastRatio,
450
+ darken,
451
+ desaturate,
452
+ grayscale,
453
+ hexToOklch,
454
+ invert,
455
+ lighten,
456
+ meetsAA,
457
+ meetsAAA,
458
+ mix,
459
+ oklabToOklch,
460
+ oklchToHex,
461
+ oklchToOklab,
462
+ oklchToSrgb,
463
+ parseHex,
464
+ parseOklchChannels,
465
+ parseOklchCss,
466
+ parseRgb,
467
+ saturate,
468
+ setAlpha,
469
+ srgbToHex,
470
+ srgbToOklch,
471
+ suggestAccessible,
472
+ toCssChannels,
473
+ toHexString,
474
+ toOklchString,
475
+ toRgbString
476
+ });
@@ -0,0 +1,213 @@
1
+ /**
2
+ * A color in the OKLCH color space.
3
+ * - `l`: Lightness, 0–1 (0 = black, 1 = white)
4
+ * - `c`: Chroma, 0–~0.4 (0 = gray, higher = more saturated)
5
+ * - `h`: Hue, 0–360 degrees
6
+ * - `alpha`: Opacity, 0–1
7
+ */
8
+ interface OklchColor {
9
+ readonly l: number;
10
+ readonly c: number;
11
+ readonly h: number;
12
+ readonly alpha: number;
13
+ }
14
+ /**
15
+ * A color in the OKLab color space (intermediate for conversions).
16
+ */
17
+ interface OklabColor {
18
+ readonly L: number;
19
+ readonly a: number;
20
+ readonly b: number;
21
+ readonly alpha: number;
22
+ }
23
+ /**
24
+ * A color in the sRGB color space.
25
+ * - `r`, `g`, `b`: 0–1 range (not 0–255)
26
+ * - `alpha`: 0–1
27
+ */
28
+ interface SrgbColor {
29
+ readonly r: number;
30
+ readonly g: number;
31
+ readonly b: number;
32
+ readonly alpha: number;
33
+ }
34
+ /** A CSS hex color string. */
35
+ type HexString = `#${string}`;
36
+ /** Semantic color mode. */
37
+ type ColorMode = "light" | "dark";
38
+
39
+ /**
40
+ * Parse an OKLCH channel string as used by `@ariaui/tokens` primitives.
41
+ *
42
+ * Accepts formats:
43
+ * - `"55.2% 0.014 286"` (L with %)
44
+ * - `"0.552 0.014 286"` (L as decimal)
45
+ * - `"55.2% 0.014 286 / 0.5"` (with alpha)
46
+ *
47
+ * @throws if the string cannot be parsed.
48
+ */
49
+ declare function parseOklchChannels(channels: string): OklchColor;
50
+ /**
51
+ * Parse an `oklch(...)` CSS function string.
52
+ *
53
+ * Accepts: `oklch(55.2% 0.014 286)`, `oklch(55.2% 0.014 286 / 0.5)`
54
+ */
55
+ declare function parseOklchCss(css: string): OklchColor;
56
+ /**
57
+ * Parse a hex color string.
58
+ *
59
+ * Accepts: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`
60
+ */
61
+ declare function parseHex(hex: string): SrgbColor;
62
+ /**
63
+ * Parse an `rgb(...)` or `rgba(...)` CSS function string.
64
+ *
65
+ * Accepts modern space-separated (`rgb(139 92 246)`, `rgb(139 92 246 / 0.5)`)
66
+ * and legacy comma-separated (`rgb(139, 92, 246)`, `rgba(139, 92, 246, 0.5)`).
67
+ */
68
+ declare function parseRgb(css: string): SrgbColor;
69
+
70
+ /** Convert OKLCH → OKLab */
71
+ declare function oklchToOklab(c: OklchColor): OklabColor;
72
+ /** Convert OKLab → OKLCH */
73
+ declare function oklabToOklch(lab: OklabColor): OklchColor;
74
+ /**
75
+ * Convert OKLCH → sRGB with CSS Color Level 4 gamut mapping.
76
+ * Out-of-gamut colors are mapped by reducing chroma while preserving
77
+ * lightness and hue, per the spec.
78
+ */
79
+ declare function oklchToSrgb(color: OklchColor): SrgbColor;
80
+ /**
81
+ * Convert sRGB → OKLCH.
82
+ */
83
+ declare function srgbToOklch(color: SrgbColor): OklchColor;
84
+ /**
85
+ * Convert sRGB → hex string.
86
+ * Values are clamped to [0, 255]. Alpha is included only if < 1.
87
+ */
88
+ declare function srgbToHex(color: SrgbColor): HexString;
89
+ /**
90
+ * Convert OKLCH → hex string (via sRGB with gamut mapping).
91
+ */
92
+ declare function oklchToHex(color: OklchColor): HexString;
93
+ /**
94
+ * Convert hex string → OKLCH.
95
+ */
96
+ declare function hexToOklch(hex: string): OklchColor;
97
+
98
+ /**
99
+ * Increase lightness by `amount` (0–1).
100
+ * `lighten(color, 0.1)` adds 0.1 to lightness (clamped to 1).
101
+ */
102
+ declare function lighten(color: OklchColor, amount: number): OklchColor;
103
+ /**
104
+ * Decrease lightness by `amount` (0–1).
105
+ * `darken(color, 0.1)` subtracts 0.1 from lightness (clamped to 0).
106
+ */
107
+ declare function darken(color: OklchColor, amount: number): OklchColor;
108
+ /**
109
+ * Increase chroma by `amount`.
110
+ * `saturate(color, 0.05)` adds 0.05 to chroma (clamped to 0).
111
+ */
112
+ declare function saturate(color: OklchColor, amount: number): OklchColor;
113
+ /**
114
+ * Decrease chroma by `amount`.
115
+ * `desaturate(color, 0.05)` subtracts 0.05 from chroma (clamped to 0).
116
+ */
117
+ declare function desaturate(color: OklchColor, amount: number): OklchColor;
118
+ /**
119
+ * Set the alpha channel.
120
+ */
121
+ declare function setAlpha(color: OklchColor, alpha: number): OklchColor;
122
+ /**
123
+ * Rotate the hue by `degrees`.
124
+ * `adjustHue(color, 30)` rotates hue by +30°.
125
+ */
126
+ declare function adjustHue(color: OklchColor, degrees: number): OklchColor;
127
+ /**
128
+ * Mix two OKLCH colors by linear interpolation.
129
+ *
130
+ * @param color1 - First color
131
+ * @param color2 - Second color
132
+ * @param ratio - 0 = 100% color1, 1 = 100% color2 (default 0.5)
133
+ *
134
+ * Hue interpolation uses the shorter arc.
135
+ */
136
+ declare function mix(color1: OklchColor, color2: OklchColor, ratio?: number): OklchColor;
137
+ /**
138
+ * Create a complement (hue + 180°).
139
+ */
140
+ declare function complement(color: OklchColor): OklchColor;
141
+ /**
142
+ * Invert a color (flip lightness).
143
+ */
144
+ declare function invert(color: OklchColor): OklchColor;
145
+ /**
146
+ * Convert to grayscale (set chroma to 0).
147
+ */
148
+ declare function grayscale(color: OklchColor): OklchColor;
149
+
150
+ /**
151
+ * Calculate WCAG 2.1 contrast ratio between two colors.
152
+ * Returns a value between 1 and 21.
153
+ *
154
+ * Accepts either OKLCH or sRGB colors (OKLCH are converted via gamut mapping).
155
+ */
156
+ declare function contrastRatio(fg: OklchColor | SrgbColor, bg: OklchColor | SrgbColor): number;
157
+ /**
158
+ * Check if a fg/bg pair meets WCAG 2.1 AA contrast requirements.
159
+ *
160
+ * - Normal text: ratio ≥ 4.5
161
+ * - Large text (≥18pt or ≥14pt bold): ratio ≥ 3
162
+ */
163
+ declare function meetsAA(fg: OklchColor | SrgbColor, bg: OklchColor | SrgbColor, size?: "normal" | "large"): boolean;
164
+ /**
165
+ * Check if a fg/bg pair meets WCAG 2.1 AAA contrast requirements.
166
+ *
167
+ * - Normal text: ratio ≥ 7
168
+ * - Large text: ratio ≥ 4.5
169
+ */
170
+ declare function meetsAAA(fg: OklchColor | SrgbColor, bg: OklchColor | SrgbColor, size?: "normal" | "large"): boolean;
171
+ /**
172
+ * Suggest an accessible foreground color by adjusting lightness to meet
173
+ * the target contrast level against the given background.
174
+ *
175
+ * Tries darkening first, then lightening. Returns the closest accessible
176
+ * OklchColor, or the original if it already passes.
177
+ *
178
+ * @param fg - Foreground color to adjust (OKLCH)
179
+ * @param bg - Background color (OKLCH or sRGB)
180
+ * @param target - "AA" (4.5:1) or "AAA" (7:1), default "AA"
181
+ * @param size - "normal" or "large" text
182
+ */
183
+ declare function suggestAccessible(fg: OklchColor, bg: OklchColor | SrgbColor, target?: "AA" | "AAA", size?: "normal" | "large"): OklchColor;
184
+
185
+ /**
186
+ * Format an OKLCH color as a CSS `oklch()` string.
187
+ *
188
+ * @example toOklchString({ l: 0.552, c: 0.014, h: 286, alpha: 1 })
189
+ * → "oklch(55.2% 0.014 286)"
190
+ */
191
+ declare function toOklchString(color: OklchColor): string;
192
+ /**
193
+ * Format an sRGB color as a CSS `rgb()` string (modern syntax).
194
+ *
195
+ * @example toRgbString({ r: 0.545, g: 0.361, b: 0.965, alpha: 1 })
196
+ * → "rgb(139 92 246)"
197
+ */
198
+ declare function toRgbString(color: SrgbColor): string;
199
+ /**
200
+ * Format a color as a hex string.
201
+ * Accepts OKLCH (converts via gamut mapping) or sRGB.
202
+ */
203
+ declare function toHexString(color: OklchColor | SrgbColor): HexString;
204
+ /**
205
+ * Format an OKLCH color back to the bare channel string format
206
+ * used by `@ariaui/tokens` primitives: `"L% C H"`.
207
+ *
208
+ * @example toCssChannels({ l: 0.552, c: 0.014, h: 286, alpha: 1 })
209
+ * → "55.2% 0.014 286"
210
+ */
211
+ declare function toCssChannels(color: OklchColor): string;
212
+
213
+ export { type ColorMode, type HexString, type OklabColor, type OklchColor, type SrgbColor, adjustHue, complement, contrastRatio, darken, desaturate, grayscale, hexToOklch, invert, lighten, meetsAA, meetsAAA, mix, oklabToOklch, oklchToHex, oklchToOklab, oklchToSrgb, parseHex, parseOklchChannels, parseOklchCss, parseRgb, saturate, setAlpha, srgbToHex, srgbToOklch, suggestAccessible, toCssChannels, toHexString, toOklchString, toRgbString };