diff --git a/.github/bin/license/check-license.mjs b/.github/bin/license/check-license.mjs
index fffcf8076..eb3d45cdd 100644
--- a/.github/bin/license/check-license.mjs
+++ b/.github/bin/license/check-license.mjs
@@ -57,7 +57,7 @@ const allFiles = (await getFiles('./')).filter((file) => {
for (const line of lines) {
if (line.includes('@license')) {
- if (line === ' * @license W3C') {
+ if (line.startsWith(' * @license W3C')) {
// W3C license is ok
continue;
}
diff --git a/package-lock.json b/package-lock.json
index 6126a5680..a7cfc614b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1823,6 +1823,10 @@
"resolved": "packages/cascade-layer-name-parser",
"link": true
},
+ "node_modules/@csstools/color-helpers": {
+ "resolved": "packages/color-helpers",
+ "link": true
+ },
"node_modules/@csstools/css-has-pseudo-experimental": {
"resolved": "experimental/css-has-pseudo",
"link": true
@@ -7031,6 +7035,18 @@
"@csstools/css-tokenizer": "^2.0.0"
}
},
+ "packages/color-helpers": {
+ "name": "@csstools/color-helpers",
+ "version": "0.0.0",
+ "license": "CC0-1.0",
+ "engines": {
+ "node": "^14 || ^16 || >=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ },
"packages/css-parser-algorithms": {
"name": "@csstools/css-parser-algorithms",
"version": "2.0.1",
diff --git a/packages/color-helpers/.gitignore b/packages/color-helpers/.gitignore
new file mode 100644
index 000000000..1069fe212
--- /dev/null
+++ b/packages/color-helpers/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+package-lock.json
+yarn.lock
+*.result.css
+*.result.css.map
diff --git a/packages/color-helpers/.nvmrc b/packages/color-helpers/.nvmrc
new file mode 100644
index 000000000..f0b10f153
--- /dev/null
+++ b/packages/color-helpers/.nvmrc
@@ -0,0 +1 @@
+v16.13.1
diff --git a/packages/color-helpers/CHANGELOG.md b/packages/color-helpers/CHANGELOG.md
new file mode 100644
index 000000000..4d98f656e
--- /dev/null
+++ b/packages/color-helpers/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changes to Color Helpers
+
+### Unreleased (major)
+
+- Initial version
diff --git a/packages/color-helpers/LICENSE.md b/packages/color-helpers/LICENSE.md
new file mode 100644
index 000000000..0bc1fa706
--- /dev/null
+++ b/packages/color-helpers/LICENSE.md
@@ -0,0 +1,108 @@
+# CC0 1.0 Universal
+
+## Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an “owner”) of an original work of
+authorship and/or a database (each, a “Work”).
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific works
+(“Commons”) that the public can reliably and without fear of later claims of
+infringement build upon, modify, incorporate in other works, reuse and
+redistribute as freely as possible in any form whatsoever and for any purposes,
+including without limitation commercial purposes. These owners may contribute
+to the Commons to promote the ideal of a free culture and the further
+production of creative, cultural and scientific works, or to gain reputation or
+greater distribution for their Work in part through the use and efforts of
+others.
+
+For these and/or other purposes and motivations, and without any expectation of
+additional consideration or compensation, the person associating CC0 with a
+Work (the “Affirmer”), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and
+publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+ protected by copyright and related or neighboring rights (“Copyright and
+ Related Rights”). Copyright and Related Rights include, but are not limited
+ to, the following:
+ 1. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+ 2. moral rights retained by the original author(s) and/or performer(s);
+ 3. publicity and privacy rights pertaining to a person’s image or likeness
+ depicted in a Work;
+ 4. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(i), below;
+ 5. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+ 6. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+ 7. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations
+ thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+ applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+ unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright
+ and Related Rights and associated claims and causes of action, whether now
+ known or unknown (including existing as well as future claims and causes of
+ action), in the Work (i) in all territories worldwide, (ii) for the maximum
+ duration provided by applicable law or treaty (including future time
+ extensions), (iii) in any current or future medium and for any number of
+ copies, and (iv) for any purpose whatsoever, including without limitation
+ commercial, advertising or promotional purposes (the “Waiver”). Affirmer
+ makes the Waiver for the benefit of each member of the public at large and
+ to the detriment of Affirmer’s heirs and successors, fully intending that
+ such Waiver shall not be subject to revocation, rescission, cancellation,
+ termination, or any other legal or equitable action to disrupt the quiet
+ enjoyment of the Work by the public as contemplated by Affirmer’s express
+ Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+ judged legally invalid or ineffective under applicable law, then the Waiver
+ shall be preserved to the maximum extent permitted taking into account
+ Affirmer’s express Statement of Purpose. In addition, to the extent the
+ Waiver is so judged Affirmer hereby grants to each affected person a
+ royalty-free, non transferable, non sublicensable, non exclusive,
+ irrevocable and unconditional license to exercise Affirmer’s Copyright and
+ Related Rights in the Work (i) in all territories worldwide, (ii) for the
+ maximum duration provided by applicable law or treaty (including future time
+ extensions), (iii) in any current or future medium and for any number of
+ copies, and (iv) for any purpose whatsoever, including without limitation
+ commercial, advertising or promotional purposes (the “License”). The License
+ shall be deemed effective as of the date CC0 was applied by Affirmer to the
+ Work. Should any part of the License for any reason be judged legally
+ invalid or ineffective under applicable law, such partial invalidity or
+ ineffectiveness shall not invalidate the remainder of the License, and in
+ such case Affirmer hereby affirms that he or she will not (i) exercise any
+ of his or her remaining Copyright and Related Rights in the Work or (ii)
+ assert any associated claims and causes of action with respect to the Work,
+ in either case contrary to Affirmer’s express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+ 1. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ 2. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or
+ otherwise, including without limitation warranties of title,
+ merchantability, fitness for a particular purpose, non infringement, or
+ the absence of latent or other defects, accuracy, or the present or
+ absence of errors, whether or not discoverable, all to the greatest
+ extent permissible under applicable law.
+ 3. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person’s Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the Work.
+ 4. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+http://creativecommons.org/publicdomain/zero/1.0/.
diff --git a/packages/color-helpers/README.md b/packages/color-helpers/README.md
new file mode 100644
index 000000000..8da7235c2
--- /dev/null
+++ b/packages/color-helpers/README.md
@@ -0,0 +1,32 @@
+# Color Helpers
+
+[
][npm-url]
+[
][cli-url]
+[
][discord]
+
+## Usage
+
+Add [Color Helpers] to your project:
+
+```bash
+npm install postcss @csstools/color-helpers --save-dev
+```
+
+This package exists to join all the different color functions scattered among the Colors 4 and Colors 5 plugins we maintain such as:
+
+* [PostCSS Color Function]
+* [PostCSS Lab Function]
+* [PostCSS OKLab Function]
+
+## Copyright
+
+This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/tree/main/css-color-4. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+
+[cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test
+[discord]: https://discord.gg/bUadyRwkJS
+[npm-url]: https://www.npmjs.com/package/@csstools/color-helpers
+
+[Color Helpers]: https://github.com/csstools/postcss-plugins/tree/main/packages/color-helpers
+[PostCSS Color Function]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-color-function
+[PostCSS Lab Function]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-lab-functionw
+[PostCSS OKLab Function]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-oklab-function
diff --git a/packages/color-helpers/dist/calculations/binary-search-gamut.d.ts b/packages/color-helpers/dist/calculations/binary-search-gamut.d.ts
new file mode 100644
index 000000000..c8b03e7c2
--- /dev/null
+++ b/packages/color-helpers/dist/calculations/binary-search-gamut.d.ts
@@ -0,0 +1 @@
+export declare function binarySearchGamut(startOKLCH: Color, toDestination: (x: Color) => Color, fromDestination: (x: Color) => Color): Color;
diff --git a/packages/color-helpers/dist/calculations/contrast.d.ts b/packages/color-helpers/dist/calculations/contrast.d.ts
new file mode 100644
index 000000000..118a372f3
--- /dev/null
+++ b/packages/color-helpers/dist/calculations/contrast.d.ts
@@ -0,0 +1 @@
+export declare function contrast(RGB1: Color, RGB2: Color): number;
diff --git a/packages/color-helpers/dist/calculations/delta-EOK.d.ts b/packages/color-helpers/dist/calculations/delta-EOK.d.ts
new file mode 100644
index 000000000..94efb8d53
--- /dev/null
+++ b/packages/color-helpers/dist/calculations/delta-EOK.d.ts
@@ -0,0 +1,13 @@
+/**
+ * @description Calculate deltaE OK which is the simple root sum of squares
+ * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @return {number} How different a color sample is from reference
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
+ */
+export declare function deltaEOK(reference: Color, sample: Color): number;
diff --git a/packages/color-helpers/dist/calculations/index.d.ts b/packages/color-helpers/dist/calculations/index.d.ts
new file mode 100644
index 000000000..3db911c00
--- /dev/null
+++ b/packages/color-helpers/dist/calculations/index.d.ts
@@ -0,0 +1,6 @@
+export * from './binary-search-gamut';
+export * from './polar-premultiply';
+export * from './map-gamut';
+export * from './delta-EOK';
+export * from './contrast';
+export * from './multiply-matrices';
diff --git a/packages/color-helpers/dist/calculations/map-gamut.d.ts b/packages/color-helpers/dist/calculations/map-gamut.d.ts
new file mode 100644
index 000000000..b5ef8c32f
--- /dev/null
+++ b/packages/color-helpers/dist/calculations/map-gamut.d.ts
@@ -0,0 +1 @@
+export declare function mapGamut(startOKLCH: Color, toDestination: (x: Color) => Color, fromDestination: (x: Color) => Color): Color;
diff --git a/plugins/postcss-oklab-function/dist/css-color-4/multiply-matrices.d.ts b/packages/color-helpers/dist/calculations/multiply-matrices.d.ts
similarity index 87%
rename from plugins/postcss-oklab-function/dist/css-color-4/multiply-matrices.d.ts
rename to packages/color-helpers/dist/calculations/multiply-matrices.d.ts
index 3055a8245..b78e13fd5 100644
--- a/plugins/postcss-oklab-function/dist/css-color-4/multiply-matrices.d.ts
+++ b/packages/color-helpers/dist/calculations/multiply-matrices.d.ts
@@ -3,8 +3,7 @@
* Warning: No error handling for incompatible dimensions!
* @author Lea Verou 2020 MIT License
*
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*
diff --git a/packages/color-helpers/dist/calculations/polar-premultiply.d.ts b/packages/color-helpers/dist/calculations/polar-premultiply.d.ts
new file mode 100644
index 000000000..b2188d710
--- /dev/null
+++ b/packages/color-helpers/dist/calculations/polar-premultiply.d.ts
@@ -0,0 +1,15 @@
+/**
+ * Given a color in a cylindical polar colorspace and an alpha value
+ * return the premultiplied form. The index says which entry in the
+ * color array corresponds to hue angle for example, in OKLCH it
+ * would be 2 while in HSL it would be 0
+ *
+ * @param color
+ * @param alpha
+ * @param hueIndex
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function polarPremultiply(color: Color, alpha: number, hueIndex: number): Color;
diff --git a/packages/color-helpers/dist/conversions/a98-rgb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/a98-rgb-to-srgb.d.ts
new file mode 100644
index 000000000..74b497bd1
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/a98-rgb-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function a98_RGB_to_sRGB(a98: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/cie-xyz-50-to-srgb.d.ts b/packages/color-helpers/dist/conversions/cie-xyz-50-to-srgb.d.ts
new file mode 100644
index 000000000..4cebd73a8
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/cie-xyz-50-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function cie_XYZ_50_to_sRGB(xyz: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/cie-xyz-65-to-srgb.d.ts b/packages/color-helpers/dist/conversions/cie-xyz-65-to-srgb.d.ts
new file mode 100644
index 000000000..2d0e0d610
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/cie-xyz-65-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function cie_XYZ_65_to_sRGB(xyz: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/constants.d.ts b/packages/color-helpers/dist/conversions/constants.d.ts
new file mode 100644
index 000000000..4d2e7a1e4
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/constants.d.ts
@@ -0,0 +1,2 @@
+export declare const D50: number[];
+export declare const D65: number[];
diff --git a/packages/color-helpers/dist/conversions/d50-to-d65.d.ts b/packages/color-helpers/dist/conversions/d50-to-d65.d.ts
new file mode 100644
index 000000000..77e2aab0b
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/d50-to-d65.d.ts
@@ -0,0 +1 @@
+export declare function D50_to_D65(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/d65-to-d50.d.ts b/packages/color-helpers/dist/conversions/d65-to-d50.d.ts
new file mode 100644
index 000000000..1593ec542
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/d65-to-d50.d.ts
@@ -0,0 +1 @@
+export declare function D65_to_D50(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/gam-2020.d.ts b/packages/color-helpers/dist/conversions/gam-2020.d.ts
new file mode 100644
index 000000000..7ebd87cd9
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/gam-2020.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0
+ * to gamma corrected form ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function gam_2020(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/gam-a98rgb.d.ts b/packages/color-helpers/dist/conversions/gam-a98rgb.d.ts
new file mode 100644
index 000000000..3199b23dd
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/gam-a98rgb.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Convert an array of linear-light a98-rgb in the range 0.0-1.0
+ * to gamma corrected form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function gam_a98rgb(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/gam-p3.d.ts b/packages/color-helpers/dist/conversions/gam-p3.d.ts
new file mode 100644
index 000000000..bb8cddac0
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/gam-p3.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0
+ * to gamma corrected form
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function gam_P3(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/gam-pro-photo.d.ts b/packages/color-helpers/dist/conversions/gam-pro-photo.d.ts
new file mode 100644
index 000000000..99a411e03
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/gam-pro-photo.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0
+ * to gamma corrected form.
+ * Transfer curve is gamma 1.8 with a small linear portion.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function gam_ProPhoto(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/gam-srgb.d.ts b/packages/color-helpers/dist/conversions/gam-srgb.d.ts
new file mode 100644
index 000000000..59850f13e
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/gam-srgb.d.ts
@@ -0,0 +1,13 @@
+/**
+ * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form
+ * Extended transfer function:
+ * For negative values, linear portion extends on reflection
+ * of axis, then uses reflected pow below that
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */
+export declare function gam_sRGB(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/hsl-to-srgb.d.ts b/packages/color-helpers/dist/conversions/hsl-to-srgb.d.ts
new file mode 100644
index 000000000..1b4cc2617
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/hsl-to-srgb.d.ts
@@ -0,0 +1,13 @@
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} sat - Saturation as percentage 0..100
+ * @param {number} light - Lightness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js
+ */
+export declare function HSL_to_sRGB(HSL: Color): number[];
diff --git a/packages/color-helpers/dist/conversions/hue-to-rgb.d.ts b/packages/color-helpers/dist/conversions/hue-to-rgb.d.ts
new file mode 100644
index 000000000..8cb5ff7cd
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/hue-to-rgb.d.ts
@@ -0,0 +1,8 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function hueToRGB(t1: number, t2: number, hue: number): number;
diff --git a/packages/color-helpers/dist/conversions/hwb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/hwb-to-srgb.d.ts
new file mode 100644
index 000000000..93f053db8
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/hwb-to-srgb.d.ts
@@ -0,0 +1,13 @@
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} white - Whiteness as percentage 0..100
+ * @param {number} black - Blackness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js
+ */
+export declare function HWB_to_sRGB(HWB: Color): number[];
diff --git a/packages/color-helpers/dist/conversions/index.d.ts b/packages/color-helpers/dist/conversions/index.d.ts
new file mode 100644
index 000000000..539f7ab8f
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/index.d.ts
@@ -0,0 +1,58 @@
+export * from './a98-rgb-to-srgb';
+export * from './cie-xyz-50-to-srgb';
+export * from './cie-xyz-65-to-srgb';
+export * from './constants';
+export * from './d50-to-d65';
+export * from './d65-to-d50';
+export * from './gam-2020';
+export * from './gam-a98rgb';
+export * from './gam-p3';
+export * from './gam-pro-photo';
+export * from './gam-srgb';
+export * from './hsl-to-srgb';
+export * from './hue-to-rgb';
+export * from './hwb-to-srgb';
+export * from './lab-to-lch';
+export * from './lab-to-p3';
+export * from './lab-to-srgb';
+export * from './lab-to-xyz';
+export * from './lch-to-lab';
+export * from './lch-to-p3';
+export * from './lch-to-rec2020';
+export * from './lch-to-srgb';
+export * from './lin-2020';
+export * from './lin-2020-to-xyz';
+export * from './lin-a98rgb';
+export * from './lin-a98rgb-to-xyz';
+export * from './lin-p3';
+export * from './lin-p3-to-xyz';
+export * from './lin-pro-photo';
+export * from './lin-pro-photo-to-xyz';
+export * from './lin-srgb';
+export * from './lin-srgb-to-xyz';
+export * from './naive-cmyk-to-srgb';
+export * from './oklab-to-oklch';
+export * from './oklab-to-p3';
+export * from './oklab-to-srgb';
+export * from './oklab-to-xyz';
+export * from './oklch-to-oklab';
+export * from './oklch-to-p3';
+export * from './oklch-to-srgb';
+export * from './p3-to-lch';
+export * from './p3-to-srgb';
+export * from './pro-photo-rgb-to-srgb';
+export * from './rec2020-to-lch';
+export * from './rec2020-to-srgb';
+export * from './srgb-linear-to-srgb';
+export * from './srgb-to-lch';
+export * from './srgb-to-luminance';
+export * from './srgb-to-srgb';
+export * from './xyz-to-lab';
+export * from './xyz-to-lin-2020';
+export * from './xyz-to-lin-a98rgb';
+export * from './xyz-to-lin-p3';
+export * from './xyz-to-lin-pro-photo';
+export * from './xyz-to-lin-srgb';
+export * from './xyz-to-oklab';
+export * from './xyz-to-uv';
+export * from './xyz-to-xy';
diff --git a/packages/color-helpers/dist/conversions/lab-to-lch.d.ts b/packages/color-helpers/dist/conversions/lab-to-lch.d.ts
new file mode 100644
index 000000000..45149efa4
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lab-to-lch.d.ts
@@ -0,0 +1,6 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function Lab_to_LCH(Lab: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lab-to-p3.d.ts b/packages/color-helpers/dist/conversions/lab-to-p3.d.ts
new file mode 100644
index 000000000..63bb93acf
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lab-to-p3.d.ts
@@ -0,0 +1 @@
+export declare function Lab_to_P3(labRaw: Color): [Color, boolean];
diff --git a/packages/color-helpers/dist/conversions/lab-to-srgb.d.ts b/packages/color-helpers/dist/conversions/lab-to-srgb.d.ts
new file mode 100644
index 000000000..7e35606af
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lab-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function Lab_to_sRGB(labRaw: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lab-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lab-to-xyz.d.ts
new file mode 100644
index 000000000..4f6851006
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lab-to-xyz.d.ts
@@ -0,0 +1 @@
+export declare function Lab_to_XYZ(Lab: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lch-to-lab.d.ts b/packages/color-helpers/dist/conversions/lch-to-lab.d.ts
new file mode 100644
index 000000000..798a55f9e
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lch-to-lab.d.ts
@@ -0,0 +1,6 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function LCH_to_Lab(LCH: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lch-to-p3.d.ts b/packages/color-helpers/dist/conversions/lch-to-p3.d.ts
new file mode 100644
index 000000000..25e86b490
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lch-to-p3.d.ts
@@ -0,0 +1 @@
+export declare function LCH_to_P3(lchRaw: Color): [Color, boolean];
diff --git a/packages/color-helpers/dist/conversions/lch-to-rec2020.d.ts b/packages/color-helpers/dist/conversions/lch-to-rec2020.d.ts
new file mode 100644
index 000000000..7195ff086
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lch-to-rec2020.d.ts
@@ -0,0 +1,14 @@
+/**
+ * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from
+ * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma
+ * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0
+ * range out of gamut colors may have negative components or components greater
+ * than 1.0 so check for that :)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function LCH_to_rec2020(LCH: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lch-to-srgb.d.ts b/packages/color-helpers/dist/conversions/lch-to-srgb.d.ts
new file mode 100644
index 000000000..0fa4a5817
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lch-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function LCH_to_sRGB(lchRaw: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-2020-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-2020-to-xyz.d.ts
new file mode 100644
index 000000000..f1b43f4de
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-2020-to-xyz.d.ts
@@ -0,0 +1,11 @@
+/**
+ * Convert an array of linear-light rec2020 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export declare function lin_2020_to_XYZ(rgb: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-2020.d.ts b/packages/color-helpers/dist/conversions/lin-2020.d.ts
new file mode 100644
index 000000000..0c951201f
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-2020.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Convert an array of rec2020 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ * ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function lin_2020(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-a98rgb-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-a98rgb-to-xyz.d.ts
new file mode 100644
index 000000000..eab3ddfe8
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-a98rgb-to-xyz.d.ts
@@ -0,0 +1,17 @@
+/**
+ * Convert an array of linear-light a98-rgb values to CIE XYZ
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * has greater numerical precision than section 4.3.5.3 of
+ * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * but the values below were calculated from first principles
+ * from the chromaticity coordinates of R G B W
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html
+ */
+export declare function lin_a98rgb_to_XYZ(rgb: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-a98rgb.d.ts b/packages/color-helpers/dist/conversions/lin-a98rgb.d.ts
new file mode 100644
index 000000000..3ccd0d9ea
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-a98rgb.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Convert an array of a98-rgb values in the range 0.0 - 1.0
+ * to linear light (un-companded) form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function lin_a98rgb(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-p3-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-p3-to-xyz.d.ts
new file mode 100644
index 000000000..44e270378
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-p3-to-xyz.d.ts
@@ -0,0 +1,11 @@
+/**
+ * Convert an array of linear-light display-p3 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export declare function lin_P3_to_XYZ(rgb: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-p3.d.ts b/packages/color-helpers/dist/conversions/lin-p3.d.ts
new file mode 100644
index 000000000..dd20b3ec7
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-p3.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Convert an array of display-p3 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function lin_P3(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-pro-photo-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-pro-photo-to-xyz.d.ts
new file mode 100644
index 000000000..076b6996e
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-pro-photo-to-xyz.d.ts
@@ -0,0 +1,11 @@
+/**
+ * Convert an array of linear-light prophoto-rgb values to CIE XYZ
+ * using D50 (so no chromatic adaptation needed afterwards)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export declare function lin_ProPhoto_to_XYZ(rgb: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-pro-photo.d.ts b/packages/color-helpers/dist/conversions/lin-pro-photo.d.ts
new file mode 100644
index 000000000..6a7151928
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-pro-photo.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Convert an array of prophoto-rgb values where in-gamut Colors are in the
+ * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is
+ * gamma 1.8 with a small linear portion. Extended transfer function
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function lin_ProPhoto(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-srgb-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-srgb-to-xyz.d.ts
new file mode 100644
index 000000000..4e11938fe
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-srgb-to-xyz.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Convert an array of linear-light sRGB values to CIE XYZ
+ * using sRGB's own white, D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function lin_sRGB_to_XYZ(rgb: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/lin-srgb.d.ts b/packages/color-helpers/dist/conversions/lin-srgb.d.ts
new file mode 100644
index 000000000..419a77ff3
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/lin-srgb.d.ts
@@ -0,0 +1,14 @@
+/**
+ * Convert an array of of sRGB values where in-gamut values are in the range
+ * [0 - 1] to linear light (un-companded) form.
+ * Extended transfer function:
+ * For negative values, linear portion is extended on reflection of axis,
+ * then reflected power function is used.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */
+export declare function lin_sRGB(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/naive-cmyk-to-srgb.d.ts b/packages/color-helpers/dist/conversions/naive-cmyk-to-srgb.d.ts
new file mode 100644
index 000000000..ed3590c98
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/naive-cmyk-to-srgb.d.ts
@@ -0,0 +1,13 @@
+/**
+ * CMYK is an array of four values in the range [0.0, 1.0] the output is an
+ * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm
+ * does not generate out of gamut colors neither does it generate accurate
+ * simulations of practical CMYK colors
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): Color;
diff --git a/packages/color-helpers/dist/conversions/oklab-to-oklch.d.ts b/packages/color-helpers/dist/conversions/oklab-to-oklch.d.ts
new file mode 100644
index 000000000..bfead2074
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/oklab-to-oklch.d.ts
@@ -0,0 +1,8 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */
+export declare function OKLab_to_OKLCH(OKLab: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/oklab-to-p3.d.ts b/packages/color-helpers/dist/conversions/oklab-to-p3.d.ts
new file mode 100644
index 000000000..ff65fa2cb
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/oklab-to-p3.d.ts
@@ -0,0 +1 @@
+export declare function OKLab_to_P3(oklabRaw: Color): [Color, boolean];
diff --git a/packages/color-helpers/dist/conversions/oklab-to-srgb.d.ts b/packages/color-helpers/dist/conversions/oklab-to-srgb.d.ts
new file mode 100644
index 000000000..03a97297d
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/oklab-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function OKLab_to_sRGB(oklabRaw: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/oklab-to-xyz.d.ts b/packages/color-helpers/dist/conversions/oklab-to-xyz.d.ts
new file mode 100644
index 000000000..8f58814f4
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/oklab-to-xyz.d.ts
@@ -0,0 +1 @@
+export declare function OKLab_to_XYZ(OKLab: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/oklch-to-oklab.d.ts b/packages/color-helpers/dist/conversions/oklch-to-oklab.d.ts
new file mode 100644
index 000000000..4ea09dd2e
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/oklch-to-oklab.d.ts
@@ -0,0 +1,8 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */
+export declare function OKLCH_to_OKLab(OKLCH: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/oklch-to-p3.d.ts b/packages/color-helpers/dist/conversions/oklch-to-p3.d.ts
new file mode 100644
index 000000000..60512c304
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/oklch-to-p3.d.ts
@@ -0,0 +1 @@
+export declare function OKLCH_to_P3(oklchRaw: Color): [Color, boolean];
diff --git a/packages/color-helpers/dist/conversions/oklch-to-srgb.d.ts b/packages/color-helpers/dist/conversions/oklch-to-srgb.d.ts
new file mode 100644
index 000000000..d12c5a3f4
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/oklch-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function OKLCH_to_sRGB(oklchRaw: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/p3-to-lch.d.ts b/packages/color-helpers/dist/conversions/p3-to-lch.d.ts
new file mode 100644
index 000000000..167543696
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/p3-to-lch.d.ts
@@ -0,0 +1,12 @@
+/**
+ * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0
+ * range to linear-light display-p3, then to CIE XYZ, then adapt from D65
+ * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function P3_to_LCH(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/p3-to-srgb.d.ts b/packages/color-helpers/dist/conversions/p3-to-srgb.d.ts
new file mode 100644
index 000000000..d91f0503a
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/p3-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function p3_to_sRGB(displayP3: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/pro-photo-rgb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/pro-photo-rgb-to-srgb.d.ts
new file mode 100644
index 000000000..9ca6a410f
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/pro-photo-rgb-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function proPhoto_RGB_to_sRGB(proPhoto: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/rec2020-to-lch.d.ts b/packages/color-helpers/dist/conversions/rec2020-to-lch.d.ts
new file mode 100644
index 000000000..8ea2244cd
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/rec2020-to-lch.d.ts
@@ -0,0 +1,12 @@
+/**
+ * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function rec_2020_to_LCH(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/rec2020-to-srgb.d.ts b/packages/color-helpers/dist/conversions/rec2020-to-srgb.d.ts
new file mode 100644
index 000000000..b35a0fdda
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/rec2020-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function rec_2020_to_sRGB(rec: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/srgb-linear-to-srgb.d.ts b/packages/color-helpers/dist/conversions/srgb-linear-to-srgb.d.ts
new file mode 100644
index 000000000..860d1a4f4
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/srgb-linear-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function sRGB_linear_to_sRGB(linearSRgb: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/srgb-to-lch.d.ts b/packages/color-helpers/dist/conversions/srgb-to-lch.d.ts
new file mode 100644
index 000000000..30d9bee35
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/srgb-to-lch.d.ts
@@ -0,0 +1,12 @@
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to
+ * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function sRGB_to_LCH(RGB: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/srgb-to-luminance.d.ts b/packages/color-helpers/dist/conversions/srgb-to-luminance.d.ts
new file mode 100644
index 000000000..71f9e589e
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/srgb-to-luminance.d.ts
@@ -0,0 +1,11 @@
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function sRGB_to_luminance(RGB: Color): number;
diff --git a/packages/color-helpers/dist/conversions/srgb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/srgb-to-srgb.d.ts
new file mode 100644
index 000000000..45e78c8fc
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/srgb-to-srgb.d.ts
@@ -0,0 +1 @@
+export declare function sRGB_to_sRGB(sRgb: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-lab.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lab.d.ts
new file mode 100644
index 000000000..79377c3b1
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-lab.d.ts
@@ -0,0 +1 @@
+export declare function XYZ_to_Lab(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-2020.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-2020.d.ts
new file mode 100644
index 000000000..cea7ab42e
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-lin-2020.d.ts
@@ -0,0 +1,8 @@
+/**
+ * Convert XYZ to linear-light rec2020
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function XYZ_to_lin_2020(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-a98rgb.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-a98rgb.d.ts
new file mode 100644
index 000000000..b628d1586
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-lin-a98rgb.d.ts
@@ -0,0 +1,8 @@
+/**
+ * Convert XYZ to linear-light a98-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function XYZ_to_lin_a98rgb(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-p3.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-p3.d.ts
new file mode 100644
index 000000000..66cb1676a
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-lin-p3.d.ts
@@ -0,0 +1,8 @@
+/**
+ * Convert XYZ to linear-light P3
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function XYZ_to_lin_P3(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-pro-photo.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-pro-photo.d.ts
new file mode 100644
index 000000000..f58fdcef2
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-lin-pro-photo.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Convert XYZ to linear-light prophoto-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export declare function XYZ_to_lin_ProPhoto(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-srgb.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-srgb.d.ts
new file mode 100644
index 000000000..ea6ec1cc5
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-lin-srgb.d.ts
@@ -0,0 +1,6 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function XYZ_to_lin_sRGB(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-oklab.d.ts b/packages/color-helpers/dist/conversions/xyz-to-oklab.d.ts
new file mode 100644
index 000000000..6fccfee6f
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-oklab.d.ts
@@ -0,0 +1,9 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * XYZ <-> LMS matrices recalculated for consistent reference white
+ * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
+ */
+export declare function XYZ_to_OKLab(XYZ: Color): Color;
diff --git a/packages/color-helpers/dist/conversions/xyz-to-uv.d.ts b/packages/color-helpers/dist/conversions/xyz-to-uv.d.ts
new file mode 100644
index 000000000..67970ebc2
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-uv.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Convert an array of three XYZ values to u*,v* chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function XYZ_to_uv(XYZ: Color): [number, number];
diff --git a/packages/color-helpers/dist/conversions/xyz-to-xy.d.ts b/packages/color-helpers/dist/conversions/xyz-to-xy.d.ts
new file mode 100644
index 000000000..b14a797a0
--- /dev/null
+++ b/packages/color-helpers/dist/conversions/xyz-to-xy.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Convert an array of three XYZ values to x,y chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export declare function XYZ_to_xy(XYZ: Color): [number, number];
diff --git a/packages/color-helpers/dist/index.cjs b/packages/color-helpers/dist/index.cjs
new file mode 100644
index 000000000..6b73cf1c6
--- /dev/null
+++ b/packages/color-helpers/dist/index.cjs
@@ -0,0 +1,441 @@
+"use strict";
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function clip(_){return _.map((_=>_<0?0:_>1?1:_))}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */function OKLCH_to_OKLab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]}
+/**
+ * @description Calculate deltaE OK which is the simple root sum of squares
+ * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @return {number} How different a color sample is from reference
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
+ */function deltaEOK(_,t){const[o,a,n]=_,[i,e,l]=t,r=o-i,s=a-e,u=n-l;return Math.sqrt(r**2+s**2+u**2)}function binarySearchGamut(_,t,o){let a=0,n=_[1];const i=_;for(;n-a>1e-4;){const _=clip(t(i));deltaEOK(OKLCH_to_OKLab(i),OKLCH_to_OKLab(o(_)))-.02<1e-4?a=i[1]:n=i[1],i[1]=(n+a)/2}return clip(t([...i]))}
+/**
+ * Given a color in a cylindical polar colorspace and an alpha value
+ * return the premultiplied form. The index says which entry in the
+ * color array corresponds to hue angle for example, in OKLCH it
+ * would be 2 while in HSL it would be 0
+ *
+ * @param color
+ * @param alpha
+ * @param hueIndex
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function mapGamut(_,t,o){return binarySearchGamut(_,t,o)}
+/**
+ * Simple matrix (and vector) multiplication
+ * Warning: No error handling for incompatible dimensions!
+ * @author Lea Verou 2020 MIT License
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js
+ */function multiplyMatrices(_,t){const o=_.length;let a,n;a=Array.isArray(_[0])?_:[_],Array.isArray(t[0])||(n=t.map((_=>[_])));const i=n[0].length,e=n[0].map(((_,t)=>n.map((_=>_[t]))));let l=a.map((_=>e.map((t=>Array.isArray(_)?_.reduce(((_,o,a)=>_+o*(t[a]||0)),0):t.reduce(((t,o)=>t+o*_),0)))));return 1===o&&(l=l[0]),1===i?l.map((_=>_[0])):l}
+/**
+ * Convert an array of linear-light sRGB values to CIE XYZ
+ * using sRGB's own white, D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_sRGB_to_XYZ(_){return multiplyMatrices([[506752/1228815,87881/245763,12673/70218],[87098/409605,175762/245763,12673/175545],[7918/409605,87881/737289,1001167/1053270]],_)}
+/**
+ * Convert an array of of sRGB values where in-gamut values are in the range
+ * [0 - 1] to linear light (un-companded) form.
+ * Extended transfer function:
+ * For negative values, linear portion is extended on reflection of axis,
+ * then reflected power function is used.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */function lin_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<.04045?_/12.92:t*Math.pow((o+.055)/1.055,2.4)}))}
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */function sRGB_to_luminance(_){return lin_sRGB_to_XYZ(lin_sRGB(_))[1]}
+/**
+ * Return WCAG 2.1 contrast ratio for two sRGB values given as arrays
+ *
+ * of 0.0 to 1.0
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ * @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
+ */var _=Object.freeze({__proto__:null,binarySearchGamut:binarySearchGamut,contrast:function contrast(_,t){const o=sRGB_to_luminance(_),a=sRGB_to_luminance(t);return o>a?(o+.05)/(a+.05):(a+.05)/(o+.05)},deltaEOK:deltaEOK,mapGamut:mapGamut,multiplyMatrices:multiplyMatrices,polarPremultiply:function polarPremultiply(_,t,o){return _.map(((_,a)=>_*(o===a?1:t)))}});
+/**
+ * Convert an array of a98-rgb values in the range 0.0 - 1.0
+ * to linear light (un-companded) form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,563/256)}))}
+/**
+ * Convert an array of linear-light a98-rgb values to CIE XYZ
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * has greater numerical precision than section 4.3.5.3 of
+ * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * but the values below were calculated from first principles
+ * from the chromaticity coordinates of R G B W
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html
+ */function lin_a98rgb_to_XYZ(_){return multiplyMatrices([[573536/994567,263643/1420810,187206/994567],[591459/1989134,6239551/9945670,374412/4972835],[53769/1989134,351524/4972835,4929758/4972835]],_)}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * XYZ <-> LMS matrices recalculated for consistent reference white
+ * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
+ */function XYZ_to_OKLab(_){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],_);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((_=>Math.cbrt(_))))}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */function OKLab_to_OKLCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(_[1]**2+_[2]**2),t>=0?t:t+360]}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function XYZ_to_lin_sRGB(_){return multiplyMatrices([[12831/3959,-329/214,-1974/3959],[-851781/878810,1648619/878810,36519/878810],[705/12673,-2585/12673,705/667]],_)}
+/**
+ * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form
+ * Extended transfer function:
+ * For negative values, linear portion extends on reflection
+ * of axis, then uses reflected pow below that
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */function gam_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>.0031308?t*(1.055*Math.pow(o,1/2.4)-.055):12.92*_}))}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function inGamut(_){const[t,o,a]=_;return t>=-1e-4&&t<=1.0001&&o>=-1e-4&&o<=1.0001&&a>=-1e-4&&a<=1.0001}
+/**
+ * Given OKLab, convert to XYZ relative to D65
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */function OKLab_to_XYZ(_){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],_);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((_=>_**3)))}
+/**
+ * Bradford chromatic adaptation from D50 to D65
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function D50_to_D65(_){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],_)}const t=[.3457/.3585,1,.2958/.3585];
+/**
+ * Bradford chromatic adaptation from D65 to D50
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+ */
+function D65_to_D50(_){return multiplyMatrices([[1.0479298208405488,.022946793341019088,-.05019222954313557],[.029627815688159344,.990434484573249,-.01707382502938514],[-.009243058152591178,.015055144896577895,.7518742899580008]],_)}
+/**
+ * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0
+ * to gamma corrected form ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function gam_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a>.018053968510807?o*(t*Math.pow(a,.45)-(t-1)):4.5*_}))}
+/**
+ * Convert an array of linear-light a98-rgb in the range 0.0-1.0
+ * to gamma corrected form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+/**
+ * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0
+ * to gamma corrected form
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function gam_P3(_){return gam_sRGB(_)}
+/**
+ * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0
+ * to gamma corrected form.
+ * Transfer curve is gamma 1.8 with a small linear portion.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} sat - Saturation as percentage 0..100
+ * @param {number} light - Lightness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js
+ */
+function HSL_to_sRGB(_){let t=_[0],o=_[1],a=_[2];function f(_){const n=(_+t/30)%12,i=o*Math.min(a,1-a);return a-i*Math.max(-1,Math.min(n-3,9-n,1))}return t%=360,t<0&&(t+=360),o/=100,a/=100,[f(0),f(8),f(4)]}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function Lab_to_LCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(Math.pow(_[1],2)+Math.pow(_[2],2)),t>=0?t:t+360]}
+/**
+ * Convert Lab to D50-adapted XYZ
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function Lab_to_XYZ(_){const o=24389/27,a=216/24389,n=[];n[1]=(_[0]+16)/116,n[0]=_[1]/500+n[1],n[2]=n[1]-_[2]/200;return[Math.pow(n[0],3)>a?Math.pow(n[0],3):(116*n[0]-16)/o,_[0]>8?Math.pow((_[0]+16)/116,3):_[0]/o,Math.pow(n[2],3)>a?Math.pow(n[2],3):(116*n[2]-16)/o].map(((_,o)=>_*t[o]))}
+/**
+ * Convert XYZ to linear-light P3
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function XYZ_to_lin_P3(_){return multiplyMatrices([[446124/178915,-333277/357830,-72051/178915],[-14852/17905,63121/35810,423/17905],[11844/330415,-50337/660830,316169/330415]],_)}
+/**
+ * Convert an array of display-p3 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_P3(_){return lin_sRGB(_)}
+/**
+ * Convert an array of linear-light display-p3 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function lin_P3_to_XYZ(_){return multiplyMatrices([[608311/1250200,189793/714400,198249/1000160],[35783/156275,247089/357200,198249/2500400],[0,32229/714400,5220557/5000800]],_)}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function LCH_to_Lab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]}
+/**
+ * Convert XYZ to linear-light rec2020
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function XYZ_to_lin_2020(_){return multiplyMatrices([[30757411/17917100,-6372589/17917100,-4539589/17917100],[-.666684351832489,1.616481236634939,467509/29648200],[792561/44930125,-1921689/44930125,.942103121235474]],_)}
+/**
+ * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from
+ * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma
+ * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0
+ * range out of gamut colors may have negative components or components greater
+ * than 1.0 so check for that :)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+/**
+ * Convert an array of rec2020 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ * ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function lin_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a<.08124285829863151?_/4.5:o*Math.pow((a+t-1)/t,1/.45)}))}
+/**
+ * Convert an array of linear-light rec2020 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function lin_2020_to_XYZ(_){return multiplyMatrices([[63426534/99577255,20160776/139408157,47086771/278816314],[26158966/99577255,.677998071518871,8267143/139408157],[0,19567812/697040785,1.0609850577107909]],_)}
+/**
+ * Convert an array of prophoto-rgb values where in-gamut Colors are in the
+ * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is
+ * gamma 1.8 with a small linear portion. Extended transfer function
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<=.03125?_/16:t*Math.pow(o,1.8)}))}
+/**
+ * Convert an array of linear-light prophoto-rgb values to CIE XYZ
+ * using D50 (so no chromatic adaptation needed afterwards)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function lin_ProPhoto_to_XYZ(_){return multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],_)}
+/**
+ * CMYK is an array of four values in the range [0.0, 1.0] the output is an
+ * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm
+ * does not generate out of gamut colors neither does it generate accurate
+ * simulations of practical CMYK colors
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+/**
+ * Assuming XYZ is relative to D50, convert to CIE Lab
+ * from CIE standard, which now defines these as a rational fraction
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function XYZ_to_Lab(_){const o=_.map(((_,o)=>_/t[o])).map((_=>_>.008856451679035631?Math.cbrt(_):(903.2962962962963*_+16)/116));return[116*o[1]-16,500*(o[0]-o[1]),200*(o[1]-o[2])]}
+/**
+ * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0
+ * range to linear-light display-p3, then to CIE XYZ, then adapt from D65
+ * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */var o=Object.freeze({__proto__:null,D50:t,D50_to_D65:D50_to_D65,D65:[.3127/.329,1,.3583/.329],D65_to_D50:D65_to_D50,HSL_to_sRGB:HSL_to_sRGB,HWB_to_sRGB:
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} white - Whiteness as percentage 0..100
+ * @param {number} black - Blackness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js
+ */
+function HWB_to_sRGB(_){const t=_[0];let o=_[1],a=_[2];if(o/=100,a/=100,o+a>=1){const _=o/(o+a);return[_,_,_]}const n=HSL_to_sRGB([t,100,50]);for(let _=0;_<3;_++)n[_]*=1-o-a,n[_]+=o;return n},LCH_to_Lab:LCH_to_Lab,LCH_to_P3:function LCH_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},LCH_to_rec2020:function LCH_to_rec2020(_){return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(_)))))},LCH_to_sRGB:function LCH_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},Lab_to_LCH:Lab_to_LCH,Lab_to_P3:function Lab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},Lab_to_XYZ:Lab_to_XYZ,Lab_to_sRGB:function Lab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLCH_to_OKLab:OKLCH_to_OKLab,OKLCH_to_P3:function OKLCH_to_P3(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_P3(i),i=gam_P3(i),inGamut(i)?[clip(i),!0]:[mapGamut(n,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLCH_to_sRGB:function OKLCH_to_sRGB(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_sRGB(i),i=gam_sRGB(i),inGamut(i)?clip(i).map((_=>Math.round(255*_))):mapGamut(n,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLab_to_OKLCH:OKLab_to_OKLCH,OKLab_to_P3:function OKLab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLab_to_XYZ:OKLab_to_XYZ,OKLab_to_sRGB:function OKLab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},P3_to_LCH:function P3_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(_)))))},XYZ_to_Lab:XYZ_to_Lab,XYZ_to_OKLab:XYZ_to_OKLab,XYZ_to_lin_2020:XYZ_to_lin_2020,XYZ_to_lin_P3:XYZ_to_lin_P3,XYZ_to_lin_ProPhoto:
+/**
+ * Convert XYZ to linear-light prophoto-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+function XYZ_to_lin_ProPhoto(_){return multiplyMatrices([[1.3457989731028281,-.25558010007997534,-.05110628506753401],[-.5446224939028347,1.5082327413132781,.02053603239147973],[0,0,1.2119675456389454]],_)}
+/**
+ * Convert an array of three XYZ values to u*,v* chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,XYZ_to_lin_a98rgb:
+/**
+ * Convert XYZ to linear-light a98-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function XYZ_to_lin_a98rgb(_){return multiplyMatrices([[1829569/896150,-506331/896150,-308931/896150],[-851781/878810,1648619/878810,36519/878810],[16779/1248040,-147721/1248040,1266979/1248040]],_)},XYZ_to_lin_sRGB:XYZ_to_lin_sRGB,XYZ_to_uv:function XYZ_to_uv(_){const t=_[0],o=_[1],a=t+15*o+3*_[2];return[4*t/a,9*o/a]}
+/**
+ * Convert an array of three XYZ values to x,y chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,XYZ_to_xy:function XYZ_to_xy(_){const t=_[0],o=_[1],a=t+o+_[2];return[t/a,o/a]},a98_RGB_to_sRGB:function a98_RGB_to_sRGB(_){let t=_.slice();t=lin_a98rgb(t),t=lin_a98rgb_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_50_to_sRGB:function cie_XYZ_50_to_sRGB(_){let t=_.slice();t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_65_to_sRGB:function cie_XYZ_65_to_sRGB(_){let t=_.slice(),o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},gam_2020:gam_2020,gam_P3:gam_P3,gam_ProPhoto:function gam_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>=.001953125?t*Math.pow(o,1/1.8):16*_}))},gam_a98rgb:function gam_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,256/563)}))},gam_sRGB:gam_sRGB,hueToRGB:function hueToRGB(_,t,o){return o<0&&(o+=6),o>=6&&(o-=6),o<1?(t-_)*o+_:o<3?t:o<4?(t-_)*(4-o)+_:_},lin_2020:lin_2020,lin_2020_to_XYZ:lin_2020_to_XYZ,lin_P3:lin_P3,lin_P3_to_XYZ:lin_P3_to_XYZ,lin_ProPhoto:lin_ProPhoto,lin_ProPhoto_to_XYZ:lin_ProPhoto_to_XYZ,lin_a98rgb:lin_a98rgb,lin_a98rgb_to_XYZ:lin_a98rgb_to_XYZ,lin_sRGB:lin_sRGB,lin_sRGB_to_XYZ:lin_sRGB_to_XYZ,naive_CMYK_to_sRGB:function naive_CMYK_to_sRGB(_){const t=_[0],o=_[1],a=_[2],n=_[3];return[1-Math.min(1,t*(1-n)+n),1-Math.min(1,o*(1-n)+n),1-Math.min(1,a*(1-n)+n)]},p3_to_sRGB:function p3_to_sRGB(_){let t=_.slice();t=lin_P3(t),t=lin_P3_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},proPhoto_RGB_to_sRGB:function proPhoto_RGB_to_sRGB(_){let t=_.slice();t=lin_ProPhoto(t),t=lin_ProPhoto_to_XYZ(t),t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}
+/**
+ * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,rec_2020_to_LCH:function rec_2020_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(_)))))},rec_2020_to_sRGB:function rec_2020_to_sRGB(_){let t=_.slice();t=lin_2020(t),t=lin_2020_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},sRGB_linear_to_sRGB:function sRGB_linear_to_sRGB(_){let t=_.slice();t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to
+ * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,sRGB_to_LCH:function sRGB_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(_)))))},sRGB_to_luminance:sRGB_to_luminance,sRGB_to_sRGB:function sRGB_to_sRGB(_){let t=_.slice();t=lin_sRGB(t),t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}}),a=Object.freeze({__proto__:null,clip:clip,inGamut:inGamut});exports.calculations=_,exports.conversions=o,exports.namedColors={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},exports.utils=a;
diff --git a/packages/color-helpers/dist/index.d.ts b/packages/color-helpers/dist/index.d.ts
new file mode 100644
index 000000000..2a876cf2f
--- /dev/null
+++ b/packages/color-helpers/dist/index.d.ts
@@ -0,0 +1,4 @@
+export * as calculations from './calculations';
+export * as conversions from './conversions';
+export * as utils from './utils';
+export { namedColors } from './named-colors';
diff --git a/packages/color-helpers/dist/index.mjs b/packages/color-helpers/dist/index.mjs
new file mode 100644
index 000000000..f023dc9e3
--- /dev/null
+++ b/packages/color-helpers/dist/index.mjs
@@ -0,0 +1,441 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function clip(_){return _.map((_=>_<0?0:_>1?1:_))}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */function OKLCH_to_OKLab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]}
+/**
+ * @description Calculate deltaE OK which is the simple root sum of squares
+ * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @return {number} How different a color sample is from reference
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
+ */function deltaEOK(_,t){const[o,a,n]=_,[i,e,l]=t,r=o-i,s=a-e,u=n-l;return Math.sqrt(r**2+s**2+u**2)}function binarySearchGamut(_,t,o){let a=0,n=_[1];const i=_;for(;n-a>1e-4;){const _=clip(t(i));deltaEOK(OKLCH_to_OKLab(i),OKLCH_to_OKLab(o(_)))-.02<1e-4?a=i[1]:n=i[1],i[1]=(n+a)/2}return clip(t([...i]))}
+/**
+ * Given a color in a cylindical polar colorspace and an alpha value
+ * return the premultiplied form. The index says which entry in the
+ * color array corresponds to hue angle for example, in OKLCH it
+ * would be 2 while in HSL it would be 0
+ *
+ * @param color
+ * @param alpha
+ * @param hueIndex
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function mapGamut(_,t,o){return binarySearchGamut(_,t,o)}
+/**
+ * Simple matrix (and vector) multiplication
+ * Warning: No error handling for incompatible dimensions!
+ * @author Lea Verou 2020 MIT License
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js
+ */function multiplyMatrices(_,t){const o=_.length;let a,n;a=Array.isArray(_[0])?_:[_],Array.isArray(t[0])||(n=t.map((_=>[_])));const i=n[0].length,e=n[0].map(((_,t)=>n.map((_=>_[t]))));let l=a.map((_=>e.map((t=>Array.isArray(_)?_.reduce(((_,o,a)=>_+o*(t[a]||0)),0):t.reduce(((t,o)=>t+o*_),0)))));return 1===o&&(l=l[0]),1===i?l.map((_=>_[0])):l}
+/**
+ * Convert an array of linear-light sRGB values to CIE XYZ
+ * using sRGB's own white, D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_sRGB_to_XYZ(_){return multiplyMatrices([[506752/1228815,87881/245763,12673/70218],[87098/409605,175762/245763,12673/175545],[7918/409605,87881/737289,1001167/1053270]],_)}
+/**
+ * Convert an array of of sRGB values where in-gamut values are in the range
+ * [0 - 1] to linear light (un-companded) form.
+ * Extended transfer function:
+ * For negative values, linear portion is extended on reflection of axis,
+ * then reflected power function is used.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */function lin_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<.04045?_/12.92:t*Math.pow((o+.055)/1.055,2.4)}))}
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */function sRGB_to_luminance(_){return lin_sRGB_to_XYZ(lin_sRGB(_))[1]}
+/**
+ * Return WCAG 2.1 contrast ratio for two sRGB values given as arrays
+ *
+ * of 0.0 to 1.0
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ * @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
+ */var _=Object.freeze({__proto__:null,binarySearchGamut:binarySearchGamut,contrast:function contrast(_,t){const o=sRGB_to_luminance(_),a=sRGB_to_luminance(t);return o>a?(o+.05)/(a+.05):(a+.05)/(o+.05)},deltaEOK:deltaEOK,mapGamut:mapGamut,multiplyMatrices:multiplyMatrices,polarPremultiply:function polarPremultiply(_,t,o){return _.map(((_,a)=>_*(o===a?1:t)))}});
+/**
+ * Convert an array of a98-rgb values in the range 0.0 - 1.0
+ * to linear light (un-companded) form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,563/256)}))}
+/**
+ * Convert an array of linear-light a98-rgb values to CIE XYZ
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * has greater numerical precision than section 4.3.5.3 of
+ * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * but the values below were calculated from first principles
+ * from the chromaticity coordinates of R G B W
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html
+ */function lin_a98rgb_to_XYZ(_){return multiplyMatrices([[573536/994567,263643/1420810,187206/994567],[591459/1989134,6239551/9945670,374412/4972835],[53769/1989134,351524/4972835,4929758/4972835]],_)}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * XYZ <-> LMS matrices recalculated for consistent reference white
+ * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
+ */function XYZ_to_OKLab(_){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],_);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((_=>Math.cbrt(_))))}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */function OKLab_to_OKLCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(_[1]**2+_[2]**2),t>=0?t:t+360]}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function XYZ_to_lin_sRGB(_){return multiplyMatrices([[12831/3959,-329/214,-1974/3959],[-851781/878810,1648619/878810,36519/878810],[705/12673,-2585/12673,705/667]],_)}
+/**
+ * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form
+ * Extended transfer function:
+ * For negative values, linear portion extends on reflection
+ * of axis, then uses reflected pow below that
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */function gam_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>.0031308?t*(1.055*Math.pow(o,1/2.4)-.055):12.92*_}))}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function inGamut(_){const[t,o,a]=_;return t>=-1e-4&&t<=1.0001&&o>=-1e-4&&o<=1.0001&&a>=-1e-4&&a<=1.0001}
+/**
+ * Given OKLab, convert to XYZ relative to D65
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */function OKLab_to_XYZ(_){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],_);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((_=>_**3)))}
+/**
+ * Bradford chromatic adaptation from D50 to D65
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function D50_to_D65(_){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],_)}const t=[.3457/.3585,1,.2958/.3585];
+/**
+ * Bradford chromatic adaptation from D65 to D50
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+ */
+function D65_to_D50(_){return multiplyMatrices([[1.0479298208405488,.022946793341019088,-.05019222954313557],[.029627815688159344,.990434484573249,-.01707382502938514],[-.009243058152591178,.015055144896577895,.7518742899580008]],_)}
+/**
+ * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0
+ * to gamma corrected form ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function gam_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a>.018053968510807?o*(t*Math.pow(a,.45)-(t-1)):4.5*_}))}
+/**
+ * Convert an array of linear-light a98-rgb in the range 0.0-1.0
+ * to gamma corrected form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+/**
+ * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0
+ * to gamma corrected form
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function gam_P3(_){return gam_sRGB(_)}
+/**
+ * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0
+ * to gamma corrected form.
+ * Transfer curve is gamma 1.8 with a small linear portion.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} sat - Saturation as percentage 0..100
+ * @param {number} light - Lightness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js
+ */
+function HSL_to_sRGB(_){let t=_[0],o=_[1],a=_[2];function f(_){const n=(_+t/30)%12,i=o*Math.min(a,1-a);return a-i*Math.max(-1,Math.min(n-3,9-n,1))}return t%=360,t<0&&(t+=360),o/=100,a/=100,[f(0),f(8),f(4)]}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function Lab_to_LCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(Math.pow(_[1],2)+Math.pow(_[2],2)),t>=0?t:t+360]}
+/**
+ * Convert Lab to D50-adapted XYZ
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function Lab_to_XYZ(_){const o=24389/27,a=216/24389,n=[];n[1]=(_[0]+16)/116,n[0]=_[1]/500+n[1],n[2]=n[1]-_[2]/200;return[Math.pow(n[0],3)>a?Math.pow(n[0],3):(116*n[0]-16)/o,_[0]>8?Math.pow((_[0]+16)/116,3):_[0]/o,Math.pow(n[2],3)>a?Math.pow(n[2],3):(116*n[2]-16)/o].map(((_,o)=>_*t[o]))}
+/**
+ * Convert XYZ to linear-light P3
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function XYZ_to_lin_P3(_){return multiplyMatrices([[446124/178915,-333277/357830,-72051/178915],[-14852/17905,63121/35810,423/17905],[11844/330415,-50337/660830,316169/330415]],_)}
+/**
+ * Convert an array of display-p3 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_P3(_){return lin_sRGB(_)}
+/**
+ * Convert an array of linear-light display-p3 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function lin_P3_to_XYZ(_){return multiplyMatrices([[608311/1250200,189793/714400,198249/1000160],[35783/156275,247089/357200,198249/2500400],[0,32229/714400,5220557/5000800]],_)}
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function LCH_to_Lab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]}
+/**
+ * Convert XYZ to linear-light rec2020
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function XYZ_to_lin_2020(_){return multiplyMatrices([[30757411/17917100,-6372589/17917100,-4539589/17917100],[-.666684351832489,1.616481236634939,467509/29648200],[792561/44930125,-1921689/44930125,.942103121235474]],_)}
+/**
+ * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from
+ * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma
+ * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0
+ * range out of gamut colors may have negative components or components greater
+ * than 1.0 so check for that :)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+/**
+ * Convert an array of rec2020 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ * ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function lin_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a<.08124285829863151?_/4.5:o*Math.pow((a+t-1)/t,1/.45)}))}
+/**
+ * Convert an array of linear-light rec2020 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function lin_2020_to_XYZ(_){return multiplyMatrices([[63426534/99577255,20160776/139408157,47086771/278816314],[26158966/99577255,.677998071518871,8267143/139408157],[0,19567812/697040785,1.0609850577107909]],_)}
+/**
+ * Convert an array of prophoto-rgb values where in-gamut Colors are in the
+ * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is
+ * gamma 1.8 with a small linear portion. Extended transfer function
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */function lin_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<=.03125?_/16:t*Math.pow(o,1.8)}))}
+/**
+ * Convert an array of linear-light prophoto-rgb values to CIE XYZ
+ * using D50 (so no chromatic adaptation needed afterwards)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */function lin_ProPhoto_to_XYZ(_){return multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],_)}
+/**
+ * CMYK is an array of four values in the range [0.0, 1.0] the output is an
+ * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm
+ * does not generate out of gamut colors neither does it generate accurate
+ * simulations of practical CMYK colors
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+/**
+ * Assuming XYZ is relative to D50, convert to CIE Lab
+ * from CIE standard, which now defines these as a rational fraction
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function XYZ_to_Lab(_){const o=_.map(((_,o)=>_/t[o])).map((_=>_>.008856451679035631?Math.cbrt(_):(903.2962962962963*_+16)/116));return[116*o[1]-16,500*(o[0]-o[1]),200*(o[1]-o[2])]}
+/**
+ * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0
+ * range to linear-light display-p3, then to CIE XYZ, then adapt from D65
+ * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */var o=Object.freeze({__proto__:null,D50:t,D50_to_D65:D50_to_D65,D65:[.3127/.329,1,.3583/.329],D65_to_D50:D65_to_D50,HSL_to_sRGB:HSL_to_sRGB,HWB_to_sRGB:
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} white - Whiteness as percentage 0..100
+ * @param {number} black - Blackness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js
+ */
+function HWB_to_sRGB(_){const t=_[0];let o=_[1],a=_[2];if(o/=100,a/=100,o+a>=1){const _=o/(o+a);return[_,_,_]}const n=HSL_to_sRGB([t,100,50]);for(let _=0;_<3;_++)n[_]*=1-o-a,n[_]+=o;return n},LCH_to_Lab:LCH_to_Lab,LCH_to_P3:function LCH_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},LCH_to_rec2020:function LCH_to_rec2020(_){return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(_)))))},LCH_to_sRGB:function LCH_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},Lab_to_LCH:Lab_to_LCH,Lab_to_P3:function Lab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},Lab_to_XYZ:Lab_to_XYZ,Lab_to_sRGB:function Lab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLCH_to_OKLab:OKLCH_to_OKLab,OKLCH_to_P3:function OKLCH_to_P3(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_P3(i),i=gam_P3(i),inGamut(i)?[clip(i),!0]:[mapGamut(n,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLCH_to_sRGB:function OKLCH_to_sRGB(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_sRGB(i),i=gam_sRGB(i),inGamut(i)?clip(i).map((_=>Math.round(255*_))):mapGamut(n,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLab_to_OKLCH:OKLab_to_OKLCH,OKLab_to_P3:function OKLab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLab_to_XYZ:OKLab_to_XYZ,OKLab_to_sRGB:function OKLab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},P3_to_LCH:function P3_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(_)))))},XYZ_to_Lab:XYZ_to_Lab,XYZ_to_OKLab:XYZ_to_OKLab,XYZ_to_lin_2020:XYZ_to_lin_2020,XYZ_to_lin_P3:XYZ_to_lin_P3,XYZ_to_lin_ProPhoto:
+/**
+ * Convert XYZ to linear-light prophoto-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+function XYZ_to_lin_ProPhoto(_){return multiplyMatrices([[1.3457989731028281,-.25558010007997534,-.05110628506753401],[-.5446224939028347,1.5082327413132781,.02053603239147973],[0,0,1.2119675456389454]],_)}
+/**
+ * Convert an array of three XYZ values to u*,v* chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,XYZ_to_lin_a98rgb:
+/**
+ * Convert XYZ to linear-light a98-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+function XYZ_to_lin_a98rgb(_){return multiplyMatrices([[1829569/896150,-506331/896150,-308931/896150],[-851781/878810,1648619/878810,36519/878810],[16779/1248040,-147721/1248040,1266979/1248040]],_)},XYZ_to_lin_sRGB:XYZ_to_lin_sRGB,XYZ_to_uv:function XYZ_to_uv(_){const t=_[0],o=_[1],a=t+15*o+3*_[2];return[4*t/a,9*o/a]}
+/**
+ * Convert an array of three XYZ values to x,y chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,XYZ_to_xy:function XYZ_to_xy(_){const t=_[0],o=_[1],a=t+o+_[2];return[t/a,o/a]},a98_RGB_to_sRGB:function a98_RGB_to_sRGB(_){let t=_.slice();t=lin_a98rgb(t),t=lin_a98rgb_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_50_to_sRGB:function cie_XYZ_50_to_sRGB(_){let t=_.slice();t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_65_to_sRGB:function cie_XYZ_65_to_sRGB(_){let t=_.slice(),o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},gam_2020:gam_2020,gam_P3:gam_P3,gam_ProPhoto:function gam_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>=.001953125?t*Math.pow(o,1/1.8):16*_}))},gam_a98rgb:function gam_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,256/563)}))},gam_sRGB:gam_sRGB,hueToRGB:function hueToRGB(_,t,o){return o<0&&(o+=6),o>=6&&(o-=6),o<1?(t-_)*o+_:o<3?t:o<4?(t-_)*(4-o)+_:_},lin_2020:lin_2020,lin_2020_to_XYZ:lin_2020_to_XYZ,lin_P3:lin_P3,lin_P3_to_XYZ:lin_P3_to_XYZ,lin_ProPhoto:lin_ProPhoto,lin_ProPhoto_to_XYZ:lin_ProPhoto_to_XYZ,lin_a98rgb:lin_a98rgb,lin_a98rgb_to_XYZ:lin_a98rgb_to_XYZ,lin_sRGB:lin_sRGB,lin_sRGB_to_XYZ:lin_sRGB_to_XYZ,naive_CMYK_to_sRGB:function naive_CMYK_to_sRGB(_){const t=_[0],o=_[1],a=_[2],n=_[3];return[1-Math.min(1,t*(1-n)+n),1-Math.min(1,o*(1-n)+n),1-Math.min(1,a*(1-n)+n)]},p3_to_sRGB:function p3_to_sRGB(_){let t=_.slice();t=lin_P3(t),t=lin_P3_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},proPhoto_RGB_to_sRGB:function proPhoto_RGB_to_sRGB(_){let t=_.slice();t=lin_ProPhoto(t),t=lin_ProPhoto_to_XYZ(t),t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}
+/**
+ * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,rec_2020_to_LCH:function rec_2020_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(_)))))},rec_2020_to_sRGB:function rec_2020_to_sRGB(_){let t=_.slice();t=lin_2020(t),t=lin_2020_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},sRGB_linear_to_sRGB:function sRGB_linear_to_sRGB(_){let t=_.slice();t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to
+ * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */,sRGB_to_LCH:function sRGB_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(_)))))},sRGB_to_luminance:sRGB_to_luminance,sRGB_to_sRGB:function sRGB_to_sRGB(_){let t=_.slice();t=lin_sRGB(t),t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}}),a=Object.freeze({__proto__:null,clip:clip,inGamut:inGamut});const n={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]};export{_ as calculations,o as conversions,n as namedColors,a as utils};
diff --git a/packages/color-helpers/dist/named-colors/index.d.ts b/packages/color-helpers/dist/named-colors/index.d.ts
new file mode 100644
index 000000000..1ff07d599
--- /dev/null
+++ b/packages/color-helpers/dist/named-colors/index.d.ts
@@ -0,0 +1 @@
+export declare const namedColors: Record;
diff --git a/packages/color-helpers/dist/utils/clip.d.ts b/packages/color-helpers/dist/utils/clip.d.ts
new file mode 100644
index 000000000..71126b1bb
--- /dev/null
+++ b/packages/color-helpers/dist/utils/clip.d.ts
@@ -0,0 +1,6 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function clip(color: Color): Color;
diff --git a/packages/color-helpers/dist/utils/in-gamut.d.ts b/packages/color-helpers/dist/utils/in-gamut.d.ts
new file mode 100644
index 000000000..917d403f0
--- /dev/null
+++ b/packages/color-helpers/dist/utils/in-gamut.d.ts
@@ -0,0 +1,6 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export declare function inGamut(x: Color): boolean;
diff --git a/packages/color-helpers/dist/utils/index.d.ts b/packages/color-helpers/dist/utils/index.d.ts
new file mode 100644
index 000000000..b73e4598c
--- /dev/null
+++ b/packages/color-helpers/dist/utils/index.d.ts
@@ -0,0 +1,2 @@
+export * from './clip';
+export * from './in-gamut';
diff --git a/packages/color-helpers/package.json b/packages/color-helpers/package.json
new file mode 100644
index 000000000..a492c1678
--- /dev/null
+++ b/packages/color-helpers/package.json
@@ -0,0 +1,73 @@
+{
+ "name": "@csstools/color-helpers",
+ "description": "Color helpers to ease transformation between formats, gamut, etc",
+ "version": "0.0.0",
+ "contributors": [
+ {
+ "name": "Antonio Laguna",
+ "email": "antonio@laguna.es",
+ "url": "https://antonio.laguna.es"
+ },
+ {
+ "name": "Romain Menke ",
+ "email": "romainmenke@gmail.com"
+ }
+ ],
+ "license": "CC0-1.0",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ },
+ "engines": {
+ "node": "^14 || ^16 || >=18"
+ },
+ "main": "dist/index.cjs",
+ "module": "dist/index.mjs",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": "./dist/index.mjs",
+ "require": "./dist/index.cjs",
+ "default": "./dist/index.mjs"
+ }
+ },
+ "files": [
+ "CHANGELOG.md",
+ "LICENSE.md",
+ "README.md",
+ "dist"
+ ],
+ "scripts": {
+ "prebuild": "npm run clean",
+ "build": "rollup -c ../../rollup/default.mjs",
+ "check-sources-integrity": "node ./scripts/check-changes.mjs",
+ "check-sources-integrity:rewrite": "REWRITE_HASHES=true node ./scripts/check-changes.mjs",
+ "clean": "node -e \"fs.rmSync('./dist', { recursive: true, force: true }); fs.mkdirSync('./dist');\"",
+ "lint": "npm run lint:eslint && npm run lint:package-json",
+ "lint:eslint": "eslint ./src --ext .js --ext .ts --ext .mjs --no-error-on-unmatched-pattern",
+ "lint:package-json": "node ../../.github/bin/format-package-json.mjs",
+ "prepublishOnly": "npm run clean && npm run build && npm run test",
+ "stryker": "stryker run --logLevel error",
+ "test": "npm run test:exports",
+ "test:exports": "node ./test/_import.mjs && node ./test/_require.cjs"
+ },
+ "homepage": "https://github.com/csstools/postcss-plugins/tree/main/packages/color-helpers#readme",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/csstools/postcss-plugins.git",
+ "directory": "packages/color-helpers"
+ },
+ "bugs": "https://github.com/csstools/postcss-plugins/issues",
+ "keywords": [
+ "colors",
+ "css"
+ ],
+ "volta": {
+ "extends": "../../package.json"
+ },
+ "eslintConfig": {
+ "rules": {
+ "@typescript-eslint/no-loss-of-precision": "off"
+ }
+ }
+}
diff --git a/packages/color-helpers/scripts/check-changes.mjs b/packages/color-helpers/scripts/check-changes.mjs
new file mode 100644
index 000000000..1de24d762
--- /dev/null
+++ b/packages/color-helpers/scripts/check-changes.mjs
@@ -0,0 +1,45 @@
+import crypto from 'crypto';
+import path from 'path';
+import { URL } from 'url';
+import fs from 'fs/promises';
+
+const __dirname = new URL('.', import.meta.url).pathname;
+const hashesPath = path.resolve(__dirname, './hashes.json');
+const hashesFile = await fs.readFile(hashesPath, 'utf8').then(JSON.parse);
+const isRewriting = process.env.REWRITE_HASHES;
+
+const WATCHED_FILES = [
+ 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/utilities.js',
+ 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/conversions.js',
+ 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/deltaEOK.js',
+ 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/multiply-matrices.js',
+ 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/hslToRgb.js',
+ 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/hwbToRgb.js',
+];
+
+const newHashes = await Promise.all(WATCHED_FILES.map(async urlPath => {
+ const content = await fetch(urlPath).then(response => response.text());
+ const hash = crypto.createHash('md5');
+ hash.update(content, 'utf8');
+ return hash.digest('hex');
+}));
+
+const changes = newHashes
+ .map((hash, index) => [hash, WATCHED_FILES[index]])
+ .filter(([hash], index) => hashesFile[index] !== hash)
+ .map(([,file]) => file);
+
+if (changes.length) {
+ console.log('Changes have been detected in the following files:');
+ changes.forEach(change => console.log('└ %s', change));
+
+ if (isRewriting) {
+ await fs.writeFile(hashesPath, JSON.stringify(newHashes, null, '\t'));
+ console.log('Changes have been updated.');
+ process.exit(0);
+ } else {
+ process.exit(1);
+ }
+}
+
+console.log('No changes detected');
diff --git a/packages/color-helpers/scripts/hashes.json b/packages/color-helpers/scripts/hashes.json
new file mode 100644
index 000000000..f4ac63379
--- /dev/null
+++ b/packages/color-helpers/scripts/hashes.json
@@ -0,0 +1,8 @@
+[
+ "384d52db3fcd98381e18743e1eba590a",
+ "6014c79b98dfe166e3e02232d8c3beaa",
+ "094c9859b0960c4e394947cc4832b54f",
+ "c9e2f2a3b2cba543a01cb8aa5d77c04a",
+ "f28e9d179704b95a9cd40fbf5b5f1164",
+ "a0b388982712b1849c991ce0e323828e"
+]
\ No newline at end of file
diff --git a/plugins/postcss-color-function/src/css-color-4/LICENSE.md b/packages/color-helpers/src/calculations/LICENSE.md
similarity index 100%
rename from plugins/postcss-color-function/src/css-color-4/LICENSE.md
rename to packages/color-helpers/src/calculations/LICENSE.md
diff --git a/packages/color-helpers/src/calculations/binary-search-gamut.ts b/packages/color-helpers/src/calculations/binary-search-gamut.ts
new file mode 100644
index 000000000..b170fe181
--- /dev/null
+++ b/packages/color-helpers/src/calculations/binary-search-gamut.ts
@@ -0,0 +1,28 @@
+import { clip } from 'utils/clip';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { deltaEOK } from 'calculations/delta-EOK';
+
+export function binarySearchGamut(
+ startOKLCH: Color,
+ toDestination: (x: Color) => Color,
+ fromDestination: (x: Color) => Color,
+): Color {
+ let min = 0;
+ let max = startOKLCH[1];
+ const current = startOKLCH;
+
+ while (max - min > 0.0001) {
+ const clipped = clip(toDestination(current));
+ const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped)));
+ // are we inside the gamut (or very close to the boundary, outside)
+ if (deltaE - 0.02 < 0.0001) {
+ min = current[1];
+ } else {
+ max = current[1];
+ }
+ // binary search
+ current[1] = (max + min) / 2;
+ }
+
+ return clip(toDestination([...current]));
+}
diff --git a/packages/color-helpers/src/calculations/contrast.ts b/packages/color-helpers/src/calculations/contrast.ts
new file mode 100644
index 000000000..b8c12e60d
--- /dev/null
+++ b/packages/color-helpers/src/calculations/contrast.ts
@@ -0,0 +1,23 @@
+/**
+ * Return WCAG 2.1 contrast ratio for two sRGB values given as arrays
+ *
+ * of 0.0 to 1.0
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ * @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
+ */
+import { sRGB_to_luminance } from 'conversions/srgb-to-luminance';
+
+export function contrast(RGB1: Color, RGB2: Color): number {
+ const L1 = sRGB_to_luminance(RGB1);
+ const L2 = sRGB_to_luminance(RGB2);
+
+ if (L1 > L2) {
+ return (L1 + 0.05) / (L2 + 0.05);
+ }
+
+ return (L2 + 0.05) / (L1 + 0.05);
+}
diff --git a/plugins/postcss-oklab-function/src/css-color-4/deltaEOK.ts b/packages/color-helpers/src/calculations/delta-EOK.ts
similarity index 53%
rename from plugins/postcss-oklab-function/src/css-color-4/deltaEOK.ts
rename to packages/color-helpers/src/calculations/delta-EOK.ts
index ce023047e..c6a9c208a 100644
--- a/plugins/postcss-oklab-function/src/css-color-4/deltaEOK.ts
+++ b/packages/color-helpers/src/calculations/delta-EOK.ts
@@ -1,16 +1,16 @@
/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ * @description Calculate deltaE OK which is the simple root sum of squares
+ * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1
+ * @return {number} How different a color sample is from reference
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*
* @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
*/
-
-// Calculate deltaE OK
-// simple root sum of squares
-type color = [number, number, number];
-export function deltaEOK(reference: color, sample: color): number {
+export function deltaEOK(reference: Color, sample: Color): number {
// Given reference and sample are both in OKLab
const [L1, a1, b1] = reference;
const [L2, a2, b2] = sample;
diff --git a/packages/color-helpers/src/calculations/index.ts b/packages/color-helpers/src/calculations/index.ts
new file mode 100644
index 000000000..3db911c00
--- /dev/null
+++ b/packages/color-helpers/src/calculations/index.ts
@@ -0,0 +1,6 @@
+export * from './binary-search-gamut';
+export * from './polar-premultiply';
+export * from './map-gamut';
+export * from './delta-EOK';
+export * from './contrast';
+export * from './multiply-matrices';
diff --git a/packages/color-helpers/src/calculations/map-gamut.ts b/packages/color-helpers/src/calculations/map-gamut.ts
new file mode 100644
index 000000000..78de6f0e1
--- /dev/null
+++ b/packages/color-helpers/src/calculations/map-gamut.ts
@@ -0,0 +1,5 @@
+import { binarySearchGamut } from 'calculations/binary-search-gamut';
+
+export function mapGamut(startOKLCH: Color, toDestination: (x: Color) => Color, fromDestination: (x: Color) => Color): Color {
+ return binarySearchGamut(startOKLCH, toDestination, fromDestination);
+}
diff --git a/plugins/postcss-color-function/src/css-color-4/multiply-matrices.ts b/packages/color-helpers/src/calculations/multiply-matrices.ts
similarity index 94%
rename from plugins/postcss-color-function/src/css-color-4/multiply-matrices.ts
rename to packages/color-helpers/src/calculations/multiply-matrices.ts
index e8a827309..4590dda6e 100644
--- a/plugins/postcss-color-function/src/css-color-4/multiply-matrices.ts
+++ b/packages/color-helpers/src/calculations/multiply-matrices.ts
@@ -3,8 +3,7 @@
* Warning: No error handling for incompatible dimensions!
* @author Lea Verou 2020 MIT License
*
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*
diff --git a/packages/color-helpers/src/calculations/polar-premultiply.ts b/packages/color-helpers/src/calculations/polar-premultiply.ts
new file mode 100644
index 000000000..e17d7664f
--- /dev/null
+++ b/packages/color-helpers/src/calculations/polar-premultiply.ts
@@ -0,0 +1,17 @@
+/**
+ * Given a color in a cylindical polar colorspace and an alpha value
+ * return the premultiplied form. The index says which entry in the
+ * color array corresponds to hue angle for example, in OKLCH it
+ * would be 2 while in HSL it would be 0
+ *
+ * @param color
+ * @param alpha
+ * @param hueIndex
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function polarPremultiply(color: Color, alpha: number, hueIndex: number): Color {
+ return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/LICENSE.md b/packages/color-helpers/src/conversions/LICENSE.md
new file mode 100644
index 000000000..0913e1881
--- /dev/null
+++ b/packages/color-helpers/src/conversions/LICENSE.md
@@ -0,0 +1,3 @@
+Some documents in this Directory are licensed by contributors
+under the
+[W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software).
diff --git a/packages/color-helpers/src/conversions/a98-rgb-to-srgb.ts b/packages/color-helpers/src/conversions/a98-rgb-to-srgb.ts
new file mode 100644
index 000000000..09564e2c2
--- /dev/null
+++ b/packages/color-helpers/src/conversions/a98-rgb-to-srgb.ts
@@ -0,0 +1,54 @@
+import { lin_a98rgb } from 'conversions/lin-a98rgb';
+import { lin_a98rgb_to_XYZ } from 'conversions/lin-a98rgb-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+
+export function a98_RGB_to_sRGB(a98: Color): Color {
+ let conversion = a98.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ conversion = lin_a98rgb(conversion);
+ conversion = lin_a98rgb_to_XYZ(conversion);
+
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/cie-xyz-50-to-srgb.ts b/packages/color-helpers/src/conversions/cie-xyz-50-to-srgb.ts
new file mode 100644
index 000000000..c713b0506
--- /dev/null
+++ b/packages/color-helpers/src/conversions/cie-xyz-50-to-srgb.ts
@@ -0,0 +1,52 @@
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { D50_to_D65 } from 'conversions/d50-to-d65';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+
+export function cie_XYZ_50_to_sRGB(xyz: Color): Color {
+ let conversion = xyz.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ conversion = D50_to_D65(conversion);
+
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/cie-xyz-65-to-srgb.ts b/packages/color-helpers/src/conversions/cie-xyz-65-to-srgb.ts
new file mode 100644
index 000000000..6d444bb3e
--- /dev/null
+++ b/packages/color-helpers/src/conversions/cie-xyz-65-to-srgb.ts
@@ -0,0 +1,49 @@
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+
+export function cie_XYZ_65_to_sRGB(xyz: Color): Color {
+ let conversion = xyz.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/constants.ts b/packages/color-helpers/src/conversions/constants.ts
new file mode 100644
index 000000000..04b1a4cbe
--- /dev/null
+++ b/packages/color-helpers/src/conversions/constants.ts
@@ -0,0 +1,3 @@
+// standard white points, defined by 4-figure CIE x,y chromaticities
+export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
+export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290];
diff --git a/packages/color-helpers/src/conversions/d50-to-d65.ts b/packages/color-helpers/src/conversions/d50-to-d65.ts
new file mode 100644
index 000000000..1af0962a4
--- /dev/null
+++ b/packages/color-helpers/src/conversions/d50-to-d65.ts
@@ -0,0 +1,18 @@
+/**
+ * Bradford chromatic adaptation from D50 to D65
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+export function D50_to_D65(XYZ: Color): Color {
+ const M = [
+ [0.9554734527042182, -0.023098536874261423, 0.0632593086610217],
+ [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008],
+ [0.012314001688319899, -0.020507696433477912, 1.3303659366080753],
+ ];
+
+ return multiplyMatrices(M, XYZ) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/d65-to-d50.ts b/packages/color-helpers/src/conversions/d65-to-d50.ts
new file mode 100644
index 000000000..fea324afd
--- /dev/null
+++ b/packages/color-helpers/src/conversions/d65-to-d50.ts
@@ -0,0 +1,23 @@
+/**
+ * Bradford chromatic adaptation from D65 to D50
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+ */
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+export function D65_to_D50(XYZ: Color): Color {
+ // The matrix below is the result of three operations:
+ // - convert from XYZ to retinal cone domain
+ // - scale components from one reference white to another
+ // - convert back to XYZ
+ const M = [
+ [1.0479298208405488, 0.022946793341019088, -0.05019222954313557],
+ [0.029627815688159344, 0.990434484573249, -0.01707382502938514],
+ [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008],
+ ];
+
+ return multiplyMatrices(M, XYZ) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/gam-2020.ts b/packages/color-helpers/src/conversions/gam-2020.ts
new file mode 100644
index 000000000..02d6f71a3
--- /dev/null
+++ b/packages/color-helpers/src/conversions/gam-2020.ts
@@ -0,0 +1,23 @@
+/**
+ * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0
+ * to gamma corrected form ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function gam_2020(RGB: Color): Color {
+ const α = 1.09929682680944;
+ const β = 0.018053968510807;
+
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ if (abs > β) {
+ return sign * (α * Math.pow(abs, 0.45) - (α - 1));
+ }
+
+ return 4.5 * val;
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/gam-a98rgb.ts b/packages/color-helpers/src/conversions/gam-a98rgb.ts
new file mode 100644
index 000000000..9981f9d53
--- /dev/null
+++ b/packages/color-helpers/src/conversions/gam-a98rgb.ts
@@ -0,0 +1,16 @@
+/**
+ * Convert an array of linear-light a98-rgb in the range 0.0-1.0
+ * to gamma corrected form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function gam_a98rgb(RGB: Color): Color {
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ return sign * Math.pow(abs, 256 / 563);
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/gam-p3.ts b/packages/color-helpers/src/conversions/gam-p3.ts
new file mode 100644
index 000000000..8eaf70671
--- /dev/null
+++ b/packages/color-helpers/src/conversions/gam-p3.ts
@@ -0,0 +1,13 @@
+import { gam_sRGB } from 'conversions/gam-srgb';
+
+/**
+ * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0
+ * to gamma corrected form
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function gam_P3(RGB: Color): Color {
+ return gam_sRGB(RGB); // same as sRGB
+}
diff --git a/packages/color-helpers/src/conversions/gam-pro-photo.ts b/packages/color-helpers/src/conversions/gam-pro-photo.ts
new file mode 100644
index 000000000..0f00a0806
--- /dev/null
+++ b/packages/color-helpers/src/conversions/gam-pro-photo.ts
@@ -0,0 +1,24 @@
+
+/**
+ * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0
+ * to gamma corrected form.
+ * Transfer curve is gamma 1.8 with a small linear portion.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function gam_ProPhoto(RGB: Color): Color {
+ // TODO for negative values, extend linear portion on reflection of axis, then add pow below that
+ const Et = 1 / 512;
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ if (abs >= Et) {
+ return sign * Math.pow(abs, 1 / 1.8);
+ }
+
+ return 16 * val;
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/gam-srgb.ts b/packages/color-helpers/src/conversions/gam-srgb.ts
new file mode 100644
index 000000000..150de0bd3
--- /dev/null
+++ b/packages/color-helpers/src/conversions/gam-srgb.ts
@@ -0,0 +1,24 @@
+/**
+ * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form
+ * Extended transfer function:
+ * For negative values, linear portion extends on reflection
+ * of axis, then uses reflected pow below that
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */
+export function gam_sRGB(RGB: Color): Color {
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ if (abs > 0.0031308) {
+ return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055);
+ }
+
+ return 12.92 * val;
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/hsl-to-srgb.ts b/packages/color-helpers/src/conversions/hsl-to-srgb.ts
new file mode 100644
index 000000000..a7eadc5dd
--- /dev/null
+++ b/packages/color-helpers/src/conversions/hsl-to-srgb.ts
@@ -0,0 +1,34 @@
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} sat - Saturation as percentage 0..100
+ * @param {number} light - Lightness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js
+ */
+export function HSL_to_sRGB(HSL: Color) {
+ let hue = HSL[0];
+ let sat = HSL[1];
+ let light = HSL[2];
+
+ hue = hue % 360;
+
+ if (hue < 0) {
+ hue += 360;
+ }
+
+ sat /= 100;
+ light /= 100;
+
+ function f(n) {
+ const k = (n + hue / 30) % 12;
+ const a = sat * Math.min(light, 1 - light);
+ return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
+ }
+
+ return [f(0), f(8), f(4)];
+}
diff --git a/packages/color-helpers/src/conversions/hue-to-rgb.ts b/packages/color-helpers/src/conversions/hue-to-rgb.ts
new file mode 100644
index 000000000..b1cc563d3
--- /dev/null
+++ b/packages/color-helpers/src/conversions/hue-to-rgb.ts
@@ -0,0 +1,25 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function hueToRGB(t1: number, t2: number, hue: number): number {
+ if (hue < 0) {
+ hue += 6;
+ }
+ if (hue >= 6) {
+ hue -= 6;
+ }
+
+ if (hue < 1) {
+ return (t2 - t1) * hue + t1;
+ } else if (hue < 3) {
+ return t2;
+ } else if (hue < 4) {
+ return (t2 - t1) * (4 - hue) + t1;
+ } else {
+ return t1;
+ }
+}
diff --git a/packages/color-helpers/src/conversions/hwb-to-srgb.ts b/packages/color-helpers/src/conversions/hwb-to-srgb.ts
new file mode 100644
index 000000000..b1bd64e91
--- /dev/null
+++ b/packages/color-helpers/src/conversions/hwb-to-srgb.ts
@@ -0,0 +1,34 @@
+import { HSL_to_sRGB } from './hsl-to-srgb';
+
+/**
+ * @param {number} hue - Hue as degrees 0..360
+ * @param {number} white - Whiteness as percentage 0..100
+ * @param {number} black - Blackness as percentage 0..100
+ * @return {number[]} Array of RGB components 0..1
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js
+ */
+export function HWB_to_sRGB(HWB: Color) {
+ const hue = HWB[0];
+ let white = HWB[1];
+ let black = HWB[2];
+
+ white /= 100;
+ black /= 100;
+ if (white + black >= 1) {
+ const gray = white / (white + black);
+ return [gray, gray, gray];
+ }
+
+ const rgb = HSL_to_sRGB([hue, 100, 50]);
+ for (let i = 0; i < 3; i++) {
+ rgb[i] *= (1 - white - black);
+ rgb[i] += white;
+ }
+
+ return rgb;
+}
diff --git a/packages/color-helpers/src/conversions/index.ts b/packages/color-helpers/src/conversions/index.ts
new file mode 100644
index 000000000..539f7ab8f
--- /dev/null
+++ b/packages/color-helpers/src/conversions/index.ts
@@ -0,0 +1,58 @@
+export * from './a98-rgb-to-srgb';
+export * from './cie-xyz-50-to-srgb';
+export * from './cie-xyz-65-to-srgb';
+export * from './constants';
+export * from './d50-to-d65';
+export * from './d65-to-d50';
+export * from './gam-2020';
+export * from './gam-a98rgb';
+export * from './gam-p3';
+export * from './gam-pro-photo';
+export * from './gam-srgb';
+export * from './hsl-to-srgb';
+export * from './hue-to-rgb';
+export * from './hwb-to-srgb';
+export * from './lab-to-lch';
+export * from './lab-to-p3';
+export * from './lab-to-srgb';
+export * from './lab-to-xyz';
+export * from './lch-to-lab';
+export * from './lch-to-p3';
+export * from './lch-to-rec2020';
+export * from './lch-to-srgb';
+export * from './lin-2020';
+export * from './lin-2020-to-xyz';
+export * from './lin-a98rgb';
+export * from './lin-a98rgb-to-xyz';
+export * from './lin-p3';
+export * from './lin-p3-to-xyz';
+export * from './lin-pro-photo';
+export * from './lin-pro-photo-to-xyz';
+export * from './lin-srgb';
+export * from './lin-srgb-to-xyz';
+export * from './naive-cmyk-to-srgb';
+export * from './oklab-to-oklch';
+export * from './oklab-to-p3';
+export * from './oklab-to-srgb';
+export * from './oklab-to-xyz';
+export * from './oklch-to-oklab';
+export * from './oklch-to-p3';
+export * from './oklch-to-srgb';
+export * from './p3-to-lch';
+export * from './p3-to-srgb';
+export * from './pro-photo-rgb-to-srgb';
+export * from './rec2020-to-lch';
+export * from './rec2020-to-srgb';
+export * from './srgb-linear-to-srgb';
+export * from './srgb-to-lch';
+export * from './srgb-to-luminance';
+export * from './srgb-to-srgb';
+export * from './xyz-to-lab';
+export * from './xyz-to-lin-2020';
+export * from './xyz-to-lin-a98rgb';
+export * from './xyz-to-lin-p3';
+export * from './xyz-to-lin-pro-photo';
+export * from './xyz-to-lin-srgb';
+export * from './xyz-to-oklab';
+export * from './xyz-to-uv';
+export * from './xyz-to-xy';
diff --git a/packages/color-helpers/src/conversions/lab-to-lch.ts b/packages/color-helpers/src/conversions/lab-to-lch.ts
new file mode 100644
index 000000000..2fb0c496c
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lab-to-lch.ts
@@ -0,0 +1,14 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function Lab_to_LCH(Lab: Color): Color {
+ // Convert to polar form
+ const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI;
+ return [
+ Lab[0], // L is still L
+ Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma
+ hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
+ ];
+}
diff --git a/plugins/postcss-lab-function/src/convert-lab-to-display-p3.ts b/packages/color-helpers/src/conversions/lab-to-p3.ts
similarity index 57%
rename from plugins/postcss-lab-function/src/convert-lab-to-display-p3.ts
rename to packages/color-helpers/src/conversions/lab-to-p3.ts
index 848c64964..bc3b5f0be 100644
--- a/plugins/postcss-lab-function/src/convert-lab-to-display-p3.ts
+++ b/packages/color-helpers/src/conversions/lab-to-p3.ts
@@ -1,9 +1,18 @@
-import { D50_to_D65, gam_P3, Lab_to_XYZ, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
+import { Lab_to_XYZ } from 'conversions/lab-to-xyz';
+import { D50_to_D65 } from 'conversions/d50-to-d65';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3';
+import { gam_P3 } from 'conversions/gam-p3';
+import { clip } from 'utils/clip';
+import { inGamut } from 'utils/in-gamut';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_P3 } from 'conversions/lin-p3';
+import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz';
-type color = [number, number, number];
-
-export function labToDisplayP3(labRaw: color): [color, boolean] {
+export function Lab_to_P3(labRaw: Color): [Color, boolean] {
const [labLRaw, labARaw, labBRaw] = labRaw;
const labL = Math.max(
@@ -29,22 +38,22 @@ export function labToDisplayP3(labRaw: color): [color, boolean] {
const lab = [labL, labA, labB];
- let conversion = lab as color;
+ let conversion = lab as Color;
// https://drafts.csswg.org/css-color-4/#oklab-lab-to-predefined
// 1. Convert Lab to(D50 - adapted) XYZ
conversion = Lab_to_XYZ(conversion);
- let oklch = conversion.slice() as color;
+ let oklch = conversion.slice() as Color;
oklch = D50_to_D65(oklch);
oklch = XYZ_to_OKLab(oklch);
oklch = OKLab_to_OKLCH(oklch);
if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
+ oklch = [0, 0, 0] as Color;
}
if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
+ oklch = [1, 0, 0] as Color;
}
// 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step.
@@ -58,12 +67,12 @@ export function labToDisplayP3(labRaw: color): [color, boolean] {
return [clip(conversion), true];
}
- return [mapGamut(oklch, (x: color) => {
+ return [mapGamut(oklch, (x: Color) => {
x = OKLCH_to_OKLab(x);
x = OKLab_to_XYZ(x);
x = XYZ_to_lin_P3(x);
return gam_P3(x);
- }, (x: color) => {
+ }, (x: Color) => {
x = lin_P3(x);
x = lin_P3_to_XYZ(x);
x = XYZ_to_OKLab(x);
diff --git a/plugins/postcss-lab-function/src/convert-lab-to-srgb.ts b/packages/color-helpers/src/conversions/lab-to-srgb.ts
similarity index 58%
rename from plugins/postcss-lab-function/src/convert-lab-to-srgb.ts
rename to packages/color-helpers/src/conversions/lab-to-srgb.ts
index b19cefa55..739346759 100644
--- a/plugins/postcss-lab-function/src/convert-lab-to-srgb.ts
+++ b/packages/color-helpers/src/conversions/lab-to-srgb.ts
@@ -1,9 +1,18 @@
-import { D50_to_D65, gam_sRGB, Lab_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
+import { Lab_to_XYZ } from 'conversions/lab-to-xyz';
+import { D50_to_D65 } from 'conversions/d50-to-d65';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
-type color = [number, number, number];
-
-export function labToSRgb(labRaw: color): color {
+export function Lab_to_sRGB(labRaw: Color): Color {
const [labLRaw, labARaw, labBRaw] = labRaw;
const labL = Math.max(
@@ -29,22 +38,22 @@ export function labToSRgb(labRaw: color): color {
const lab = [labL, labA, labB];
- let conversion = lab as color;
+ let conversion = lab as Color;
// https://drafts.csswg.org/css-color-4/#oklab-lab-to-predefined
// 1. Convert Lab to(D50 - adapted) XYZ
conversion = Lab_to_XYZ(conversion);
- let oklch = conversion.slice() as color;
+ let oklch = conversion.slice() as Color;
oklch = D50_to_D65(oklch);
oklch = XYZ_to_OKLab(oklch);
oklch = OKLab_to_OKLCH(oklch);
if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
+ oklch = [0, 0, 0] as Color;
}
if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
+ oklch = [1, 0, 0] as Color;
}
// 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step.
@@ -57,20 +66,20 @@ export function labToSRgb(labRaw: color): color {
if (inGamut(conversion)) {
return clip(conversion).map((x) => {
return Math.round(x * 255);
- }) as color;
+ }) as Color;
}
- return mapGamut(oklch, (x: color) => {
+ return mapGamut(oklch, (x: Color) => {
x = OKLCH_to_OKLab(x);
x = OKLab_to_XYZ(x);
x = XYZ_to_lin_sRGB(x);
return gam_sRGB(x);
- }, (x: color) => {
+ }, (x: Color) => {
x = lin_sRGB(x);
x = lin_sRGB_to_XYZ(x);
x = XYZ_to_OKLab(x);
return OKLab_to_OKLCH(x);
}).map((x) => {
return Math.round(x * 255);
- }) as color;
+ }) as Color;
}
diff --git a/packages/color-helpers/src/conversions/lab-to-xyz.ts b/packages/color-helpers/src/conversions/lab-to-xyz.ts
new file mode 100644
index 000000000..f040e3bb6
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lab-to-xyz.ts
@@ -0,0 +1,30 @@
+/**
+ * Convert Lab to D50-adapted XYZ
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+import { D50 } from 'conversions/constants';
+
+export function Lab_to_XYZ(Lab: Color): Color {
+ const κ = 24389 / 27; // 29^3/3^3
+ const ε = 216 / 24389; // 6^3/29^3
+ const f = [];
+
+ // compute f, starting with the luminance-related term
+ f[1] = (Lab[0] + 16) / 116;
+ f[0] = Lab[1] / 500 + f[1];
+ f[2] = f[1] - Lab[2] / 200;
+
+ // compute xyz
+ const xyz = [
+ Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ,
+ Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ,
+ Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ,
+ ];
+
+ // Compute XYZ by scaling xyz by reference white
+ return xyz.map((value, i) => value * D50[i]) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lch-to-lab.ts b/packages/color-helpers/src/conversions/lch-to-lab.ts
new file mode 100644
index 000000000..9c97e5346
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lch-to-lab.ts
@@ -0,0 +1,13 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function LCH_to_Lab(LCH: Color): Color {
+ // Convert from polar form
+ return [
+ LCH[0], // L is still L
+ LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a
+ LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b
+ ];
+}
diff --git a/plugins/postcss-lab-function/src/convert-lch-to-display-p3.ts b/packages/color-helpers/src/conversions/lch-to-p3.ts
similarity index 52%
rename from plugins/postcss-lab-function/src/convert-lch-to-display-p3.ts
rename to packages/color-helpers/src/conversions/lch-to-p3.ts
index b622a195e..9c32fddeb 100644
--- a/plugins/postcss-lab-function/src/convert-lch-to-display-p3.ts
+++ b/packages/color-helpers/src/conversions/lch-to-p3.ts
@@ -1,9 +1,19 @@
-import { D50_to_D65, gam_P3, Lab_to_XYZ, LCH_to_Lab, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
+import { gam_P3 } from 'conversions/gam-p3';
+import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3';
+import { D50_to_D65 } from 'conversions/d50-to-d65';
+import { Lab_to_XYZ } from 'conversions/lab-to-xyz';
+import { LCH_to_Lab } from 'conversions/lch-to-lab';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_P3 } from 'conversions/lin-p3';
+import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
-type color = [number, number, number];
-
-export function lchToDisplayP3(lchRaw: color): [color, boolean] {
+export function LCH_to_P3(lchRaw: Color): [Color, boolean] {
const [lchLRaw, lchCRaw, lchHRaw] = lchRaw;
const lchL = Math.max(
@@ -11,25 +21,23 @@ export function lchToDisplayP3(lchRaw: color): [color, boolean] {
0,
);
- const lch = [lchL, lchCRaw, lchHRaw % 360] as color;
-
- let conversion = lch;
+ let conversion = [ lchL, lchCRaw, lchHRaw % 360 ] as Color;
conversion = LCH_to_Lab(conversion);
// https://www.w3.org/TR/css-color-4/#oklab-lab-to-predefined
// 1. Convert Lab to(D50 - adapted) XYZ
conversion = Lab_to_XYZ(conversion);
- let oklch = conversion.slice() as color;
+ let oklch = conversion.slice() as Color;
oklch = D50_to_D65(oklch);
oklch = XYZ_to_OKLab(oklch);
oklch = OKLab_to_OKLCH(oklch);
if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
+ oklch = [0, 0, 0] as Color;
}
if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
+ oklch = [1, 0, 0] as Color;
}
// 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step.
@@ -43,12 +51,12 @@ export function lchToDisplayP3(lchRaw: color): [color, boolean] {
return [clip(conversion), true];
}
- return [mapGamut(oklch, (x: color) => {
+ return [mapGamut(oklch, (x: Color) => {
x = OKLCH_to_OKLab(x);
x = OKLab_to_XYZ(x);
x = XYZ_to_lin_P3(x);
return gam_P3(x);
- }, (x: color) => {
+ }, (x: Color) => {
x = lin_P3(x);
x = lin_P3_to_XYZ(x);
x = XYZ_to_OKLab(x);
diff --git a/packages/color-helpers/src/conversions/lch-to-rec2020.ts b/packages/color-helpers/src/conversions/lch-to-rec2020.ts
new file mode 100644
index 000000000..4b6efe771
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lch-to-rec2020.ts
@@ -0,0 +1,22 @@
+import { gam_2020 } from 'conversions/gam-2020';
+import { XYZ_to_lin_2020 } from 'conversions/xyz-to-lin-2020';
+import { D50_to_D65 } from 'conversions/d50-to-d65';
+import { Lab_to_XYZ } from 'conversions/lab-to-xyz';
+import { LCH_to_Lab } from 'conversions/lch-to-lab';
+
+/**
+ * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from
+ * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma
+ * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0
+ * range out of gamut colors may have negative components or components greater
+ * than 1.0 so check for that :)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function LCH_to_rec2020(LCH: Color): Color {
+ return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
+}
diff --git a/plugins/postcss-lab-function/src/convert-lch-to-srgb.ts b/packages/color-helpers/src/conversions/lch-to-srgb.ts
similarity index 54%
rename from plugins/postcss-lab-function/src/convert-lch-to-srgb.ts
rename to packages/color-helpers/src/conversions/lch-to-srgb.ts
index 0648f6506..1c391b7a2 100644
--- a/plugins/postcss-lab-function/src/convert-lch-to-srgb.ts
+++ b/packages/color-helpers/src/conversions/lch-to-srgb.ts
@@ -1,9 +1,19 @@
-import { D50_to_D65, gam_sRGB, Lab_to_XYZ, LCH_to_Lab, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { D50_to_D65 } from 'conversions/d50-to-d65';
+import { Lab_to_XYZ } from 'conversions/lab-to-xyz';
+import { LCH_to_Lab } from 'conversions/lch-to-lab';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
-type color = [number, number, number];
-
-export function lchToSRgb(lchRaw: color): color {
+export function LCH_to_sRGB(lchRaw: Color): Color {
const [lchLRaw, lchCRaw, lchHRaw] = lchRaw;
const lchL = Math.max(
@@ -11,7 +21,7 @@ export function lchToSRgb(lchRaw: color): color {
0,
);
- const lch = [lchL, lchCRaw, lchHRaw % 360] as color;
+ const lch = [lchL, lchCRaw, lchHRaw % 360] as Color;
let conversion = lch;
conversion = LCH_to_Lab(conversion);
@@ -20,16 +30,16 @@ export function lchToSRgb(lchRaw: color): color {
// 1. Convert Lab to(D50 - adapted) XYZ
conversion = Lab_to_XYZ(conversion);
- let oklch = conversion.slice() as color;
+ let oklch = conversion.slice() as Color;
oklch = D50_to_D65(oklch);
oklch = XYZ_to_OKLab(oklch);
oklch = OKLab_to_OKLCH(oklch);
if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
+ oklch = [0, 0, 0] as Color;
}
if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
+ oklch = [1, 0, 0] as Color;
}
// 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step.
@@ -42,20 +52,20 @@ export function lchToSRgb(lchRaw: color): color {
if (inGamut(conversion)) {
return clip(conversion).map((x) => {
return Math.round(x * 255);
- }) as color;
+ }) as Color;
}
- return mapGamut(oklch, (x: color) => {
+ return mapGamut(oklch, (x: Color) => {
x = OKLCH_to_OKLab(x);
x = OKLab_to_XYZ(x);
x = XYZ_to_lin_sRGB(x);
return gam_sRGB(x);
- }, (x: color) => {
+ }, (x: Color) => {
x = lin_sRGB(x);
x = lin_sRGB_to_XYZ(x);
x = XYZ_to_OKLab(x);
return OKLab_to_OKLCH(x);
}).map((x) => {
return Math.round(x * 255);
- }) as color;
+ }) as Color;
}
diff --git a/packages/color-helpers/src/conversions/lin-2020-to-xyz.ts b/packages/color-helpers/src/conversions/lin-2020-to-xyz.ts
new file mode 100644
index 000000000..4e03581fe
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-2020-to-xyz.ts
@@ -0,0 +1,22 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert an array of linear-light rec2020 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export function lin_2020_to_XYZ(rgb: Color): Color {
+ const M = [
+ [63426534 / 99577255, 20160776 / 139408157, 47086771 / 278816314],
+ [26158966 / 99577255, 472592308 / 697040785, 8267143 / 139408157],
+ [0 / 1, 19567812 / 697040785, 295819943 / 278816314],
+ ];
+ // 0 is actually calculated as 4.994106574466076e-17
+
+ return multiplyMatrices(M, rgb) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-2020.ts b/packages/color-helpers/src/conversions/lin-2020.ts
new file mode 100644
index 000000000..614f1e9f0
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-2020.ts
@@ -0,0 +1,24 @@
+/**
+ * Convert an array of rec2020 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ * ITU-R BT.2020-2 p.4
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function lin_2020(RGB: Color): Color {
+ const α = 1.09929682680944;
+ const β = 0.018053968510807;
+
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ if (abs < β * 4.5) {
+ return val / 4.5;
+ }
+
+ return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45));
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-a98rgb-to-xyz.ts b/packages/color-helpers/src/conversions/lin-a98rgb-to-xyz.ts
new file mode 100644
index 000000000..4954bb855
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-a98rgb-to-xyz.ts
@@ -0,0 +1,27 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert an array of linear-light a98-rgb values to CIE XYZ
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * has greater numerical precision than section 4.3.5.3 of
+ * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * but the values below were calculated from first principles
+ * from the chromaticity coordinates of R G B W
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html
+ */
+export function lin_a98rgb_to_XYZ(rgb: Color): Color {
+ const M = [
+ [573536 / 994567, 263643 / 1420810, 187206 / 994567],
+ [591459 / 1989134, 6239551 / 9945670, 374412 / 4972835],
+ [53769 / 1989134, 351524 / 4972835, 4929758 / 4972835],
+ ];
+
+ return multiplyMatrices(M, rgb) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-a98rgb.ts b/packages/color-helpers/src/conversions/lin-a98rgb.ts
new file mode 100644
index 000000000..7b64e4df0
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-a98rgb.ts
@@ -0,0 +1,16 @@
+/**
+ * Convert an array of a98-rgb values in the range 0.0 - 1.0
+ * to linear light (un-companded) form. Negative values are also now accepted
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function lin_a98rgb(RGB: Color): Color {
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ return sign * Math.pow(abs, 563 / 256);
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-p3-to-xyz.ts b/packages/color-helpers/src/conversions/lin-p3-to-xyz.ts
new file mode 100644
index 000000000..4e298155e
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-p3-to-xyz.ts
@@ -0,0 +1,21 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert an array of linear-light display-p3 values to CIE XYZ
+ * using D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export function lin_P3_to_XYZ(rgb: Color): Color {
+ const M = [
+ [608311 / 1250200, 189793 / 714400, 198249 / 1000160],
+ [35783 / 156275, 247089 / 357200, 198249 / 2500400],
+ [0 / 1, 32229 / 714400, 5220557 / 5000800],
+ ];
+
+ return multiplyMatrices(M, rgb) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-p3.ts b/packages/color-helpers/src/conversions/lin-p3.ts
new file mode 100644
index 000000000..95193445e
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-p3.ts
@@ -0,0 +1,13 @@
+import { lin_sRGB } from 'conversions/lin-srgb';
+
+/**
+ * Convert an array of display-p3 RGB values in the range 0.0 - 1.0
+ * to linear light (un-companded) form.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function lin_P3(RGB: Color): Color {
+ return lin_sRGB(RGB); // same as sRGB
+}
diff --git a/packages/color-helpers/src/conversions/lin-pro-photo-to-xyz.ts b/packages/color-helpers/src/conversions/lin-pro-photo-to-xyz.ts
new file mode 100644
index 000000000..4639d6a7b
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-pro-photo-to-xyz.ts
@@ -0,0 +1,21 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert an array of linear-light prophoto-rgb values to CIE XYZ
+ * using D50 (so no chromatic adaptation needed afterwards)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export function lin_ProPhoto_to_XYZ(rgb: Color): Color {
+ const M = [
+ [0.7977604896723027, 0.13518583717574031, 0.0313493495815248],
+ [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902],
+ [0.0, 0.0, 0.8251046025104601],
+ ];
+
+ return multiplyMatrices(M, rgb) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-pro-photo.ts b/packages/color-helpers/src/conversions/lin-pro-photo.ts
new file mode 100644
index 000000000..de338a0d3
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-pro-photo.ts
@@ -0,0 +1,22 @@
+/**
+ * Convert an array of prophoto-rgb values where in-gamut Colors are in the
+ * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is
+ * gamma 1.8 with a small linear portion. Extended transfer function
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function lin_ProPhoto(RGB: Color): Color {
+ const Et2 = 16 / 512;
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ if (abs <= Et2) {
+ return val / 16;
+ }
+
+ return sign * Math.pow(abs, 1.8);
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-srgb-to-xyz.ts b/packages/color-helpers/src/conversions/lin-srgb-to-xyz.ts
new file mode 100644
index 000000000..aa0b460bc
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-srgb-to-xyz.ts
@@ -0,0 +1,18 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert an array of linear-light sRGB values to CIE XYZ
+ * using sRGB's own white, D65 (no chromatic adaptation)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function lin_sRGB_to_XYZ(rgb: Color): Color {
+ const M = [
+ [506752 / 1228815, 87881 / 245763, 12673 / 70218],
+ [87098 / 409605, 175762 / 245763, 12673 / 175545],
+ [7918 / 409605, 87881 / 737289, 1001167 / 1053270],
+ ];
+ return multiplyMatrices(M, rgb) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/lin-srgb.ts b/packages/color-helpers/src/conversions/lin-srgb.ts
new file mode 100644
index 000000000..f55a29620
--- /dev/null
+++ b/packages/color-helpers/src/conversions/lin-srgb.ts
@@ -0,0 +1,25 @@
+/**
+ * Convert an array of of sRGB values where in-gamut values are in the range
+ * [0 - 1] to linear light (un-companded) form.
+ * Extended transfer function:
+ * For negative values, linear portion is extended on reflection of axis,
+ * then reflected power function is used.
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://en.wikipedia.org/wiki/SRGB
+ */
+export function lin_sRGB(RGB: Color): Color {
+ return RGB.map(function (val) {
+ const sign = val < 0 ? -1 : 1;
+ const abs = Math.abs(val);
+
+ if (abs < 0.04045) {
+ return val / 12.92;
+ }
+
+ return sign * (Math.pow((abs + 0.055) / 1.055, 2.4));
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/naive-cmyk-to-srgb.ts b/packages/color-helpers/src/conversions/naive-cmyk-to-srgb.ts
new file mode 100644
index 000000000..712669915
--- /dev/null
+++ b/packages/color-helpers/src/conversions/naive-cmyk-to-srgb.ts
@@ -0,0 +1,21 @@
+/**
+ * CMYK is an array of four values in the range [0.0, 1.0] the output is an
+ * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm
+ * does not generate out of gamut colors neither does it generate accurate
+ * simulations of practical CMYK colors
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): Color {
+ const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3];
+
+ const red = 1 - Math.min(1, cyan * (1 - black) + black);
+ const green = 1 - Math.min(1, magenta * (1 - black) + black);
+ const blue = 1 - Math.min(1, yellow * (1 - black) + black);
+
+ return [red, green, blue];
+}
diff --git a/packages/color-helpers/src/conversions/oklab-to-oklch.ts b/packages/color-helpers/src/conversions/oklab-to-oklch.ts
new file mode 100644
index 000000000..8cc976172
--- /dev/null
+++ b/packages/color-helpers/src/conversions/oklab-to-oklch.ts
@@ -0,0 +1,15 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */
+export function OKLab_to_OKLCH(OKLab: Color): Color {
+ const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI;
+ return [
+ OKLab[0], // L is still L
+ Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma
+ hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
+ ];
+}
diff --git a/packages/color-helpers/src/conversions/oklab-to-p3.ts b/packages/color-helpers/src/conversions/oklab-to-p3.ts
new file mode 100644
index 000000000..db8eb42c6
--- /dev/null
+++ b/packages/color-helpers/src/conversions/oklab-to-p3.ts
@@ -0,0 +1,52 @@
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3';
+import { gam_P3 } from 'conversions/gam-p3';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { lin_P3 } from 'conversions/lin-p3';
+import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+
+export function OKLab_to_P3(oklabRaw: Color): [Color, boolean] {
+ const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw;
+
+ const oklabL = Math.max(
+ oklabLRaw,
+ 0,
+ );
+
+ const oklab = [oklabL, oklabARaw, oklabBRaw] as Color;
+
+ let conversion = oklab as Color;
+ let oklch = OKLab_to_OKLCH(conversion);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ conversion = OKLab_to_XYZ(conversion);
+ conversion = XYZ_to_lin_P3(conversion);
+ conversion = gam_P3(conversion);
+
+ if (inGamut(conversion)) {
+ return [clip(conversion), true];
+ }
+
+ return [mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_P3(x);
+ return gam_P3(x);
+ }, (x: Color) => {
+ x = lin_P3(x);
+ x = lin_P3_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ }), false];
+}
diff --git a/packages/color-helpers/src/conversions/oklab-to-srgb.ts b/packages/color-helpers/src/conversions/oklab-to-srgb.ts
new file mode 100644
index 000000000..ac56839ab
--- /dev/null
+++ b/packages/color-helpers/src/conversions/oklab-to-srgb.ts
@@ -0,0 +1,56 @@
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+
+export function OKLab_to_sRGB(oklabRaw: Color): Color {
+ const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw;
+
+ const oklabL = Math.max(
+ oklabLRaw,
+ 0,
+ );
+
+ const oklab = [oklabL, oklabARaw, oklabBRaw] as Color;
+
+ let conversion = oklab as Color;
+ let oklch = OKLab_to_OKLCH(conversion);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ conversion = OKLab_to_XYZ(conversion);
+ conversion = XYZ_to_lin_sRGB(conversion);
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion).map((x) => {
+ return Math.round(x * 255);
+ }) as Color;
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ }).map((x) => {
+ return Math.round(x * 255);
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/oklab-to-xyz.ts b/packages/color-helpers/src/conversions/oklab-to-xyz.ts
new file mode 100644
index 000000000..2da348462
--- /dev/null
+++ b/packages/color-helpers/src/conversions/oklab-to-xyz.ts
@@ -0,0 +1,27 @@
+/**
+ * Given OKLab, convert to XYZ relative to D65
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+export function OKLab_to_XYZ(OKLab: Color): Color {
+ const LMStoXYZ = [
+ [1.2268798733741557, -0.5578149965554813, 0.28139105017721583],
+ [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701],
+ [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418],
+ ];
+ const OKLabtoLMS = [
+ [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339],
+ [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402],
+ [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399],
+ ];
+
+ const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as Color;
+
+ return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/oklch-to-oklab.ts b/packages/color-helpers/src/conversions/oklch-to-oklab.ts
new file mode 100644
index 000000000..91b87cb4f
--- /dev/null
+++ b/packages/color-helpers/src/conversions/oklch-to-oklab.ts
@@ -0,0 +1,15 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
+ */
+
+export function OKLCH_to_OKLab(OKLCH: Color): Color {
+ return [
+ OKLCH[0], // L is still L
+ OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a
+ OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b
+ ];
+}
diff --git a/packages/color-helpers/src/conversions/oklch-to-p3.ts b/packages/color-helpers/src/conversions/oklch-to-p3.ts
new file mode 100644
index 000000000..54775db91
--- /dev/null
+++ b/packages/color-helpers/src/conversions/oklch-to-p3.ts
@@ -0,0 +1,52 @@
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3';
+import { gam_P3 } from 'conversions/gam-p3';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { lin_P3 } from 'conversions/lin-p3';
+import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+
+export function OKLCH_to_P3(oklchRaw: Color): [Color, boolean] {
+ const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw;
+
+ const oklchL = Math.max(
+ oklchLRaw,
+ 0,
+ );
+
+ const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as Color;
+
+ let conversion = oklch as Color;
+ if (conversion[0] < 0.000001) {
+ conversion = [0, 0, 0] as Color;
+ }
+
+ if (conversion[0] > 0.999999) {
+ conversion = [1, 0, 0] as Color;
+ }
+
+ conversion = OKLCH_to_OKLab(conversion);
+ conversion = OKLab_to_XYZ(conversion);
+ conversion = XYZ_to_lin_P3(conversion);
+ conversion = gam_P3(conversion);
+
+ if (inGamut(conversion)) {
+ return [clip(conversion), true];
+ }
+
+ return [mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_P3(x);
+ return gam_P3(x);
+ }, (x: Color) => {
+ x = lin_P3(x);
+ x = lin_P3_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ }), false];
+}
diff --git a/packages/color-helpers/src/conversions/oklch-to-srgb.ts b/packages/color-helpers/src/conversions/oklch-to-srgb.ts
new file mode 100644
index 000000000..98cd3dd01
--- /dev/null
+++ b/packages/color-helpers/src/conversions/oklch-to-srgb.ts
@@ -0,0 +1,56 @@
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+
+export function OKLCH_to_sRGB(oklchRaw: Color): Color {
+ const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw;
+
+ const oklchL = Math.max(
+ oklchLRaw,
+ 0,
+ );
+
+ const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as Color;
+
+ let conversion = oklch as Color;
+ if (conversion[0] < 0.000001) {
+ conversion = [0, 0, 0] as Color;
+ }
+
+ if (conversion[0] > 0.999999) {
+ conversion = [1, 0, 0] as Color;
+ }
+
+ conversion = OKLCH_to_OKLab(conversion);
+ conversion = OKLab_to_XYZ(conversion);
+ conversion = XYZ_to_lin_sRGB(conversion);
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion).map((x) => {
+ return Math.round(x * 255);
+ }) as Color;
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ }).map((x) => {
+ return Math.round(x * 255);
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/p3-to-lch.ts b/packages/color-helpers/src/conversions/p3-to-lch.ts
new file mode 100644
index 000000000..78b0ffef6
--- /dev/null
+++ b/packages/color-helpers/src/conversions/p3-to-lch.ts
@@ -0,0 +1,20 @@
+import { Lab_to_LCH } from 'conversions/lab-to-lch';
+import { XYZ_to_Lab } from 'conversions/xyz-to-lab';
+import { D65_to_D50 } from 'conversions/d65-to-d50';
+import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz';
+import { lin_P3 } from 'conversions/lin-p3';
+
+/**
+ * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0
+ * range to linear-light display-p3, then to CIE XYZ, then adapt from D65
+ * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function P3_to_LCH(RGB: Color): Color {
+ return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB)))));
+}
diff --git a/packages/color-helpers/src/conversions/p3-to-srgb.ts b/packages/color-helpers/src/conversions/p3-to-srgb.ts
new file mode 100644
index 000000000..967b4090f
--- /dev/null
+++ b/packages/color-helpers/src/conversions/p3-to-srgb.ts
@@ -0,0 +1,54 @@
+import { lin_P3 } from 'conversions/lin-p3';
+import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+
+export function p3_to_sRGB(displayP3: Color): Color {
+ let conversion = displayP3.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ conversion = lin_P3(conversion);
+ conversion = lin_P3_to_XYZ(conversion);
+
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/pro-photo-rgb-to-srgb.ts b/packages/color-helpers/src/conversions/pro-photo-rgb-to-srgb.ts
new file mode 100644
index 000000000..2b2cefab4
--- /dev/null
+++ b/packages/color-helpers/src/conversions/pro-photo-rgb-to-srgb.ts
@@ -0,0 +1,56 @@
+import { lin_ProPhoto } from 'conversions/lin-pro-photo';
+import { lin_ProPhoto_to_XYZ } from 'conversions/lin-pro-photo-to-xyz';
+import { D50_to_D65 } from 'conversions/d50-to-d65';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { mapGamut } from 'calculations/map-gamut';
+
+export function proPhoto_RGB_to_sRGB(proPhoto: Color): Color {
+ let conversion = proPhoto.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ conversion = lin_ProPhoto(conversion);
+ conversion = lin_ProPhoto_to_XYZ(conversion);
+ conversion = D50_to_D65(conversion);
+
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/rec2020-to-lch.ts b/packages/color-helpers/src/conversions/rec2020-to-lch.ts
new file mode 100644
index 000000000..830dd43f6
--- /dev/null
+++ b/packages/color-helpers/src/conversions/rec2020-to-lch.ts
@@ -0,0 +1,20 @@
+import { Lab_to_LCH } from 'conversions/lab-to-lch';
+import { XYZ_to_Lab } from 'conversions/xyz-to-lab';
+import { D65_to_D50 } from 'conversions/d65-to-d50';
+import { lin_2020_to_XYZ } from 'conversions/lin-2020-to-xyz';
+import { lin_2020 } from 'conversions/lin-2020';
+
+/**
+ * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function rec_2020_to_LCH(RGB: Color): Color {
+ return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB)))));
+}
diff --git a/packages/color-helpers/src/conversions/rec2020-to-srgb.ts b/packages/color-helpers/src/conversions/rec2020-to-srgb.ts
new file mode 100644
index 000000000..109239d23
--- /dev/null
+++ b/packages/color-helpers/src/conversions/rec2020-to-srgb.ts
@@ -0,0 +1,54 @@
+import { lin_2020 } from 'conversions/lin-2020';
+import { lin_2020_to_XYZ } from 'conversions/lin-2020-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+
+export function rec_2020_to_sRGB(rec: Color): Color {
+ let conversion = rec.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ conversion = lin_2020(conversion);
+ conversion = lin_2020_to_XYZ(conversion);
+
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/srgb-linear-to-srgb.ts b/packages/color-helpers/src/conversions/srgb-linear-to-srgb.ts
new file mode 100644
index 000000000..cb5d63b64
--- /dev/null
+++ b/packages/color-helpers/src/conversions/srgb-linear-to-srgb.ts
@@ -0,0 +1,51 @@
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+
+export function sRGB_linear_to_sRGB(linearSRgb: Color): Color {
+ let conversion = linearSRgb.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ conversion = lin_sRGB_to_XYZ(conversion);
+
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/srgb-to-lch.ts b/packages/color-helpers/src/conversions/srgb-to-lch.ts
new file mode 100644
index 000000000..d2fd53c4d
--- /dev/null
+++ b/packages/color-helpers/src/conversions/srgb-to-lch.ts
@@ -0,0 +1,20 @@
+import { Lab_to_LCH } from 'conversions/lab-to-lch';
+import { XYZ_to_Lab } from 'conversions/xyz-to-lab';
+import { D65_to_D50 } from 'conversions/d65-to-d50';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to
+ * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then
+ * convert XYZ to CIE Lab and finally, convert to CIE LCH
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function sRGB_to_LCH(RGB: Color): Color {
+ return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB)))));
+}
diff --git a/packages/color-helpers/src/conversions/srgb-to-luminance.ts b/packages/color-helpers/src/conversions/srgb-to-luminance.ts
new file mode 100644
index 000000000..6ddb326f1
--- /dev/null
+++ b/packages/color-helpers/src/conversions/srgb-to-luminance.ts
@@ -0,0 +1,17 @@
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { lin_sRGB } from 'conversions/lin-srgb';
+
+/**
+ * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range
+ * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value)
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function sRGB_to_luminance(RGB: Color): number {
+ const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB));
+ return XYZ[1];
+}
diff --git a/packages/color-helpers/src/conversions/srgb-to-srgb.ts b/packages/color-helpers/src/conversions/srgb-to-srgb.ts
new file mode 100644
index 000000000..7cb479f5f
--- /dev/null
+++ b/packages/color-helpers/src/conversions/srgb-to-srgb.ts
@@ -0,0 +1,52 @@
+import { lin_sRGB } from 'conversions/lin-srgb';
+import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
+import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
+import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
+import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
+import { gam_sRGB } from 'conversions/gam-srgb';
+import { inGamut } from 'utils/in-gamut';
+import { clip } from 'utils/clip';
+import { mapGamut } from 'calculations/map-gamut';
+import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
+import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
+
+export function sRGB_to_sRGB(sRgb: Color): Color {
+ let conversion = sRgb.slice() as Color;
+
+ // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
+ conversion = lin_sRGB(conversion);
+ conversion = lin_sRGB_to_XYZ(conversion);
+
+ let oklch = conversion.slice() as Color;
+ oklch = XYZ_to_OKLab(oklch);
+ oklch = OKLab_to_OKLCH(oklch);
+ if (oklch[0] < 0.000001) {
+ oklch = [0, 0, 0] as Color;
+ }
+
+ if (oklch[0] > 0.999999) {
+ oklch = [1, 0, 0] as Color;
+ }
+
+ // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
+ conversion = XYZ_to_lin_sRGB(conversion);
+ // 4. Convert from linear - light RGB to RGB(do gamma encoding)
+ conversion = gam_sRGB(conversion);
+
+ if (inGamut(conversion)) {
+ return clip(conversion);
+ }
+
+ return mapGamut(oklch, (x: Color) => {
+ x = OKLCH_to_OKLab(x);
+ x = OKLab_to_XYZ(x);
+ x = XYZ_to_lin_sRGB(x);
+ return gam_sRGB(x);
+ }, (x: Color) => {
+ x = lin_sRGB(x);
+ x = lin_sRGB_to_XYZ(x);
+ x = XYZ_to_OKLab(x);
+ return OKLab_to_OKLCH(x);
+ });
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-lab.ts b/packages/color-helpers/src/conversions/xyz-to-lab.ts
new file mode 100644
index 000000000..fdbf1f449
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-lab.ts
@@ -0,0 +1,27 @@
+/**
+ * Assuming XYZ is relative to D50, convert to CIE Lab
+ * from CIE standard, which now defines these as a rational fraction
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+import { D50 } from 'conversions/constants';
+
+export function XYZ_to_Lab(XYZ: Color): Color {
+ const ε = 216 / 24389; // 6^3/29^3
+ const κ = 24389 / 27; // 29^3/3^3
+
+ // compute xyz, which is XYZ scaled relative to reference white
+ const xyz = XYZ.map((value, i) => value / D50[i]);
+
+ // now compute f
+ const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116);
+
+ return [
+ (116 * f[1]) - 16, // L
+ 500 * (f[0] - f[1]), // a
+ 200 * (f[1] - f[2]), // b
+ ];
+ // L in range [0,100]. For use in CSS, add a percent
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-2020.ts b/packages/color-helpers/src/conversions/xyz-to-lin-2020.ts
new file mode 100644
index 000000000..5f2f92406
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-lin-2020.ts
@@ -0,0 +1,18 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert XYZ to linear-light rec2020
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function XYZ_to_lin_2020(XYZ: Color): Color {
+ const M = [
+ [30757411 / 17917100, -6372589 / 17917100, -4539589 / 17917100],
+ [-19765991 / 29648200, 47925759 / 29648200, 467509 / 29648200],
+ [792561 / 44930125, -1921689 / 44930125, 42328811 / 44930125],
+ ];
+
+ return multiplyMatrices(M, XYZ) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-a98rgb.ts b/packages/color-helpers/src/conversions/xyz-to-lin-a98rgb.ts
new file mode 100644
index 000000000..9ec1a0b59
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-lin-a98rgb.ts
@@ -0,0 +1,18 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert XYZ to linear-light a98-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function XYZ_to_lin_a98rgb(XYZ: Color): Color {
+ const M = [
+ [1829569 / 896150, -506331 / 896150, -308931 / 896150],
+ [-851781 / 878810, 1648619 / 878810, 36519 / 878810],
+ [16779 / 1248040, -147721 / 1248040, 1266979 / 1248040],
+ ];
+
+ return multiplyMatrices(M, XYZ) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-p3.ts b/packages/color-helpers/src/conversions/xyz-to-lin-p3.ts
new file mode 100644
index 000000000..d6cc5193d
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-lin-p3.ts
@@ -0,0 +1,18 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert XYZ to linear-light P3
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function XYZ_to_lin_P3(XYZ: Color): Color {
+ const M = [
+ [446124 / 178915, -333277 / 357830, -72051 / 178915],
+ [-14852 / 17905, 63121 / 35810, 423 / 17905],
+ [11844 / 330415, -50337 / 660830, 316169 / 330415],
+ ];
+
+ return multiplyMatrices(M, XYZ) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-pro-photo.ts b/packages/color-helpers/src/conversions/xyz-to-lin-pro-photo.ts
new file mode 100644
index 000000000..facafc9bb
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-lin-pro-photo.ts
@@ -0,0 +1,20 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * Convert XYZ to linear-light prophoto-rgb
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export function XYZ_to_lin_ProPhoto(XYZ: Color): Color {
+ const M = [
+ [1.3457989731028281, -0.25558010007997534, -0.05110628506753401],
+ [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973],
+ [0.0, 0.0, 1.2119675456389454],
+ ];
+
+ return multiplyMatrices(M, XYZ) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-srgb.ts b/packages/color-helpers/src/conversions/xyz-to-lin-srgb.ts
new file mode 100644
index 000000000..be79af764
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-lin-srgb.ts
@@ -0,0 +1,16 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function XYZ_to_lin_sRGB(XYZ: Color): Color {
+ const M = [
+ [12831 / 3959, -329 / 214, -1974 / 3959],
+ [-851781 / 878810, 1648619 / 878810, 36519 / 878810],
+ [705 / 12673, -2585 / 12673, 705 / 667],
+ ];
+
+ return multiplyMatrices(M, XYZ) as Color;
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-oklab.ts b/packages/color-helpers/src/conversions/xyz-to-oklab.ts
new file mode 100644
index 000000000..52df715b3
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-oklab.ts
@@ -0,0 +1,27 @@
+import { multiplyMatrices } from 'calculations/multiply-matrices';
+
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * XYZ <-> LMS matrices recalculated for consistent reference white
+ * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
+ */
+export function XYZ_to_OKLab(XYZ: Color): Color {
+ // Given XYZ relative to D65, convert to OKLab
+ const XYZtoLMS = [
+ [0.8190224432164319, 0.3619062562801221, -0.12887378261216414],
+ [0.0329836671980271, 0.9292868468965546, 0.03614466816999844],
+ [0.048177199566046255, 0.26423952494422764, 0.6335478258136937],
+ ];
+ const LMStoOKLab = [
+ [0.2104542553, 0.7936177850, -0.0040720468],
+ [1.9779984951, -2.4285922050, 0.4505937099],
+ [0.0259040371, 0.7827717662, -0.8086757660],
+ ];
+
+ const LMS = multiplyMatrices(XYZtoLMS, XYZ) as Color;
+ return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as Color;
+ // L in range [0,1]. For use in CSS, multiply by 100 and add a percent
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-uv.ts b/packages/color-helpers/src/conversions/xyz-to-uv.ts
new file mode 100644
index 000000000..8e0e4fe15
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-uv.ts
@@ -0,0 +1,16 @@
+/**
+ * Convert an array of three XYZ values to u*,v* chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function XYZ_to_uv(XYZ: Color): [number, number] {
+ const X = XYZ[0];
+ const Y = XYZ[1];
+ const Z = XYZ[2];
+ const denom = X + 15 * Y + 3 * Z;
+ return [4 * X / denom, 9 * Y / denom];
+}
diff --git a/packages/color-helpers/src/conversions/xyz-to-xy.ts b/packages/color-helpers/src/conversions/xyz-to-xy.ts
new file mode 100644
index 000000000..a64dd66ca
--- /dev/null
+++ b/packages/color-helpers/src/conversions/xyz-to-xy.ts
@@ -0,0 +1,16 @@
+/**
+ * Convert an array of three XYZ values to x,y chromaticity coordinates
+ *
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ *
+ * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
+ */
+export function XYZ_to_xy(XYZ: Color): [number, number] {
+ const X = XYZ[0];
+ const Y = XYZ[1];
+ const Z = XYZ[2];
+ const sum = X + Y + Z;
+ return [X / sum, Y / sum];
+}
diff --git a/packages/color-helpers/src/index.ts b/packages/color-helpers/src/index.ts
new file mode 100644
index 000000000..2a876cf2f
--- /dev/null
+++ b/packages/color-helpers/src/index.ts
@@ -0,0 +1,4 @@
+export * as calculations from './calculations';
+export * as conversions from './conversions';
+export * as utils from './utils';
+export { namedColors } from './named-colors';
diff --git a/packages/color-helpers/src/named-colors/index.ts b/packages/color-helpers/src/named-colors/index.ts
new file mode 100644
index 000000000..722ef6ea0
--- /dev/null
+++ b/packages/color-helpers/src/named-colors/index.ts
@@ -0,0 +1,151 @@
+// https://www.w3.org/TR/css-color-4/#named-colors
+export const namedColors: Record = {
+ aliceblue: [240, 248, 255],
+ antiquewhite: [250, 235, 215],
+ aqua: [0, 255, 255],
+ aquamarine: [127, 255, 212],
+ azure: [240, 255, 255],
+ beige: [245, 245, 220],
+ bisque: [255, 228, 196],
+ black: [0, 0, 0],
+ blanchedalmond: [255, 235, 205],
+ blue: [0, 0, 255],
+ blueviolet: [138, 43, 226],
+ brown: [165, 42, 42],
+ burlywood: [222, 184, 135],
+ cadetblue: [95, 158, 160],
+ chartreuse: [127, 255, 0],
+ chocolate: [210, 105, 30],
+ coral: [255, 127, 80],
+ cornflowerblue: [100, 149, 237],
+ cornsilk: [255, 248, 220],
+ crimson: [220, 20, 60],
+ cyan: [0, 255, 255],
+ darkblue: [0, 0, 139],
+ darkcyan: [0, 139, 139],
+ darkgoldenrod: [184, 134, 11],
+ darkgray: [169, 169, 169],
+ darkgreen: [0, 100, 0],
+ darkgrey: [169, 169, 169],
+ darkkhaki: [189, 183, 107],
+ darkmagenta: [139, 0, 139],
+ darkolivegreen: [85, 107, 47],
+ darkorange: [255, 140, 0],
+ darkorchid: [153, 50, 204],
+ darkred: [139, 0, 0],
+ darksalmon: [233, 150, 122],
+ darkseagreen: [143, 188, 143],
+ darkslateblue: [72, 61, 139],
+ darkslategray: [47, 79, 79],
+ darkslategrey: [47, 79, 79],
+ darkturquoise: [0, 206, 209],
+ darkviolet: [148, 0, 211],
+ deeppink: [255, 20, 147],
+ deepskyblue: [0, 191, 255],
+ dimgray: [105, 105, 105],
+ dimgrey: [105, 105, 105],
+ dodgerblue: [30, 144, 255],
+ firebrick: [178, 34, 34],
+ floralwhite: [255, 250, 240],
+ forestgreen: [34, 139, 34],
+ fuchsia: [255, 0, 255],
+ gainsboro: [220, 220, 220],
+ ghostwhite: [248, 248, 255],
+ gold: [255, 215, 0],
+ goldenrod: [218, 165, 32],
+ gray: [128, 128, 128],
+ green: [0, 128, 0],
+ greenyellow: [173, 255, 47],
+ grey: [128, 128, 128],
+ honeydew: [240, 255, 240],
+ hotpink: [255, 105, 180],
+ indianred: [205, 92, 92],
+ indigo: [75, 0, 130],
+ ivory: [255, 255, 240],
+ khaki: [240, 230, 140],
+ lavender: [230, 230, 250],
+ lavenderblush: [255, 240, 245],
+ lawngreen: [124, 252, 0],
+ lemonchiffon: [255, 250, 205],
+ lightblue: [173, 216, 230],
+ lightcoral: [240, 128, 128],
+ lightcyan: [224, 255, 255],
+ lightgoldenrodyellow: [250, 250, 210],
+ lightgray: [211, 211, 211],
+ lightgreen: [144, 238, 144],
+ lightgrey: [211, 211, 211],
+ lightpink: [255, 182, 193],
+ lightsalmon: [255, 160, 122],
+ lightseagreen: [32, 178, 170],
+ lightskyblue: [135, 206, 250],
+ lightslategray: [119, 136, 153],
+ lightslategrey: [119, 136, 153],
+ lightsteelblue: [176, 196, 222],
+ lightyellow: [255, 255, 224],
+ lime: [0, 255, 0],
+ limegreen: [50, 205, 50],
+ linen: [250, 240, 230],
+ magenta: [255, 0, 255],
+ maroon: [128, 0, 0],
+ mediumaquamarine: [102, 205, 170],
+ mediumblue: [0, 0, 205],
+ mediumorchid: [186, 85, 211],
+ mediumpurple: [147, 112, 219],
+ mediumseagreen: [60, 179, 113],
+ mediumslateblue: [123, 104, 238],
+ mediumspringgreen: [0, 250, 154],
+ mediumturquoise: [72, 209, 204],
+ mediumvioletred: [199, 21, 133],
+ midnightblue: [25, 25, 112],
+ mintcream: [245, 255, 250],
+ mistyrose: [255, 228, 225],
+ moccasin: [255, 228, 181],
+ navajowhite: [255, 222, 173],
+ navy: [0, 0, 128],
+ oldlace: [253, 245, 230],
+ olive: [128, 128, 0],
+ olivedrab: [107, 142, 35],
+ orange: [255, 165, 0],
+ orangered: [255, 69, 0],
+ orchid: [218, 112, 214],
+ palegoldenrod: [238, 232, 170],
+ palegreen: [152, 251, 152],
+ paleturquoise: [175, 238, 238],
+ palevioletred: [219, 112, 147],
+ papayawhip: [255, 239, 213],
+ peachpuff: [255, 218, 185],
+ peru: [205, 133, 63],
+ pink: [255, 192, 203],
+ plum: [221, 160, 221],
+ powderblue: [176, 224, 230],
+ purple: [128, 0, 128],
+ rebeccapurple: [102, 51, 153],
+ red: [255, 0, 0],
+ rosybrown: [188, 143, 143],
+ royalblue: [65, 105, 225],
+ saddlebrown: [139, 69, 19],
+ salmon: [250, 128, 114],
+ sandybrown: [244, 164, 96],
+ seagreen: [46, 139, 87],
+ seashell: [255, 245, 238],
+ sienna: [160, 82, 45],
+ silver: [192, 192, 192],
+ skyblue: [135, 206, 235],
+ slateblue: [106, 90, 205],
+ slategray: [112, 128, 144],
+ slategrey: [112, 128, 144],
+ snow: [255, 250, 250],
+ springgreen: [0, 255, 127],
+ steelblue: [70, 130, 180],
+ tan: [210, 180, 140],
+ teal: [0, 128, 128],
+ thistle: [216, 191, 216],
+ tomato: [255, 99, 71],
+ turquoise: [64, 224, 208],
+ violet: [238, 130, 238],
+ wheat: [245, 222, 179],
+ white: [255, 255, 255],
+ whitesmoke: [245, 245, 245],
+ yellow: [255, 255, 0],
+ yellowgreen: [154, 205, 50],
+};
diff --git a/plugins/postcss-lab-function/src/css-color-4/LICENSE.md b/packages/color-helpers/src/utils/LICENSE.md
similarity index 66%
rename from plugins/postcss-lab-function/src/css-color-4/LICENSE.md
rename to packages/color-helpers/src/utils/LICENSE.md
index ea4236ffc..7293506b4 100644
--- a/plugins/postcss-lab-function/src/css-color-4/LICENSE.md
+++ b/packages/color-helpers/src/utils/LICENSE.md
@@ -1,5 +1,3 @@
All documents in this Directory are licensed by contributors
under the
[W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software).
-
-See [w3c/csswg-drafts](https://github.com/w3c/csswg-drafts) for the original work.
diff --git a/packages/color-helpers/src/utils/clip.ts b/packages/color-helpers/src/utils/clip.ts
new file mode 100644
index 000000000..2a79c2d72
--- /dev/null
+++ b/packages/color-helpers/src/utils/clip.ts
@@ -0,0 +1,16 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function clip(color: Color): Color {
+ return color.map(val => {
+ if (val < 0) {
+ return 0;
+ } else if (val > 1) {
+ return 1;
+ } else {
+ return val;
+ }
+ }) as Color;
+}
diff --git a/packages/color-helpers/src/utils/in-gamut.ts b/packages/color-helpers/src/utils/in-gamut.ts
new file mode 100644
index 000000000..f8b93fd0c
--- /dev/null
+++ b/packages/color-helpers/src/utils/in-gamut.ts
@@ -0,0 +1,9 @@
+/**
+ * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
+ */
+export function inGamut(x: Color): boolean {
+ const [xX, xY, xZ] = x;
+ return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001;
+}
diff --git a/packages/color-helpers/src/utils/index.ts b/packages/color-helpers/src/utils/index.ts
new file mode 100644
index 000000000..b73e4598c
--- /dev/null
+++ b/packages/color-helpers/src/utils/index.ts
@@ -0,0 +1,2 @@
+export * from './clip';
+export * from './in-gamut';
diff --git a/packages/color-helpers/stryker.conf.json b/packages/color-helpers/stryker.conf.json
new file mode 100644
index 000000000..015ebbb73
--- /dev/null
+++ b/packages/color-helpers/stryker.conf.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "../../node_modules/@stryker-mutator/core/schema/stryker-schema.json",
+ "mutate": [
+ "src/**/*.ts"
+ ],
+ "buildCommand": "npm run build",
+ "testRunner": "command",
+ "coverageAnalysis": "perTest",
+ "tempDirName": "../../.stryker-tmp",
+ "commandRunner": {
+ "command": "npm run test"
+ },
+ "thresholds": {
+ "high": 100,
+ "low": 100,
+ "break": 100
+ },
+ "inPlace": true
+}
diff --git a/packages/color-helpers/test/_import.mjs b/packages/color-helpers/test/_import.mjs
new file mode 100644
index 000000000..e7d81f6e9
--- /dev/null
+++ b/packages/color-helpers/test/_import.mjs
@@ -0,0 +1,7 @@
+import assert from 'assert';
+import { calculations } from '@csstools/color-helpers';
+
+const { deltaEOK } = calculations;
+
+assert.equal(typeof deltaEOK, 'function', 'should export nested libraries');
+assert.equal(typeof calculations.deltaEOK, 'function', 'should be possible to import from index');
diff --git a/packages/color-helpers/test/_require.cjs b/packages/color-helpers/test/_require.cjs
new file mode 100644
index 000000000..16a9da00a
--- /dev/null
+++ b/packages/color-helpers/test/_require.cjs
@@ -0,0 +1,6 @@
+const assert = require('assert');
+const { deltaEOK } = require('@csstools/color-helpers').calculations;
+const { calculations } = require('@csstools/color-helpers');
+
+assert.equal(typeof deltaEOK, 'function', 'should export nested libraries');
+assert.equal(typeof calculations.deltaEOK, 'function', 'should be possible to import from index');
diff --git a/packages/color-helpers/tsconfig.json b/packages/color-helpers/tsconfig.json
new file mode 100644
index 000000000..f8ce32b15
--- /dev/null
+++ b/packages/color-helpers/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "declarationDir": ".",
+ "baseUrl": "./src/"
+ },
+ "include": [
+ "./src/**/*",
+ "types/global.d.ts"
+ ],
+ "exclude": ["dist"]
+}
diff --git a/packages/color-helpers/types/global.d.ts b/packages/color-helpers/types/global.d.ts
new file mode 100644
index 000000000..9ed8ef549
--- /dev/null
+++ b/packages/color-helpers/types/global.d.ts
@@ -0,0 +1,5 @@
+export {};
+
+declare global {
+ type Color = [number, number, number];
+}
diff --git a/plugins/postcss-color-function/CHANGELOG.md b/plugins/postcss-color-function/CHANGELOG.md
index 0de243786..cec56c98c 100644
--- a/plugins/postcss-color-function/CHANGELOG.md
+++ b/plugins/postcss-color-function/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changes to PostCSS Color Function
+### Unreleased (minor)
+
+- Add: `@csstools/color-helpers` dependency for all color value transformations.
+
### 2.0.1 (January 28, 2023)
- Improve `types` declaration in `package.json`
diff --git a/plugins/postcss-color-function/dist/convert-a98-rgb-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-a98-rgb-to-srgb.d.ts
deleted file mode 100644
index 846c0a37f..000000000
--- a/plugins/postcss-color-function/dist/convert-a98-rgb-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function a98RgbToSRgb(a98: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/convert-cie-xyz-50-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-cie-xyz-50-to-srgb.d.ts
deleted file mode 100644
index 07b637c6a..000000000
--- a/plugins/postcss-color-function/dist/convert-cie-xyz-50-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function cieXyz50ToSRgb(xyz: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/convert-cie-xyz-65-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-cie-xyz-65-to-srgb.d.ts
deleted file mode 100644
index b287e1e80..000000000
--- a/plugins/postcss-color-function/dist/convert-cie-xyz-65-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function cieXyz65ToSRgb(xyz: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/convert-display-p3-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-display-p3-to-srgb.d.ts
deleted file mode 100644
index d0451a4e9..000000000
--- a/plugins/postcss-color-function/dist/convert-display-p3-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function displayP3ToSRgb(displayP3: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/convert-prophoto-rgb-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-prophoto-rgb-to-srgb.d.ts
deleted file mode 100644
index 6a230a065..000000000
--- a/plugins/postcss-color-function/dist/convert-prophoto-rgb-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function prophotoRgbToSRgb(prophoto: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/convert-rec2020-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-rec2020-to-srgb.d.ts
deleted file mode 100644
index adb1f02aa..000000000
--- a/plugins/postcss-color-function/dist/convert-rec2020-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function rec2020ToSRgb(rec: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/convert-srgb-linear-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-srgb-linear-to-srgb.d.ts
deleted file mode 100644
index 0006647e8..000000000
--- a/plugins/postcss-color-function/dist/convert-srgb-linear-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function sRgbLinearToSRgb(linearSRgb: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/convert-srgb-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-srgb-to-srgb.d.ts
deleted file mode 100644
index 09d78d917..000000000
--- a/plugins/postcss-color-function/dist/convert-srgb-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function sRgbToSRgb(sRgb: color): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/css-color-4/conversions.d.ts b/plugins/postcss-color-function/dist/css-color-4/conversions.d.ts
deleted file mode 100644
index a48b1e5bc..000000000
--- a/plugins/postcss-color-function/dist/css-color-4/conversions.d.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */
-type color = [number, number, number];
-export declare const D50: number[];
-export declare const D65: number[];
-export declare function lin_sRGB(RGB: color): color;
-export declare function gam_sRGB(RGB: color): color;
-export declare function lin_sRGB_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_sRGB(XYZ: color): color;
-export declare function lin_P3(RGB: color): color;
-export declare function gam_P3(RGB: color): color;
-export declare function lin_P3_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_P3(XYZ: color): color;
-export declare function lin_ProPhoto(RGB: color): color;
-export declare function gam_ProPhoto(RGB: color): color;
-export declare function lin_ProPhoto_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_ProPhoto(XYZ: color): color;
-export declare function lin_a98rgb(RGB: color): color;
-export declare function gam_a98rgb(RGB: color): color;
-export declare function lin_a98rgb_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_a98rgb(XYZ: color): color;
-export declare function lin_2020(RGB: color): color;
-export declare function gam_2020(RGB: color): color;
-export declare function lin_2020_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_2020(XYZ: color): color;
-export declare function D65_to_D50(XYZ: color): color;
-export declare function D50_to_D65(XYZ: color): color;
-export declare function XYZ_to_Lab(XYZ: color): color;
-export declare function Lab_to_XYZ(Lab: color): color;
-export declare function Lab_to_LCH(Lab: color): color;
-export declare function LCH_to_Lab(LCH: color): color;
-export declare function XYZ_to_OKLab(XYZ: color): color;
-export declare function OKLab_to_XYZ(OKLab: color): color;
-export declare function OKLab_to_OKLCH(OKLab: color): color;
-export declare function OKLCH_to_OKLab(OKLCH: color): color;
-export declare function rectangular_premultiply(color: color, alpha: number): color;
-export declare function rectangular_un_premultiply(color: color, alpha: number): color;
-export declare function polar_premultiply(color: color, alpha: number, hueIndex: number): color;
-export declare function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color;
-export declare function hsl_premultiply(color: color, alpha: number): color;
-export {};
diff --git a/plugins/postcss-color-function/dist/css-color-4/deltaEOK.d.ts b/plugins/postcss-color-function/dist/css-color-4/deltaEOK.d.ts
deleted file mode 100644
index d744ffaad..000000000
--- a/plugins/postcss-color-function/dist/css-color-4/deltaEOK.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */
-type color = [number, number, number];
-export declare function deltaEOK(reference: color, sample: color): number;
-export {};
diff --git a/plugins/postcss-color-function/dist/css-color-4/map-gamut.d.ts b/plugins/postcss-color-function/dist/css-color-4/map-gamut.d.ts
deleted file mode 100644
index 1a4ee6e95..000000000
--- a/plugins/postcss-color-function/dist/css-color-4/map-gamut.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-type color = [number, number, number];
-export declare function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color;
-export declare function clip(color: color): color;
-export declare function inGamut(x: color): boolean;
-export {};
diff --git a/plugins/postcss-color-function/dist/css-color-4/multiply-matrices.d.ts b/plugins/postcss-color-function/dist/css-color-4/multiply-matrices.d.ts
deleted file mode 100644
index 3055a8245..000000000
--- a/plugins/postcss-color-function/dist/css-color-4/multiply-matrices.d.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * Simple matrix (and vector) multiplication
- * Warning: No error handling for incompatible dimensions!
- * @author Lea Verou 2020 MIT License
- *
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js
- */
-export declare function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array;
diff --git a/plugins/postcss-color-function/dist/css-color-4/utilities.d.ts b/plugins/postcss-color-function/dist/css-color-4/utilities.d.ts
deleted file mode 100644
index a5bb9da80..000000000
--- a/plugins/postcss-color-function/dist/css-color-4/utilities.d.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
- */
-type color = [number, number, number];
-export declare function sRGB_to_luminance(RGB: color): number;
-export declare function contrast(RGB1: color, RGB2: color): number;
-export declare function sRGB_to_LCH(RGB: color): color;
-export declare function P3_to_LCH(RGB: color): color;
-export declare function r2020_to_LCH(RGB: color): color;
-export declare function LCH_to_sRGB(LCH: color): color;
-export declare function LCH_to_P3(LCH: color): color;
-export declare function LCH_to_r2020(LCH: color): color;
-export declare function hslToRgb(hsl: color): color;
-export declare function hueToRgb(t1: number, t2: number, hue: number): number;
-export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color;
-export declare function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number];
-export declare function XYZ_to_xy(XYZ: color): [number, number];
-export declare function xy_to_uv(xy: [number, number]): [number, number];
-export declare function XYZ_to_uv(XYZ: color): [number, number];
-export {};
diff --git a/plugins/postcss-color-function/dist/index.cjs b/plugins/postcss-color-function/dist/index.cjs
index efbb944b1..6671672e4 100644
--- a/plugins/postcss-color-function/dist/index.cjs
+++ b/plugins/postcss-color-function/dist/index.cjs
@@ -1,29 +1 @@
-"use strict";var t=require("@csstools/postcss-progressive-custom-properties"),e=require("postcss-value-parser");function hasFallback(t){const e=t.parent;if(!e)return!1;const r=t.prop.toLowerCase(),n=e.index(t);for(let t=0;t[t])));const o=a[0].length,s=a[0].map(((t,e)=>a.map((t=>t[e]))));let i=n.map((t=>s.map((e=>Array.isArray(t)?t.reduce(((t,r,n)=>t+r*(e[n]||0)),0):e.reduce(((e,r)=>e+r*t),0)))));return 1===r&&(i=i[0]),1===o?i.map((t=>t[0])):i}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */function lin_sRGB(t){return t.map((function(t){const e=t<0?-1:1,r=Math.abs(t);return r<.04045?t/12.92:e*Math.pow((r+.055)/1.055,2.4)}))}function gam_sRGB(t){return t.map((function(t){const e=t<0?-1:1,r=Math.abs(t);return r>.0031308?e*(1.055*Math.pow(r,1/2.4)-.055):12.92*t}))}function lin_sRGB_to_XYZ(t){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],t)}function XYZ_to_lin_sRGB(t){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],t)}function lin_2020(t){const e=1.09929682680944;return t.map((function(t){const r=t<0?-1:1,n=Math.abs(t);return n<.08124285829863151?t/4.5:r*Math.pow((n+e-1)/e,1/.45)}))}function D50_to_D65(t){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],t)}function XYZ_to_OKLab(t){const e=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],t);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],e.map((t=>Math.cbrt(t))))}function OKLab_to_XYZ(t){const e=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],t);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],e.map((t=>t**3)))}function OKLab_to_OKLCH(t){const e=180*Math.atan2(t[2],t[1])/Math.PI;return[t[0],Math.sqrt(t[1]**2+t[2]**2),e>=0?e:e+360]}function OKLCH_to_OKLab(t){return[t[0],t[1]*Math.cos(t[2]*Math.PI/180),t[1]*Math.sin(t[2]*Math.PI/180)]}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */function deltaEOK(t,e){const[r,n,a]=t,[o,s,i]=e,u=r-o,c=n-s,l=a-i;return Math.sqrt(u**2+c**2+l**2)}function mapGamut(t,e,r){return binarySearchGamut(t,e,r)}function binarySearchGamut(t,e,r){let n=0,a=t[1];const o=t;for(;a-n>1e-4;){const t=clip(e(o));deltaEOK(OKLCH_to_OKLab(o),OKLCH_to_OKLab(r(t)))-.02<1e-4?n=o[1]:a=o[1],o[1]=(a+n)/2}return clip(e([...o]))}function clip(t){return t.map((t=>t<0?0:t>1?1:t))}function inGamut(t){const[e,r,n]=t;return e>=-1e-4&&e<=1.0001&&r>=-1e-4&&r<=1.0001&&n>=-1e-4&&n<=1.0001}function a98RgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1,r=Math.abs(t);return e*Math.pow(r,563/256)})),e=multiplyMatrices([[.5766690429101305,.1855582379065463,.1882286462349947],[.29734497525053605,.6273635662554661,.07529145849399788],[.02703136138641234,.07068885253582723,.9913375368376388]],e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz50ToSRgb(t){let e=t.slice();e=D50_to_D65(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz65ToSRgb(t){let e=t.slice(),r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function displayP3ToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function prophotoRgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1;return Math.abs(t)<=.03125?t/16:e*Math.pow(t,1.8)})),e=multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],e),e=D50_to_D65(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function rec2020ToSRgb(t){let e=t.slice();e=lin_2020(e),e=multiplyMatrices([[.6369580483012914,.14461690358620832,.1688809751641721],[.2627002120112671,.6779980715188708,.05930171646986196],[0,.028072693049087428,1.060985057710791]],e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbLinearToSRgb(t){let e=t.slice();e=lin_sRGB_to_XYZ(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=lin_sRGB_to_XYZ(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function onCSSFunctionSRgb(t,r,n,a){const o=e.stringify(t),s=t.value,i=t.nodes.slice().filter((t=>"comment"!==t.type&&"space"!==t.type));let u,c=null;if("color"===s.toLowerCase()&&(c=colorFunctionContents(i)),!c)return;switch(t.value="rgb",transformAlpha(t,c.slash,c.alpha),c.colorSpace){case"srgb":u=sRgbToSRgb;break;case"srgb-linear":u=sRgbLinearToSRgb;break;case"a98-rgb":u=a98RgbToSRgb;break;case"prophoto-rgb":u=prophotoRgbToSRgb;break;case"display-p3":u=displayP3ToSRgb;break;case"rec2020":u=rec2020ToSRgb;break;case"xyz-d50":u=cieXyz50ToSRgb;break;case"xyz-d65":case"xyz":u=cieXyz65ToSRgb;break;default:return}const l=(_=c,_.parameters.map((t=>t.value))).map((t=>parseFloat(t.number)));var _;const p=u(l);!inGamut(l)&&a&&r.warn(n,`"${o}" is out of gamut for "${c.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),t.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[2])),type:"word"}],c.alpha&&(t.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),t.nodes.push(c.alpha))}function isColorSpaceNode(t){if(!t||"word"!==t.type)return!1;switch(t.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const r=e.unit(t.value);return!!r&&!!r.number}function isNumericNodePercentageOrNumber(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const r=e.unit(t.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(t){return t&&"function"===t.type&&"calc"===t.value.toLowerCase()}function isVarNode(t){return t&&"function"===t.type&&"var"===t.value.toLowerCase()}function colorFunctionContents(t){if(!isColorSpaceNode(t[0]))return null;const r={colorSpace:t[0].value.toLowerCase(),colorSpaceNode:t[0],parameters:[]};for(let a=1;a3&&(r.parameters=r.parameters.slice(0,3))),r}function transformAlpha(t,r,n){if(!r||!n)return;if(t.value="rgba",r.value=",",r.before="",!isNumericNode(n))return;const a=e.unit(n.value);a&&"%"===a.unit&&(a.number=String(parseFloat(a.number)/100),n.value=String(a.number))}function canParseAsUnit(t){if(!t||!t.value)return!1;try{return!1!==e.unit(t.value)}catch(t){return!1}}function modifiedValues(t,r,n,a){let o;try{o=e(t)}catch(e){r.warn(n,`Failed to parse value '${t}' as a color function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((t=>{t.type&&"function"===t.type&&"color"===t.value.toLowerCase()&&onCSSFunctionSRgb(t,r,n,a)}));const s=String(o);return s!==t?s:void 0}const basePlugin=t=>{const e="preserve"in Object(t)&&Boolean(t.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(t,{result:r})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const n=t.value;if(!n.toLowerCase().includes("color("))return;const a=modifiedValues(n,t,r,e);void 0!==a&&(t.cloneBefore({value:a}),e||t.remove())}}};basePlugin.postcss=!0;const postcssPlugin=e=>{const r=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},e);return r.enableProgressiveCustomProperties&&r.preserve?{postcssPlugin:"postcss-color-function",plugins:[t(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0,module.exports=postcssPlugin;
+"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),r=require("postcss-value-parser"),o=require("@csstools/color-helpers");function hasFallback(e){const r=e.parent;if(!r)return!1;const o=e.prop.toLowerCase(),n=r.index(e);for(let e=0;e"comment"!==e.type&&"space"!==e.type));let i,l=null;if("color"===u.toLowerCase()&&(l=colorFunctionContents(c)),!l)return;switch(e.value="rgb",transformAlpha(e,l.slash,l.alpha),l.colorSpace){case"srgb":i=o.conversions.sRGB_to_sRGB;break;case"srgb-linear":i=o.conversions.sRGB_linear_to_sRGB;break;case"a98-rgb":i=o.conversions.a98_RGB_to_sRGB;break;case"prophoto-rgb":i=o.conversions.proPhoto_RGB_to_sRGB;break;case"display-p3":i=o.conversions.p3_to_sRGB;break;case"rec2020":i=o.conversions.rec_2020_to_sRGB;break;case"xyz-d50":i=o.conversions.cie_XYZ_50_to_sRGB;break;case"xyz-d65":case"xyz":i=o.conversions.cie_XYZ_65_to_sRGB;break;default:return}const p=(d=l,d.parameters.map((e=>e.value))).map((e=>parseFloat(e.number)));var d;const v=i(p);!o.utils.inGamut(p)&&s&&n.warn(t,`"${a}" is out of gamut for "${l.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[2])),type:"word"}],l.alpha&&(e.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.push(l.alpha))}function isColorSpaceNode(e){if(!e||"word"!==e.type)return!1;switch(e.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const o=r.unit(e.value);return!!o&&!!o.number}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const o=r.unit(e.value);return!!o&&("%"===o.unit||""===o.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function colorFunctionContents(e){if(!isColorSpaceNode(e[0]))return null;const o={colorSpace:e[0].value.toLowerCase(),colorSpaceNode:e[0],parameters:[]};for(let t=1;t3&&(o.parameters=o.parameters.slice(0,3))),o}function transformAlpha(e,o,n){if(!o||!n)return;if(e.value="rgba",o.value=",",o.before="",!isNumericNode(n))return;const t=r.unit(n.value);t&&"%"===t.unit&&(t.number=String(parseFloat(t.number)/100),n.value=String(t.number))}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==r.unit(e.value)}catch(e){return!1}}function modifiedValues(e,o,n,t){let s;try{s=r(e)}catch(r){o.warn(n,`Failed to parse value '${e}' as a color function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&"color"===e.value.toLowerCase()&&onCSSFunctionSRgb(e,o,n,t)}));const a=String(s);return a!==e?a:void 0}const basePlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(e,{result:o})=>{if(hasFallback(e))return;if(hasSupportsAtRuleAncestor(e))return;const n=e.value;if(!n.toLowerCase().includes("color("))return;const t=modifiedValues(n,e,o,r);void 0!==t&&(e.cloneBefore({value:t}),r||e.remove())}}};basePlugin.postcss=!0;const postcssPlugin=r=>{const o=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},r);return o.enableProgressiveCustomProperties&&o.preserve?{postcssPlugin:"postcss-color-function",plugins:[e(),basePlugin(o)]}:basePlugin(o)};postcssPlugin.postcss=!0,module.exports=postcssPlugin;
diff --git a/plugins/postcss-color-function/dist/index.mjs b/plugins/postcss-color-function/dist/index.mjs
index 3087f58d4..1449c4584 100644
--- a/plugins/postcss-color-function/dist/index.mjs
+++ b/plugins/postcss-color-function/dist/index.mjs
@@ -1,29 +1 @@
-import t from"@csstools/postcss-progressive-custom-properties";import e from"postcss-value-parser";function hasFallback(t){const e=t.parent;if(!e)return!1;const n=t.prop.toLowerCase(),r=e.index(t);for(let t=0;t[t])));const a=o[0].length,s=o[0].map(((t,e)=>o.map((t=>t[e]))));let i=r.map((t=>s.map((e=>Array.isArray(t)?t.reduce(((t,n,r)=>t+n*(e[r]||0)),0):e.reduce(((e,n)=>e+n*t),0)))));return 1===n&&(i=i[0]),1===a?i.map((t=>t[0])):i}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */function lin_sRGB(t){return t.map((function(t){const e=t<0?-1:1,n=Math.abs(t);return n<.04045?t/12.92:e*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(t){return t.map((function(t){const e=t<0?-1:1,n=Math.abs(t);return n>.0031308?e*(1.055*Math.pow(n,1/2.4)-.055):12.92*t}))}function lin_sRGB_to_XYZ(t){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],t)}function XYZ_to_lin_sRGB(t){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],t)}function lin_2020(t){const e=1.09929682680944;return t.map((function(t){const n=t<0?-1:1,r=Math.abs(t);return r<.08124285829863151?t/4.5:n*Math.pow((r+e-1)/e,1/.45)}))}function D50_to_D65(t){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],t)}function XYZ_to_OKLab(t){const e=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],t);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],e.map((t=>Math.cbrt(t))))}function OKLab_to_XYZ(t){const e=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],t);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],e.map((t=>t**3)))}function OKLab_to_OKLCH(t){const e=180*Math.atan2(t[2],t[1])/Math.PI;return[t[0],Math.sqrt(t[1]**2+t[2]**2),e>=0?e:e+360]}function OKLCH_to_OKLab(t){return[t[0],t[1]*Math.cos(t[2]*Math.PI/180),t[1]*Math.sin(t[2]*Math.PI/180)]}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */function deltaEOK(t,e){const[n,r,o]=t,[a,s,i]=e,u=n-a,c=r-s,l=o-i;return Math.sqrt(u**2+c**2+l**2)}function mapGamut(t,e,n){return binarySearchGamut(t,e,n)}function binarySearchGamut(t,e,n){let r=0,o=t[1];const a=t;for(;o-r>1e-4;){const t=clip(e(a));deltaEOK(OKLCH_to_OKLab(a),OKLCH_to_OKLab(n(t)))-.02<1e-4?r=a[1]:o=a[1],a[1]=(o+r)/2}return clip(e([...a]))}function clip(t){return t.map((t=>t<0?0:t>1?1:t))}function inGamut(t){const[e,n,r]=t;return e>=-1e-4&&e<=1.0001&&n>=-1e-4&&n<=1.0001&&r>=-1e-4&&r<=1.0001}function a98RgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1,n=Math.abs(t);return e*Math.pow(n,563/256)})),e=multiplyMatrices([[.5766690429101305,.1855582379065463,.1882286462349947],[.29734497525053605,.6273635662554661,.07529145849399788],[.02703136138641234,.07068885253582723,.9913375368376388]],e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz50ToSRgb(t){let e=t.slice();e=D50_to_D65(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz65ToSRgb(t){let e=t.slice(),n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function displayP3ToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function prophotoRgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1;return Math.abs(t)<=.03125?t/16:e*Math.pow(t,1.8)})),e=multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],e),e=D50_to_D65(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function rec2020ToSRgb(t){let e=t.slice();e=lin_2020(e),e=multiplyMatrices([[.6369580483012914,.14461690358620832,.1688809751641721],[.2627002120112671,.6779980715188708,.05930171646986196],[0,.028072693049087428,1.060985057710791]],e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbLinearToSRgb(t){let e=t.slice();e=lin_sRGB_to_XYZ(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=lin_sRGB_to_XYZ(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function onCSSFunctionSRgb(t,n,r,o){const a=e.stringify(t),s=t.value,i=t.nodes.slice().filter((t=>"comment"!==t.type&&"space"!==t.type));let u,c=null;if("color"===s.toLowerCase()&&(c=colorFunctionContents(i)),!c)return;switch(t.value="rgb",transformAlpha(t,c.slash,c.alpha),c.colorSpace){case"srgb":u=sRgbToSRgb;break;case"srgb-linear":u=sRgbLinearToSRgb;break;case"a98-rgb":u=a98RgbToSRgb;break;case"prophoto-rgb":u=prophotoRgbToSRgb;break;case"display-p3":u=displayP3ToSRgb;break;case"rec2020":u=rec2020ToSRgb;break;case"xyz-d50":u=cieXyz50ToSRgb;break;case"xyz-d65":case"xyz":u=cieXyz65ToSRgb;break;default:return}const l=(_=c,_.parameters.map((t=>t.value))).map((t=>parseFloat(t.number)));var _;const p=u(l);!inGamut(l)&&o&&n.warn(r,`"${a}" is out of gamut for "${c.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),t.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[2])),type:"word"}],c.alpha&&(t.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),t.nodes.push(c.alpha))}function isColorSpaceNode(t){if(!t||"word"!==t.type)return!1;switch(t.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const n=e.unit(t.value);return!!n&&!!n.number}function isNumericNodePercentageOrNumber(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const n=e.unit(t.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(t){return t&&"function"===t.type&&"calc"===t.value.toLowerCase()}function isVarNode(t){return t&&"function"===t.type&&"var"===t.value.toLowerCase()}function colorFunctionContents(t){if(!isColorSpaceNode(t[0]))return null;const n={colorSpace:t[0].value.toLowerCase(),colorSpaceNode:t[0],parameters:[]};for(let o=1;o3&&(n.parameters=n.parameters.slice(0,3))),n}function transformAlpha(t,n,r){if(!n||!r)return;if(t.value="rgba",n.value=",",n.before="",!isNumericNode(r))return;const o=e.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function canParseAsUnit(t){if(!t||!t.value)return!1;try{return!1!==e.unit(t.value)}catch(t){return!1}}function modifiedValues(t,n,r,o){let a;try{a=e(t)}catch(e){n.warn(r,`Failed to parse value '${t}' as a color function. Leaving the original value intact.`)}if(void 0===a)return;a.walk((t=>{t.type&&"function"===t.type&&"color"===t.value.toLowerCase()&&onCSSFunctionSRgb(t,n,r,o)}));const s=String(a);return s!==t?s:void 0}const basePlugin=t=>{const e="preserve"in Object(t)&&Boolean(t.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const r=t.value;if(!r.toLowerCase().includes("color("))return;const o=modifiedValues(r,t,n,e);void 0!==o&&(t.cloneBefore({value:o}),e||t.remove())}}};basePlugin.postcss=!0;const postcssPlugin=e=>{const n=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},e);return n.enableProgressiveCustomProperties&&n.preserve?{postcssPlugin:"postcss-color-function",plugins:[t(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0;export{postcssPlugin as default};
+import e from"@csstools/postcss-progressive-custom-properties";import r from"postcss-value-parser";import{conversions as t,utils as o}from"@csstools/color-helpers";function hasFallback(e){const r=e.parent;if(!r)return!1;const t=e.prop.toLowerCase(),o=r.index(e);for(let e=0;e"comment"!==e.type&&"space"!==e.type));let l,p=null;if("color"===c.toLowerCase()&&(p=colorFunctionContents(i)),!p)return;switch(e.value="rgb",transformAlpha(e,p.slash,p.alpha),p.colorSpace){case"srgb":l=t.sRGB_to_sRGB;break;case"srgb-linear":l=t.sRGB_linear_to_sRGB;break;case"a98-rgb":l=t.a98_RGB_to_sRGB;break;case"prophoto-rgb":l=t.proPhoto_RGB_to_sRGB;break;case"display-p3":l=t.p3_to_sRGB;break;case"rec2020":l=t.rec_2020_to_sRGB;break;case"xyz-d50":l=t.cie_XYZ_50_to_sRGB;break;case"xyz-d65":case"xyz":l=t.cie_XYZ_65_to_sRGB;break;default:return}const d=(f=p,f.parameters.map((e=>e.value))).map((e=>parseFloat(e.number)));var f;const v=l(d);!o.inGamut(d)&&a&&n.warn(s,`"${u}" is out of gamut for "${p.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[2])),type:"word"}],p.alpha&&(e.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.push(p.alpha))}function isColorSpaceNode(e){if(!e||"word"!==e.type)return!1;switch(e.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=r.unit(e.value);return!!t&&!!t.number}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=r.unit(e.value);return!!t&&("%"===t.unit||""===t.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function colorFunctionContents(e){if(!isColorSpaceNode(e[0]))return null;const t={colorSpace:e[0].value.toLowerCase(),colorSpaceNode:e[0],parameters:[]};for(let n=1;n3&&(t.parameters=t.parameters.slice(0,3))),t}function transformAlpha(e,t,o){if(!t||!o)return;if(e.value="rgba",t.value=",",t.before="",!isNumericNode(o))return;const n=r.unit(o.value);n&&"%"===n.unit&&(n.number=String(parseFloat(n.number)/100),o.value=String(n.number))}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==r.unit(e.value)}catch(e){return!1}}function modifiedValues(e,t,o,n){let s;try{s=r(e)}catch(r){t.warn(o,`Failed to parse value '${e}' as a color function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&"color"===e.value.toLowerCase()&&onCSSFunctionSRgb(e,t,o,n)}));const a=String(s);return a!==e?a:void 0}const basePlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(e,{result:t})=>{if(hasFallback(e))return;if(hasSupportsAtRuleAncestor(e))return;const o=e.value;if(!o.toLowerCase().includes("color("))return;const n=modifiedValues(o,e,t,r);void 0!==n&&(e.cloneBefore({value:n}),r||e.remove())}}};basePlugin.postcss=!0;const postcssPlugin=r=>{const t=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},r);return t.enableProgressiveCustomProperties&&t.preserve?{postcssPlugin:"postcss-color-function",plugins:[e(),basePlugin(t)]}:basePlugin(t)};postcssPlugin.postcss=!0;export{postcssPlugin as default};
diff --git a/plugins/postcss-color-function/package.json b/plugins/postcss-color-function/package.json
index b7be2767b..7b9cf910c 100644
--- a/plugins/postcss-color-function/package.json
+++ b/plugins/postcss-color-function/package.json
@@ -29,6 +29,7 @@
"dist"
],
"dependencies": {
+ "@csstools/color-helpers": "^0.0.0",
"@csstools/postcss-progressive-custom-properties": "^2.0.0",
"postcss-value-parser": "^4.2.0"
},
diff --git a/plugins/postcss-color-function/src/convert-a98-rgb-to-srgb.ts b/plugins/postcss-color-function/src/convert-a98-rgb-to-srgb.ts
deleted file mode 100644
index 939e35a46..000000000
--- a/plugins/postcss-color-function/src/convert-a98-rgb-to-srgb.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { gam_sRGB, lin_a98rgb, lin_a98rgb_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function a98RgbToSRgb(a98: color): color {
- let conversion = a98.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- conversion = lin_a98rgb(conversion);
- conversion = lin_a98rgb_to_XYZ(conversion);
-
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/convert-cie-xyz-50-to-srgb.ts b/plugins/postcss-color-function/src/convert-cie-xyz-50-to-srgb.ts
deleted file mode 100644
index 598ffe16d..000000000
--- a/plugins/postcss-color-function/src/convert-cie-xyz-50-to-srgb.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { D50_to_D65, gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function cieXyz50ToSRgb(xyz: color): color {
- let conversion = xyz.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- conversion = D50_to_D65(conversion);
-
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/convert-cie-xyz-65-to-srgb.ts b/plugins/postcss-color-function/src/convert-cie-xyz-65-to-srgb.ts
deleted file mode 100644
index fc3f58ed2..000000000
--- a/plugins/postcss-color-function/src/convert-cie-xyz-65-to-srgb.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function cieXyz65ToSRgb(xyz: color): color {
- let conversion = xyz.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/convert-display-p3-to-srgb.ts b/plugins/postcss-color-function/src/convert-display-p3-to-srgb.ts
deleted file mode 100644
index 8ea108b5b..000000000
--- a/plugins/postcss-color-function/src/convert-display-p3-to-srgb.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { gam_sRGB, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function displayP3ToSRgb(displayP3: color): color {
- let conversion = displayP3.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- conversion = lin_P3(conversion);
- conversion = lin_P3_to_XYZ(conversion);
-
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/convert-prophoto-rgb-to-srgb.ts b/plugins/postcss-color-function/src/convert-prophoto-rgb-to-srgb.ts
deleted file mode 100644
index 327205d19..000000000
--- a/plugins/postcss-color-function/src/convert-prophoto-rgb-to-srgb.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { D50_to_D65, gam_sRGB, lin_ProPhoto, lin_ProPhoto_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function prophotoRgbToSRgb(prophoto: color): color {
- let conversion = prophoto.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- conversion = lin_ProPhoto(conversion);
- conversion = lin_ProPhoto_to_XYZ(conversion);
- conversion = D50_to_D65(conversion);
-
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/convert-rec2020-to-srgb.ts b/plugins/postcss-color-function/src/convert-rec2020-to-srgb.ts
deleted file mode 100644
index e6629f79b..000000000
--- a/plugins/postcss-color-function/src/convert-rec2020-to-srgb.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { gam_sRGB, lin_2020, lin_2020_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function rec2020ToSRgb(rec: color): color {
- let conversion = rec.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- conversion = lin_2020(conversion);
- conversion = lin_2020_to_XYZ(conversion);
-
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/convert-srgb-linear-to-srgb.ts b/plugins/postcss-color-function/src/convert-srgb-linear-to-srgb.ts
deleted file mode 100644
index 94e8edb98..000000000
--- a/plugins/postcss-color-function/src/convert-srgb-linear-to-srgb.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function sRgbLinearToSRgb(linearSRgb: color): color {
- let conversion = linearSRgb.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- conversion = lin_sRGB_to_XYZ(conversion);
-
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/convert-srgb-to-srgb.ts b/plugins/postcss-color-function/src/convert-srgb-to-srgb.ts
deleted file mode 100644
index 3bf206768..000000000
--- a/plugins/postcss-color-function/src/convert-srgb-to-srgb.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function sRgbToSRgb(sRgb: color): color {
- let conversion = sRgb.slice() as color;
-
- // https://www.w3.org/TR/css-color-4/#predefined-to-predefined
- // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
- conversion = lin_sRGB(conversion);
- conversion = lin_sRGB_to_XYZ(conversion);
-
- let oklch = conversion.slice() as color;
- oklch = XYZ_to_OKLab(oklch);
- oklch = OKLab_to_OKLCH(oklch);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
- conversion = XYZ_to_lin_sRGB(conversion);
- // 4. Convert from linear - light RGB to RGB(do gamma encoding)
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion);
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- });
-}
diff --git a/plugins/postcss-color-function/src/css-color-4/conversions.ts b/plugins/postcss-color-function/src/css-color-4/conversions.ts
deleted file mode 100644
index 636f08f90..000000000
--- a/plugins/postcss-color-function/src/css-color-4/conversions.ts
+++ /dev/null
@@ -1,512 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */
-
-/* eslint-disable @typescript-eslint/no-loss-of-precision */
-
-import { multiplyMatrices } from './multiply-matrices';
-
-type color = [number, number, number];
-
-// Sample code for color conversions
-// Conversion can also be done using ICC profiles and a Color Management System
-// For clarity, a library is used for matrix multiplication (multiply-matrices.js)
-
-// standard white points, defined by 4-figure CIE x,y chromaticities
-export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
-export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290];
-
-// sRGB-related functions
-
-export function lin_sRGB(RGB: color): color {
- // convert an array of sRGB values
- // where in-gamut values are in the range [0 - 1]
- // to linear light (un-companded) form.
- // https://en.wikipedia.org/wiki/SRGB
- // Extended transfer function:
- // for negative values, linear portion is extended on reflection of axis,
- // then reflected power function is used.
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs < 0.04045) {
- return val / 12.92;
- }
-
- return sign * (Math.pow((abs + 0.055) / 1.055, 2.4));
- }) as color;
-}
-
-export function gam_sRGB(RGB: color): color {
- // convert an array of linear-light sRGB values in the range 0.0-1.0
- // to gamma corrected form
- // https://en.wikipedia.org/wiki/SRGB
- // Extended transfer function:
- // For negative values, linear portion extends on reflection
- // of axis, then uses reflected pow below that
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs > 0.0031308) {
- return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055);
- }
-
- return 12.92 * val;
- }) as color;
-}
-
-export function lin_sRGB_to_XYZ(rgb: color): color {
- // convert an array of linear-light sRGB values to CIE XYZ
- // using sRGB's own white, D65 (no chromatic adaptation)
-
- const M = [
- [0.41239079926595934, 0.357584339383878, 0.1804807884018343],
- [0.21263900587151027, 0.715168678767756, 0.07219231536073371],
- [0.01933081871559182, 0.11919477979462598, 0.9505321522496607],
- ];
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_sRGB(XYZ: color): color {
- // convert XYZ to linear-light sRGB
-
- const M = [
- [3.2409699419045226, -1.537383177570094, -0.4986107602930034],
- [-0.9692436362808796, 1.8759675015077202, 0.04155505740717559],
- [0.05563007969699366, -0.20397695888897652, 1.0569715142428786],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// display-p3-related functions
-
-
-export function lin_P3(RGB: color): color {
- // convert an array of display-p3 RGB values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
-
- return lin_sRGB(RGB); // same as sRGB
-}
-
-export function gam_P3(RGB: color): color {
- // convert an array of linear-light display-p3 RGB in the range 0.0-1.0
- // to gamma corrected form
-
- return gam_sRGB(RGB); // same as sRGB
-}
-
-export function lin_P3_to_XYZ(rgb: color): color {
- // convert an array of linear-light display-p3 values to CIE XYZ
- // using D65 (no chromatic adaptation)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.4865709486482162, 0.26566769316909306, 0.1982172852343625],
- [0.2289745640697488, 0.6917385218365064, 0.079286914093745],
- [0.0000000000000000, 0.04511338185890264, 1.043944368900976],
- ];
- // 0 was computed as -3.972075516933488e-17
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_P3(XYZ: color): color {
- // convert XYZ to linear-light P3
- const M = [
- [2.493496911941425, -0.9313836179191239, -0.40271078445071684],
- [-0.8294889695615747, 1.7626640603183463, 0.023624685841943577],
- [0.03584583024378447, -0.07617238926804182, 0.9568845240076872],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// prophoto-rgb functions
-
-export function lin_ProPhoto(RGB: color): color {
- // convert an array of prophoto-rgb values
- // where in-gamut colors are in the range [0.0 - 1.0]
- // to linear light (un-companded) form.
- // Transfer curve is gamma 1.8 with a small linear portion
- // Extended transfer function
- const Et2 = 16 / 512;
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs <= Et2) {
- return val / 16;
- }
-
- return sign * Math.pow(val, 1.8);
- }) as color;
-}
-
-export function gam_ProPhoto(RGB: color): color {
- // convert an array of linear-light prophoto-rgb in the range 0.0-1.0
- // to gamma corrected form
- // Transfer curve is gamma 1.8 with a small linear portion
- // TODO for negative values, extend linear portion on reflection of axis, then add pow below that
- const Et = 1 / 512;
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs >= Et) {
- return sign * Math.pow(abs, 1 / 1.8);
- }
-
- return 16 * val;
- }) as color;
-}
-
-export function lin_ProPhoto_to_XYZ(rgb: color): color {
- // convert an array of linear-light prophoto-rgb values to CIE XYZ
- // using D50 (so no chromatic adaptation needed afterwards)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.7977604896723027, 0.13518583717574031, 0.0313493495815248],
- [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902],
- [0.0, 0.0, 0.8251046025104601],
- ];
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_ProPhoto(XYZ: color): color {
- // convert XYZ to linear-light prophoto-rgb
- const M = [
- [1.3457989731028281, -0.25558010007997534, -0.05110628506753401],
- [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973],
- [0.0, 0.0, 1.2119675456389454],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// a98-rgb functions
-
-export function lin_a98rgb(RGB: color): color {
- // convert an array of a98-rgb values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
- // negative values are also now accepted
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- return sign * Math.pow(abs, 563 / 256);
- }) as color;
-}
-
-export function gam_a98rgb(RGB: color): color {
- // convert an array of linear-light a98-rgb in the range 0.0-1.0
- // to gamma corrected form
- // negative values are also now accepted
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- return sign * Math.pow(abs, 256 / 563);
- }) as color;
-}
-
-export function lin_a98rgb_to_XYZ(rgb: color): color {
- // convert an array of linear-light a98-rgb values to CIE XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- // has greater numerical precision than section 4.3.5.3 of
- // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
- // but the values below were calculated from first principles
- // from the chromaticity coordinates of R G B W
- // see matrixmaker.html
- const M = [
- [0.5766690429101305, 0.1855582379065463, 0.1882286462349947],
- [0.29734497525053605, 0.6273635662554661, 0.07529145849399788],
- [0.02703136138641234, 0.07068885253582723, 0.9913375368376388],
- ];
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_a98rgb(XYZ: color): color {
- // convert XYZ to linear-light a98-rgb
- const M = [
- [2.0415879038107465, -0.5650069742788596, -0.34473135077832956],
- [-0.9692436362808795, 1.8759675015077202, 0.04155505740717557],
- [0.013444280632031142, -0.11836239223101838, 1.0151749943912054],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-//Rec. 2020-related functions
-
-export function lin_2020(RGB: color): color {
- // convert an array of rec2020 RGB values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
- // ITU-R BT.2020-2 p.4
-
- const α = 1.09929682680944;
- const β = 0.018053968510807;
-
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs < β * 4.5) {
- return val / 4.5;
- }
-
- return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45));
- }) as color;
-}
-
-export function gam_2020(RGB: color): color {
- // convert an array of linear-light rec2020 RGB in the range 0.0-1.0
- // to gamma corrected form
- // ITU-R BT.2020-2 p.4
-
- const α = 1.09929682680944;
- const β = 0.018053968510807;
-
-
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs > β) {
- return sign * (α * Math.pow(abs, 0.45) - (α - 1));
- }
-
- return 4.5 * val;
- }) as color;
-}
-
-export function lin_2020_to_XYZ(rgb: color): color {
- // convert an array of linear-light rec2020 values to CIE XYZ
- // using D65 (no chromatic adaptation)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.6369580483012914, 0.14461690358620832, 0.1688809751641721],
- [0.2627002120112671, 0.6779980715188708, 0.05930171646986196],
- [0.000000000000000, 0.028072693049087428, 1.060985057710791],
- ];
- // 0 is actually calculated as 4.994106574466076e-17
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_2020(XYZ: color): color {
- // convert XYZ to linear-light rec2020
- const M = [
- [1.7166511879712674, -0.35567078377639233, -0.25336628137365974],
- [-0.6666843518324892, 1.6164812366349395, 0.01576854581391113],
- [0.017639857445310783, -0.042770613257808524, 0.9421031212354738],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// Chromatic adaptation
-
-export function D65_to_D50(XYZ: color): color {
- // Bradford chromatic adaptation from D65 to D50
- // The matrix below is the result of three operations:
- // - convert from XYZ to retinal cone domain
- // - scale components from one reference white to another
- // - convert back to XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
- const M = [
- [1.0479298208405488, 0.022946793341019088, -0.05019222954313557],
- [0.029627815688159344, 0.990434484573249, -0.01707382502938514],
- [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-export function D50_to_D65(XYZ: color): color {
- // Bradford chromatic adaptation from D50 to D65
- const M = [
- [0.9554734527042182, -0.023098536874261423, 0.0632593086610217],
- [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008],
- [0.012314001688319899, -0.020507696433477912, 1.3303659366080753],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// CIE Lab and LCH
-
-export function XYZ_to_Lab(XYZ: color): color {
- // Assuming XYZ is relative to D50, convert to CIE Lab
- // from CIE standard, which now defines these as a rational fraction
- const ε = 216 / 24389; // 6^3/29^3
- const κ = 24389 / 27; // 29^3/3^3
-
- // compute xyz, which is XYZ scaled relative to reference white
- const xyz = XYZ.map((value, i) => value / D50[i]);
-
- // now compute f
- const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116);
-
- return [
- (116 * f[1]) - 16, // L
- 500 * (f[0] - f[1]), // a
- 200 * (f[1] - f[2]), // b
- ];
- // L in range [0,100]. For use in CSS, add a percent
-}
-
-export function Lab_to_XYZ(Lab: color): color {
- // Convert Lab to D50-adapted XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const κ = 24389 / 27; // 29^3/3^3
- const ε = 216 / 24389; // 6^3/29^3
- const f = [];
-
- // compute f, starting with the luminance-related term
- f[1] = (Lab[0] + 16) / 116;
- f[0] = Lab[1] / 500 + f[1];
- f[2] = f[1] - Lab[2] / 200;
-
- // compute xyz
- const xyz = [
- Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ,
- Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ,
- Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ,
- ];
-
- // Compute XYZ by scaling xyz by reference white
- return xyz.map((value, i) => value * D50[i]) as color;
-}
-
-export function Lab_to_LCH(Lab: color): color {
- // Convert to polar form
- const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI;
- return [
- Lab[0], // L is still L
- Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma
- hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
- ];
-}
-
-export function LCH_to_Lab(LCH: color): color {
- // Convert from polar form
- return [
- LCH[0], // L is still L
- LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a
- LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b
- ];
-}
-
-// OKLab and OKLCH
-// https://bottosson.github.io/posts/oklab/
-
-// XYZ <-> LMS matrices recalculated for consistent reference white
-// see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
-
-export function XYZ_to_OKLab(XYZ: color): color {
- // Given XYZ relative to D65, convert to OKLab
- const XYZtoLMS = [
- [0.8190224432164319, 0.3619062562801221, -0.12887378261216414],
- [0.0329836671980271, 0.9292868468965546, 0.03614466816999844],
- [0.048177199566046255, 0.26423952494422764, 0.6335478258136937],
- ];
- const LMStoOKLab = [
- [0.2104542553, 0.7936177850, -0.0040720468],
- [1.9779984951, -2.4285922050, 0.4505937099],
- [0.0259040371, 0.7827717662, -0.8086757660],
- ];
-
- const LMS = multiplyMatrices(XYZtoLMS, XYZ) as color;
- return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as color;
- // L in range [0,1]. For use in CSS, multiply by 100 and add a percent
-}
-
-export function OKLab_to_XYZ(OKLab: color): color {
- // Given OKLab, convert to XYZ relative to D65
- const LMStoXYZ = [
- [1.2268798733741557, -0.5578149965554813, 0.28139105017721583],
- [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701],
- [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418],
- ];
- const OKLabtoLMS = [
- [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339],
- [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402],
- [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399],
- ];
-
- const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as color;
- return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as color;
-}
-
-export function OKLab_to_OKLCH(OKLab: color): color {
- const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI;
- return [
- OKLab[0], // L is still L
- Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma
- hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
- ];
-}
-
-export function OKLCH_to_OKLab(OKLCH: color): color {
- return [
- OKLCH[0], // L is still L
- OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a
- OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b
- ];
-}
-
-// Premultiplied alpha conversions
-
-export function rectangular_premultiply(color: color, alpha: number): color {
- // given a color in a rectangular orthogonal colorspace
- // and an alpha value
- // return the premultiplied form
- return color.map((c) => c * alpha) as color;
-}
-
-export function rectangular_un_premultiply(color: color, alpha: number): color {
- // given a premultiplied color in a rectangular orthogonal colorspace
- // and an alpha value
- // return the actual color
- if (alpha === 0) {
- return color; // avoid divide by zero
- }
- return color.map((c) => c / alpha) as color;
-}
-
-export function polar_premultiply(color: color, alpha: number, hueIndex: number): color {
- // given a color in a cylindicalpolar colorspace
- // and an alpha value
- // return the premultiplied form.
- // the index says which entry in the color array corresponds to hue angle
- // for example, in OKLCH it would be 2
- // while in HSL it would be 0
- return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as color;
-}
-
-export function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color {
- // given a color in a cylindicalpolar colorspace
- // and an alpha value
- // return the actual color.
- // the hueIndex says which entry in the color array corresponds to hue angle
- // for example, in OKLCH it would be 2
- // while in HSL it would be 0
- if (alpha === 0) {
- return color; // avoid divide by zero
- }
- return color.map((c, i) => c / (hueIndex === i ? 1 : alpha)) as color;
-}
-
-// Convenience functions can easily be defined, such as
-export function hsl_premultiply(color: color, alpha: number): color {
- return polar_premultiply(color, alpha, 0);
-}
diff --git a/plugins/postcss-color-function/src/css-color-4/deltaEOK.ts b/plugins/postcss-color-function/src/css-color-4/deltaEOK.ts
deleted file mode 100644
index ce023047e..000000000
--- a/plugins/postcss-color-function/src/css-color-4/deltaEOK.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */
-
-// Calculate deltaE OK
-// simple root sum of squares
-type color = [number, number, number];
-export function deltaEOK(reference: color, sample: color): number {
- // Given reference and sample are both in OKLab
- const [L1, a1, b1] = reference;
- const [L2, a2, b2] = sample;
- const ΔL = L1 - L2;
- const Δa = a1 - a2;
- const Δb = b1 - b2;
- return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2);
-}
diff --git a/plugins/postcss-color-function/src/css-color-4/map-gamut.ts b/plugins/postcss-color-function/src/css-color-4/map-gamut.ts
deleted file mode 100644
index 168068986..000000000
--- a/plugins/postcss-color-function/src/css-color-4/map-gamut.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { OKLCH_to_OKLab } from './conversions';
-import { deltaEOK } from './deltaEOK';
-
-type color = [number, number, number];
-
-export function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color {
- return binarySearchGamut(startOKLCH, toDestination, fromDestination);
-}
-
-function binarySearchGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color {
- let min = 0;
- let max = startOKLCH[1];
- const current = startOKLCH;
-
- while (max - min > 0.0001) {
- const clipped = clip(toDestination(current));
- const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped)));
- // are we inside the gamut (or very close to the boundary, outside)
- if (deltaE - 0.02 < 0.0001) {
- min = current[1];
- } else {
- max = current[1];
- }
- // binary search
- current[1] = (max + min) / 2;
- }
-
- return clip(toDestination([...current]));
-}
-
-export function clip(color: color): color {
- return color.map(val => {
- if (val < 0) {
- return 0;
- } else if (val > 1) {
- return 1;
- } else {
- return val;
- }
- }) as color;
-}
-
-export function inGamut(x: color): boolean {
- const [xX, xY, xZ] = x;
- return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001;
-}
-
diff --git a/plugins/postcss-color-function/src/css-color-4/utilities.ts b/plugins/postcss-color-function/src/css-color-4/utilities.ts
deleted file mode 100644
index b3c4368cd..000000000
--- a/plugins/postcss-color-function/src/css-color-4/utilities.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
- */
-
-import { D50_to_D65, D65_to_D50, gam_2020, gam_P3, gam_sRGB, Lab_to_LCH, Lab_to_XYZ, LCH_to_Lab, lin_2020, lin_2020_to_XYZ, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, XYZ_to_Lab, XYZ_to_lin_2020, XYZ_to_lin_P3, XYZ_to_lin_sRGB } from './conversions';
-
-type color = [number, number, number];
-
-// utility functions for color conversions
-// needs conversions.js
-
-export function sRGB_to_luminance(RGB: color): number {
- // convert an array of gamma-corrected sRGB values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ
- // and return luminance (the Y value)
-
- const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB));
- return XYZ[1];
-}
-
-export function contrast(RGB1: color, RGB2: color): number {
- // return WCAG 2.1 contrast ratio
- // https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
- // for two sRGB values
- // given as arrays of 0.0 to 1.0
-
- const L1 = sRGB_to_luminance(RGB1);
- const L2 = sRGB_to_luminance(RGB2);
-
- if (L1 > L2) {
- return (L1 + 0.05) / (L2 + 0.05);
- }
-
- return (L2 + 0.05) / (L1 + 0.05);
-}
-
-export function sRGB_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected sRGB values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB)))));
-}
-
-export function P3_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected display-p3 values
- // in the 0.0 to 1.0 range
- // to linear-light display-p3, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB)))));
-}
-
-export function r2020_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected rec.2020 values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB)))));
-}
-
-export function LCH_to_sRGB(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light sRGB
- // and finally to gamma corrected sRGB
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_sRGB(XYZ_to_lin_sRGB(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-export function LCH_to_P3(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light display-p3
- // and finally to gamma corrected display-p3
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_P3(XYZ_to_lin_P3(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-export function LCH_to_r2020(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light rec.2020
- // and finally to gamma corrected rec.2020
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-// this is straight from the CSS Color 4 spec
-
-export function hslToRgb(hsl: color): color {
- // For simplicity, this algorithm assumes that the hue has been normalized
- // to a number in the half-open range [0, 6), and the saturation and lightness
- // have been normalized to the range [0, 1]. It returns an array of three numbers
- // representing the red, green, and blue channels of the colors,
- // normalized to the range [0, 1]
- const [hue, sat, light] = hsl;
-
- let t2: number;
- if (light <= .5) {
- t2 = light * (sat + 1);
- } else {
- t2 = light + sat - (light * sat);
- }
- const t1 = light * 2 - t2;
- const r = hueToRgb(t1, t2, hue + 2);
- const g = hueToRgb(t1, t2, hue);
- const b = hueToRgb(t1, t2, hue - 2);
- return [r, g, b];
-}
-
-export function hueToRgb(t1: number, t2: number, hue: number): number {
- if (hue < 0) {
- hue += 6;
- }
- if (hue >= 6) {
- hue -= 6;
- }
-
- if (hue < 1) {
- return (t2 - t1) * hue + t1;
- } else if (hue < 3) {
- return t2;
- } else if (hue < 4) {
- return (t2 - t1) * (4 - hue) + t1;
- } else {
- return t1;
- }
-}
-
-// These are the naive algorithms from CS Color 4
-
-export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color {
- // CMYK is an array of four values
- // in the range [0.0, 1.0]
- // the optput is an array of [RGB]
- // also in the [0.0, 1.0] range
- // because the naive algorithm does not generate out of gamut colors
- // neither does it generate accurate simulations of practical CMYK colors
-
- const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3];
-
- const red = 1 - Math.min(1, cyan * (1 - black) + black);
- const green = 1 - Math.min(1, magenta * (1 - black) + black);
- const blue = 1 - Math.min(1, yellow * (1 - black) + black);
-
- return [red, green, blue];
-
-}
-
-export function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number] {
- // RGB is an arravy of three values
- // in the range [0.0, 1.0]
- // the output is an array of [CMYK]
- // also in the [0.0, 1.0] range
- // with maximum GCR and (I think) 200% TAC
- // the naive algorithm does not generate out of gamut colors
- // neither does it generate accurate simulations of practical CMYK colors
-
- const red = RGB[0], green = RGB[1], blue = RGB[2];
-
- const black = 1 - Math.max(red, green, blue);
- const cyan = (black == 1.0) ? 0 : (1 - red - black) / (1 - black);
- const magenta = (black == 1.0) ? 0 : (1 - green - black) / (1 - black);
- const yellow = (black == 1.0) ? 0 : (1 - blue - black) / (1 - black);
-
- return [cyan, magenta, yellow, black];
-}
-
-// Chromaticity utilities
-
-export function XYZ_to_xy(XYZ: color): [number, number] {
- // Convert an array of three XYZ values
- // to x,y chromaticity coordinates
-
- const X = XYZ[0];
- const Y = XYZ[1];
- const Z = XYZ[2];
- const sum = X + Y + Z;
- return [X / sum, Y / sum];
-}
-
-export function xy_to_uv(xy: [number, number]): [number, number] {
- // convert an x,y chromaticity pair
- // to u*,v* chromaticities
-
- const x = xy[0];
- const y = xy[1];
- const denom = -2 * x + 12 * y + 3;
- return [4 * x / denom, 9 * y / denom];
-}
-
-export function XYZ_to_uv(XYZ: color): [number, number] {
- // Convert an array of three XYZ values
- // to u*,v* chromaticity coordinates
-
- const X = XYZ[0];
- const Y = XYZ[1];
- const Z = XYZ[2];
- const denom = X + 15 * Y + 3 * Z;
- return [4 * X / denom, 9 * Y / denom];
-}
diff --git a/plugins/postcss-color-function/src/on-css-function.ts b/plugins/postcss-color-function/src/on-css-function.ts
index f02f1a768..05a3ecfdf 100644
--- a/plugins/postcss-color-function/src/on-css-function.ts
+++ b/plugins/postcss-color-function/src/on-css-function.ts
@@ -1,15 +1,7 @@
import type { Declaration, Result } from 'postcss';
import type { FunctionNode, Dimension, Node, DivNode, WordNode } from 'postcss-value-parser';
import valueParser from 'postcss-value-parser';
-import { a98RgbToSRgb } from './convert-a98-rgb-to-srgb';
-import { cieXyz50ToSRgb } from './convert-cie-xyz-50-to-srgb';
-import { cieXyz65ToSRgb } from './convert-cie-xyz-65-to-srgb';
-import { displayP3ToSRgb } from './convert-display-p3-to-srgb';
-import { prophotoRgbToSRgb } from './convert-prophoto-rgb-to-srgb';
-import { rec2020ToSRgb } from './convert-rec2020-to-srgb';
-import { sRgbLinearToSRgb } from './convert-srgb-linear-to-srgb';
-import { sRgbToSRgb } from './convert-srgb-to-srgb';
-import { inGamut } from './css-color-4/map-gamut';
+import { conversions, utils } from '@csstools/color-helpers';
export function onCSSFunctionSRgb(node: FunctionNode, decl: Declaration, result: Result, preserve: boolean) {
const originalForWarnings = valueParser.stringify(node);
@@ -38,31 +30,31 @@ export function onCSSFunctionSRgb(node: FunctionNode, decl: Declaration, result:
let toRGB: (x: [number, number, number]) => [number, number, number];
switch (nodes.colorSpace) {
case 'srgb':
- toRGB = sRgbToSRgb;
+ toRGB = conversions.sRGB_to_sRGB;
break;
case 'srgb-linear':
- toRGB = sRgbLinearToSRgb;
+ toRGB = conversions.sRGB_linear_to_sRGB;
break;
case 'a98-rgb':
- toRGB = a98RgbToSRgb;
+ toRGB = conversions.a98_RGB_to_sRGB;
break;
case 'prophoto-rgb':
- toRGB = prophotoRgbToSRgb;
+ toRGB = conversions.proPhoto_RGB_to_sRGB;
break;
case 'display-p3':
- toRGB = displayP3ToSRgb;
+ toRGB = conversions.p3_to_sRGB;
break;
case 'rec2020':
- toRGB = rec2020ToSRgb;
+ toRGB = conversions.rec_2020_to_sRGB;
break;
case 'xyz-d50':
- toRGB = cieXyz50ToSRgb;
+ toRGB = conversions.cie_XYZ_50_to_sRGB;
break;
case 'xyz-d65':
- toRGB = cieXyz65ToSRgb;
+ toRGB = conversions.cie_XYZ_65_to_sRGB;
break;
case 'xyz':
- toRGB = cieXyz65ToSRgb;
+ toRGB = conversions.cie_XYZ_65_to_sRGB;
break;
default:
return;
@@ -77,7 +69,7 @@ export function onCSSFunctionSRgb(node: FunctionNode, decl: Declaration, result:
channelNumbers,
);
- if (!inGamut(channelNumbers) && preserve) {
+ if (!utils.inGamut(channelNumbers) && preserve) {
decl.warn(
result,
`"${originalForWarnings}" is out of gamut for "${nodes.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`,
diff --git a/plugins/postcss-color-function/test/basic.expect.css b/plugins/postcss-color-function/test/basic.expect.css
index f38be16f0..c4dc2cb9a 100644
--- a/plugins/postcss-color-function/test/basic.expect.css
+++ b/plugins/postcss-color-function/test/basic.expect.css
@@ -163,7 +163,7 @@
.test-out-of-range-values-srgb {
color-1: rgb(128,0,255);
color-2: rgb(125,0,245);
- color-3: rgb(25,255,26);
+ color-3: rgb(25,255,25);
color-4: rgb(159,255,151);
}
diff --git a/plugins/postcss-color-function/test/basic.preserve-true.expect.css b/plugins/postcss-color-function/test/basic.preserve-true.expect.css
index 1eb0f0573..b0322787b 100644
--- a/plugins/postcss-color-function/test/basic.preserve-true.expect.css
+++ b/plugins/postcss-color-function/test/basic.preserve-true.expect.css
@@ -223,7 +223,7 @@
color-1: color(srgb 0.5 0 1);
color-2: rgb(125,0,245);
color-2: color(srgb 0.5 -0.2 1);
- color-3: rgb(25,255,26);
+ color-3: rgb(25,255,25);
color-3: color(srgb 0.1 1 0.1);
color-4: rgb(159,255,151);
color-4: color(srgb 0.1 1.1 0.1);
diff --git a/plugins/postcss-hwb-function/CHANGELOG.md b/plugins/postcss-hwb-function/CHANGELOG.md
index 8fa1b67d9..d077b2312 100644
--- a/plugins/postcss-hwb-function/CHANGELOG.md
+++ b/plugins/postcss-hwb-function/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changes to PostCSS HWB Function
+### Unreleased (minor)
+
+- Add: `@csstools/color-helpers` dependency for all color value transformations.
+
### 2.0.1 (January 28, 2023)
- Improve `types` declaration in `package.json`
diff --git a/plugins/postcss-hwb-function/dist/hwb.d.ts b/plugins/postcss-hwb-function/dist/hwb.d.ts
deleted file mode 100644
index 0429dd937..000000000
--- a/plugins/postcss-hwb-function/dist/hwb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function hwbToRgb(hwb: color): color;
-export {};
diff --git a/plugins/postcss-hwb-function/dist/index.cjs b/plugins/postcss-hwb-function/dist/index.cjs
index 1d410ba17..f3d085e04 100644
--- a/plugins/postcss-hwb-function/dist/index.cjs
+++ b/plugins/postcss-hwb-function/dist/index.cjs
@@ -1 +1 @@
-"use strict";var e=require("postcss-value-parser");function hasSupportsAtRuleAncestor(e){let n=e.parent;for(;n;)if("atrule"===n.type){if("supports"===n.name.toLowerCase()&&-1!==n.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;n=n.parent}else n=n.parent;return!1}function hwbToRgb(e){const n=e[0];let r=e[1],t=e[2];if(r/=100,t/=100,r+t>=1){const e=r/(r+t);return[e,e,e].map((e=>Math.round(255*e)))}const o=hslToRgb([n,100,50]);for(let e=0;e<3;e++)o[e]*=1-r-t,o[e]+=r;return o.map((e=>Math.round(255*e)))}function hslToRgb(e){let n=e[0],r=e[1],t=e[2];function f(e){const o=(e+n/30)%12,u=r*Math.min(t,1-t);return t-u*Math.max(-1,Math.min(o-3,9-o,1))}return n%=360,n<0&&(n+=360),r/=100,t/=100,[f(0),f(8),f(4)]}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),r=hwbFunctionContents(n);if(!r)return;if(n.length>3&&(!r.slash||!r.alpha))return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[t,o,u]=[(i=r).hNode,i.wNode,i.bNode];var i;const[a,s,c]=channelDimensions(r),l=hwbToRgb([a.number,s.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(t)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,t,{...t,value:String(l[0])}),replaceWith(e.nodes,o,{...o,value:String(l[1])}),replaceWith(e.nodes,u,{...u,value:String(l[2])})}function isNumericNode(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&!!r.number}function isNumericNodeHueLike(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(n){if(!isNumericNodeHueLike(n[0]))return null;if(!isNumericNodePercentageOrNumber(n[1]))return null;if(!isNumericNodePercentageOrNumber(n[2]))return null;const r={h:e.unit(n[0].value),hNode:n[0],w:e.unit(n[1].value),wNode:n[1],b:e.unit(n[2].value),bNode:n[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(normalizeBlackOrWhiteNode(r.w),normalizeBlackOrWhiteNode(r.b),(t=n[3])&&"div"===t.type&&"/"===t.value&&(r.slash=n[3]),(isNumericNodePercentageOrNumber(n[4])||isCalcNode(n[4])||isVarNode(n[4]))&&(r.alpha=n[4]),r);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(n,r,t){if(!r||!t)return;if(n.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(n){if(!n||!n.value)return!1;try{return!1!==e.unit(n.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(n,r,t){let o;try{o=e(n)}catch(e){r.warn(t,`Failed to parse value '${n}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==n?u:void 0}function insertAtSupportsAfterCorrectRule(e,n,r){let t=n,o=n.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===r;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0,module.exports=postcssPlugin;
+"use strict";var e=require("postcss-value-parser"),r=require("@csstools/color-helpers");function hasSupportsAtRuleAncestor(e){let r=e.parent;for(;r;)if("atrule"===r.type){if("supports"===r.name.toLowerCase()&&-1!==r.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;r=r.parent}else r=r.parent;return!1}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),t=hwbFunctionContents(n);if(!t)return;if(n.length>3&&(!t.slash||!t.alpha))return;e.value="rgb",transformAlpha(e,t.slash,t.alpha);const[o,u,i]=[(a=t).hNode,a.wNode,a.bNode];var a;const[s,c,l]=channelDimensions(t),p=[s.number,c.number,l.number].map((e=>parseFloat(e))),d=r.conversions.HWB_to_sRGB(p).map((e=>Math.round(255*e)));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,i,{...i,value:String(d[2])})}function isNumericNode(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&!!n.number}function isNumericNodeHueLike(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);if(!n)return!1;const t=n.unit.toLowerCase();return!!n.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(r){if(!isNumericNodeHueLike(r[0]))return null;if(!isNumericNodePercentageOrNumber(r[1]))return null;if(!isNumericNodePercentageOrNumber(r[2]))return null;const n={h:e.unit(r[0].value),hNode:r[0],w:e.unit(r[1].value),wNode:r[1],b:e.unit(r[2].value),bNode:r[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(normalizeBlackOrWhiteNode(n.w),normalizeBlackOrWhiteNode(n.b),(t=r[3])&&"div"===t.type&&"/"===t.value&&(n.slash=r[3]),(isNumericNodePercentageOrNumber(r[4])||isCalcNode(r[4])||isVarNode(r[4]))&&(n.alpha=r[4]),n);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(r,n,t){if(!n||!t)return;if(r.value="rgba",n.value=",",n.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,r,n){const t=e.indexOf(r);e[t]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(r){if(!r||!r.value)return!1;try{return!1!==e.unit(r.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(r,n,t){let o;try{o=e(r)}catch(e){n.warn(t,`Failed to parse value '${r}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==r?u:void 0}function insertAtSupportsAfterCorrectRule(e,r,n){let t=r,o=r.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===n;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0,module.exports=postcssPlugin;
diff --git a/plugins/postcss-hwb-function/dist/index.mjs b/plugins/postcss-hwb-function/dist/index.mjs
index a2ed994a3..77527c1f7 100644
--- a/plugins/postcss-hwb-function/dist/index.mjs
+++ b/plugins/postcss-hwb-function/dist/index.mjs
@@ -1 +1 @@
-import e from"postcss-value-parser";function hasSupportsAtRuleAncestor(e){let n=e.parent;for(;n;)if("atrule"===n.type){if("supports"===n.name.toLowerCase()&&-1!==n.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;n=n.parent}else n=n.parent;return!1}function hwbToRgb(e){const n=e[0];let r=e[1],t=e[2];if(r/=100,t/=100,r+t>=1){const e=r/(r+t);return[e,e,e].map((e=>Math.round(255*e)))}const o=hslToRgb([n,100,50]);for(let e=0;e<3;e++)o[e]*=1-r-t,o[e]+=r;return o.map((e=>Math.round(255*e)))}function hslToRgb(e){let n=e[0],r=e[1],t=e[2];function f(e){const o=(e+n/30)%12,u=r*Math.min(t,1-t);return t-u*Math.max(-1,Math.min(o-3,9-o,1))}return n%=360,n<0&&(n+=360),r/=100,t/=100,[f(0),f(8),f(4)]}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),r=hwbFunctionContents(n);if(!r)return;if(n.length>3&&(!r.slash||!r.alpha))return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[t,o,u]=[(i=r).hNode,i.wNode,i.bNode];var i;const[a,s,c]=channelDimensions(r),l=hwbToRgb([a.number,s.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(t)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,t,{...t,value:String(l[0])}),replaceWith(e.nodes,o,{...o,value:String(l[1])}),replaceWith(e.nodes,u,{...u,value:String(l[2])})}function isNumericNode(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&!!r.number}function isNumericNodeHueLike(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(n){if(!isNumericNodeHueLike(n[0]))return null;if(!isNumericNodePercentageOrNumber(n[1]))return null;if(!isNumericNodePercentageOrNumber(n[2]))return null;const r={h:e.unit(n[0].value),hNode:n[0],w:e.unit(n[1].value),wNode:n[1],b:e.unit(n[2].value),bNode:n[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(normalizeBlackOrWhiteNode(r.w),normalizeBlackOrWhiteNode(r.b),(t=n[3])&&"div"===t.type&&"/"===t.value&&(r.slash=n[3]),(isNumericNodePercentageOrNumber(n[4])||isCalcNode(n[4])||isVarNode(n[4]))&&(r.alpha=n[4]),r);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(n,r,t){if(!r||!t)return;if(n.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(n){if(!n||!n.value)return!1;try{return!1!==e.unit(n.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(n,r,t){let o;try{o=e(n)}catch(e){r.warn(t,`Failed to parse value '${n}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==n?u:void 0}function insertAtSupportsAfterCorrectRule(e,n,r){let t=n,o=n.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===r;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0;export{postcssPlugin as default};
+import e from"postcss-value-parser";import{conversions as r}from"@csstools/color-helpers";function hasSupportsAtRuleAncestor(e){let r=e.parent;for(;r;)if("atrule"===r.type){if("supports"===r.name.toLowerCase()&&-1!==r.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;r=r.parent}else r=r.parent;return!1}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),t=hwbFunctionContents(n);if(!t)return;if(n.length>3&&(!t.slash||!t.alpha))return;e.value="rgb",transformAlpha(e,t.slash,t.alpha);const[o,u,i]=[(a=t).hNode,a.wNode,a.bNode];var a;const[s,c,l]=channelDimensions(t),p=[s.number,c.number,l.number].map((e=>parseFloat(e))),d=r.HWB_to_sRGB(p).map((e=>Math.round(255*e)));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,i,{...i,value:String(d[2])})}function isNumericNode(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&!!n.number}function isNumericNodeHueLike(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);if(!n)return!1;const t=n.unit.toLowerCase();return!!n.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(r){if(!isNumericNodeHueLike(r[0]))return null;if(!isNumericNodePercentageOrNumber(r[1]))return null;if(!isNumericNodePercentageOrNumber(r[2]))return null;const n={h:e.unit(r[0].value),hNode:r[0],w:e.unit(r[1].value),wNode:r[1],b:e.unit(r[2].value),bNode:r[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(normalizeBlackOrWhiteNode(n.w),normalizeBlackOrWhiteNode(n.b),(t=r[3])&&"div"===t.type&&"/"===t.value&&(n.slash=r[3]),(isNumericNodePercentageOrNumber(r[4])||isCalcNode(r[4])||isVarNode(r[4]))&&(n.alpha=r[4]),n);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(r,n,t){if(!n||!t)return;if(r.value="rgba",n.value=",",n.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,r,n){const t=e.indexOf(r);e[t]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(r){if(!r||!r.value)return!1;try{return!1!==e.unit(r.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(r,n,t){let o;try{o=e(r)}catch(e){n.warn(t,`Failed to parse value '${r}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==r?u:void 0}function insertAtSupportsAfterCorrectRule(e,r,n){let t=r,o=r.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===n;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0;export{postcssPlugin as default};
diff --git a/plugins/postcss-hwb-function/package.json b/plugins/postcss-hwb-function/package.json
index 0defd2ef7..86e624699 100644
--- a/plugins/postcss-hwb-function/package.json
+++ b/plugins/postcss-hwb-function/package.json
@@ -30,6 +30,7 @@
"dist"
],
"dependencies": {
+ "@csstools/color-helpers": "^0.0.0",
"postcss-value-parser": "^4.2.0"
},
"peerDependencies": {
diff --git a/plugins/postcss-hwb-function/src/hwb.ts b/plugins/postcss-hwb-function/src/hwb.ts
deleted file mode 100644
index cd892e084..000000000
--- a/plugins/postcss-hwb-function/src/hwb.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-type color = [number, number, number];
-
-// source: https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js
-export function hwbToRgb(hwb: color): color {
- const hue = hwb[0];
- let white = hwb[1];
- let black = hwb[2];
-
- white /= 100;
- black /= 100;
- if (white + black >= 1) {
- const gray = white / (white + black);
- return [gray, gray, gray].map((x) => Math.round(x * 255)) as color;
- }
- const rgb = hslToRgb([hue, 100, 50]);
- for (let i = 0; i < 3; i++) {
- rgb[i] *= (1 - white - black);
- rgb[i] += white;
- }
- return rgb.map((x) => Math.round(x * 255)) as color;
-}
-
-// source: https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js
-function hslToRgb(hwb: color): color {
- let hue = hwb[0];
- let sat = hwb[1];
- let light = hwb[2];
-
- hue = hue % 360;
-
- if (hue < 0) {
- hue += 360;
- }
-
- sat /= 100;
- light /= 100;
-
- function f(n) {
- const k = (n + hue / 30) % 12;
- const a = sat * Math.min(light, 1 - light);
- return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
- }
-
- return [f(0), f(8), f(4)];
-}
diff --git a/plugins/postcss-hwb-function/src/on-css-function.ts b/plugins/postcss-hwb-function/src/on-css-function.ts
index 342281969..030a1c01a 100644
--- a/plugins/postcss-hwb-function/src/on-css-function.ts
+++ b/plugins/postcss-hwb-function/src/on-css-function.ts
@@ -1,6 +1,6 @@
import valueParser from 'postcss-value-parser';
import type { FunctionNode, Dimension, Node, DivNode, WordNode } from 'postcss-value-parser';
-import { hwbToRgb } from './hwb';
+import { conversions } from '@csstools/color-helpers';
export function onCSSFunctionSRgb(node: FunctionNode) {
const rawNodes = node.nodes;
@@ -35,9 +35,9 @@ export function onCSSFunctionSRgb(node: FunctionNode) {
channelNumber => parseFloat(channelNumber),
) as [number, number, number];
- const rgbValues = hwbToRgb(
+ const rgbValues = conversions.HWB_to_sRGB(
channelNumbers,
- );
+ ).map((x) => Math.round(x * 255));
node.nodes.splice(node.nodes.indexOf(channelNode1) + 1, 0, commaNode());
node.nodes.splice(node.nodes.indexOf(channelNode2) + 1, 0, commaNode());
diff --git a/plugins/postcss-lab-function/CHANGELOG.md b/plugins/postcss-lab-function/CHANGELOG.md
index 7bd77c710..42b99c974 100644
--- a/plugins/postcss-lab-function/CHANGELOG.md
+++ b/plugins/postcss-lab-function/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changes to PostCSS Lab Function
+### Unreleased (minor)
+
+- Add: `@csstools/color-helpers` dependency for all color value transformations.
+
### 5.0.1 (January 28, 2023)
- Improve `types` declaration in `package.json`
diff --git a/plugins/postcss-lab-function/dist/convert-lab-to-display-p3.d.ts b/plugins/postcss-lab-function/dist/convert-lab-to-display-p3.d.ts
deleted file mode 100644
index 8ab3896e2..000000000
--- a/plugins/postcss-lab-function/dist/convert-lab-to-display-p3.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function labToDisplayP3(labRaw: color): [color, boolean];
-export {};
diff --git a/plugins/postcss-lab-function/dist/convert-lab-to-srgb.d.ts b/plugins/postcss-lab-function/dist/convert-lab-to-srgb.d.ts
deleted file mode 100644
index a2cc12cce..000000000
--- a/plugins/postcss-lab-function/dist/convert-lab-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function labToSRgb(labRaw: color): color;
-export {};
diff --git a/plugins/postcss-lab-function/dist/convert-lch-to-display-p3.d.ts b/plugins/postcss-lab-function/dist/convert-lch-to-display-p3.d.ts
deleted file mode 100644
index 5d2040b60..000000000
--- a/plugins/postcss-lab-function/dist/convert-lch-to-display-p3.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function lchToDisplayP3(lchRaw: color): [color, boolean];
-export {};
diff --git a/plugins/postcss-lab-function/dist/convert-lch-to-srgb.d.ts b/plugins/postcss-lab-function/dist/convert-lch-to-srgb.d.ts
deleted file mode 100644
index 2ebf9f7fd..000000000
--- a/plugins/postcss-lab-function/dist/convert-lch-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function lchToSRgb(lchRaw: color): color;
-export {};
diff --git a/plugins/postcss-lab-function/dist/css-color-4/conversions.d.ts b/plugins/postcss-lab-function/dist/css-color-4/conversions.d.ts
deleted file mode 100644
index a48b1e5bc..000000000
--- a/plugins/postcss-lab-function/dist/css-color-4/conversions.d.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */
-type color = [number, number, number];
-export declare const D50: number[];
-export declare const D65: number[];
-export declare function lin_sRGB(RGB: color): color;
-export declare function gam_sRGB(RGB: color): color;
-export declare function lin_sRGB_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_sRGB(XYZ: color): color;
-export declare function lin_P3(RGB: color): color;
-export declare function gam_P3(RGB: color): color;
-export declare function lin_P3_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_P3(XYZ: color): color;
-export declare function lin_ProPhoto(RGB: color): color;
-export declare function gam_ProPhoto(RGB: color): color;
-export declare function lin_ProPhoto_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_ProPhoto(XYZ: color): color;
-export declare function lin_a98rgb(RGB: color): color;
-export declare function gam_a98rgb(RGB: color): color;
-export declare function lin_a98rgb_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_a98rgb(XYZ: color): color;
-export declare function lin_2020(RGB: color): color;
-export declare function gam_2020(RGB: color): color;
-export declare function lin_2020_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_2020(XYZ: color): color;
-export declare function D65_to_D50(XYZ: color): color;
-export declare function D50_to_D65(XYZ: color): color;
-export declare function XYZ_to_Lab(XYZ: color): color;
-export declare function Lab_to_XYZ(Lab: color): color;
-export declare function Lab_to_LCH(Lab: color): color;
-export declare function LCH_to_Lab(LCH: color): color;
-export declare function XYZ_to_OKLab(XYZ: color): color;
-export declare function OKLab_to_XYZ(OKLab: color): color;
-export declare function OKLab_to_OKLCH(OKLab: color): color;
-export declare function OKLCH_to_OKLab(OKLCH: color): color;
-export declare function rectangular_premultiply(color: color, alpha: number): color;
-export declare function rectangular_un_premultiply(color: color, alpha: number): color;
-export declare function polar_premultiply(color: color, alpha: number, hueIndex: number): color;
-export declare function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color;
-export declare function hsl_premultiply(color: color, alpha: number): color;
-export {};
diff --git a/plugins/postcss-lab-function/dist/css-color-4/deltaEOK.d.ts b/plugins/postcss-lab-function/dist/css-color-4/deltaEOK.d.ts
deleted file mode 100644
index d744ffaad..000000000
--- a/plugins/postcss-lab-function/dist/css-color-4/deltaEOK.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */
-type color = [number, number, number];
-export declare function deltaEOK(reference: color, sample: color): number;
-export {};
diff --git a/plugins/postcss-lab-function/dist/css-color-4/map-gamut.d.ts b/plugins/postcss-lab-function/dist/css-color-4/map-gamut.d.ts
deleted file mode 100644
index 1a4ee6e95..000000000
--- a/plugins/postcss-lab-function/dist/css-color-4/map-gamut.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-type color = [number, number, number];
-export declare function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color;
-export declare function clip(color: color): color;
-export declare function inGamut(x: color): boolean;
-export {};
diff --git a/plugins/postcss-lab-function/dist/css-color-4/multiply-matrices.d.ts b/plugins/postcss-lab-function/dist/css-color-4/multiply-matrices.d.ts
deleted file mode 100644
index 3055a8245..000000000
--- a/plugins/postcss-lab-function/dist/css-color-4/multiply-matrices.d.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * Simple matrix (and vector) multiplication
- * Warning: No error handling for incompatible dimensions!
- * @author Lea Verou 2020 MIT License
- *
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js
- */
-export declare function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array;
diff --git a/plugins/postcss-lab-function/dist/css-color-4/utilities.d.ts b/plugins/postcss-lab-function/dist/css-color-4/utilities.d.ts
deleted file mode 100644
index a5bb9da80..000000000
--- a/plugins/postcss-lab-function/dist/css-color-4/utilities.d.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
- */
-type color = [number, number, number];
-export declare function sRGB_to_luminance(RGB: color): number;
-export declare function contrast(RGB1: color, RGB2: color): number;
-export declare function sRGB_to_LCH(RGB: color): color;
-export declare function P3_to_LCH(RGB: color): color;
-export declare function r2020_to_LCH(RGB: color): color;
-export declare function LCH_to_sRGB(LCH: color): color;
-export declare function LCH_to_P3(LCH: color): color;
-export declare function LCH_to_r2020(LCH: color): color;
-export declare function hslToRgb(hsl: color): color;
-export declare function hueToRgb(t1: number, t2: number, hue: number): number;
-export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color;
-export declare function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number];
-export declare function XYZ_to_xy(XYZ: color): [number, number];
-export declare function xy_to_uv(xy: [number, number]): [number, number];
-export declare function XYZ_to_uv(XYZ: color): [number, number];
-export {};
diff --git a/plugins/postcss-lab-function/dist/index.cjs b/plugins/postcss-lab-function/dist/index.cjs
index f510d4f3b..fc21337f0 100644
--- a/plugins/postcss-lab-function/dist/index.cjs
+++ b/plugins/postcss-lab-function/dist/index.cjs
@@ -1,29 +1 @@
-"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),t=require("postcss-value-parser");function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let a=0;a[e])));const o=r[0].length,u=r[0].map(((e,t)=>r.map((e=>e[t]))));let i=a.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,a)=>e+n*(t[a]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===o?i.map((e=>e[0])):i}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */const n=[.3457/.3585,1,.2958/.3585];function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function D50_to_D65(e){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],e)}function Lab_to_XYZ(e){const t=24389/27,a=216/24389,r=[];r[1]=(e[0]+16)/116,r[0]=e[1]/500+r[1],r[2]=r[1]-e[2]/200;return[Math.pow(r[0],3)>a?Math.pow(r[0],3):(116*r[0]-16)/t,e[0]>8?Math.pow((e[0]+16)/116,3):e[0]/t,Math.pow(r[2],3)>a?Math.pow(r[2],3):(116*r[2]-16)/t].map(((e,t)=>e*n[t]))}function LCH_to_Lab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */function deltaEOK(e,t){const[n,a,r]=e,[o,u,i]=t,s=n-o,l=a-u,c=r-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let a=0,r=e[1];const o=e;for(;r-a>1e-4;){const e=clip(t(o));deltaEOK(OKLCH_to_OKLab(o),OKLCH_to_OKLab(n(e)))-.02<1e-4?a=o[1]:r=o[1],o[1]=(r+a)/2}return clip(t([...o]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,a]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&a>=-1e-4&&a<=1.0001}function labToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function labToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function lchToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function lchToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let a=null;if("lab"===t?a=labFunctionContents(n):"lch"===t&&(a=lchFunctionContents(n)),!a)return;e.value="rgb",transformAlpha(e,a.slash,a.alpha);const[r,o,u]=channelNodes(a),[i,s,l]=channelDimensions(a),c=("lab"===t?labToSRgb:lchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(r)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,r,{...r,value:String(c[0])}),replaceWith(e.nodes,o,{...o,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,a,r){const o=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("lab"===u?s=labFunctionContents(i):"lch"===u&&(s=lchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,_]=channelNodes(s),[p,m,b]=channelDimensions(s),d="lab"===u?labToDisplayP3:lchToDisplayP3,f=[p.number,m.number,b.number].map((e=>parseFloat(e))),[h,L]=d(f);!L&&r&&n.warn(a,`"${o}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,_,{..._,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const a=n.unit.toLowerCase();return!!n.number&&("deg"===a||"grad"===a||"rad"===a||"turn"===a||""===a)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*150).toFixed(10)),n):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*125).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*125).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,a){if(!n||!a)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(a))return;const r=t.unit(a.value);r&&"%"===r.unit&&(r.number=String(parseFloat(r.number)/100),a.value=String(r.number))}function replaceWith(e,t,n){const a=e.indexOf(t);e[a]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,a,r){let o;try{o=t(e)}catch(t){n.warn(a,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(o);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,a,r))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const a=t.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(a.toLowerCase()))return;const r=modifiedValues(a,t,n,e.preserve);void 0!==r&&(e.preserve?(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3})):(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0,module.exports=postcssPlugin;
+"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),n=require("postcss-value-parser"),r=require("@csstools/color-helpers");function hasFallback(e){const n=e.parent;if(!n)return!1;const r=n.index(e);for(let t=0;t"comment"!==e.type&&"space"!==e.type));let o=null;if("lab"===n?o=labFunctionContents(t):"lch"===n&&(o=lchFunctionContents(t)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[s,u,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("lab"===n?r.conversions.Lab_to_sRGB:r.conversions.LCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,s,{...s,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,t,o,s){const u=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("lab"===a?l=labFunctionContents(i):"lch"===a&&(l=lchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[f,b,v]=channelDimensions(l),m="lab"===a?r.conversions.Lab_to_P3:r.conversions.LCH_to_P3,h=[f.number,b.number,v.number].map((e=>parseFloat(e))),[N,g]=m(h);!g&&s&&t.warn(o,`"${u}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&!!r.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit=""),"%"===r.c.unit&&(r.c.unit="",r.c.number=(parseFloat(r.c.number)/100*150).toFixed(10)),r):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit=""),"%"===r.a.unit&&(r.a.unit="",r.a.number=(parseFloat(r.a.number)/100*125).toFixed(10)),"%"===r.b.unit&&(r.b.unit="",r.b.number=(parseFloat(r.b.number)/100*125).toFixed(10)),r):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,r,t){if(!r||!t)return;if(e.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=n.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,r,t,o){let s;try{s=n(e)}catch(n){r.warn(t,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(s);if(u===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,r,t,o))}));return{rgb:u,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(n,{result:r})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const t=n.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(t.toLowerCase()))return;const o=modifiedValues(t,n,r,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const r=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return r.subFeatures=Object.assign({displayP3:!0},r.subFeatures),r.enableProgressiveCustomProperties&&(r.preserve||r.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0,module.exports=postcssPlugin;
diff --git a/plugins/postcss-lab-function/dist/index.mjs b/plugins/postcss-lab-function/dist/index.mjs
index 9657cd879..de1161a86 100644
--- a/plugins/postcss-lab-function/dist/index.mjs
+++ b/plugins/postcss-lab-function/dist/index.mjs
@@ -1,29 +1 @@
-import e from"@csstools/postcss-progressive-custom-properties";import t from"postcss-value-parser";function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let a=0;a[e])));const o=r[0].length,u=r[0].map(((e,t)=>r.map((e=>e[t]))));let i=a.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,a)=>e+n*(t[a]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===o?i.map((e=>e[0])):i}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */const n=[.3457/.3585,1,.2958/.3585];function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function D50_to_D65(e){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],e)}function Lab_to_XYZ(e){const t=24389/27,a=216/24389,r=[];r[1]=(e[0]+16)/116,r[0]=e[1]/500+r[1],r[2]=r[1]-e[2]/200;return[Math.pow(r[0],3)>a?Math.pow(r[0],3):(116*r[0]-16)/t,e[0]>8?Math.pow((e[0]+16)/116,3):e[0]/t,Math.pow(r[2],3)>a?Math.pow(r[2],3):(116*r[2]-16)/t].map(((e,t)=>e*n[t]))}function LCH_to_Lab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */function deltaEOK(e,t){const[n,a,r]=e,[o,u,i]=t,s=n-o,l=a-u,c=r-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let a=0,r=e[1];const o=e;for(;r-a>1e-4;){const e=clip(t(o));deltaEOK(OKLCH_to_OKLab(o),OKLCH_to_OKLab(n(e)))-.02<1e-4?a=o[1]:r=o[1],o[1]=(r+a)/2}return clip(t([...o]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,a]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&a>=-1e-4&&a<=1.0001}function labToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function labToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function lchToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function lchToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let a=null;if("lab"===t?a=labFunctionContents(n):"lch"===t&&(a=lchFunctionContents(n)),!a)return;e.value="rgb",transformAlpha(e,a.slash,a.alpha);const[r,o,u]=channelNodes(a),[i,s,l]=channelDimensions(a),c=("lab"===t?labToSRgb:lchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(r)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,r,{...r,value:String(c[0])}),replaceWith(e.nodes,o,{...o,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,a,r){const o=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("lab"===u?s=labFunctionContents(i):"lch"===u&&(s=lchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,_]=channelNodes(s),[p,m,b]=channelDimensions(s),d="lab"===u?labToDisplayP3:lchToDisplayP3,f=[p.number,m.number,b.number].map((e=>parseFloat(e))),[h,L]=d(f);!L&&r&&n.warn(a,`"${o}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,_,{..._,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const a=n.unit.toLowerCase();return!!n.number&&("deg"===a||"grad"===a||"rad"===a||"turn"===a||""===a)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*150).toFixed(10)),n):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*125).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*125).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,a){if(!n||!a)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(a))return;const r=t.unit(a.value);r&&"%"===r.unit&&(r.number=String(parseFloat(r.number)/100),a.value=String(r.number))}function replaceWith(e,t,n){const a=e.indexOf(t);e[a]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,a,r){let o;try{o=t(e)}catch(t){n.warn(a,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(o);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,a,r))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const a=t.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(a.toLowerCase()))return;const r=modifiedValues(a,t,n,e.preserve);void 0!==r&&(e.preserve?(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3})):(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0;export{postcssPlugin as default};
+import e from"@csstools/postcss-progressive-custom-properties";import n from"postcss-value-parser";import{conversions as t}from"@csstools/color-helpers";function hasFallback(e){const n=e.parent;if(!n)return!1;const t=n.index(e);for(let r=0;r"comment"!==e.type&&"space"!==e.type));let o=null;if("lab"===n?o=labFunctionContents(r):"lch"===n&&(o=lchFunctionContents(r)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[u,s,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("lab"===n?t.Lab_to_sRGB:t.LCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,u,{...u,value:String(d[0])}),replaceWith(e.nodes,s,{...s,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,r,o,u){const s=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("lab"===a?l=labFunctionContents(i):"lch"===a&&(l=lchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[f,b,m]=channelDimensions(l),v="lab"===a?t.Lab_to_P3:t.LCH_to_P3,h=[f.number,b.number,m.number].map((e=>parseFloat(e))),[N,g]=v(h);!g&&u&&r.warn(o,`"${s}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=n.unit(e.value);return!!t&&!!t.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=n.unit(e.value);if(!t)return!1;const r=t.unit.toLowerCase();return!!t.number&&("deg"===r||"grad"===r||"rad"===r||"turn"===r||""===r)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=n.unit(e.value);return!!t&&("%"===t.unit||""===t.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const t={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(t.h),""!==t.h.unit?null:(isSlashNode(e[3])&&(t.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(t.alpha=e[4]),!(e.length>3)||t.slash&&t.alpha?("%"===t.l.unit&&(t.l.unit=""),"%"===t.c.unit&&(t.c.unit="",t.c.number=(parseFloat(t.c.number)/100*150).toFixed(10)),t):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const t={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(t.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(t.alpha=e[4]),!(e.length>3)||t.slash&&t.alpha?("%"===t.l.unit&&(t.l.unit=""),"%"===t.a.unit&&(t.a.unit="",t.a.number=(parseFloat(t.a.number)/100*125).toFixed(10)),"%"===t.b.unit&&(t.b.unit="",t.b.number=(parseFloat(t.b.number)/100*125).toFixed(10)),t):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,t,r){if(!t||!r)return;if(e.value="rgba",t.value=",",t.before="",!isNumericNode(r))return;const o=n.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function replaceWith(e,n,t){const r=e.indexOf(n);e[r]=t}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,t,r,o){let u;try{u=n(e)}catch(n){t.warn(r,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===u)return;u.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const s=String(u);if(s===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,t,r,o))}));return{rgb:s,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(n,{result:t})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const r=n.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(r.toLowerCase()))return;const o=modifiedValues(r,n,t,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const t=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return t.subFeatures=Object.assign({displayP3:!0},t.subFeatures),t.enableProgressiveCustomProperties&&(t.preserve||t.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(t)]}:basePlugin(t)};postcssPlugin.postcss=!0;export{postcssPlugin as default};
diff --git a/plugins/postcss-lab-function/package.json b/plugins/postcss-lab-function/package.json
index ca2e15cdd..213d64493 100644
--- a/plugins/postcss-lab-function/package.json
+++ b/plugins/postcss-lab-function/package.json
@@ -29,6 +29,7 @@
"dist"
],
"dependencies": {
+ "@csstools/color-helpers": "^0.0.0",
"@csstools/postcss-progressive-custom-properties": "^2.0.0",
"postcss-value-parser": "^4.2.0"
},
diff --git a/plugins/postcss-lab-function/src/css-color-4/conversions.ts b/plugins/postcss-lab-function/src/css-color-4/conversions.ts
deleted file mode 100644
index 636f08f90..000000000
--- a/plugins/postcss-lab-function/src/css-color-4/conversions.ts
+++ /dev/null
@@ -1,512 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */
-
-/* eslint-disable @typescript-eslint/no-loss-of-precision */
-
-import { multiplyMatrices } from './multiply-matrices';
-
-type color = [number, number, number];
-
-// Sample code for color conversions
-// Conversion can also be done using ICC profiles and a Color Management System
-// For clarity, a library is used for matrix multiplication (multiply-matrices.js)
-
-// standard white points, defined by 4-figure CIE x,y chromaticities
-export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
-export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290];
-
-// sRGB-related functions
-
-export function lin_sRGB(RGB: color): color {
- // convert an array of sRGB values
- // where in-gamut values are in the range [0 - 1]
- // to linear light (un-companded) form.
- // https://en.wikipedia.org/wiki/SRGB
- // Extended transfer function:
- // for negative values, linear portion is extended on reflection of axis,
- // then reflected power function is used.
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs < 0.04045) {
- return val / 12.92;
- }
-
- return sign * (Math.pow((abs + 0.055) / 1.055, 2.4));
- }) as color;
-}
-
-export function gam_sRGB(RGB: color): color {
- // convert an array of linear-light sRGB values in the range 0.0-1.0
- // to gamma corrected form
- // https://en.wikipedia.org/wiki/SRGB
- // Extended transfer function:
- // For negative values, linear portion extends on reflection
- // of axis, then uses reflected pow below that
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs > 0.0031308) {
- return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055);
- }
-
- return 12.92 * val;
- }) as color;
-}
-
-export function lin_sRGB_to_XYZ(rgb: color): color {
- // convert an array of linear-light sRGB values to CIE XYZ
- // using sRGB's own white, D65 (no chromatic adaptation)
-
- const M = [
- [0.41239079926595934, 0.357584339383878, 0.1804807884018343],
- [0.21263900587151027, 0.715168678767756, 0.07219231536073371],
- [0.01933081871559182, 0.11919477979462598, 0.9505321522496607],
- ];
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_sRGB(XYZ: color): color {
- // convert XYZ to linear-light sRGB
-
- const M = [
- [3.2409699419045226, -1.537383177570094, -0.4986107602930034],
- [-0.9692436362808796, 1.8759675015077202, 0.04155505740717559],
- [0.05563007969699366, -0.20397695888897652, 1.0569715142428786],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// display-p3-related functions
-
-
-export function lin_P3(RGB: color): color {
- // convert an array of display-p3 RGB values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
-
- return lin_sRGB(RGB); // same as sRGB
-}
-
-export function gam_P3(RGB: color): color {
- // convert an array of linear-light display-p3 RGB in the range 0.0-1.0
- // to gamma corrected form
-
- return gam_sRGB(RGB); // same as sRGB
-}
-
-export function lin_P3_to_XYZ(rgb: color): color {
- // convert an array of linear-light display-p3 values to CIE XYZ
- // using D65 (no chromatic adaptation)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.4865709486482162, 0.26566769316909306, 0.1982172852343625],
- [0.2289745640697488, 0.6917385218365064, 0.079286914093745],
- [0.0000000000000000, 0.04511338185890264, 1.043944368900976],
- ];
- // 0 was computed as -3.972075516933488e-17
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_P3(XYZ: color): color {
- // convert XYZ to linear-light P3
- const M = [
- [2.493496911941425, -0.9313836179191239, -0.40271078445071684],
- [-0.8294889695615747, 1.7626640603183463, 0.023624685841943577],
- [0.03584583024378447, -0.07617238926804182, 0.9568845240076872],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// prophoto-rgb functions
-
-export function lin_ProPhoto(RGB: color): color {
- // convert an array of prophoto-rgb values
- // where in-gamut colors are in the range [0.0 - 1.0]
- // to linear light (un-companded) form.
- // Transfer curve is gamma 1.8 with a small linear portion
- // Extended transfer function
- const Et2 = 16 / 512;
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs <= Et2) {
- return val / 16;
- }
-
- return sign * Math.pow(val, 1.8);
- }) as color;
-}
-
-export function gam_ProPhoto(RGB: color): color {
- // convert an array of linear-light prophoto-rgb in the range 0.0-1.0
- // to gamma corrected form
- // Transfer curve is gamma 1.8 with a small linear portion
- // TODO for negative values, extend linear portion on reflection of axis, then add pow below that
- const Et = 1 / 512;
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs >= Et) {
- return sign * Math.pow(abs, 1 / 1.8);
- }
-
- return 16 * val;
- }) as color;
-}
-
-export function lin_ProPhoto_to_XYZ(rgb: color): color {
- // convert an array of linear-light prophoto-rgb values to CIE XYZ
- // using D50 (so no chromatic adaptation needed afterwards)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.7977604896723027, 0.13518583717574031, 0.0313493495815248],
- [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902],
- [0.0, 0.0, 0.8251046025104601],
- ];
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_ProPhoto(XYZ: color): color {
- // convert XYZ to linear-light prophoto-rgb
- const M = [
- [1.3457989731028281, -0.25558010007997534, -0.05110628506753401],
- [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973],
- [0.0, 0.0, 1.2119675456389454],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// a98-rgb functions
-
-export function lin_a98rgb(RGB: color): color {
- // convert an array of a98-rgb values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
- // negative values are also now accepted
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- return sign * Math.pow(abs, 563 / 256);
- }) as color;
-}
-
-export function gam_a98rgb(RGB: color): color {
- // convert an array of linear-light a98-rgb in the range 0.0-1.0
- // to gamma corrected form
- // negative values are also now accepted
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- return sign * Math.pow(abs, 256 / 563);
- }) as color;
-}
-
-export function lin_a98rgb_to_XYZ(rgb: color): color {
- // convert an array of linear-light a98-rgb values to CIE XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- // has greater numerical precision than section 4.3.5.3 of
- // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
- // but the values below were calculated from first principles
- // from the chromaticity coordinates of R G B W
- // see matrixmaker.html
- const M = [
- [0.5766690429101305, 0.1855582379065463, 0.1882286462349947],
- [0.29734497525053605, 0.6273635662554661, 0.07529145849399788],
- [0.02703136138641234, 0.07068885253582723, 0.9913375368376388],
- ];
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_a98rgb(XYZ: color): color {
- // convert XYZ to linear-light a98-rgb
- const M = [
- [2.0415879038107465, -0.5650069742788596, -0.34473135077832956],
- [-0.9692436362808795, 1.8759675015077202, 0.04155505740717557],
- [0.013444280632031142, -0.11836239223101838, 1.0151749943912054],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-//Rec. 2020-related functions
-
-export function lin_2020(RGB: color): color {
- // convert an array of rec2020 RGB values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
- // ITU-R BT.2020-2 p.4
-
- const α = 1.09929682680944;
- const β = 0.018053968510807;
-
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs < β * 4.5) {
- return val / 4.5;
- }
-
- return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45));
- }) as color;
-}
-
-export function gam_2020(RGB: color): color {
- // convert an array of linear-light rec2020 RGB in the range 0.0-1.0
- // to gamma corrected form
- // ITU-R BT.2020-2 p.4
-
- const α = 1.09929682680944;
- const β = 0.018053968510807;
-
-
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs > β) {
- return sign * (α * Math.pow(abs, 0.45) - (α - 1));
- }
-
- return 4.5 * val;
- }) as color;
-}
-
-export function lin_2020_to_XYZ(rgb: color): color {
- // convert an array of linear-light rec2020 values to CIE XYZ
- // using D65 (no chromatic adaptation)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.6369580483012914, 0.14461690358620832, 0.1688809751641721],
- [0.2627002120112671, 0.6779980715188708, 0.05930171646986196],
- [0.000000000000000, 0.028072693049087428, 1.060985057710791],
- ];
- // 0 is actually calculated as 4.994106574466076e-17
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_2020(XYZ: color): color {
- // convert XYZ to linear-light rec2020
- const M = [
- [1.7166511879712674, -0.35567078377639233, -0.25336628137365974],
- [-0.6666843518324892, 1.6164812366349395, 0.01576854581391113],
- [0.017639857445310783, -0.042770613257808524, 0.9421031212354738],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// Chromatic adaptation
-
-export function D65_to_D50(XYZ: color): color {
- // Bradford chromatic adaptation from D65 to D50
- // The matrix below is the result of three operations:
- // - convert from XYZ to retinal cone domain
- // - scale components from one reference white to another
- // - convert back to XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
- const M = [
- [1.0479298208405488, 0.022946793341019088, -0.05019222954313557],
- [0.029627815688159344, 0.990434484573249, -0.01707382502938514],
- [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-export function D50_to_D65(XYZ: color): color {
- // Bradford chromatic adaptation from D50 to D65
- const M = [
- [0.9554734527042182, -0.023098536874261423, 0.0632593086610217],
- [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008],
- [0.012314001688319899, -0.020507696433477912, 1.3303659366080753],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// CIE Lab and LCH
-
-export function XYZ_to_Lab(XYZ: color): color {
- // Assuming XYZ is relative to D50, convert to CIE Lab
- // from CIE standard, which now defines these as a rational fraction
- const ε = 216 / 24389; // 6^3/29^3
- const κ = 24389 / 27; // 29^3/3^3
-
- // compute xyz, which is XYZ scaled relative to reference white
- const xyz = XYZ.map((value, i) => value / D50[i]);
-
- // now compute f
- const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116);
-
- return [
- (116 * f[1]) - 16, // L
- 500 * (f[0] - f[1]), // a
- 200 * (f[1] - f[2]), // b
- ];
- // L in range [0,100]. For use in CSS, add a percent
-}
-
-export function Lab_to_XYZ(Lab: color): color {
- // Convert Lab to D50-adapted XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const κ = 24389 / 27; // 29^3/3^3
- const ε = 216 / 24389; // 6^3/29^3
- const f = [];
-
- // compute f, starting with the luminance-related term
- f[1] = (Lab[0] + 16) / 116;
- f[0] = Lab[1] / 500 + f[1];
- f[2] = f[1] - Lab[2] / 200;
-
- // compute xyz
- const xyz = [
- Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ,
- Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ,
- Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ,
- ];
-
- // Compute XYZ by scaling xyz by reference white
- return xyz.map((value, i) => value * D50[i]) as color;
-}
-
-export function Lab_to_LCH(Lab: color): color {
- // Convert to polar form
- const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI;
- return [
- Lab[0], // L is still L
- Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma
- hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
- ];
-}
-
-export function LCH_to_Lab(LCH: color): color {
- // Convert from polar form
- return [
- LCH[0], // L is still L
- LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a
- LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b
- ];
-}
-
-// OKLab and OKLCH
-// https://bottosson.github.io/posts/oklab/
-
-// XYZ <-> LMS matrices recalculated for consistent reference white
-// see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
-
-export function XYZ_to_OKLab(XYZ: color): color {
- // Given XYZ relative to D65, convert to OKLab
- const XYZtoLMS = [
- [0.8190224432164319, 0.3619062562801221, -0.12887378261216414],
- [0.0329836671980271, 0.9292868468965546, 0.03614466816999844],
- [0.048177199566046255, 0.26423952494422764, 0.6335478258136937],
- ];
- const LMStoOKLab = [
- [0.2104542553, 0.7936177850, -0.0040720468],
- [1.9779984951, -2.4285922050, 0.4505937099],
- [0.0259040371, 0.7827717662, -0.8086757660],
- ];
-
- const LMS = multiplyMatrices(XYZtoLMS, XYZ) as color;
- return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as color;
- // L in range [0,1]. For use in CSS, multiply by 100 and add a percent
-}
-
-export function OKLab_to_XYZ(OKLab: color): color {
- // Given OKLab, convert to XYZ relative to D65
- const LMStoXYZ = [
- [1.2268798733741557, -0.5578149965554813, 0.28139105017721583],
- [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701],
- [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418],
- ];
- const OKLabtoLMS = [
- [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339],
- [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402],
- [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399],
- ];
-
- const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as color;
- return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as color;
-}
-
-export function OKLab_to_OKLCH(OKLab: color): color {
- const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI;
- return [
- OKLab[0], // L is still L
- Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma
- hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
- ];
-}
-
-export function OKLCH_to_OKLab(OKLCH: color): color {
- return [
- OKLCH[0], // L is still L
- OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a
- OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b
- ];
-}
-
-// Premultiplied alpha conversions
-
-export function rectangular_premultiply(color: color, alpha: number): color {
- // given a color in a rectangular orthogonal colorspace
- // and an alpha value
- // return the premultiplied form
- return color.map((c) => c * alpha) as color;
-}
-
-export function rectangular_un_premultiply(color: color, alpha: number): color {
- // given a premultiplied color in a rectangular orthogonal colorspace
- // and an alpha value
- // return the actual color
- if (alpha === 0) {
- return color; // avoid divide by zero
- }
- return color.map((c) => c / alpha) as color;
-}
-
-export function polar_premultiply(color: color, alpha: number, hueIndex: number): color {
- // given a color in a cylindicalpolar colorspace
- // and an alpha value
- // return the premultiplied form.
- // the index says which entry in the color array corresponds to hue angle
- // for example, in OKLCH it would be 2
- // while in HSL it would be 0
- return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as color;
-}
-
-export function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color {
- // given a color in a cylindicalpolar colorspace
- // and an alpha value
- // return the actual color.
- // the hueIndex says which entry in the color array corresponds to hue angle
- // for example, in OKLCH it would be 2
- // while in HSL it would be 0
- if (alpha === 0) {
- return color; // avoid divide by zero
- }
- return color.map((c, i) => c / (hueIndex === i ? 1 : alpha)) as color;
-}
-
-// Convenience functions can easily be defined, such as
-export function hsl_premultiply(color: color, alpha: number): color {
- return polar_premultiply(color, alpha, 0);
-}
diff --git a/plugins/postcss-lab-function/src/css-color-4/deltaEOK.ts b/plugins/postcss-lab-function/src/css-color-4/deltaEOK.ts
deleted file mode 100644
index ce023047e..000000000
--- a/plugins/postcss-lab-function/src/css-color-4/deltaEOK.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */
-
-// Calculate deltaE OK
-// simple root sum of squares
-type color = [number, number, number];
-export function deltaEOK(reference: color, sample: color): number {
- // Given reference and sample are both in OKLab
- const [L1, a1, b1] = reference;
- const [L2, a2, b2] = sample;
- const ΔL = L1 - L2;
- const Δa = a1 - a2;
- const Δb = b1 - b2;
- return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2);
-}
diff --git a/plugins/postcss-lab-function/src/css-color-4/map-gamut.ts b/plugins/postcss-lab-function/src/css-color-4/map-gamut.ts
deleted file mode 100644
index 168068986..000000000
--- a/plugins/postcss-lab-function/src/css-color-4/map-gamut.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { OKLCH_to_OKLab } from './conversions';
-import { deltaEOK } from './deltaEOK';
-
-type color = [number, number, number];
-
-export function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color {
- return binarySearchGamut(startOKLCH, toDestination, fromDestination);
-}
-
-function binarySearchGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color {
- let min = 0;
- let max = startOKLCH[1];
- const current = startOKLCH;
-
- while (max - min > 0.0001) {
- const clipped = clip(toDestination(current));
- const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped)));
- // are we inside the gamut (or very close to the boundary, outside)
- if (deltaE - 0.02 < 0.0001) {
- min = current[1];
- } else {
- max = current[1];
- }
- // binary search
- current[1] = (max + min) / 2;
- }
-
- return clip(toDestination([...current]));
-}
-
-export function clip(color: color): color {
- return color.map(val => {
- if (val < 0) {
- return 0;
- } else if (val > 1) {
- return 1;
- } else {
- return val;
- }
- }) as color;
-}
-
-export function inGamut(x: color): boolean {
- const [xX, xY, xZ] = x;
- return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001;
-}
-
diff --git a/plugins/postcss-lab-function/src/css-color-4/multiply-matrices.ts b/plugins/postcss-lab-function/src/css-color-4/multiply-matrices.ts
deleted file mode 100644
index 776f8c597..000000000
--- a/plugins/postcss-lab-function/src/css-color-4/multiply-matrices.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Simple matrix (and vector) multiplication
- * Warning: No error handling for incompatible dimensions!
- * @author Lea Verou 2020 MIT License
- *
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js
- */
-
-// A is m x n. B is n x p. product is m x p.
-export function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array {
- const m = a.length;
-
- let A: Array>;
- if (!Array.isArray(a[0])) {
- // A is vector, convert to [[a, b, c, ...]]
- A = [a as Array];
- } else {
- A = a as Array>;
- }
-
- let B: Array>;
- if (!Array.isArray(b[0])) {
- // B is vector, convert to [[a], [b], [c], ...]]
- B = (b as Array).map(x => [x]);
- }
-
- const p = B[0].length;
- const B_cols = B[0].map((_, i) => B.map(x => x[i])); // transpose B
- let product: Array> | Array = A.map(row => B_cols.map(col => {
- if (!Array.isArray(row)) {
- return col.reduce((d, f) => d + f * row, 0);
- }
-
- return row.reduce((d, f, i) => d + f * (col[i] || 0), 0);
- }));
-
- if (m === 1) {
- product = product[0]; // Avoid [[a, b, c, ...]]
- }
-
- if (p === 1) {
- return product.map(x => x[0]); // Avoid [[a], [b], [c], ...]]
- }
-
- return product;
-}
diff --git a/plugins/postcss-lab-function/src/css-color-4/utilities.ts b/plugins/postcss-lab-function/src/css-color-4/utilities.ts
deleted file mode 100644
index b3c4368cd..000000000
--- a/plugins/postcss-lab-function/src/css-color-4/utilities.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
- */
-
-import { D50_to_D65, D65_to_D50, gam_2020, gam_P3, gam_sRGB, Lab_to_LCH, Lab_to_XYZ, LCH_to_Lab, lin_2020, lin_2020_to_XYZ, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, XYZ_to_Lab, XYZ_to_lin_2020, XYZ_to_lin_P3, XYZ_to_lin_sRGB } from './conversions';
-
-type color = [number, number, number];
-
-// utility functions for color conversions
-// needs conversions.js
-
-export function sRGB_to_luminance(RGB: color): number {
- // convert an array of gamma-corrected sRGB values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ
- // and return luminance (the Y value)
-
- const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB));
- return XYZ[1];
-}
-
-export function contrast(RGB1: color, RGB2: color): number {
- // return WCAG 2.1 contrast ratio
- // https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
- // for two sRGB values
- // given as arrays of 0.0 to 1.0
-
- const L1 = sRGB_to_luminance(RGB1);
- const L2 = sRGB_to_luminance(RGB2);
-
- if (L1 > L2) {
- return (L1 + 0.05) / (L2 + 0.05);
- }
-
- return (L2 + 0.05) / (L1 + 0.05);
-}
-
-export function sRGB_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected sRGB values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB)))));
-}
-
-export function P3_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected display-p3 values
- // in the 0.0 to 1.0 range
- // to linear-light display-p3, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB)))));
-}
-
-export function r2020_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected rec.2020 values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB)))));
-}
-
-export function LCH_to_sRGB(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light sRGB
- // and finally to gamma corrected sRGB
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_sRGB(XYZ_to_lin_sRGB(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-export function LCH_to_P3(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light display-p3
- // and finally to gamma corrected display-p3
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_P3(XYZ_to_lin_P3(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-export function LCH_to_r2020(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light rec.2020
- // and finally to gamma corrected rec.2020
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-// this is straight from the CSS Color 4 spec
-
-export function hslToRgb(hsl: color): color {
- // For simplicity, this algorithm assumes that the hue has been normalized
- // to a number in the half-open range [0, 6), and the saturation and lightness
- // have been normalized to the range [0, 1]. It returns an array of three numbers
- // representing the red, green, and blue channels of the colors,
- // normalized to the range [0, 1]
- const [hue, sat, light] = hsl;
-
- let t2: number;
- if (light <= .5) {
- t2 = light * (sat + 1);
- } else {
- t2 = light + sat - (light * sat);
- }
- const t1 = light * 2 - t2;
- const r = hueToRgb(t1, t2, hue + 2);
- const g = hueToRgb(t1, t2, hue);
- const b = hueToRgb(t1, t2, hue - 2);
- return [r, g, b];
-}
-
-export function hueToRgb(t1: number, t2: number, hue: number): number {
- if (hue < 0) {
- hue += 6;
- }
- if (hue >= 6) {
- hue -= 6;
- }
-
- if (hue < 1) {
- return (t2 - t1) * hue + t1;
- } else if (hue < 3) {
- return t2;
- } else if (hue < 4) {
- return (t2 - t1) * (4 - hue) + t1;
- } else {
- return t1;
- }
-}
-
-// These are the naive algorithms from CS Color 4
-
-export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color {
- // CMYK is an array of four values
- // in the range [0.0, 1.0]
- // the optput is an array of [RGB]
- // also in the [0.0, 1.0] range
- // because the naive algorithm does not generate out of gamut colors
- // neither does it generate accurate simulations of practical CMYK colors
-
- const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3];
-
- const red = 1 - Math.min(1, cyan * (1 - black) + black);
- const green = 1 - Math.min(1, magenta * (1 - black) + black);
- const blue = 1 - Math.min(1, yellow * (1 - black) + black);
-
- return [red, green, blue];
-
-}
-
-export function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number] {
- // RGB is an arravy of three values
- // in the range [0.0, 1.0]
- // the output is an array of [CMYK]
- // also in the [0.0, 1.0] range
- // with maximum GCR and (I think) 200% TAC
- // the naive algorithm does not generate out of gamut colors
- // neither does it generate accurate simulations of practical CMYK colors
-
- const red = RGB[0], green = RGB[1], blue = RGB[2];
-
- const black = 1 - Math.max(red, green, blue);
- const cyan = (black == 1.0) ? 0 : (1 - red - black) / (1 - black);
- const magenta = (black == 1.0) ? 0 : (1 - green - black) / (1 - black);
- const yellow = (black == 1.0) ? 0 : (1 - blue - black) / (1 - black);
-
- return [cyan, magenta, yellow, black];
-}
-
-// Chromaticity utilities
-
-export function XYZ_to_xy(XYZ: color): [number, number] {
- // Convert an array of three XYZ values
- // to x,y chromaticity coordinates
-
- const X = XYZ[0];
- const Y = XYZ[1];
- const Z = XYZ[2];
- const sum = X + Y + Z;
- return [X / sum, Y / sum];
-}
-
-export function xy_to_uv(xy: [number, number]): [number, number] {
- // convert an x,y chromaticity pair
- // to u*,v* chromaticities
-
- const x = xy[0];
- const y = xy[1];
- const denom = -2 * x + 12 * y + 3;
- return [4 * x / denom, 9 * y / denom];
-}
-
-export function XYZ_to_uv(XYZ: color): [number, number] {
- // Convert an array of three XYZ values
- // to u*,v* chromaticity coordinates
-
- const X = XYZ[0];
- const Y = XYZ[1];
- const Z = XYZ[2];
- const denom = X + 15 * Y + 3 * Z;
- return [4 * X / denom, 9 * Y / denom];
-}
diff --git a/plugins/postcss-lab-function/src/on-css-function.ts b/plugins/postcss-lab-function/src/on-css-function.ts
index 925553172..a93f0914a 100644
--- a/plugins/postcss-lab-function/src/on-css-function.ts
+++ b/plugins/postcss-lab-function/src/on-css-function.ts
@@ -1,10 +1,7 @@
import type { FunctionNode, Dimension, Node, DivNode, WordNode, SpaceNode } from 'postcss-value-parser';
import valueParser from 'postcss-value-parser';
import { Declaration, Result } from 'postcss';
-import { labToDisplayP3 } from './convert-lab-to-display-p3';
-import { labToSRgb } from './convert-lab-to-srgb';
-import { lchToDisplayP3 } from './convert-lch-to-display-p3';
-import { lchToSRgb } from './convert-lch-to-srgb';
+import { conversions } from '@csstools/color-helpers';
export function onCSSFunctionSRgb(node: FunctionNode) {
const value = node.value.toLowerCase();
@@ -34,7 +31,7 @@ export function onCSSFunctionSRgb(node: FunctionNode) {
const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes);
/** Corresponding Color transformer. */
- const toRGB = value === 'lab' ? labToSRgb : lchToSRgb;
+ const toRGB = value === 'lab' ? conversions.Lab_to_sRGB : conversions.LCH_to_sRGB;
/** RGB channels from the source color. */
const channelNumbers: [number, number, number] = [
@@ -100,7 +97,7 @@ export function onCSSFunctionDisplayP3(node: FunctionNode, decl: Declaration, re
const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes);
/** Corresponding Color transformer. */
- const toDisplayP3 = value === 'lab' ? labToDisplayP3 : lchToDisplayP3;
+ const toDisplayP3 = value === 'lab' ? conversions.Lab_to_P3 : conversions.LCH_to_P3;
/** RGB channels from the source color. */
const channelNumbers: [number, number, number] = [
diff --git a/plugins/postcss-oklab-function/CHANGELOG.md b/plugins/postcss-oklab-function/CHANGELOG.md
index b377a4aa2..3b62a9962 100644
--- a/plugins/postcss-oklab-function/CHANGELOG.md
+++ b/plugins/postcss-oklab-function/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changes to PostCSS OKLab Function
+### Unreleased (minor)
+
+- Add: `@csstools/color-helpers` dependency for all color value transformations.
+
### 2.0.1 (January 28, 2023)
- Improve `types` declaration in `package.json`
diff --git a/plugins/postcss-oklab-function/dist/convert-oklab-to-display-p3.d.ts b/plugins/postcss-oklab-function/dist/convert-oklab-to-display-p3.d.ts
deleted file mode 100644
index 0afadfa1e..000000000
--- a/plugins/postcss-oklab-function/dist/convert-oklab-to-display-p3.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function oklabToDisplayP3(oklabRaw: color): [color, boolean];
-export {};
diff --git a/plugins/postcss-oklab-function/dist/convert-oklab-to-srgb.d.ts b/plugins/postcss-oklab-function/dist/convert-oklab-to-srgb.d.ts
deleted file mode 100644
index 01b638750..000000000
--- a/plugins/postcss-oklab-function/dist/convert-oklab-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function oklabToSRgb(oklabRaw: color): color;
-export {};
diff --git a/plugins/postcss-oklab-function/dist/convert-oklch-to-display-p3.d.ts b/plugins/postcss-oklab-function/dist/convert-oklch-to-display-p3.d.ts
deleted file mode 100644
index 123a19ef6..000000000
--- a/plugins/postcss-oklab-function/dist/convert-oklch-to-display-p3.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function oklchToDisplayP3(oklchRaw: color): [color, boolean];
-export {};
diff --git a/plugins/postcss-oklab-function/dist/convert-oklch-to-srgb.d.ts b/plugins/postcss-oklab-function/dist/convert-oklch-to-srgb.d.ts
deleted file mode 100644
index ad4c40134..000000000
--- a/plugins/postcss-oklab-function/dist/convert-oklch-to-srgb.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type color = [number, number, number];
-export declare function oklchToSRgb(oklchRaw: color): color;
-export {};
diff --git a/plugins/postcss-oklab-function/dist/css-color-4/conversions.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/conversions.d.ts
deleted file mode 100644
index a48b1e5bc..000000000
--- a/plugins/postcss-oklab-function/dist/css-color-4/conversions.d.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */
-type color = [number, number, number];
-export declare const D50: number[];
-export declare const D65: number[];
-export declare function lin_sRGB(RGB: color): color;
-export declare function gam_sRGB(RGB: color): color;
-export declare function lin_sRGB_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_sRGB(XYZ: color): color;
-export declare function lin_P3(RGB: color): color;
-export declare function gam_P3(RGB: color): color;
-export declare function lin_P3_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_P3(XYZ: color): color;
-export declare function lin_ProPhoto(RGB: color): color;
-export declare function gam_ProPhoto(RGB: color): color;
-export declare function lin_ProPhoto_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_ProPhoto(XYZ: color): color;
-export declare function lin_a98rgb(RGB: color): color;
-export declare function gam_a98rgb(RGB: color): color;
-export declare function lin_a98rgb_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_a98rgb(XYZ: color): color;
-export declare function lin_2020(RGB: color): color;
-export declare function gam_2020(RGB: color): color;
-export declare function lin_2020_to_XYZ(rgb: color): color;
-export declare function XYZ_to_lin_2020(XYZ: color): color;
-export declare function D65_to_D50(XYZ: color): color;
-export declare function D50_to_D65(XYZ: color): color;
-export declare function XYZ_to_Lab(XYZ: color): color;
-export declare function Lab_to_XYZ(Lab: color): color;
-export declare function Lab_to_LCH(Lab: color): color;
-export declare function LCH_to_Lab(LCH: color): color;
-export declare function XYZ_to_OKLab(XYZ: color): color;
-export declare function OKLab_to_XYZ(OKLab: color): color;
-export declare function OKLab_to_OKLCH(OKLab: color): color;
-export declare function OKLCH_to_OKLab(OKLCH: color): color;
-export declare function rectangular_premultiply(color: color, alpha: number): color;
-export declare function rectangular_un_premultiply(color: color, alpha: number): color;
-export declare function polar_premultiply(color: color, alpha: number, hueIndex: number): color;
-export declare function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color;
-export declare function hsl_premultiply(color: color, alpha: number): color;
-export {};
diff --git a/plugins/postcss-oklab-function/dist/css-color-4/deltaEOK.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/deltaEOK.d.ts
deleted file mode 100644
index d744ffaad..000000000
--- a/plugins/postcss-oklab-function/dist/css-color-4/deltaEOK.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */
-type color = [number, number, number];
-export declare function deltaEOK(reference: color, sample: color): number;
-export {};
diff --git a/plugins/postcss-oklab-function/dist/css-color-4/map-gamut.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/map-gamut.d.ts
deleted file mode 100644
index 1a4ee6e95..000000000
--- a/plugins/postcss-oklab-function/dist/css-color-4/map-gamut.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-type color = [number, number, number];
-export declare function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color;
-export declare function clip(color: color): color;
-export declare function inGamut(x: color): boolean;
-export {};
diff --git a/plugins/postcss-oklab-function/dist/css-color-4/utilities.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/utilities.d.ts
deleted file mode 100644
index a5bb9da80..000000000
--- a/plugins/postcss-oklab-function/dist/css-color-4/utilities.d.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
- */
-type color = [number, number, number];
-export declare function sRGB_to_luminance(RGB: color): number;
-export declare function contrast(RGB1: color, RGB2: color): number;
-export declare function sRGB_to_LCH(RGB: color): color;
-export declare function P3_to_LCH(RGB: color): color;
-export declare function r2020_to_LCH(RGB: color): color;
-export declare function LCH_to_sRGB(LCH: color): color;
-export declare function LCH_to_P3(LCH: color): color;
-export declare function LCH_to_r2020(LCH: color): color;
-export declare function hslToRgb(hsl: color): color;
-export declare function hueToRgb(t1: number, t2: number, hue: number): number;
-export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color;
-export declare function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number];
-export declare function XYZ_to_xy(XYZ: color): [number, number];
-export declare function xy_to_uv(xy: [number, number]): [number, number];
-export declare function XYZ_to_uv(XYZ: color): [number, number];
-export {};
diff --git a/plugins/postcss-oklab-function/dist/index.cjs b/plugins/postcss-oklab-function/dist/index.cjs
index 6680f2cd9..10795571c 100644
--- a/plugins/postcss-oklab-function/dist/index.cjs
+++ b/plugins/postcss-oklab-function/dist/index.cjs
@@ -1,29 +1 @@
-"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),t=require("postcss-value-parser");function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let r=0;r[e])));const a=o[0].length,u=o[0].map(((e,t)=>o.map((e=>e[t]))));let i=r.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,r)=>e+n*(t[r]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===a?i.map((e=>e[0])):i}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */function deltaEOK(e,t){const[n,r,o]=e,[a,u,i]=t,s=n-a,l=r-u,c=o-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let r=0,o=e[1];const a=e;for(;o-r>1e-4;){const e=clip(t(a));deltaEOK(OKLCH_to_OKLab(a),OKLCH_to_OKLab(n(e)))-.02<1e-4?r=a[1]:o=a[1],a[1]=(o+r)/2}return clip(t([...a]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,r]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&r>=-1e-4&&r<=1.0001}function oklabToDisplayP3(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_P3(o),o=gam_P3(o),inGamut(o)?[clip(o),!0]:[mapGamut(a,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklchToDisplayP3(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_P3(a),a=gam_P3(a),inGamut(a)?[clip(a),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklabToSRgb(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_sRGB(o),o=gam_sRGB(o),inGamut(o)?clip(o).map((e=>Math.round(255*e))):mapGamut(a,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function oklchToSRgb(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_sRGB(a),a=gam_sRGB(a),inGamut(a)?clip(a).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let r=null;if("oklab"===t?r=oklabFunctionContents(n):"oklch"===t&&(r=oklchFunctionContents(n)),!r)return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[o,a,u]=channelNodes(r),[i,s,l]=channelDimensions(r),c=("oklab"===t?oklabToSRgb:oklchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(a)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(c[0])}),replaceWith(e.nodes,a,{...a,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,r,o){const a=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("oklab"===u?s=oklabFunctionContents(i):"oklch"===u&&(s=oklchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,p]=channelNodes(s),[m,b,d]=channelDimensions(s),_="oklab"===u?oklabToDisplayP3:oklchToDisplayP3,f=[m.number,b.number,d.number].map((e=>parseFloat(e))),[h,L]=_(f);!L&&o&&n.warn(r,`"${a}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const r=n.unit.toLowerCase();return!!n.number&&("deg"===r||"grad"===r||"rad"===r||"turn"===r||""===r)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*.4).toFixed(10)),n):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*.4).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*.4).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,r){if(!n||!r)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(r))return;const o=t.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function replaceWith(e,t,n){const r=e.indexOf(t);e[r]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,r,o){let a;try{a=t(e)}catch(t){n.warn(r,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===a)return;a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(a);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,r,o))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const r=t.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(r.toLowerCase()))return;const o=modifiedValues(r,t,n,e.preserve);void 0!==o&&(e.preserve?(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3})):(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0,module.exports=postcssPlugin;
+"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),n=require("postcss-value-parser"),r=require("@csstools/color-helpers");function hasFallback(e){const n=e.parent;if(!n)return!1;const r=n.index(e);for(let t=0;t"comment"!==e.type&&"space"!==e.type));let o=null;if("oklab"===n?o=oklabFunctionContents(t):"oklch"===n&&(o=oklchFunctionContents(t)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[s,u,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("oklab"===n?r.conversions.OKLab_to_sRGB:r.conversions.OKLCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,s,{...s,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,t,o,s){const u=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("oklab"===a?l=oklabFunctionContents(i):"oklch"===a&&(l=oklchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[b,f,m]=channelDimensions(l),v="oklab"===a?r.conversions.OKLab_to_P3:r.conversions.OKLCH_to_P3,h=[b.number,f.number,m.number].map((e=>parseFloat(e))),[N,g]=v(h);!g&&s&&t.warn(o,`"${u}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&!!r.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.c.unit&&(r.c.unit="",r.c.number=(parseFloat(r.c.number)/100*.4).toFixed(10)),r):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.a.unit&&(r.a.unit="",r.a.number=(parseFloat(r.a.number)/100*.4).toFixed(10)),"%"===r.b.unit&&(r.b.unit="",r.b.number=(parseFloat(r.b.number)/100*.4).toFixed(10)),r):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,r,t){if(!r||!t)return;if(e.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=n.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,r,t,o){let s;try{s=n(e)}catch(n){r.warn(t,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(s);if(u===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,r,t,o))}));return{rgb:u,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(n,{result:r})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const t=n.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(t.toLowerCase()))return;const o=modifiedValues(t,n,r,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const r=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return r.subFeatures=Object.assign({displayP3:!0},r.subFeatures),r.enableProgressiveCustomProperties&&(r.preserve||r.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0,module.exports=postcssPlugin;
diff --git a/plugins/postcss-oklab-function/dist/index.mjs b/plugins/postcss-oklab-function/dist/index.mjs
index 3dae4ab67..4337b86a4 100644
--- a/plugins/postcss-oklab-function/dist/index.mjs
+++ b/plugins/postcss-oklab-function/dist/index.mjs
@@ -1,29 +1 @@
-import e from"@csstools/postcss-progressive-custom-properties";import t from"postcss-value-parser";function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let r=0;r[e])));const a=o[0].length,u=o[0].map(((e,t)=>o.map((e=>e[t]))));let i=r.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,r)=>e+n*(t[r]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===a?i.map((e=>e[0])):i}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
- */function deltaEOK(e,t){const[n,r,o]=e,[a,u,i]=t,s=n-a,l=r-u,c=o-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let r=0,o=e[1];const a=e;for(;o-r>1e-4;){const e=clip(t(a));deltaEOK(OKLCH_to_OKLab(a),OKLCH_to_OKLab(n(e)))-.02<1e-4?r=a[1]:o=a[1],a[1]=(o+r)/2}return clip(t([...a]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,r]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&r>=-1e-4&&r<=1.0001}function oklabToDisplayP3(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_P3(o),o=gam_P3(o),inGamut(o)?[clip(o),!0]:[mapGamut(a,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklchToDisplayP3(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_P3(a),a=gam_P3(a),inGamut(a)?[clip(a),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklabToSRgb(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_sRGB(o),o=gam_sRGB(o),inGamut(o)?clip(o).map((e=>Math.round(255*e))):mapGamut(a,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function oklchToSRgb(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_sRGB(a),a=gam_sRGB(a),inGamut(a)?clip(a).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let r=null;if("oklab"===t?r=oklabFunctionContents(n):"oklch"===t&&(r=oklchFunctionContents(n)),!r)return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[o,a,u]=channelNodes(r),[i,s,l]=channelDimensions(r),c=("oklab"===t?oklabToSRgb:oklchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(a)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(c[0])}),replaceWith(e.nodes,a,{...a,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,r,o){const a=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("oklab"===u?s=oklabFunctionContents(i):"oklch"===u&&(s=oklchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,p]=channelNodes(s),[m,b,d]=channelDimensions(s),_="oklab"===u?oklabToDisplayP3:oklchToDisplayP3,f=[m.number,b.number,d.number].map((e=>parseFloat(e))),[h,L]=_(f);!L&&o&&n.warn(r,`"${a}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const r=n.unit.toLowerCase();return!!n.number&&("deg"===r||"grad"===r||"rad"===r||"turn"===r||""===r)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*.4).toFixed(10)),n):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*.4).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*.4).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,r){if(!n||!r)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(r))return;const o=t.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function replaceWith(e,t,n){const r=e.indexOf(t);e[r]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,r,o){let a;try{a=t(e)}catch(t){n.warn(r,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===a)return;a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(a);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,r,o))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const r=t.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(r.toLowerCase()))return;const o=modifiedValues(r,t,n,e.preserve);void 0!==o&&(e.preserve?(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3})):(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0;export{postcssPlugin as default};
+import e from"@csstools/postcss-progressive-custom-properties";import n from"postcss-value-parser";import{conversions as r}from"@csstools/color-helpers";function hasFallback(e){const n=e.parent;if(!n)return!1;const r=n.index(e);for(let t=0;t"comment"!==e.type&&"space"!==e.type));let o=null;if("oklab"===n?o=oklabFunctionContents(t):"oklch"===n&&(o=oklchFunctionContents(t)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[u,s,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("oklab"===n?r.OKLab_to_sRGB:r.OKLCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,u,{...u,value:String(d[0])}),replaceWith(e.nodes,s,{...s,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,t,o,u){const s=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("oklab"===a?l=oklabFunctionContents(i):"oklch"===a&&(l=oklchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[f,b,m]=channelDimensions(l),v="oklab"===a?r.OKLab_to_P3:r.OKLCH_to_P3,h=[f.number,b.number,m.number].map((e=>parseFloat(e))),[N,g]=v(h);!g&&u&&t.warn(o,`"${s}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&!!r.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.c.unit&&(r.c.unit="",r.c.number=(parseFloat(r.c.number)/100*.4).toFixed(10)),r):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.a.unit&&(r.a.unit="",r.a.number=(parseFloat(r.a.number)/100*.4).toFixed(10)),"%"===r.b.unit&&(r.b.unit="",r.b.number=(parseFloat(r.b.number)/100*.4).toFixed(10)),r):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,r,t){if(!r||!t)return;if(e.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=n.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,r,t,o){let u;try{u=n(e)}catch(n){r.warn(t,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===u)return;u.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const s=String(u);if(s===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,r,t,o))}));return{rgb:s,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(n,{result:r})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const t=n.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(t.toLowerCase()))return;const o=modifiedValues(t,n,r,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const r=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return r.subFeatures=Object.assign({displayP3:!0},r.subFeatures),r.enableProgressiveCustomProperties&&(r.preserve||r.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0;export{postcssPlugin as default};
diff --git a/plugins/postcss-oklab-function/package.json b/plugins/postcss-oklab-function/package.json
index ee1d9c15a..2327f6ed1 100644
--- a/plugins/postcss-oklab-function/package.json
+++ b/plugins/postcss-oklab-function/package.json
@@ -29,6 +29,7 @@
"dist"
],
"dependencies": {
+ "@csstools/color-helpers": "^0.0.0",
"@csstools/postcss-progressive-custom-properties": "^2.0.0",
"postcss-value-parser": "^4.2.0"
},
diff --git a/plugins/postcss-oklab-function/src/convert-oklab-to-display-p3.ts b/plugins/postcss-oklab-function/src/convert-oklab-to-display-p3.ts
deleted file mode 100644
index b363d3590..000000000
--- a/plugins/postcss-oklab-function/src/convert-oklab-to-display-p3.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { gam_P3, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function oklabToDisplayP3(oklabRaw: color): [color, boolean] {
- const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw;
-
- const oklabL = Math.max(
- oklabLRaw,
- 0,
- );
-
- const oklab = [oklabL, oklabARaw, oklabBRaw] as color;
-
- let conversion = oklab as color;
- let oklch = OKLab_to_OKLCH(conversion);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- conversion = OKLab_to_XYZ(conversion);
- conversion = XYZ_to_lin_P3(conversion);
- conversion = gam_P3(conversion);
-
- if (inGamut(conversion)) {
- return [clip(conversion), true];
- }
-
- return [mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_P3(x);
- return gam_P3(x);
- }, (x: color) => {
- x = lin_P3(x);
- x = lin_P3_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- }), false];
-}
diff --git a/plugins/postcss-oklab-function/src/convert-oklab-to-srgb.ts b/plugins/postcss-oklab-function/src/convert-oklab-to-srgb.ts
deleted file mode 100644
index 2c554dbd5..000000000
--- a/plugins/postcss-oklab-function/src/convert-oklab-to-srgb.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function oklabToSRgb(oklabRaw: color): color {
- const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw;
-
- const oklabL = Math.max(
- oklabLRaw,
- 0,
- );
-
- const oklab = [oklabL, oklabARaw, oklabBRaw] as color;
-
- let conversion = oklab as color;
- let oklch = OKLab_to_OKLCH(conversion);
- if (oklch[0] < 0.000001) {
- oklch = [0, 0, 0] as color;
- }
-
- if (oklch[0] > 0.999999) {
- oklch = [1, 0, 0] as color;
- }
-
- conversion = OKLab_to_XYZ(conversion);
- conversion = XYZ_to_lin_sRGB(conversion);
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion).map((x) => {
- return Math.round(x * 255);
- }) as color;
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- }).map((x) => {
- return Math.round(x * 255);
- }) as color;
-}
diff --git a/plugins/postcss-oklab-function/src/convert-oklch-to-display-p3.ts b/plugins/postcss-oklab-function/src/convert-oklch-to-display-p3.ts
deleted file mode 100644
index c561d5f87..000000000
--- a/plugins/postcss-oklab-function/src/convert-oklch-to-display-p3.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { gam_P3, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function oklchToDisplayP3(oklchRaw: color): [color, boolean] {
- const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw;
-
- const oklchL = Math.max(
- oklchLRaw,
- 0,
- );
-
- const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as color;
-
- let conversion = oklch as color;
- if (conversion[0] < 0.000001) {
- conversion = [0, 0, 0] as color;
- }
-
- if (conversion[0] > 0.999999) {
- conversion = [1, 0, 0] as color;
- }
-
- conversion = OKLCH_to_OKLab(conversion);
- conversion = OKLab_to_XYZ(conversion);
- conversion = XYZ_to_lin_P3(conversion);
- conversion = gam_P3(conversion);
-
- if (inGamut(conversion)) {
- return [clip(conversion), true];
- }
-
- return [mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_P3(x);
- return gam_P3(x);
- }, (x: color) => {
- x = lin_P3(x);
- x = lin_P3_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- }), false];
-}
diff --git a/plugins/postcss-oklab-function/src/convert-oklch-to-srgb.ts b/plugins/postcss-oklab-function/src/convert-oklch-to-srgb.ts
deleted file mode 100644
index 83db7e474..000000000
--- a/plugins/postcss-oklab-function/src/convert-oklch-to-srgb.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js';
-import { clip, inGamut, mapGamut } from './css-color-4/map-gamut';
-
-type color = [number, number, number];
-
-export function oklchToSRgb(oklchRaw: color): color {
- const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw;
-
- const oklchL = Math.max(
- oklchLRaw,
- 0,
- );
-
- const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as color;
-
- let conversion = oklch as color;
- if (conversion[0] < 0.000001) {
- conversion = [0, 0, 0] as color;
- }
-
- if (conversion[0] > 0.999999) {
- conversion = [1, 0, 0] as color;
- }
-
- conversion = OKLCH_to_OKLab(conversion);
- conversion = OKLab_to_XYZ(conversion);
- conversion = XYZ_to_lin_sRGB(conversion);
- conversion = gam_sRGB(conversion);
-
- if (inGamut(conversion)) {
- return clip(conversion).map((x) => {
- return Math.round(x * 255);
- }) as color;
- }
-
- return mapGamut(oklch, (x: color) => {
- x = OKLCH_to_OKLab(x);
- x = OKLab_to_XYZ(x);
- x = XYZ_to_lin_sRGB(x);
- return gam_sRGB(x);
- }, (x: color) => {
- x = lin_sRGB(x);
- x = lin_sRGB_to_XYZ(x);
- x = XYZ_to_OKLab(x);
- return OKLab_to_OKLCH(x);
- }).map((x) => {
- return Math.round(x * 255);
- }) as color;
-}
diff --git a/plugins/postcss-oklab-function/src/css-color-4/LICENSE.md b/plugins/postcss-oklab-function/src/css-color-4/LICENSE.md
deleted file mode 100644
index ea4236ffc..000000000
--- a/plugins/postcss-oklab-function/src/css-color-4/LICENSE.md
+++ /dev/null
@@ -1,5 +0,0 @@
-All documents in this Directory are licensed by contributors
-under the
-[W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software).
-
-See [w3c/csswg-drafts](https://github.com/w3c/csswg-drafts) for the original work.
diff --git a/plugins/postcss-oklab-function/src/css-color-4/conversions.ts b/plugins/postcss-oklab-function/src/css-color-4/conversions.ts
deleted file mode 100644
index 636f08f90..000000000
--- a/plugins/postcss-oklab-function/src/css-color-4/conversions.ts
+++ /dev/null
@@ -1,512 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js
- */
-
-/* eslint-disable @typescript-eslint/no-loss-of-precision */
-
-import { multiplyMatrices } from './multiply-matrices';
-
-type color = [number, number, number];
-
-// Sample code for color conversions
-// Conversion can also be done using ICC profiles and a Color Management System
-// For clarity, a library is used for matrix multiplication (multiply-matrices.js)
-
-// standard white points, defined by 4-figure CIE x,y chromaticities
-export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
-export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290];
-
-// sRGB-related functions
-
-export function lin_sRGB(RGB: color): color {
- // convert an array of sRGB values
- // where in-gamut values are in the range [0 - 1]
- // to linear light (un-companded) form.
- // https://en.wikipedia.org/wiki/SRGB
- // Extended transfer function:
- // for negative values, linear portion is extended on reflection of axis,
- // then reflected power function is used.
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs < 0.04045) {
- return val / 12.92;
- }
-
- return sign * (Math.pow((abs + 0.055) / 1.055, 2.4));
- }) as color;
-}
-
-export function gam_sRGB(RGB: color): color {
- // convert an array of linear-light sRGB values in the range 0.0-1.0
- // to gamma corrected form
- // https://en.wikipedia.org/wiki/SRGB
- // Extended transfer function:
- // For negative values, linear portion extends on reflection
- // of axis, then uses reflected pow below that
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs > 0.0031308) {
- return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055);
- }
-
- return 12.92 * val;
- }) as color;
-}
-
-export function lin_sRGB_to_XYZ(rgb: color): color {
- // convert an array of linear-light sRGB values to CIE XYZ
- // using sRGB's own white, D65 (no chromatic adaptation)
-
- const M = [
- [0.41239079926595934, 0.357584339383878, 0.1804807884018343],
- [0.21263900587151027, 0.715168678767756, 0.07219231536073371],
- [0.01933081871559182, 0.11919477979462598, 0.9505321522496607],
- ];
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_sRGB(XYZ: color): color {
- // convert XYZ to linear-light sRGB
-
- const M = [
- [3.2409699419045226, -1.537383177570094, -0.4986107602930034],
- [-0.9692436362808796, 1.8759675015077202, 0.04155505740717559],
- [0.05563007969699366, -0.20397695888897652, 1.0569715142428786],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// display-p3-related functions
-
-
-export function lin_P3(RGB: color): color {
- // convert an array of display-p3 RGB values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
-
- return lin_sRGB(RGB); // same as sRGB
-}
-
-export function gam_P3(RGB: color): color {
- // convert an array of linear-light display-p3 RGB in the range 0.0-1.0
- // to gamma corrected form
-
- return gam_sRGB(RGB); // same as sRGB
-}
-
-export function lin_P3_to_XYZ(rgb: color): color {
- // convert an array of linear-light display-p3 values to CIE XYZ
- // using D65 (no chromatic adaptation)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.4865709486482162, 0.26566769316909306, 0.1982172852343625],
- [0.2289745640697488, 0.6917385218365064, 0.079286914093745],
- [0.0000000000000000, 0.04511338185890264, 1.043944368900976],
- ];
- // 0 was computed as -3.972075516933488e-17
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_P3(XYZ: color): color {
- // convert XYZ to linear-light P3
- const M = [
- [2.493496911941425, -0.9313836179191239, -0.40271078445071684],
- [-0.8294889695615747, 1.7626640603183463, 0.023624685841943577],
- [0.03584583024378447, -0.07617238926804182, 0.9568845240076872],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// prophoto-rgb functions
-
-export function lin_ProPhoto(RGB: color): color {
- // convert an array of prophoto-rgb values
- // where in-gamut colors are in the range [0.0 - 1.0]
- // to linear light (un-companded) form.
- // Transfer curve is gamma 1.8 with a small linear portion
- // Extended transfer function
- const Et2 = 16 / 512;
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs <= Et2) {
- return val / 16;
- }
-
- return sign * Math.pow(val, 1.8);
- }) as color;
-}
-
-export function gam_ProPhoto(RGB: color): color {
- // convert an array of linear-light prophoto-rgb in the range 0.0-1.0
- // to gamma corrected form
- // Transfer curve is gamma 1.8 with a small linear portion
- // TODO for negative values, extend linear portion on reflection of axis, then add pow below that
- const Et = 1 / 512;
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs >= Et) {
- return sign * Math.pow(abs, 1 / 1.8);
- }
-
- return 16 * val;
- }) as color;
-}
-
-export function lin_ProPhoto_to_XYZ(rgb: color): color {
- // convert an array of linear-light prophoto-rgb values to CIE XYZ
- // using D50 (so no chromatic adaptation needed afterwards)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.7977604896723027, 0.13518583717574031, 0.0313493495815248],
- [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902],
- [0.0, 0.0, 0.8251046025104601],
- ];
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_ProPhoto(XYZ: color): color {
- // convert XYZ to linear-light prophoto-rgb
- const M = [
- [1.3457989731028281, -0.25558010007997534, -0.05110628506753401],
- [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973],
- [0.0, 0.0, 1.2119675456389454],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// a98-rgb functions
-
-export function lin_a98rgb(RGB: color): color {
- // convert an array of a98-rgb values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
- // negative values are also now accepted
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- return sign * Math.pow(abs, 563 / 256);
- }) as color;
-}
-
-export function gam_a98rgb(RGB: color): color {
- // convert an array of linear-light a98-rgb in the range 0.0-1.0
- // to gamma corrected form
- // negative values are also now accepted
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- return sign * Math.pow(abs, 256 / 563);
- }) as color;
-}
-
-export function lin_a98rgb_to_XYZ(rgb: color): color {
- // convert an array of linear-light a98-rgb values to CIE XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- // has greater numerical precision than section 4.3.5.3 of
- // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
- // but the values below were calculated from first principles
- // from the chromaticity coordinates of R G B W
- // see matrixmaker.html
- const M = [
- [0.5766690429101305, 0.1855582379065463, 0.1882286462349947],
- [0.29734497525053605, 0.6273635662554661, 0.07529145849399788],
- [0.02703136138641234, 0.07068885253582723, 0.9913375368376388],
- ];
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_a98rgb(XYZ: color): color {
- // convert XYZ to linear-light a98-rgb
- const M = [
- [2.0415879038107465, -0.5650069742788596, -0.34473135077832956],
- [-0.9692436362808795, 1.8759675015077202, 0.04155505740717557],
- [0.013444280632031142, -0.11836239223101838, 1.0151749943912054],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-//Rec. 2020-related functions
-
-export function lin_2020(RGB: color): color {
- // convert an array of rec2020 RGB values in the range 0.0 - 1.0
- // to linear light (un-companded) form.
- // ITU-R BT.2020-2 p.4
-
- const α = 1.09929682680944;
- const β = 0.018053968510807;
-
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs < β * 4.5) {
- return val / 4.5;
- }
-
- return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45));
- }) as color;
-}
-
-export function gam_2020(RGB: color): color {
- // convert an array of linear-light rec2020 RGB in the range 0.0-1.0
- // to gamma corrected form
- // ITU-R BT.2020-2 p.4
-
- const α = 1.09929682680944;
- const β = 0.018053968510807;
-
-
- return RGB.map(function (val) {
- const sign = val < 0 ? -1 : 1;
- const abs = Math.abs(val);
-
- if (abs > β) {
- return sign * (α * Math.pow(abs, 0.45) - (α - 1));
- }
-
- return 4.5 * val;
- }) as color;
-}
-
-export function lin_2020_to_XYZ(rgb: color): color {
- // convert an array of linear-light rec2020 values to CIE XYZ
- // using D65 (no chromatic adaptation)
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const M = [
- [0.6369580483012914, 0.14461690358620832, 0.1688809751641721],
- [0.2627002120112671, 0.6779980715188708, 0.05930171646986196],
- [0.000000000000000, 0.028072693049087428, 1.060985057710791],
- ];
- // 0 is actually calculated as 4.994106574466076e-17
-
- return multiplyMatrices(M, rgb) as color;
-}
-
-export function XYZ_to_lin_2020(XYZ: color): color {
- // convert XYZ to linear-light rec2020
- const M = [
- [1.7166511879712674, -0.35567078377639233, -0.25336628137365974],
- [-0.6666843518324892, 1.6164812366349395, 0.01576854581391113],
- [0.017639857445310783, -0.042770613257808524, 0.9421031212354738],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// Chromatic adaptation
-
-export function D65_to_D50(XYZ: color): color {
- // Bradford chromatic adaptation from D65 to D50
- // The matrix below is the result of three operations:
- // - convert from XYZ to retinal cone domain
- // - scale components from one reference white to another
- // - convert back to XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
- const M = [
- [1.0479298208405488, 0.022946793341019088, -0.05019222954313557],
- [0.029627815688159344, 0.990434484573249, -0.01707382502938514],
- [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-export function D50_to_D65(XYZ: color): color {
- // Bradford chromatic adaptation from D50 to D65
- const M = [
- [0.9554734527042182, -0.023098536874261423, 0.0632593086610217],
- [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008],
- [0.012314001688319899, -0.020507696433477912, 1.3303659366080753],
- ];
-
- return multiplyMatrices(M, XYZ) as color;
-}
-
-// CIE Lab and LCH
-
-export function XYZ_to_Lab(XYZ: color): color {
- // Assuming XYZ is relative to D50, convert to CIE Lab
- // from CIE standard, which now defines these as a rational fraction
- const ε = 216 / 24389; // 6^3/29^3
- const κ = 24389 / 27; // 29^3/3^3
-
- // compute xyz, which is XYZ scaled relative to reference white
- const xyz = XYZ.map((value, i) => value / D50[i]);
-
- // now compute f
- const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116);
-
- return [
- (116 * f[1]) - 16, // L
- 500 * (f[0] - f[1]), // a
- 200 * (f[1] - f[2]), // b
- ];
- // L in range [0,100]. For use in CSS, add a percent
-}
-
-export function Lab_to_XYZ(Lab: color): color {
- // Convert Lab to D50-adapted XYZ
- // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
- const κ = 24389 / 27; // 29^3/3^3
- const ε = 216 / 24389; // 6^3/29^3
- const f = [];
-
- // compute f, starting with the luminance-related term
- f[1] = (Lab[0] + 16) / 116;
- f[0] = Lab[1] / 500 + f[1];
- f[2] = f[1] - Lab[2] / 200;
-
- // compute xyz
- const xyz = [
- Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ,
- Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ,
- Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ,
- ];
-
- // Compute XYZ by scaling xyz by reference white
- return xyz.map((value, i) => value * D50[i]) as color;
-}
-
-export function Lab_to_LCH(Lab: color): color {
- // Convert to polar form
- const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI;
- return [
- Lab[0], // L is still L
- Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma
- hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
- ];
-}
-
-export function LCH_to_Lab(LCH: color): color {
- // Convert from polar form
- return [
- LCH[0], // L is still L
- LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a
- LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b
- ];
-}
-
-// OKLab and OKLCH
-// https://bottosson.github.io/posts/oklab/
-
-// XYZ <-> LMS matrices recalculated for consistent reference white
-// see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
-
-export function XYZ_to_OKLab(XYZ: color): color {
- // Given XYZ relative to D65, convert to OKLab
- const XYZtoLMS = [
- [0.8190224432164319, 0.3619062562801221, -0.12887378261216414],
- [0.0329836671980271, 0.9292868468965546, 0.03614466816999844],
- [0.048177199566046255, 0.26423952494422764, 0.6335478258136937],
- ];
- const LMStoOKLab = [
- [0.2104542553, 0.7936177850, -0.0040720468],
- [1.9779984951, -2.4285922050, 0.4505937099],
- [0.0259040371, 0.7827717662, -0.8086757660],
- ];
-
- const LMS = multiplyMatrices(XYZtoLMS, XYZ) as color;
- return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as color;
- // L in range [0,1]. For use in CSS, multiply by 100 and add a percent
-}
-
-export function OKLab_to_XYZ(OKLab: color): color {
- // Given OKLab, convert to XYZ relative to D65
- const LMStoXYZ = [
- [1.2268798733741557, -0.5578149965554813, 0.28139105017721583],
- [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701],
- [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418],
- ];
- const OKLabtoLMS = [
- [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339],
- [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402],
- [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399],
- ];
-
- const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as color;
- return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as color;
-}
-
-export function OKLab_to_OKLCH(OKLab: color): color {
- const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI;
- return [
- OKLab[0], // L is still L
- Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma
- hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360)
- ];
-}
-
-export function OKLCH_to_OKLab(OKLCH: color): color {
- return [
- OKLCH[0], // L is still L
- OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a
- OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b
- ];
-}
-
-// Premultiplied alpha conversions
-
-export function rectangular_premultiply(color: color, alpha: number): color {
- // given a color in a rectangular orthogonal colorspace
- // and an alpha value
- // return the premultiplied form
- return color.map((c) => c * alpha) as color;
-}
-
-export function rectangular_un_premultiply(color: color, alpha: number): color {
- // given a premultiplied color in a rectangular orthogonal colorspace
- // and an alpha value
- // return the actual color
- if (alpha === 0) {
- return color; // avoid divide by zero
- }
- return color.map((c) => c / alpha) as color;
-}
-
-export function polar_premultiply(color: color, alpha: number, hueIndex: number): color {
- // given a color in a cylindicalpolar colorspace
- // and an alpha value
- // return the premultiplied form.
- // the index says which entry in the color array corresponds to hue angle
- // for example, in OKLCH it would be 2
- // while in HSL it would be 0
- return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as color;
-}
-
-export function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color {
- // given a color in a cylindicalpolar colorspace
- // and an alpha value
- // return the actual color.
- // the hueIndex says which entry in the color array corresponds to hue angle
- // for example, in OKLCH it would be 2
- // while in HSL it would be 0
- if (alpha === 0) {
- return color; // avoid divide by zero
- }
- return color.map((c, i) => c / (hueIndex === i ? 1 : alpha)) as color;
-}
-
-// Convenience functions can easily be defined, such as
-export function hsl_premultiply(color: color, alpha: number): color {
- return polar_premultiply(color, alpha, 0);
-}
diff --git a/plugins/postcss-oklab-function/src/css-color-4/map-gamut.ts b/plugins/postcss-oklab-function/src/css-color-4/map-gamut.ts
deleted file mode 100644
index 168068986..000000000
--- a/plugins/postcss-oklab-function/src/css-color-4/map-gamut.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { OKLCH_to_OKLab } from './conversions';
-import { deltaEOK } from './deltaEOK';
-
-type color = [number, number, number];
-
-export function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color {
- return binarySearchGamut(startOKLCH, toDestination, fromDestination);
-}
-
-function binarySearchGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color {
- let min = 0;
- let max = startOKLCH[1];
- const current = startOKLCH;
-
- while (max - min > 0.0001) {
- const clipped = clip(toDestination(current));
- const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped)));
- // are we inside the gamut (or very close to the boundary, outside)
- if (deltaE - 0.02 < 0.0001) {
- min = current[1];
- } else {
- max = current[1];
- }
- // binary search
- current[1] = (max + min) / 2;
- }
-
- return clip(toDestination([...current]));
-}
-
-export function clip(color: color): color {
- return color.map(val => {
- if (val < 0) {
- return 0;
- } else if (val > 1) {
- return 1;
- } else {
- return val;
- }
- }) as color;
-}
-
-export function inGamut(x: color): boolean {
- const [xX, xY, xZ] = x;
- return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001;
-}
-
diff --git a/plugins/postcss-oklab-function/src/css-color-4/multiply-matrices.ts b/plugins/postcss-oklab-function/src/css-color-4/multiply-matrices.ts
deleted file mode 100644
index 776f8c597..000000000
--- a/plugins/postcss-oklab-function/src/css-color-4/multiply-matrices.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Simple matrix (and vector) multiplication
- * Warning: No error handling for incompatible dimensions!
- * @author Lea Verou 2020 MIT License
- *
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js
- */
-
-// A is m x n. B is n x p. product is m x p.
-export function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array {
- const m = a.length;
-
- let A: Array>;
- if (!Array.isArray(a[0])) {
- // A is vector, convert to [[a, b, c, ...]]
- A = [a as Array];
- } else {
- A = a as Array>;
- }
-
- let B: Array>;
- if (!Array.isArray(b[0])) {
- // B is vector, convert to [[a], [b], [c], ...]]
- B = (b as Array).map(x => [x]);
- }
-
- const p = B[0].length;
- const B_cols = B[0].map((_, i) => B.map(x => x[i])); // transpose B
- let product: Array> | Array = A.map(row => B_cols.map(col => {
- if (!Array.isArray(row)) {
- return col.reduce((d, f) => d + f * row, 0);
- }
-
- return row.reduce((d, f, i) => d + f * (col[i] || 0), 0);
- }));
-
- if (m === 1) {
- product = product[0]; // Avoid [[a, b, c, ...]]
- }
-
- if (p === 1) {
- return product.map(x => x[0]); // Avoid [[a], [b], [c], ...]]
- }
-
- return product;
-}
diff --git a/plugins/postcss-oklab-function/src/css-color-4/utilities.ts b/plugins/postcss-oklab-function/src/css-color-4/utilities.ts
deleted file mode 100644
index b3c4368cd..000000000
--- a/plugins/postcss-oklab-function/src/css-color-4/utilities.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * @license W3C
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
- *
- * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
- */
-
-import { D50_to_D65, D65_to_D50, gam_2020, gam_P3, gam_sRGB, Lab_to_LCH, Lab_to_XYZ, LCH_to_Lab, lin_2020, lin_2020_to_XYZ, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, XYZ_to_Lab, XYZ_to_lin_2020, XYZ_to_lin_P3, XYZ_to_lin_sRGB } from './conversions';
-
-type color = [number, number, number];
-
-// utility functions for color conversions
-// needs conversions.js
-
-export function sRGB_to_luminance(RGB: color): number {
- // convert an array of gamma-corrected sRGB values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ
- // and return luminance (the Y value)
-
- const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB));
- return XYZ[1];
-}
-
-export function contrast(RGB1: color, RGB2: color): number {
- // return WCAG 2.1 contrast ratio
- // https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
- // for two sRGB values
- // given as arrays of 0.0 to 1.0
-
- const L1 = sRGB_to_luminance(RGB1);
- const L2 = sRGB_to_luminance(RGB2);
-
- if (L1 > L2) {
- return (L1 + 0.05) / (L2 + 0.05);
- }
-
- return (L2 + 0.05) / (L1 + 0.05);
-}
-
-export function sRGB_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected sRGB values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB)))));
-}
-
-export function P3_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected display-p3 values
- // in the 0.0 to 1.0 range
- // to linear-light display-p3, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB)))));
-}
-
-export function r2020_to_LCH(RGB: color): color {
- // convert an array of gamma-corrected rec.2020 values
- // in the 0.0 to 1.0 range
- // to linear-light sRGB, then to CIE XYZ,
- // then adapt from D65 to D50,
- // then convert XYZ to CIE Lab
- // and finally, convert to CIE LCH
-
- return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB)))));
-}
-
-export function LCH_to_sRGB(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light sRGB
- // and finally to gamma corrected sRGB
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_sRGB(XYZ_to_lin_sRGB(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-export function LCH_to_P3(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light display-p3
- // and finally to gamma corrected display-p3
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_P3(XYZ_to_lin_P3(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-export function LCH_to_r2020(LCH: color): color {
- // convert an array of CIE LCH values
- // to CIE Lab, and then to XYZ,
- // adapt from D50 to D65,
- // then convert XYZ to linear-light rec.2020
- // and finally to gamma corrected rec.2020
- // for in-gamut colors, components are in the 0.0 to 1.0 range
- // out of gamut colors may have negative components
- // or components greater than 1.0
- // so check for that :)
-
- return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH)))));
-}
-
-// this is straight from the CSS Color 4 spec
-
-export function hslToRgb(hsl: color): color {
- // For simplicity, this algorithm assumes that the hue has been normalized
- // to a number in the half-open range [0, 6), and the saturation and lightness
- // have been normalized to the range [0, 1]. It returns an array of three numbers
- // representing the red, green, and blue channels of the colors,
- // normalized to the range [0, 1]
- const [hue, sat, light] = hsl;
-
- let t2: number;
- if (light <= .5) {
- t2 = light * (sat + 1);
- } else {
- t2 = light + sat - (light * sat);
- }
- const t1 = light * 2 - t2;
- const r = hueToRgb(t1, t2, hue + 2);
- const g = hueToRgb(t1, t2, hue);
- const b = hueToRgb(t1, t2, hue - 2);
- return [r, g, b];
-}
-
-export function hueToRgb(t1: number, t2: number, hue: number): number {
- if (hue < 0) {
- hue += 6;
- }
- if (hue >= 6) {
- hue -= 6;
- }
-
- if (hue < 1) {
- return (t2 - t1) * hue + t1;
- } else if (hue < 3) {
- return t2;
- } else if (hue < 4) {
- return (t2 - t1) * (4 - hue) + t1;
- } else {
- return t1;
- }
-}
-
-// These are the naive algorithms from CS Color 4
-
-export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color {
- // CMYK is an array of four values
- // in the range [0.0, 1.0]
- // the optput is an array of [RGB]
- // also in the [0.0, 1.0] range
- // because the naive algorithm does not generate out of gamut colors
- // neither does it generate accurate simulations of practical CMYK colors
-
- const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3];
-
- const red = 1 - Math.min(1, cyan * (1 - black) + black);
- const green = 1 - Math.min(1, magenta * (1 - black) + black);
- const blue = 1 - Math.min(1, yellow * (1 - black) + black);
-
- return [red, green, blue];
-
-}
-
-export function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number] {
- // RGB is an arravy of three values
- // in the range [0.0, 1.0]
- // the output is an array of [CMYK]
- // also in the [0.0, 1.0] range
- // with maximum GCR and (I think) 200% TAC
- // the naive algorithm does not generate out of gamut colors
- // neither does it generate accurate simulations of practical CMYK colors
-
- const red = RGB[0], green = RGB[1], blue = RGB[2];
-
- const black = 1 - Math.max(red, green, blue);
- const cyan = (black == 1.0) ? 0 : (1 - red - black) / (1 - black);
- const magenta = (black == 1.0) ? 0 : (1 - green - black) / (1 - black);
- const yellow = (black == 1.0) ? 0 : (1 - blue - black) / (1 - black);
-
- return [cyan, magenta, yellow, black];
-}
-
-// Chromaticity utilities
-
-export function XYZ_to_xy(XYZ: color): [number, number] {
- // Convert an array of three XYZ values
- // to x,y chromaticity coordinates
-
- const X = XYZ[0];
- const Y = XYZ[1];
- const Z = XYZ[2];
- const sum = X + Y + Z;
- return [X / sum, Y / sum];
-}
-
-export function xy_to_uv(xy: [number, number]): [number, number] {
- // convert an x,y chromaticity pair
- // to u*,v* chromaticities
-
- const x = xy[0];
- const y = xy[1];
- const denom = -2 * x + 12 * y + 3;
- return [4 * x / denom, 9 * y / denom];
-}
-
-export function XYZ_to_uv(XYZ: color): [number, number] {
- // Convert an array of three XYZ values
- // to u*,v* chromaticity coordinates
-
- const X = XYZ[0];
- const Y = XYZ[1];
- const Z = XYZ[2];
- const denom = X + 15 * Y + 3 * Z;
- return [4 * X / denom, 9 * Y / denom];
-}
diff --git a/plugins/postcss-oklab-function/src/on-css-function.ts b/plugins/postcss-oklab-function/src/on-css-function.ts
index 1f81acd82..0f660a598 100644
--- a/plugins/postcss-oklab-function/src/on-css-function.ts
+++ b/plugins/postcss-oklab-function/src/on-css-function.ts
@@ -1,10 +1,7 @@
import valueParser from 'postcss-value-parser';
import type { FunctionNode, Dimension, Node, DivNode, WordNode, SpaceNode } from 'postcss-value-parser';
-import { oklabToDisplayP3 } from './convert-oklab-to-display-p3';
-import { oklchToDisplayP3 } from './convert-oklch-to-display-p3';
import { Declaration, Result } from 'postcss';
-import { oklabToSRgb } from './convert-oklab-to-srgb';
-import { oklchToSRgb } from './convert-oklch-to-srgb';
+import { conversions } from '@csstools/color-helpers';
export function onCSSFunctionSRgb(node: FunctionNode) {
const value = node.value.toLowerCase();
@@ -34,7 +31,7 @@ export function onCSSFunctionSRgb(node: FunctionNode) {
const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes);
/** Corresponding Color transformer. */
- const toRGB = value === 'oklab' ? oklabToSRgb : oklchToSRgb;
+ const toRGB = value === 'oklab' ? conversions.OKLab_to_sRGB : conversions.OKLCH_to_sRGB;
/** RGB channels from the source color. */
const channelNumbers: [number, number, number] = [
@@ -100,7 +97,7 @@ export function onCSSFunctionDisplayP3(node: FunctionNode, decl: Declaration, re
const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes);
/** Corresponding Color transformer. */
- const toDisplayP3 = value === 'oklab' ? oklabToDisplayP3 : oklchToDisplayP3;
+ const toDisplayP3 = value === 'oklab' ? conversions.OKLab_to_P3 : conversions.OKLCH_to_P3;
/** RGB channels from the source color. */
const channelNumbers: [number, number, number] = [
diff --git a/plugins/postcss-text-decoration-shorthand/CHANGELOG.md b/plugins/postcss-text-decoration-shorthand/CHANGELOG.md
index 1e3a6332d..0dde53614 100644
--- a/plugins/postcss-text-decoration-shorthand/CHANGELOG.md
+++ b/plugins/postcss-text-decoration-shorthand/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changes to PostCSS Text Decoration Shorthand
+### Unreleased (minor)
+
+- Add: `@csstools/color-helpers` dependency for the named colors list.
+
### 2.1.0 (January 28, 2023)
- Add: support for multiple line values (`text-decoration: overline underline;`)
diff --git a/plugins/postcss-text-decoration-shorthand/dist/index.cjs b/plugins/postcss-text-decoration-shorthand/dist/index.cjs
index fb9145f78..89dcfc4c8 100644
--- a/plugins/postcss-text-decoration-shorthand/dist/index.cjs
+++ b/plugins/postcss-text-decoration-shorthand/dist/index.cjs
@@ -1 +1 @@
-"use strict";var e=require("postcss-value-parser");const creator=n=>{const a=Object.assign({preserve:!1},n);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const n=new Map;return{OnceExit:()=>{n.clear()},Declaration:i=>{if("text-decoration"!==i.prop.toLowerCase())return;const s=i.parent.index(i);if(i.parent.nodes.some((e=>"decl"===e.type&&"text-decoration"===e.prop.toLowerCase()&&n.get(i.value)===e.value&&i.parent.index(e)!==s)))return;const u=e(i.value),d=u.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(d.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(d.find((e=>"word"===e.type&&r.includes(e.value))))return;const c={line:[],style:null,color:null,thickness:null};for(let r=0;r{const l=Object.assign({preserve:!1},e);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const e=new Map;return{OnceExit:()=>{e.clear()},Declaration:i=>{if("text-decoration"!==i.prop.toLowerCase())return;const a=i.parent.index(i);if(i.parent.nodes.some((t=>"decl"===t.type&&"text-decoration"===t.prop.toLowerCase()&&e.get(i.value)===t.value&&i.parent.index(t)!==a)))return;const c=t(i.value),u=c.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(u.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(u.find((e=>"word"===e.type&&o.includes(e.value))))return;const p={line:[],style:null,color:null,thickness:null};for(let e=0;e{const a=Object.assign({preserve:!1},n);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const n=new Map;return{OnceExit:()=>{n.clear()},Declaration:i=>{if("text-decoration"!==i.prop.toLowerCase())return;const s=i.parent.index(i);if(i.parent.nodes.some((e=>"decl"===e.type&&"text-decoration"===e.prop.toLowerCase()&&n.get(i.value)===e.value&&i.parent.index(e)!==s)))return;const u=e(i.value),d=u.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(d.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(d.find((e=>"word"===e.type&&r.includes(e.value))))return;const c={line:[],style:null,color:null,thickness:null};for(let r=0;r{const l=Object.assign({preserve:!1},e);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const e=new Map;return{OnceExit:()=>{e.clear()},Declaration:a=>{if("text-decoration"!==a.prop.toLowerCase())return;const i=a.parent.index(a);if(a.parent.nodes.some((t=>"decl"===t.type&&"text-decoration"===t.prop.toLowerCase()&&e.get(a.value)===t.value&&a.parent.index(t)!==i)))return;const c=t(a.value),u=c.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(u.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(u.find((e=>"word"===e.type&&o.includes(e.value))))return;const p={line:[],style:null,color:null,thickness:null};for(let e=0;e