@zag-js/color-utils 1.41.1 → 2.0.0-next.0

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.
@@ -0,0 +1,396 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+
22
+ // src/oklab-color.ts
23
+ var oklab_color_exports = {};
24
+ __export(oklab_color_exports, {
25
+ OklabColor: () => OklabColor,
26
+ OklchColor: () => OklchColor,
27
+ parseOklabParams: () => parseOklabParams,
28
+ parseOklchParams: () => parseOklchParams
29
+ });
30
+ module.exports = __toCommonJS(oklab_color_exports);
31
+ var import_utils = require("@zag-js/utils");
32
+ var import_color = require("./color.js");
33
+ var import_hsb_color = require("./hsb-color.js");
34
+ var import_rgb_color = require("./rgb-color.js");
35
+ var import_oklab_math = require("./oklab-math.js");
36
+ function oklabToHsb(L, a, b, alpha) {
37
+ const lin = (0, import_oklab_math.oklabToLinearRgb)(L, a, b);
38
+ return import_hsb_color.HSBColor.fromSrgbFloat(
39
+ (0, import_oklab_math.linearChannelToSrgb)(lin.r),
40
+ (0, import_oklab_math.linearChannelToSrgb)(lin.g),
41
+ (0, import_oklab_math.linearChannelToSrgb)(lin.b),
42
+ alpha
43
+ );
44
+ }
45
+ var OKLAB_HEAD = /^oklab\(\s*/i;
46
+ function parseCssNumber(token) {
47
+ const t = token.trim().toLowerCase();
48
+ if (t === "none") return void 0;
49
+ if (t.endsWith("%")) return Number.parseFloat(t) / 100;
50
+ const n = Number.parseFloat(t);
51
+ return Number.isFinite(n) ? n : void 0;
52
+ }
53
+ function parseOklabParams(inner) {
54
+ const [main, alphaPart] = inner.split(/\s*\/\s*/);
55
+ const tokens = main.trim().split(/\s+/).filter(Boolean);
56
+ if (tokens.length < 3) return;
57
+ const L = parseCssNumber(tokens[0]);
58
+ const a = parseCssNumber(tokens[1]);
59
+ const b = parseCssNumber(tokens[2]);
60
+ if (L === void 0 || a === void 0 || b === void 0) return;
61
+ let alpha = 1;
62
+ if (alphaPart) {
63
+ const at = alphaPart.trim().toLowerCase();
64
+ if (at !== "none") {
65
+ const av = at.endsWith("%") ? Number.parseFloat(at) / 100 : Number.parseFloat(at);
66
+ if (Number.isFinite(av)) alpha = (0, import_utils.clampValue)(av, 0, 1);
67
+ }
68
+ }
69
+ return { L: (0, import_utils.clampValue)(L, 0, 1), a, b, alpha };
70
+ }
71
+ var _OklabColor = class _OklabColor extends import_color.Color {
72
+ constructor(lightness, a, b, alpha) {
73
+ super();
74
+ __publicField(this, "lightness", lightness);
75
+ __publicField(this, "a", a);
76
+ __publicField(this, "b", b);
77
+ __publicField(this, "alpha", alpha);
78
+ }
79
+ static parse(value) {
80
+ if (!OKLAB_HEAD.test(value)) return;
81
+ const end = value.lastIndexOf(")");
82
+ if (end < 0) return;
83
+ const inner = value.slice(value.indexOf("(") + 1, end);
84
+ const p = parseOklabParams(inner);
85
+ if (!p) return;
86
+ return new _OklabColor(p.L, p.a, p.b, p.alpha);
87
+ }
88
+ toString(format = "css") {
89
+ switch (format) {
90
+ case "hex":
91
+ return this.toFormat("rgba").toString("hex");
92
+ case "hexa":
93
+ return this.toFormat("rgba").toString("hexa");
94
+ case "oklab":
95
+ return formatOklabCss(this.lightness, this.a, this.b, this.alpha);
96
+ case "css":
97
+ return formatOklabCss(this.lightness, this.a, this.b, this.alpha);
98
+ default:
99
+ return this.toFormat(format).toString(format);
100
+ }
101
+ }
102
+ toFormat(format) {
103
+ switch (format) {
104
+ case "oklab":
105
+ return this;
106
+ case "oklch":
107
+ return this.toOklch();
108
+ case "rgba":
109
+ return this.toRgb();
110
+ case "hsla":
111
+ return this.toRgb().toFormat("hsla");
112
+ case "hsba":
113
+ return oklabToHsb(this.lightness, this.a, this.b, this.alpha);
114
+ default:
115
+ throw new Error("Unsupported color conversion: oklab -> " + format);
116
+ }
117
+ }
118
+ toRgb() {
119
+ const { r, g, b } = (0, import_oklab_math.linearRgbToSrgb)((0, import_oklab_math.oklabToLinearRgb)(this.lightness, this.a, this.b));
120
+ return new import_rgb_color.RGBColor(r, g, b, (0, import_utils.toFixedNumber)(this.alpha, 4));
121
+ }
122
+ toOklch() {
123
+ const { L, C, H } = (0, import_oklab_math.oklabToOklch)(this.lightness, this.a, this.b);
124
+ return new OklchColor(L, H, C, (0, import_utils.toFixedNumber)(this.alpha, 4));
125
+ }
126
+ clone() {
127
+ return new _OklabColor(this.lightness, this.a, this.b, this.alpha);
128
+ }
129
+ getChannelValue(channel) {
130
+ switch (channel) {
131
+ case "lightness":
132
+ return this.lightness;
133
+ case "a":
134
+ return this.a;
135
+ case "b":
136
+ return this.b;
137
+ case "alpha":
138
+ return this.alpha;
139
+ default:
140
+ throw new Error("Unsupported color channel: " + channel);
141
+ }
142
+ }
143
+ withChannelValue(channel, value) {
144
+ const { minValue, maxValue } = this.getChannelRange(channel);
145
+ const v = (0, import_utils.clampValue)(value, minValue, maxValue);
146
+ switch (channel) {
147
+ case "lightness":
148
+ return new _OklabColor(v, this.a, this.b, this.alpha);
149
+ case "a":
150
+ return new _OklabColor(this.lightness, v, this.b, this.alpha);
151
+ case "b":
152
+ return new _OklabColor(this.lightness, this.a, v, this.alpha);
153
+ case "alpha":
154
+ return new _OklabColor(this.lightness, this.a, this.b, v);
155
+ default:
156
+ throw new Error("Unsupported color channel: " + channel);
157
+ }
158
+ }
159
+ formatChannelValue(channel, locale) {
160
+ const options = this.getChannelFormatOptions(channel);
161
+ const val = this.getChannelValue(channel);
162
+ return new Intl.NumberFormat(locale, options).format(val);
163
+ }
164
+ getChannelFormatOptions(channel) {
165
+ switch (channel) {
166
+ case "lightness":
167
+ case "a":
168
+ case "b":
169
+ case "alpha":
170
+ return { style: "decimal", maximumFractionDigits: 4 };
171
+ default:
172
+ throw new Error("Unknown color channel: " + channel);
173
+ }
174
+ }
175
+ getChannelRange(channel) {
176
+ switch (channel) {
177
+ case "lightness":
178
+ return { minValue: 0, maxValue: 1, step: 1e-3, pageSize: 0.05 };
179
+ case "a":
180
+ case "b":
181
+ return { minValue: -0.4, maxValue: 0.4, step: 1e-3, pageSize: 0.02 };
182
+ case "alpha":
183
+ return { minValue: 0, maxValue: 1, step: 0.01, pageSize: 0.1 };
184
+ default:
185
+ throw new Error("Unknown color channel: " + channel);
186
+ }
187
+ }
188
+ toJSON() {
189
+ return { l: this.lightness, a: this.a, b: this.b, alpha: this.alpha };
190
+ }
191
+ getFormat() {
192
+ return "oklab";
193
+ }
194
+ getChannels() {
195
+ return _OklabColor.colorChannels;
196
+ }
197
+ isEqual(color) {
198
+ if (color.getFormat() !== "oklab") return super.isEqual(color);
199
+ const o = color;
200
+ return this.lightness === o.lightness && this.a === o.a && this.b === o.b && this.alpha === o.alpha;
201
+ }
202
+ };
203
+ __publicField(_OklabColor, "colorChannels", ["lightness", "a", "b"]);
204
+ var OklabColor = _OklabColor;
205
+ function formatOklabCss(L, a, b, alpha) {
206
+ const l = (0, import_utils.toFixedNumber)(L, 4);
207
+ const aa = (0, import_utils.toFixedNumber)(a, 4);
208
+ const bb = (0, import_utils.toFixedNumber)(b, 4);
209
+ if (alpha >= 1) return `oklab(${l} ${aa} ${bb})`;
210
+ return `oklab(${l} ${aa} ${bb} / ${(0, import_utils.toFixedNumber)(alpha, 4)})`;
211
+ }
212
+ var OKLCH_HEAD = /^oklch\(\s*/i;
213
+ function parseCssNumberOrAngle(token) {
214
+ const t = token.trim().toLowerCase();
215
+ if (t === "none") return void 0;
216
+ if (t.endsWith("deg")) return Number.parseFloat(t);
217
+ if (t.endsWith("turn")) return Number.parseFloat(t) * 360;
218
+ if (t.endsWith("grad")) return Number.parseFloat(t) / 400 * 360;
219
+ if (t.endsWith("rad")) return Number.parseFloat(t) * 180 / Math.PI;
220
+ if (t.endsWith("%")) return Number.parseFloat(t) / 100;
221
+ const n = Number.parseFloat(t);
222
+ return Number.isFinite(n) ? n : void 0;
223
+ }
224
+ function parseOklchParams(inner) {
225
+ const [main, alphaPart] = inner.split(/\s*\/\s*/);
226
+ const tokens = main.trim().split(/\s+/).filter(Boolean);
227
+ if (tokens.length < 3) return;
228
+ const Lraw = parseCssNumberOrAngle(tokens[0]);
229
+ const Craw = parseCssNumberOrAngle(tokens[1]);
230
+ const Hraw = parseCssNumberOrAngle(tokens[2]);
231
+ if (Lraw === void 0 || Craw === void 0 || Hraw === void 0) return;
232
+ const L = tokens[0].trim().endsWith("%") ? Lraw : (0, import_utils.clampValue)(Lraw, 0, 1);
233
+ const C = tokens[1].trim().endsWith("%") ? Craw * 0.5 : Craw;
234
+ const H = (0, import_utils.mod)(Hraw, 360);
235
+ let alpha = 1;
236
+ if (alphaPart) {
237
+ const at = alphaPart.trim().toLowerCase();
238
+ if (at !== "none") {
239
+ const av = at.endsWith("%") ? Number.parseFloat(at) / 100 : Number.parseFloat(at);
240
+ if (Number.isFinite(av)) alpha = (0, import_utils.clampValue)(av, 0, 1);
241
+ }
242
+ }
243
+ return { L, C: (0, import_utils.clampValue)(C, 0, 0.5), H, alpha };
244
+ }
245
+ var _OklchColor = class _OklchColor extends import_color.Color {
246
+ constructor(lightness, hue, chroma, alpha) {
247
+ super();
248
+ __publicField(this, "lightness", lightness);
249
+ __publicField(this, "hue", hue);
250
+ __publicField(this, "chroma", chroma);
251
+ __publicField(this, "alpha", alpha);
252
+ }
253
+ static parse(value) {
254
+ if (!OKLCH_HEAD.test(value)) return;
255
+ const end = value.lastIndexOf(")");
256
+ if (end < 0) return;
257
+ const inner = value.slice(value.indexOf("(") + 1, end);
258
+ const p = parseOklchParams(inner);
259
+ if (!p) return;
260
+ return new _OklchColor(p.L, p.H, p.C, p.alpha);
261
+ }
262
+ toString(format = "css") {
263
+ switch (format) {
264
+ case "hex":
265
+ return this.toFormat("rgba").toString("hex");
266
+ case "hexa":
267
+ return this.toFormat("rgba").toString("hexa");
268
+ case "oklch":
269
+ return formatOklchCss(this.lightness, this.chroma, this.hue, this.alpha);
270
+ case "css":
271
+ return formatOklchCss(this.lightness, this.chroma, this.hue, this.alpha);
272
+ default:
273
+ return this.toFormat(format).toString(format);
274
+ }
275
+ }
276
+ toFormat(format) {
277
+ switch (format) {
278
+ case "oklch":
279
+ return this;
280
+ case "oklab":
281
+ return this.toOklab();
282
+ case "rgba":
283
+ return this.toRgb();
284
+ case "hsla":
285
+ return this.toRgb().toFormat("hsla");
286
+ case "hsba": {
287
+ const { a, b, L } = (0, import_oklab_math.oklchToOklab)(this.lightness, this.chroma, this.hue);
288
+ return oklabToHsb(L, a, b, this.alpha);
289
+ }
290
+ default:
291
+ throw new Error("Unsupported color conversion: oklch -> " + format);
292
+ }
293
+ }
294
+ toOklab() {
295
+ const { a, b, L } = (0, import_oklab_math.oklchToOklab)(this.lightness, this.chroma, this.hue);
296
+ return new OklabColor(L, a, b, (0, import_utils.toFixedNumber)(this.alpha, 4));
297
+ }
298
+ toRgb() {
299
+ return this.toOklab().toFormat("rgba");
300
+ }
301
+ clone() {
302
+ return new _OklchColor(this.lightness, this.hue, this.chroma, this.alpha);
303
+ }
304
+ getChannelValue(channel) {
305
+ switch (channel) {
306
+ case "lightness":
307
+ return this.lightness;
308
+ case "hue":
309
+ return this.hue;
310
+ case "chroma":
311
+ return this.chroma;
312
+ case "alpha":
313
+ return this.alpha;
314
+ default:
315
+ throw new Error("Unsupported color channel: " + channel);
316
+ }
317
+ }
318
+ withChannelValue(channel, value) {
319
+ const { minValue, maxValue } = this.getChannelRange(channel);
320
+ let v = (0, import_utils.clampValue)(value, minValue, maxValue);
321
+ if (channel === "hue") v = (0, import_utils.mod)(v, 360);
322
+ switch (channel) {
323
+ case "lightness":
324
+ return new _OklchColor(v, this.hue, this.chroma, this.alpha);
325
+ case "hue":
326
+ return new _OklchColor(this.lightness, v, this.chroma, this.alpha);
327
+ case "chroma":
328
+ return new _OklchColor(this.lightness, this.hue, v, this.alpha);
329
+ case "alpha":
330
+ return new _OklchColor(this.lightness, this.hue, this.chroma, v);
331
+ default:
332
+ throw new Error("Unsupported color channel: " + channel);
333
+ }
334
+ }
335
+ formatChannelValue(channel, locale) {
336
+ const options = this.getChannelFormatOptions(channel);
337
+ const val = this.getChannelValue(channel);
338
+ return new Intl.NumberFormat(locale, options).format(val);
339
+ }
340
+ getChannelFormatOptions(channel) {
341
+ switch (channel) {
342
+ case "lightness":
343
+ case "chroma":
344
+ case "alpha":
345
+ return { style: "decimal", maximumFractionDigits: 4 };
346
+ case "hue":
347
+ return { style: "unit", unit: "degree", unitDisplay: "narrow" };
348
+ default:
349
+ throw new Error("Unknown color channel: " + channel);
350
+ }
351
+ }
352
+ getChannelRange(channel) {
353
+ switch (channel) {
354
+ case "lightness":
355
+ return { minValue: 0, maxValue: 1, step: 1e-3, pageSize: 0.05 };
356
+ case "hue":
357
+ return { minValue: 0, maxValue: 360, step: 0.01, pageSize: 15 };
358
+ case "chroma":
359
+ return { minValue: 0, maxValue: 0.5, step: 1e-3, pageSize: 0.02 };
360
+ case "alpha":
361
+ return { minValue: 0, maxValue: 1, step: 0.01, pageSize: 0.1 };
362
+ default:
363
+ throw new Error("Unknown color channel: " + channel);
364
+ }
365
+ }
366
+ toJSON() {
367
+ return { l: this.lightness, h: this.hue, c: this.chroma, alpha: this.alpha };
368
+ }
369
+ getFormat() {
370
+ return "oklch";
371
+ }
372
+ getChannels() {
373
+ return _OklchColor.colorChannels;
374
+ }
375
+ isEqual(color) {
376
+ if (color.getFormat() !== "oklch") return super.isEqual(color);
377
+ const o = color;
378
+ return this.lightness === o.lightness && this.hue === o.hue && this.chroma === o.chroma && this.alpha === o.alpha;
379
+ }
380
+ };
381
+ __publicField(_OklchColor, "colorChannels", ["lightness", "hue", "chroma"]);
382
+ var OklchColor = _OklchColor;
383
+ function formatOklchCss(L, C, H, alpha) {
384
+ const l = (0, import_utils.toFixedNumber)(L, 4);
385
+ const c = (0, import_utils.toFixedNumber)(C, 4);
386
+ const h = (0, import_utils.toFixedNumber)(H, 2);
387
+ if (alpha >= 1) return `oklch(${l} ${c} ${h})`;
388
+ return `oklch(${l} ${c} ${h} / ${(0, import_utils.toFixedNumber)(alpha, 4)})`;
389
+ }
390
+ // Annotate the CommonJS export names for ESM import in node:
391
+ 0 && (module.exports = {
392
+ OklabColor,
393
+ OklchColor,
394
+ parseOklabParams,
395
+ parseOklchParams
396
+ });