@soybeanjs/colord 0.0.4 → 0.0.6

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 (38) hide show
  1. package/dist/{colord-C3iU53g-.js → colord-CLzIbIN2.js} +20 -7
  2. package/dist/{colord-xpgrVWRV.d.ts → colord-Dc09uNcG.d.ts} +10 -0
  3. package/dist/colord.d.ts +1 -1
  4. package/dist/colord.js +8 -8
  5. package/dist/{extend-DrPfn2Q1.d.ts → extend-D_jQFvDk.d.ts} +1 -1
  6. package/dist/{get-D0jfz1WU.js → get-SLuYLSG9.js} +1 -1
  7. package/dist/{hsv-BKcGyyrD.js → hsv-OOAVcaRH.js} +1 -1
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +8 -8
  10. package/dist/lab-9NsKpGel.js +219 -0
  11. package/dist/{manipulate-C3CvrU4m.js → manipulate-DCHNBCkU.js} +3 -3
  12. package/dist/plugins/a11y.d.ts +2 -2
  13. package/dist/plugins/a11y.js +3 -3
  14. package/dist/plugins/cmyk.d.ts +2 -2
  15. package/dist/plugins/cmyk.js +1 -1
  16. package/dist/plugins/harmonies.d.ts +1 -1
  17. package/dist/plugins/hwb.d.ts +2 -2
  18. package/dist/plugins/hwb.js +2 -2
  19. package/dist/plugins/lab.d.ts +6 -2
  20. package/dist/plugins/lab.js +11 -8
  21. package/dist/plugins/lch.d.ts +2 -2
  22. package/dist/plugins/lch.js +99 -25
  23. package/dist/plugins/minify.d.ts +1 -1
  24. package/dist/plugins/minify.js +1 -1
  25. package/dist/plugins/mix.d.ts +2 -2
  26. package/dist/plugins/mix.js +6 -6
  27. package/dist/plugins/names.d.ts +1 -1
  28. package/dist/plugins/oklab.d.ts +2 -2
  29. package/dist/plugins/oklab.js +50 -17
  30. package/dist/plugins/oklch.d.ts +2 -2
  31. package/dist/plugins/oklch.js +93 -24
  32. package/dist/plugins/xyz.d.ts +2 -2
  33. package/dist/plugins/xyz.js +5 -5
  34. package/dist/{rgb-DNYno5F7.js → rgb-BVkoWOmR.js} +8 -9
  35. package/dist/{utils-DajWVr6Z.js → utils-CshL9w1R.js} +18 -1
  36. package/dist/{xyz-CXEZJhV8.js → xyz-DsYRwYO_.js} +22 -9
  37. package/package.json +1 -1
  38. package/dist/lab-B5wAd4fu.js +0 -128
@@ -1,7 +1,7 @@
1
- import { i as isPresent, l as round, n as clampHue, o as parseAlpha, s as parseHue, t as clamp, v as ALPHA_PRECISION } from "../utils-DajWVr6Z.js";
2
- import "../rgb-DNYno5F7.js";
3
- import "../xyz-CXEZJhV8.js";
4
- import { a as rgbToLab, n as labToRgb } from "../lab-B5wAd4fu.js";
1
+ import { i as isPresent, l as round, n as clampHue, o as parseAlpha, s as parseHue, t as clamp, v as ALPHA_PRECISION } from "../utils-CshL9w1R.js";
2
+ import { n as clampRgb } from "../rgb-BVkoWOmR.js";
3
+ import "../xyz-DsYRwYO_.js";
4
+ import { n as labToRgb, o as rgbToLab } from "../lab-9NsKpGel.js";
5
5
 
6
6
  //#region src/models/lch.ts
7
7
  /**
@@ -13,7 +13,7 @@ const clampLch = (lab) => {
13
13
  const { l, c, h, alpha } = lab;
14
14
  return {
15
15
  l: clamp(l, 0, 100),
16
- c: clamp(c),
16
+ c: clamp(c, 0, 150),
17
17
  h: clampHue(h),
18
18
  alpha: clamp(alpha)
19
19
  };
@@ -48,10 +48,9 @@ const rgbToLch = (rgb) => {
48
48
  };
49
49
  };
50
50
  /**
51
- * Performs CIELCH CIELAB CIEXYZ RGB color conversion
52
- * https://www.w3.org/TR/css-color-4/#color-conversion-code
51
+ * Convert LCH to RGB without gamut checking (internal helper)
53
52
  */
54
- const lchaToRgb = (lcha) => {
53
+ const lchToRgbDirect = (lcha) => {
55
54
  const { l, c, h, alpha } = lcha;
56
55
  const hRad = h * Math.PI / 180;
57
56
  return labToRgb({
@@ -61,14 +60,74 @@ const lchaToRgb = (lcha) => {
61
60
  alpha
62
61
  });
63
62
  };
63
+ /**
64
+ * Check if RGB is within sRGB gamut
65
+ * Note: RGB values are in [0, 255] range (not [0, 1])
66
+ */
67
+ const isRgbInGamut = (rgb, epsilon = .01) => {
68
+ return rgb.r >= -epsilon && rgb.r <= 255 + epsilon && rgb.g >= -epsilon && rgb.g <= 255 + epsilon && rgb.b >= -epsilon && rgb.b <= 255 + epsilon;
69
+ };
70
+ /**
71
+ * Binary search to find maximum chroma that fits in sRGB gamut for LCH
72
+ * Similar to OKLCH's findGamutChroma
73
+ * @param l - Lightness (0-100)
74
+ * @param h - Hue (0-360)
75
+ * @param alpha - Alpha (0-1)
76
+ * @returns Maximum chroma that fits in sRGB gamut
77
+ */
78
+ const findGamutChromaForLch = (l, h, alpha) => {
79
+ let min = 0;
80
+ let max = 150;
81
+ const epsilon = .01;
82
+ if (isRgbInGamut(lchToRgbDirect({
83
+ l,
84
+ c: max,
85
+ h,
86
+ alpha
87
+ }))) return max;
88
+ while (max - min > epsilon) {
89
+ const mid = (min + max) / 2;
90
+ if (isRgbInGamut(lchToRgbDirect({
91
+ l,
92
+ c: mid,
93
+ h,
94
+ alpha
95
+ }))) min = mid;
96
+ else max = mid;
97
+ }
98
+ return min;
99
+ };
100
+ /**
101
+ * Performs CIELCH → CIELAB → CIEXYZ → RGB color conversion with gamut mapping
102
+ * https://www.w3.org/TR/css-color-4/#color-conversion-code
103
+ *
104
+ * Similar to OKLCH, if the color is out of sRGB gamut, reduce chroma
105
+ * while preserving lightness and hue
106
+ */
107
+ const lchaToRgb = (lcha) => {
108
+ const { l, h, alpha } = lcha;
109
+ let rgb = lchToRgbDirect(lcha);
110
+ if (!isRgbInGamut(rgb)) rgb = lchToRgbDirect({
111
+ l,
112
+ c: findGamutChromaForLch(l, h, alpha),
113
+ h,
114
+ alpha
115
+ });
116
+ return clampRgb(rgb);
117
+ };
64
118
  const parseLch = ({ l, c, h, alpha = 1 }) => {
65
119
  if (!isPresent(l) || !isPresent(c) || !isPresent(h)) return null;
66
- return lchaToRgb(clampLch({
120
+ return clampLch({
67
121
  l: Number(l),
68
122
  c: Number(c),
69
123
  h: Number(h),
70
124
  alpha: Number(alpha)
71
- }));
125
+ });
126
+ };
127
+ const parseLchToRgb = (input) => {
128
+ const lch = parseLch(input);
129
+ if (!lch) return null;
130
+ return lchaToRgb(lch);
72
131
  };
73
132
  /**
74
133
  * Parsing syntax: lch(L c h [/ alpha])
@@ -76,28 +135,43 @@ const parseLch = ({ l, c, h, alpha = 1 }) => {
76
135
  * - c: <number> [0,150]
77
136
  * - h: <number|angle> [0,360] (deg, rad, grad, turn)
78
137
  * - alpha: <number|percentage> [0,1]
79
- *
80
138
  */
81
139
  const lchaMatcher = /^lch\(\s*([+-]?[\d.]+)%?\s+([+-]?[\d.]+)\s+([+-]?[\d.]+)(deg|grad|rad|turn)?(?:\s*\/\s*([+-]?[\d.]+%?))?\s*\)$/i;
82
- /**
83
- * Parses a valid LCH CSS color function/string
84
- * https://www.w3.org/TR/css-color-4/#specifying-lab-lch
85
- */
86
140
  const parseLchString = (input) => {
87
141
  const match = lchaMatcher.exec(input);
88
142
  if (!match) return null;
89
- const [, l, c, h, unit, alpha] = match;
90
- return lchaToRgb(clampLch({
143
+ const [_, l, c, h, unit, alpha] = match;
144
+ return clampLch({
91
145
  l: Number.parseFloat(l),
92
146
  c: Number.parseFloat(c),
93
147
  h: parseHue(h, unit),
94
148
  alpha: parseAlpha(alpha)
95
- }));
149
+ });
96
150
  };
97
- const rgbToLchString = (rgb) => {
98
- const { l, c, h, alpha } = roundLch(rgbToLch(rgb));
151
+ const parseLchStringToRgb = (input) => {
152
+ const lch = parseLchString(input);
153
+ if (!lch) return null;
154
+ return lchaToRgb(lch);
155
+ };
156
+ const toLchString = (lch) => {
157
+ const { l, c, h, alpha } = roundLch(lch);
99
158
  return alpha < 1 ? `lch(${l}% ${c} ${h} / ${alpha})` : `lch(${l}% ${c} ${h})`;
100
159
  };
160
+ const rgbToLchString = (rgb) => {
161
+ return toLchString(rgbToLch(rgb));
162
+ };
163
+ const parseLchBySource = (source) => {
164
+ if (!source || source.format !== "lch") return null;
165
+ const { input } = source;
166
+ if (typeof input === "string") return parseLchString(input);
167
+ if (typeof input === "object") return parseLch(input);
168
+ return null;
169
+ };
170
+ const toLchStringBySource = (source) => {
171
+ const lch = parseLchBySource(source);
172
+ if (!lch) return null;
173
+ return toLchString(lch);
174
+ };
101
175
 
102
176
  //#endregion
103
177
  //#region src/plugins/lch.ts
@@ -108,13 +182,13 @@ const rgbToLchString = (rgb) => {
108
182
  */
109
183
  const lchPlugin = (ColordClass, parsers) => {
110
184
  ColordClass.prototype.toLch = function toLch() {
111
- return roundLch(rgbToLch(this.rgb));
185
+ return roundLch(parseLchBySource(this.getSource()) || rgbToLch(this.rgb));
112
186
  };
113
- ColordClass.prototype.toLchString = function toLchString() {
114
- return rgbToLchString(this.rgb);
187
+ ColordClass.prototype.toLchString = function toLchString$1() {
188
+ return toLchStringBySource(this.getSource()) || rgbToLchString(this.rgb);
115
189
  };
116
- parsers.string.push([parseLchString, "lch"]);
117
- parsers.object.push([parseLch, "lch"]);
190
+ parsers.string.push([parseLchStringToRgb, "lch"]);
191
+ parsers.object.push([parseLchToRgb, "lch"]);
118
192
  };
119
193
  var lch_default = lchPlugin;
120
194
 
@@ -1,4 +1,4 @@
1
- import { t as Plugin } from "../extend-DrPfn2Q1.js";
1
+ import { t as Plugin } from "../extend-D_jQFvDk.js";
2
2
 
3
3
  //#region src/plugins/minify.d.ts
4
4
  interface MinificationOptions {
@@ -1,4 +1,4 @@
1
- import { l as round } from "../utils-DajWVr6Z.js";
1
+ import { l as round } from "../utils-CshL9w1R.js";
2
2
 
3
3
  //#region src/plugins/minify.ts
4
4
  /**
@@ -1,5 +1,5 @@
1
- import { r as AnyColor } from "../colord-xpgrVWRV.js";
2
- import { t as Plugin } from "../extend-DrPfn2Q1.js";
1
+ import { r as AnyColor } from "../colord-Dc09uNcG.js";
2
+ import { t as Plugin } from "../extend-D_jQFvDk.js";
3
3
 
4
4
  //#region src/plugins/mix.d.ts
5
5
  declare module '@soybeanjs/colord' {
@@ -1,9 +1,9 @@
1
- import "../utils-DajWVr6Z.js";
2
- import "../rgb-DNYno5F7.js";
3
- import "../hsv-BKcGyyrD.js";
4
- import { i as mix } from "../manipulate-C3CvrU4m.js";
5
- import "../xyz-CXEZJhV8.js";
6
- import "../lab-B5wAd4fu.js";
1
+ import "../utils-CshL9w1R.js";
2
+ import "../rgb-BVkoWOmR.js";
3
+ import "../hsv-OOAVcaRH.js";
4
+ import { i as mix } from "../manipulate-DCHNBCkU.js";
5
+ import "../xyz-DsYRwYO_.js";
6
+ import "../lab-9NsKpGel.js";
7
7
 
8
8
  //#region src/plugins/mix.ts
9
9
  /**
@@ -1,4 +1,4 @@
1
- import { t as Plugin } from "../extend-DrPfn2Q1.js";
1
+ import { t as Plugin } from "../extend-D_jQFvDk.js";
2
2
 
3
3
  //#region src/plugins/names.d.ts
4
4
  interface ConvertOptions {
@@ -1,5 +1,5 @@
1
- import { f as OklabColor } from "../colord-xpgrVWRV.js";
2
- import { t as Plugin } from "../extend-DrPfn2Q1.js";
1
+ import { f as OklabColor } from "../colord-Dc09uNcG.js";
2
+ import { t as Plugin } from "../extend-D_jQFvDk.js";
3
3
 
4
4
  //#region src/plugins/oklab.d.ts
5
5
  declare module '@soybeanjs/colord' {
@@ -1,11 +1,11 @@
1
- import { _ as OKLAB_M2_INV, a as mul3x3, c as parseValueToDecimal, g as OKLAB_M2, h as OKLAB_M1_INV, i as isPresent, l as round, m as OKLAB_M1, o as parseAlpha, t as clamp, v as ALPHA_PRECISION } from "../utils-DajWVr6Z.js";
2
- import { n as clampRgb, o as rgbToLinearRgb, r as linearRgbToRgb, t as clampLinearRgb } from "../rgb-DNYno5F7.js";
1
+ import { _ as OKLAB_M2_INV, a as mul3x3, c as parseValueToDecimal, g as OKLAB_M2, h as OKLAB_M1_INV, i as isPresent, l as round, m as OKLAB_M1, o as parseAlpha, t as clamp, v as ALPHA_PRECISION } from "../utils-CshL9w1R.js";
2
+ import { n as clampRgb, o as rgbToLinearRgb, r as linearRgbToRgb, t as clampLinearRgb } from "../rgb-BVkoWOmR.js";
3
3
 
4
4
  //#region src/models/oklab.ts
5
5
  const clampOklab = (oklab) => {
6
6
  const { l, a, b, alpha } = oklab;
7
7
  return {
8
- l: clamp(l, 1e-4, 1),
8
+ l: clamp(l, 0, 1),
9
9
  a: clamp(a, -.4, .4),
10
10
  b: clamp(b, -.4, .4),
11
11
  alpha: clamp(alpha)
@@ -49,12 +49,17 @@ const rgbToOklab = (rgb) => {
49
49
  };
50
50
  const parseOklab = ({ l, a, b, alpha = 1 }) => {
51
51
  if (!isPresent(l) || !isPresent(a) || !isPresent(b)) return null;
52
- return oklabToRgb(clampOklab({
52
+ return clampOklab({
53
53
  l: Number(l),
54
54
  a: Number(a),
55
55
  b: Number(b),
56
56
  alpha: Number(alpha)
57
- }));
57
+ });
58
+ };
59
+ const parseOklabToRgb = (input) => {
60
+ const oklab = parseOklab(input);
61
+ if (!oklab) return null;
62
+ return oklabToRgb(oklab);
58
63
  };
59
64
  /**
60
65
  * Parsing syntax: oklab(L a b [/ alpha])
@@ -65,26 +70,54 @@ const parseOklab = ({ l, a, b, alpha = 1 }) => {
65
70
  */
66
71
  const oklabMatcher = /^oklab\(\s*([+-]?[\d.]+)%?\s+([+-]?[\d.]+)\s+([+-]?[\d.]+)(?:\s*\/\s*([+-]?[\d.]+%?))?\s*\)$/i;
67
72
  /**
68
- * Parses a valid OKLAB CSS color function/string
73
+ * Parses a valid OKLAB CSS color function/string to OKLAB object
69
74
  * https://www.w3.org/TR/css-color-4/#specifying-oklab
70
- * @param input
71
- * @returns
72
75
  */
73
76
  const parseOklabString = (input) => {
74
77
  const match = oklabMatcher.exec(input);
75
78
  if (!match) return null;
76
79
  const [_, l, a, b, alpha] = match;
77
- return oklabToRgb(clampOklab({
80
+ return clampOklab({
78
81
  l: parseValueToDecimal(l),
79
82
  a: Number.parseFloat(a),
80
83
  b: Number.parseFloat(b),
81
84
  alpha: parseAlpha(alpha)
82
- }));
85
+ });
83
86
  };
84
- const rgbToOklabString = (rgb) => {
85
- const { l, a, b, alpha } = roundOklab(rgbToOklab(rgb));
87
+ /**
88
+ * Parses a valid OKLAB CSS color function/string to RGB
89
+ * https://www.w3.org/TR/css-color-4/#specifying-oklab
90
+ */
91
+ const parseOklabStringToRgb = (input) => {
92
+ const oklab = parseOklabString(input);
93
+ if (!oklab) return null;
94
+ return oklabToRgb(oklab);
95
+ };
96
+ const toOklabString = (oklab) => {
97
+ const { l, a, b, alpha } = roundOklab(oklab);
86
98
  return alpha < 1 ? `oklab(${l}% ${a} ${b} / ${alpha})` : `oklab(${l}% ${a} ${b})`;
87
99
  };
100
+ const rgbToOklabString = (rgb) => {
101
+ return toOklabString(rgbToOklab(rgb));
102
+ };
103
+ /**
104
+ * Parse OKLAB from cached source input to avoid conversion loss
105
+ */
106
+ const parseOklabBySource = (source) => {
107
+ if (!source || source.format !== "oklab") return null;
108
+ const { input } = source;
109
+ if (typeof input === "string") return parseOklabString(input);
110
+ if (typeof input === "object") return parseOklab(input);
111
+ return null;
112
+ };
113
+ /**
114
+ * Convert to OKLAB string from cached source input to avoid conversion loss
115
+ */
116
+ const toOklabStringBySource = (source) => {
117
+ const oklab = parseOklabBySource(source);
118
+ if (!oklab) return null;
119
+ return toOklabString(oklab);
120
+ };
88
121
 
89
122
  //#endregion
90
123
  //#region src/plugins/oklab.ts
@@ -94,13 +127,13 @@ const rgbToOklabString = (rgb) => {
94
127
  */
95
128
  const oklabPlugin = (ColordClass, parsers) => {
96
129
  ColordClass.prototype.toOklab = function toOklab() {
97
- return roundOklab(rgbToOklab(this.rgb));
130
+ return roundOklab(parseOklabBySource(this.getSource()) || rgbToOklab(this.rgb));
98
131
  };
99
- ColordClass.prototype.toOklabString = function toOklabString() {
100
- return rgbToOklabString(this.rgb);
132
+ ColordClass.prototype.toOklabString = function toOklabString$1() {
133
+ return toOklabStringBySource(this.getSource()) || rgbToOklabString(this.rgb);
101
134
  };
102
- parsers.string.push([parseOklabString, "oklab"]);
103
- parsers.object.push([parseOklab, "oklab"]);
135
+ parsers.string.push([parseOklabStringToRgb, "oklab"]);
136
+ parsers.object.push([parseOklabToRgb, "oklab"]);
104
137
  };
105
138
  var oklab_default = oklabPlugin;
106
139
 
@@ -1,5 +1,5 @@
1
- import { p as OklchColor } from "../colord-xpgrVWRV.js";
2
- import { t as Plugin } from "../extend-DrPfn2Q1.js";
1
+ import { p as OklchColor } from "../colord-Dc09uNcG.js";
2
+ import { t as Plugin } from "../extend-D_jQFvDk.js";
3
3
 
4
4
  //#region src/plugins/oklch.d.ts
5
5
  declare module '@soybeanjs/colord' {
@@ -1,12 +1,12 @@
1
- import { _ as OKLAB_M2_INV, a as mul3x3, c as parseValueToDecimal, g as OKLAB_M2, h as OKLAB_M1_INV, i as isPresent, l as round, m as OKLAB_M1, n as clampHue, o as parseAlpha, s as parseHue, t as clamp, v as ALPHA_PRECISION } from "../utils-DajWVr6Z.js";
2
- import { n as clampRgb, o as rgbToLinearRgb, r as linearRgbToRgb, t as clampLinearRgb } from "../rgb-DNYno5F7.js";
1
+ import { _ as OKLAB_M2_INV, a as mul3x3, c as parseValueToDecimal, g as OKLAB_M2, h as OKLAB_M1_INV, i as isPresent, l as round, m as OKLAB_M1, n as clampHue, o as parseAlpha, s as parseHue, t as clamp, v as ALPHA_PRECISION } from "../utils-CshL9w1R.js";
2
+ import { n as clampRgb, o as rgbToLinearRgb, r as linearRgbToRgb, t as clampLinearRgb } from "../rgb-BVkoWOmR.js";
3
3
 
4
4
  //#region src/models/oklch.ts
5
5
  const clampOklch = (oklch) => {
6
6
  const { l, c, h, alpha } = oklch;
7
7
  return {
8
- l: clamp(l, 1e-4, 1),
9
- c: clamp(c, 1e-4, .37),
8
+ l: clamp(l, 0, 1),
9
+ c: clamp(c, 0, .37),
10
10
  h: clampHue(h),
11
11
  alpha: clamp(alpha)
12
12
  };
@@ -20,7 +20,10 @@ const roundOklch = (oklch) => {
20
20
  alpha: round(alpha, ALPHA_PRECISION)
21
21
  };
22
22
  };
23
- const oklchToRgb = (oklch) => {
23
+ /**
24
+ * Convert OKLCH to Linear RGB without gamut mapping
25
+ */
26
+ const oklchToLinearRgb = (oklch) => {
24
27
  const { l, c, h, alpha } = oklch;
25
28
  const hRad = h * Math.PI / 180;
26
29
  const [r, g, b] = mul3x3(OKLAB_M1_INV, mul3x3(OKLAB_M2_INV, [
@@ -28,12 +31,59 @@ const oklchToRgb = (oklch) => {
28
31
  c * Math.cos(hRad),
29
32
  c * Math.sin(hRad)
30
33
  ]).map((v) => v * v * v));
31
- return clampRgb(linearRgbToRgb(clampLinearRgb({
34
+ return {
32
35
  r,
33
36
  g,
34
37
  b,
35
38
  alpha
36
- })));
39
+ };
40
+ };
41
+ /**
42
+ * Check if a linear RGB color is within sRGB gamut
43
+ */
44
+ const isInGamut = (linearRgb, epsilon = 1e-6) => {
45
+ return linearRgb.r >= -epsilon && linearRgb.r <= 1 + epsilon && linearRgb.g >= -epsilon && linearRgb.g <= 1 + epsilon && linearRgb.b >= -epsilon && linearRgb.b <= 1 + epsilon;
46
+ };
47
+ /**
48
+ * Binary search to find maximum chroma that fits in sRGB gamut
49
+ * @param l - Lightness (0-1)
50
+ * @param h - Hue (0-360)
51
+ * @param alpha - Alpha (0-1)
52
+ * @returns Maximum chroma that fits in sRGB gamut
53
+ */
54
+ const findGamutChroma = (l, h, alpha) => {
55
+ let min = 0;
56
+ let max = .37;
57
+ const epsilon = 1e-5;
58
+ if (isInGamut(oklchToLinearRgb({
59
+ l,
60
+ c: max,
61
+ h,
62
+ alpha
63
+ }), epsilon)) return max;
64
+ while (max - min > epsilon) {
65
+ const mid = (min + max) / 2;
66
+ if (isInGamut(oklchToLinearRgb({
67
+ l,
68
+ c: mid,
69
+ h,
70
+ alpha
71
+ }), epsilon)) min = mid;
72
+ else max = mid;
73
+ }
74
+ return min;
75
+ };
76
+ const oklchToRgb = (oklch) => {
77
+ const { l, h, alpha } = oklch;
78
+ let linearRgb = oklchToLinearRgb(oklch);
79
+ if (!isInGamut(linearRgb)) linearRgb = oklchToLinearRgb({
80
+ l,
81
+ c: findGamutChroma(l, h, alpha),
82
+ h,
83
+ alpha
84
+ });
85
+ linearRgb = clampLinearRgb(linearRgb);
86
+ return clampRgb(linearRgbToRgb(linearRgb));
37
87
  };
38
88
  const rgbToOklch = (rgb) => {
39
89
  const lRgb = rgbToLinearRgb(rgb);
@@ -58,12 +108,17 @@ const rgbToOklch = (rgb) => {
58
108
  };
59
109
  const parseOklch = ({ l, c, h, alpha = 1 }) => {
60
110
  if (!isPresent(l) || !isPresent(c) || !isPresent(h)) return null;
61
- return oklchToRgb(clampOklch({
111
+ return clampOklch({
62
112
  l: Number(l),
63
113
  c: Number(c),
64
114
  h: Number(h),
65
115
  alpha: Number(alpha)
66
- }));
116
+ });
117
+ };
118
+ const parseOklchToRgb = (input) => {
119
+ const oklch = parseOklch(input);
120
+ if (!oklch) return null;
121
+ return oklchToRgb(oklch);
67
122
  };
68
123
  /**
69
124
  * Parsing syntax: oklch(L c h [/ alpha])
@@ -73,27 +128,41 @@ const parseOklch = ({ l, c, h, alpha = 1 }) => {
73
128
  * - alpha: <number|percentage>
74
129
  */
75
130
  const oklchMatcher = /^oklch\(\s*([+-]?[\d.]+)%?\s+([+-]?[\d.]+)\s+([+-]?[\d.]+)(deg|grad|rad|turn)?(?:\s*\/\s*([+-]?[\d.]+%?))?\s*\)$/i;
76
- /**
77
- * Parses a valid OKLCH CSS color function/string
78
- * https://www.w3.org/TR/css-color-4/#specifying-oklch
79
- * @param input
80
- * @returns
81
- */
82
131
  const parseOklchString = (input) => {
83
132
  const match = oklchMatcher.exec(input);
84
133
  if (!match) return null;
85
134
  const [_, l, c, h, unit, alpha] = match;
86
- return oklchToRgb(clampOklch({
135
+ return clampOklch({
87
136
  l: parseValueToDecimal(l),
88
137
  c: Number.parseFloat(c),
89
138
  h: parseHue(h, unit),
90
139
  alpha: parseAlpha(alpha)
91
- }));
140
+ });
92
141
  };
93
- const rgbToOklchString = (rgb) => {
94
- const { l, c, h, alpha } = roundOklch(rgbToOklch(rgb));
142
+ const parseOklchStringToRgb = (input) => {
143
+ const oklch = parseOklchString(input);
144
+ if (!oklch) return null;
145
+ return oklchToRgb(oklch);
146
+ };
147
+ const toOklchString = (oklch) => {
148
+ const { l, c, h, alpha } = roundOklch(oklch);
95
149
  return alpha < 1 ? `oklch(${l} ${c} ${h} / ${alpha})` : `oklch(${l} ${c} ${h})`;
96
150
  };
151
+ const rgbToOklchString = (rgb) => {
152
+ return toOklchString(rgbToOklch(rgb));
153
+ };
154
+ const parseOklchBySource = (source) => {
155
+ if (!source || source.format !== "oklch") return null;
156
+ const { input } = source;
157
+ if (typeof input === "string") return parseOklchString(input);
158
+ if (typeof input === "object") return parseOklch(input);
159
+ return null;
160
+ };
161
+ const toOklchStringBySource = (source) => {
162
+ const oklch = parseOklchBySource(source);
163
+ if (!oklch) return null;
164
+ return toOklchString(oklch);
165
+ };
97
166
 
98
167
  //#endregion
99
168
  //#region src/plugins/oklch.ts
@@ -103,13 +172,13 @@ const rgbToOklchString = (rgb) => {
103
172
  */
104
173
  const oklchPlugin = (ColordClass, parsers) => {
105
174
  ColordClass.prototype.toOklch = function toOklch() {
106
- return roundOklch(rgbToOklch(this.rgb));
175
+ return roundOklch(parseOklchBySource(this.getSource()) || rgbToOklch(this.rgb));
107
176
  };
108
- ColordClass.prototype.toOklchString = function toOklchString() {
109
- return rgbToOklchString(this.rgb);
177
+ ColordClass.prototype.toOklchString = function toOklchString$1() {
178
+ return toOklchStringBySource(this.getSource()) || rgbToOklchString(this.rgb);
110
179
  };
111
- parsers.string.push([parseOklchString, "oklch"]);
112
- parsers.object.push([parseOklch, "oklch"]);
180
+ parsers.string.push([parseOklchStringToRgb, "oklch"]);
181
+ parsers.object.push([parseOklchToRgb, "oklch"]);
113
182
  };
114
183
  var oklch_default = oklchPlugin;
115
184
 
@@ -1,5 +1,5 @@
1
- import { g as XyzColor } from "../colord-xpgrVWRV.js";
2
- import { t as Plugin } from "../extend-DrPfn2Q1.js";
1
+ import { g as XyzColor } from "../colord-Dc09uNcG.js";
2
+ import { t as Plugin } from "../extend-D_jQFvDk.js";
3
3
 
4
4
  //#region src/plugins/xyz.d.ts
5
5
  declare module '@soybeanjs/colord' {
@@ -1,6 +1,6 @@
1
- import "../utils-DajWVr6Z.js";
2
- import "../rgb-DNYno5F7.js";
3
- import { n as rgbToXyz, r as roundXyz, t as parseXyz } from "../xyz-CXEZJhV8.js";
1
+ import "../utils-CshL9w1R.js";
2
+ import "../rgb-BVkoWOmR.js";
3
+ import { i as roundXyz, n as parseXyzToRgb, r as rgbToXyz, t as parseXyzBySource } from "../xyz-DsYRwYO_.js";
4
4
 
5
5
  //#region src/plugins/xyz.ts
6
6
  /**
@@ -10,9 +10,9 @@ import { n as rgbToXyz, r as roundXyz, t as parseXyz } from "../xyz-CXEZJhV8.js"
10
10
  */
11
11
  const xyzPlugin = (ColordClass, parsers) => {
12
12
  ColordClass.prototype.toXyz = function toXyz() {
13
- return roundXyz(rgbToXyz(this.rgb));
13
+ return roundXyz(parseXyzBySource(this.getSource()) || rgbToXyz(this.rgb));
14
14
  };
15
- parsers.object.push([parseXyz, "xyz"]);
15
+ parsers.object.push([parseXyzToRgb, "xyz"]);
16
16
  };
17
17
  var xyz_default = xyzPlugin;
18
18
 
@@ -1,4 +1,4 @@
1
- import { i as isPresent, l as round, o as parseAlpha, t as clamp, v as ALPHA_PRECISION } from "./utils-DajWVr6Z.js";
1
+ import { i as isPresent, l as round, o as parseAlpha, t as clamp, v as ALPHA_PRECISION } from "./utils-CshL9w1R.js";
2
2
 
3
3
  //#region src/models/rgb.ts
4
4
  const clampRgb = (rgb) => {
@@ -13,18 +13,18 @@ const clampRgb = (rgb) => {
13
13
  const roundRgb = (rgb) => {
14
14
  const { r, g, b, alpha } = rgb;
15
15
  return {
16
- r: round(r),
17
- g: round(g),
18
- b: round(b),
16
+ r: round(r, 2),
17
+ g: round(g, 2),
18
+ b: round(b, 2),
19
19
  alpha: round(alpha, ALPHA_PRECISION)
20
20
  };
21
21
  };
22
22
  const clampLinearRgb = (rgb) => {
23
23
  const { r, g, b, alpha } = rgb;
24
24
  return {
25
- r: clamp(r, 1e-4, 1),
26
- g: clamp(g, 1e-4, 1),
27
- b: clamp(b, 1e-4, 1),
25
+ r: clamp(r),
26
+ g: clamp(g),
27
+ b: clamp(b),
28
28
  alpha: clamp(alpha)
29
29
  };
30
30
  };
@@ -63,8 +63,7 @@ const rgbToLinear = (value) => {
63
63
  * @param value - Linear light value (0-1)
64
64
  */
65
65
  function linearToRgb(value) {
66
- const v = value <= .0031308 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - .055;
67
- return Math.round(v * 255);
66
+ return (value <= .0031308 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - .055) * 255;
68
67
  }
69
68
  /**
70
69
  * Converts an RGBA color to Linear RGB color space.
@@ -13,6 +13,23 @@ const ANGLE_UNITS = {
13
13
  turn: 360,
14
14
  rad: 360 / (Math.PI * 2)
15
15
  };
16
+ /**
17
+ * D65 Standard Illuminant white point.
18
+ *
19
+ * D65 represents average daylight (including ultraviolet)
20
+ * with a correlated color temperature of approximately 6500K.
21
+ * It is the standard white point for sRGB, Display P3, and most
22
+ * web-related color spaces.
23
+ *
24
+ * Values are normalized with Y = 1.0.
25
+ *
26
+ * @see https://en.wikipedia.org/wiki/Illuminant_D65
27
+ */
28
+ const D65 = {
29
+ x: .95047,
30
+ y: 1,
31
+ z: 1.08883
32
+ };
16
33
  const D50 = {
17
34
  x: .96422,
18
35
  y: 1,
@@ -236,4 +253,4 @@ function parseValueToDecimal(value) {
236
253
  }
237
254
 
238
255
  //#endregion
239
- export { OKLAB_M2_INV as _, mul3x3 as a, parseValueToDecimal as c, M_D65_TO_D50 as d, M_SRGB_TO_XYZ_D65 as f, OKLAB_M2 as g, OKLAB_M1_INV as h, isPresent as i, round as l, OKLAB_M1 as m, clampHue as n, parseAlpha as o, M_XYZ_D65_TO_SRGB as p, floor as r, parseHue as s, clamp as t, M_D50_TO_D65 as u, ALPHA_PRECISION as v, D50 as y };
256
+ export { OKLAB_M2_INV as _, mul3x3 as a, D65 as b, parseValueToDecimal as c, M_D65_TO_D50 as d, M_SRGB_TO_XYZ_D65 as f, OKLAB_M2 as g, OKLAB_M1_INV as h, isPresent as i, round as l, OKLAB_M1 as m, clampHue as n, parseAlpha as o, M_XYZ_D65_TO_SRGB as p, floor as r, parseHue as s, clamp as t, M_D50_TO_D65 as u, ALPHA_PRECISION as v, D50 as y };