@thi.ng/color 5.3.2 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-02-17T20:06:13Z
3
+ - **Last updated**: 2023-03-02T18:09:03Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,44 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [5.4.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/color@5.4.0) (2023-03-02)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add oklch mode impl/support ([3e77420](https://github.com/thi-ng/umbrella/commit/3e77420))
17
+ - add oklch() factory & class decl
18
+ - add oklab<>oklch conversions
19
+ - update analog() & rotate()
20
+ - add CSS Level4 oklab/oklch support ([137d322](https://github.com/thi-ng/umbrella/commit/137d322))
21
+ - update parseCss() to support oklab/oklch colors
22
+ - add oklab/oklch CSS serializers
23
+ - update css() to optionally support CSS Color Module L4
24
+ - add CSS_LEVEL3 / CSS_LEVEL4 conversions
25
+ - update color() to accept CSS color strings ([0d5b3e9](https://github.com/thi-ng/umbrella/commit/0d5b3e9))
26
+
27
+ #### 🩹 Bug fixes
28
+
29
+ - update oklab LMS matrices ([6e2cb75](https://github.com/thi-ng/umbrella/commit/6e2cb75))
30
+ - according to @bottosson they were already updated in 01/2021
31
+ - update parseCss()/parseHex() ([dbbdc7d](https://github.com/thi-ng/umbrella/commit/dbbdc7d))
32
+ - fix support for percentages
33
+ - fix channel scale factors
34
+ - fix alpha-channel handling in parseHex()
35
+ - rename internal helpers
36
+ - add/update tests
37
+
38
+ #### ⏱ Performance improvements
39
+
40
+ - refactor distLch() ([fa2d4e0](https://github.com/thi-ng/umbrella/commit/fa2d4e0))
41
+ - use Law of Cosines impl to avoid 1x cos and 2x sin ops
42
+
43
+ #### ♻️ Refactoring
44
+
45
+ - update oklab/oklch channel ranges, add docs ([d87b30d](https://github.com/thi-ng/umbrella/commit/d87b30d))
46
+ - update (ok)lab/lch CSS serializers ([8492f5e](https://github.com/thi-ng/umbrella/commit/8492f5e))
47
+ - extract internal helpers
48
+ - update/fix channel scale factors
49
+
12
50
  ## [5.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/color@5.3.0) (2023-02-10)
13
51
 
14
52
  #### 🚀 Features
package/README.md CHANGED
@@ -60,28 +60,30 @@ from the integer types).
60
60
  - [Lab](https://en.wikipedia.org/wiki/CIELAB_color_space) (float4, D50/D65 versions)
61
61
  - [LCH](https://en.wikipedia.org/wiki/HCL_color_space) (float4)
62
62
  - [Oklab](https://bottosson.github.io/posts/oklab/) (float4)
63
+ - [Oklch](https://bottosson.github.io/posts/oklab/) (float4) (polar version of oklab)
63
64
  - [RGB](https://en.wikipedia.org/wiki/RGB_color_space) (float4, _linear_)
64
65
  - [sRGB](https://en.wikipedia.org/wiki/SRGB) (float4, [gamma corrected](https://en.wikipedia.org/wiki/Gamma_correction))
65
66
  - [XYY](https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space) (float4)
66
67
  - [XYZ](https://en.wikipedia.org/wiki/CIE_1931_color_space) (float4, aka CIE 1931, D50/D65 versions)
67
68
  - [YCC](https://en.wikipedia.org/wiki/YCbCr) (float4, aka YCbCr)
68
69
 
69
- | From/To | CSS | HCY | HSI | HSL | HSV | Int | Lab | LCH | Oklab | RGB | sRGB | XYY | XYZ | YCC |
70
- |-----------|-----|-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|-----|-------|-----------------|-----------------|-----|-----------------|-----------------|
71
- | **CSS** | ✅ | 🆎 | 🆎 | ✅ | 🆎 | ✅<sup>(1)</sup> | ✅<sup>(4)</sup> | ✅ | 🆎 | ✅ | ✅ | 🆎 | 🆎 | 🆎 |
72
- | **HCY** | 🆎 | ✅ | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
73
- | **HSI** | 🆎 | 🆎 | ✅ | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
74
- | **HSL** | ✅ | 🆎 | 🆎 | ✅ | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
75
- | **HSV** | 🆎 | 🆎 | 🆎 | ✅ | ✅ | ❌ | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
76
- | **Int** | ✅ | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | ✅ | ✅ | 🆎 | 🆎 |
77
- | **Lab** | | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | ✅<sup>(3)</sup> | ✅ | 🆎 | ✅<sup>(3)</sup> | 🆎 | 🆎 | ✅<sup>(3)</sup> | 🆎 |
78
- | **LCH** | | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | ✅ | ✅ | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 |
79
- | **Oklab** | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | ✅ | ✅ | 🆎 | 🆎 | ✅ | 🆎 |
80
- | **RGB** | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | | ✅<sup>(3)</sup> | ✅ | ✅ | | | 🆎 | ✅<sup>(3)</sup> | ✅<sup>(2)</sup> |
81
- | **sRGB** | | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅ | 🆎 | 🆎 | 🆎 | ✅ | ✅ | 🆎 | 🆎 | 🆎 |
82
- | **XYY** | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | | ✅ | 🆎 |
83
- | **XYZ** | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | | 🆎 | 🆎 | | 🆎 | ✅ | ✅<sup>(3)</sup> | 🆎 |
84
- | **YCC** | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 | ✅ |
70
+ | From/To | CSS | HCY | HSI | HSL | HSV | Int | Lab | LCH | Oklab | Oklch | RGB | sRGB | XYY | XYZ | YCC |
71
+ |-----------|-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|-----|-------|-------|-----------------|-----------------|-----|-----------------|-----------------|
72
+ | **CSS** | ✅ | 🆎 | 🆎 | ✅ | 🆎 | ✅<sup>(1)</sup> | ✅<sup>(4)</sup> | ✅ | | ✅ | ✅ | ✅ | 🆎 | 🆎 | 🆎 |
73
+ | **HCY** | 🆎 | ✅ | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
74
+ | **HSI** | 🆎 | 🆎 | ✅ | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
75
+ | **HSL** | ✅ | 🆎 | 🆎 | ✅ | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
76
+ | **HSV** | 🆎 | 🆎 | 🆎 | ✅ | ✅ | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 |
77
+ | **Int** | ✅ | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ✅ | ✅ | 🆎 | 🆎 |
78
+ | **Lab** | ✅<sup>(5)</sup> | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | ✅<sup>(3)</sup> | ✅ | 🆎 | 🆎 | ✅<sup>(3)</sup> | 🆎 | 🆎 | ✅<sup>(3)</sup> | 🆎 |
79
+ | **LCH** | ✅<sup>(5)</sup> | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | ✅ | ✅ | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 |
80
+ | **Oklab** | ✅<sup>(5)</sup> | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | ✅ | ✅ | ✅ | 🆎 | 🆎 | ✅ | 🆎 |
81
+ | **Oklch** | ✅<sup>(5)</sup> | 🆎 | 🆎 | 🆎 | 🆎 | | 🆎 | 🆎 | ✅ | ✅ | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 |
82
+ | **RGB** | 🆎 | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅ | ✅<sup>(3)</sup> | | ✅ | 🆎 | ✅ | ✅ | 🆎 | ✅<sup>(3)</sup> | ✅<sup>(2)</sup> |
83
+ | **sRGB** | | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | ✅<sup>(2)</sup> | | 🆎 | 🆎 | 🆎 | 🆎 | ✅ | ✅ | 🆎 | 🆎 | 🆎 |
84
+ | **XYY** | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ✅ | | 🆎 |
85
+ | **XYZ** | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | | 🆎 | 🆎 | 🆎 | ✅ | 🆎 | ✅ | ✅<sup>(3)</sup> | 🆎 |
86
+ | **YCC** | 🆎 | 🆎 | 🆎 | 🆎 | 🆎 | ❌ | 🆎 | 🆎 | 🆎 | 🆎 | ✅<sup>(2)</sup> | 🆎 | 🆎 | 🆎 | ✅ |
85
87
 
86
88
  - ✅ - direct conversion
87
89
  - 🆎 - indirect conversion (mostly via RGB/sRGB)
@@ -90,6 +92,7 @@ from the integer types).
90
92
  (see [Wikipedia](https://en.wikipedia.org/wiki/HSL_and_HSV#cite_note-26))
91
93
  - (3) - including [D50/D65 illuminant](https://en.wikipedia.org/wiki/Illuminant_D65) options
92
94
  - (4) - parsed as Lab w/ D50 illuminant as per [CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/#lab-colors)
95
+ - (5) - only if targeting CSS Color Module Level 4 or newer
93
96
 
94
97
  #### Color creation / conversion
95
98
 
@@ -98,9 +101,9 @@ from other models/spaces. These functions can take the following arguments:
98
101
 
99
102
  - CSS string
100
103
  - number (interpreted as packed ARGB int32)
101
- - array (used as is)
104
+ - array of color channel values (used as is)
102
105
  - scalars (one per channel, alpha optional, always defaults to 1.0)
103
- - color instance (triggers conversion)
106
+ - color instance (might trigger conversion if needed)
104
107
 
105
108
  Additionally, an optional target backing buffer, start index and stride can be
106
109
  given. See [next section](#storage--memory-mapping).
@@ -598,7 +601,7 @@ For Node.js REPL:
598
601
  const color = await import("@thi.ng/color");
599
602
  ```
600
603
 
601
- Package sizes (brotli'd, pre-treeshake): ESM: 15.25 KB
604
+ Package sizes (brotli'd, pre-treeshake): ESM: 15.51 KB
602
605
 
603
606
  ## Dependencies
604
607
 
package/alpha.d.ts CHANGED
@@ -1,4 +1,12 @@
1
1
  import type { Color, ReadonlyColor } from "./api.js";
2
2
  export declare const alpha: (src: ReadonlyColor) => number;
3
+ /**
4
+ * Creates version of `src` color with modified `alpha` and writes result into
5
+ * `out` (or if null, back into `src`).
6
+ *
7
+ * @param out
8
+ * @param src
9
+ * @param alpha
10
+ */
3
11
  export declare const setAlpha: (out: Color | null, src: ReadonlyColor, alpha: number) => import("@thi.ng/vectors").Vec;
4
12
  //# sourceMappingURL=alpha.d.ts.map
package/alpha.js CHANGED
@@ -1,3 +1,11 @@
1
1
  import { setC4 } from "@thi.ng/vectors/setc";
2
2
  export const alpha = (src) => src[3] !== undefined ? src[3] : 1;
3
+ /**
4
+ * Creates version of `src` color with modified `alpha` and writes result into
5
+ * `out` (or if null, back into `src`).
6
+ *
7
+ * @param out
8
+ * @param src
9
+ * @param alpha
10
+ */
3
11
  export const setAlpha = (out, src, alpha) => setC4(out || src, src[0], src[1], src[2], alpha);
package/analog.d.ts CHANGED
@@ -8,6 +8,10 @@ export declare const defAnalog: FnU3<Fn3<number, number, IRandom, number>, Fn4<C
8
8
  * provided
9
9
  * [`IRandom`](https://docs.thi.ng/umbrella/random/interfaces/IRandom.html)
10
10
  * PRNG.
11
+ *
12
+ * @remarks
13
+ * If `out` is null, the resulting color will be written back into `src`.
14
+ *
11
15
  */
12
16
  export declare const analog: import("@thi.ng/defmulti").MultiFn4<import("@thi.ng/vectors").Vec | null, TypedColor<any>, number, IRandom | undefined, import("@thi.ng/vectors").Vec>;
13
17
  /**
package/analog.js CHANGED
@@ -28,8 +28,12 @@ const analogNUU = defAnalog(analogN, analogU, analogU);
28
28
  * provided
29
29
  * [`IRandom`](https://docs.thi.ng/umbrella/random/interfaces/IRandom.html)
30
30
  * PRNG.
31
+ *
32
+ * @remarks
33
+ * If `out` is null, the resulting color will be written back into `src`.
34
+ *
31
35
  */
32
- export const analog = defmulti(__dispatch1, {}, {
36
+ export const analog = defmulti(__dispatch1, { oklab: "lab50", oklch: "lch" }, {
33
37
  hcy: analogHNN,
34
38
  hsi: analogHNN,
35
39
  hsl: analogHNN,
package/api.d.ts CHANGED
@@ -4,8 +4,11 @@ import type { IVector, ReadonlyVec, Vec } from "@thi.ng/vectors";
4
4
  export type Color = Vec;
5
5
  export type ReadonlyColor = ReadonlyVec;
6
6
  export type MaybeColor = TypedColor<any> | IParsedColor | ReadonlyColor | string | number;
7
+ /**
8
+ * Color manipulation function. If `out` is null, the `src` will be mutated.
9
+ */
7
10
  export type ColorOp = (out: Color | null, src: ReadonlyColor) => Color;
8
- export type ColorMode = "argb32" | "abgr32" | "hcy" | "hsi" | "hsl" | "hsv" | "lab50" | "lab65" | "lch" | "oklab" | "rgb" | "srgb" | "xyy" | "xyz50" | "xyz65" | "ycc";
11
+ export type ColorMode = "argb32" | "abgr32" | "hcy" | "hsi" | "hsl" | "hsv" | "lab50" | "lab65" | "lch" | "oklab" | "oklch" | "rgb" | "srgb" | "xyy" | "xyz50" | "xyz65" | "ycc";
9
12
  /**
10
13
  * Hue names in radial order, e.g. used by {@link namedHueRgb}.
11
14
  */
@@ -28,7 +31,15 @@ export interface IColor {
28
31
  }
29
32
  export interface ChannelSpec {
30
33
  /**
31
- * Acceptable value range for this channel. Used by {@link TypedColor.clamp}.
34
+ * Acceptable approximate value range for this color channel. Used by
35
+ * {@link TypedColor.clamp} and {@link TypedColor.randomize}. At current and
36
+ * for compatibility reasons, the "valid" ranges for each color channel are
37
+ * configured such that they combined only approximately cover the full sRGB
38
+ * gamut (even though some color modes have gamuts larger than that).
39
+ * However, due to only using individual per-channel/per-axis definitions
40
+ * for those value ranges, it's still possible for colors in those larger
41
+ * color spaces to be slightly outside that sRGB gamut. These are soft
42
+ * limits, for orientation only.
32
43
  *
33
44
  * @defaultValue [0,1]
34
45
  */
package/clamp.d.ts CHANGED
@@ -1,8 +1,15 @@
1
1
  import type { Color, ReadonlyColor } from "./api.js";
2
2
  /**
3
- * Clamps all color channels to [0,1] interval and calls `ensureAlpha`
4
- * to ensure alpha channel is defined (if missing sets it to `alpha`,
5
- * default: 1).
3
+ * Clamps all color channels to [0,1] interval and calls `ensureAlpha` to ensure
4
+ * alpha channel is defined (if missing sets it to `alpha`, default: 1).
5
+ *
6
+ * @remarks
7
+ * If `out` is null, the resulting color will be written back into `src`.
8
+ *
9
+ * Note: The result of this function might be different than
10
+ * {@link TypedColor.clamp}. The latter is taking into account pre-configured
11
+ * channel value ranges (per color mode). See {@link ChannelSpec.range} for
12
+ * details.
6
13
  *
7
14
  * @param out - result
8
15
  * @param src - source color
@@ -13,6 +20,9 @@ export declare const clamp: (out: Color | null, src: ReadonlyColor, alpha?: numb
13
20
  * Similar to {@link clamp}, but calls `ensureHue` to fold (instead of
14
21
  * clamping) the hue into [0,1] interval.
15
22
  *
23
+ * @remarks
24
+ * If `out` is null, the resulting color will be written back into `src`.
25
+ *
16
26
  * @param out - result
17
27
  * @param src - source color
18
28
  * @param alpha - alpha value
package/clamp.js CHANGED
@@ -3,9 +3,16 @@ import { fract } from "@thi.ng/math/prec";
3
3
  import { setC4 } from "@thi.ng/vectors/setc";
4
4
  import { __ensureAlpha } from "./internal/ensure.js";
5
5
  /**
6
- * Clamps all color channels to [0,1] interval and calls `ensureAlpha`
7
- * to ensure alpha channel is defined (if missing sets it to `alpha`,
8
- * default: 1).
6
+ * Clamps all color channels to [0,1] interval and calls `ensureAlpha` to ensure
7
+ * alpha channel is defined (if missing sets it to `alpha`, default: 1).
8
+ *
9
+ * @remarks
10
+ * If `out` is null, the resulting color will be written back into `src`.
11
+ *
12
+ * Note: The result of this function might be different than
13
+ * {@link TypedColor.clamp}. The latter is taking into account pre-configured
14
+ * channel value ranges (per color mode). See {@link ChannelSpec.range} for
15
+ * details.
9
16
  *
10
17
  * @param out - result
11
18
  * @param src - source color
@@ -16,6 +23,9 @@ export const clamp = (out, src, alpha = 1) => setC4(out || src, clamp01(src[0]),
16
23
  * Similar to {@link clamp}, but calls `ensureHue` to fold (instead of
17
24
  * clamping) the hue into [0,1] interval.
18
25
  *
26
+ * @remarks
27
+ * If `out` is null, the resulting color will be written back into `src`.
28
+ *
19
29
  * @param out - result
20
30
  * @param src - source color
21
31
  * @param alpha - alpha value
package/color.d.ts CHANGED
@@ -1,4 +1,27 @@
1
1
  import type { Color, ColorMode, ParsedColor, TypedColor } from "./api.js";
2
+ /**
3
+ * Takes an CSS color string or the result of {@link parseCss} or a
4
+ * {@link ColorMode} and raw buffer and returns a suitable typed color wrapper
5
+ * for it (potentially by first parsing the color).
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * color("springgreen");
10
+ * // $Color [srgb] { offset: 0, stride: 1, buf: [ 0, 1, 0.498, 1 ] }
11
+ *
12
+ * color("#ff0")
13
+ * // $Color [srgb] { offset: 0, stride: 1, buf: [ 1, 1, 0, 1 ] }
14
+ *
15
+ * color("oklch(60% 0.15 50)");
16
+ * // $Color [oklch] { offset: 0, stride: 1, buf: [ 0.6, 0.0015, 0.139, 1 ] }
17
+ *
18
+ * color("hsv", [0.5, 1, 1, 1])
19
+ * // $Color [hsv] { offset: 0, stride: 1, buf: [ 0.5, 1, 1, 1 ] }
20
+ * ```
21
+ *
22
+ * @param src
23
+ */
24
+ export declare function color(src: string): TypedColor<any>;
2
25
  export declare function color(src: ParsedColor, buf?: Color, idx?: number, stride?: number): TypedColor<any>;
3
26
  export declare function color(mode: ColorMode, buf: Color, idx?: number, stride?: number): TypedColor<any>;
4
27
  //# sourceMappingURL=color.d.ts.map
package/color.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isString } from "@thi.ng/checks/is-string";
2
+ import { parseCss } from "./css/parse-css.js";
2
3
  import { hcy } from "./hcy/hcy.js";
3
4
  import { hsi } from "./hsi/hsi.js";
4
5
  import { hsl } from "./hsl/hsl.js";
@@ -8,6 +9,7 @@ import { labD50 } from "./lab/lab50.js";
8
9
  import { labD65 } from "./lab/lab65.js";
9
10
  import { lch } from "./lch/lch.js";
10
11
  import { oklab } from "./oklab/oklab.js";
12
+ import { oklch } from "./oklch/oklch.js";
11
13
  import { rgb } from "./rgb/rgb.js";
12
14
  import { srgb } from "./srgb/srgb.js";
13
15
  import { xyy } from "./xyy/xyy.js";
@@ -25,6 +27,7 @@ const FACTORIES = {
25
27
  lab65: labD65,
26
28
  lch,
27
29
  oklab,
30
+ oklch,
28
31
  rgb,
29
32
  srgb,
30
33
  xyy,
@@ -34,7 +37,9 @@ const FACTORIES = {
34
37
  };
35
38
  export function color(src, buf, idx, stride) {
36
39
  if (isString(src))
37
- return FACTORIES[src](buf, idx, stride);
40
+ return buf
41
+ ? FACTORIES[src](buf, idx, stride)
42
+ : color(parseCss(src));
38
43
  if (buf) {
39
44
  const res = FACTORIES[src.mode](buf, idx, stride);
40
45
  res.set(src.deref());
package/convert.d.ts CHANGED
@@ -9,5 +9,14 @@ export declare const CONVERSIONS: Partial<Record<ColorMode, Conversions>>;
9
9
  * @internal
10
10
  */
11
11
  export declare const defConversions: (mode: ColorMode, spec: ColorSpec<any, any>["from"]) => void;
12
+ /**
13
+ * Converts a (raw, untyped) color from one mode to another and writes result
14
+ * into `out` (or if null, back into `src`).
15
+ *
16
+ * @param res
17
+ * @param src
18
+ * @param destMode
19
+ * @param srcMode
20
+ */
12
21
  export declare const convert: <T extends import("@thi.ng/vectors").Vec>(res: T | null, src: ReadonlyColor, destMode: ColorMode, srcMode: ColorMode) => T;
13
22
  //# sourceMappingURL=convert.d.ts.map
package/convert.js CHANGED
@@ -25,6 +25,15 @@ export const defConversions = (mode, spec) => {
25
25
  }
26
26
  CONVERSIONS[mode] = { ...CONVERSIONS[mode], ...spec };
27
27
  };
28
+ /**
29
+ * Converts a (raw, untyped) color from one mode to another and writes result
30
+ * into `out` (or if null, back into `src`).
31
+ *
32
+ * @param res
33
+ * @param src
34
+ * @param destMode
35
+ * @param srcMode
36
+ */
28
37
  export const convert = (res, src, destMode, srcMode) => {
29
38
  const spec = CONVERSIONS[destMode];
30
39
  assert(!!spec, `no conversions available for ${destMode}`);
package/css/css.d.ts CHANGED
@@ -1,14 +1,32 @@
1
- import type { IParsedColor, MaybeColor } from "../api.js";
1
+ import type { Fn } from "@thi.ng/api";
2
+ import type { ColorMode, IParsedColor, MaybeColor } from "../api.js";
3
+ export type CSSConversions = Partial<Record<ColorMode, Fn<any, string>>>;
4
+ export declare const CSS_LEVEL3: CSSConversions;
2
5
  /**
3
- * Takes a color in one of the following formats and tries to convert it
4
- * to a CSS string:
6
+ * Extended set of direct CSS conversions for use with CSS Color Module Level 4.
7
+ * Based on {@link CSS_LEVEL3}.
8
+ */
9
+ export declare const CSS_LEVEL4: CSSConversions;
10
+ /**
11
+ * Takes a color in one of the following formats and tries to convert it to a
12
+ * CSS string.
13
+ *
14
+ * @remarks
15
+ * The following input formats are supported:
5
16
  *
6
17
  * - any {@link TypedColor} instance
7
18
  * - raw sRGB(A) vector
8
19
  * - number (packed 0xaarrggbb int, MUST provide alpha channel)
9
20
  * - string (passthrough)
10
21
  *
22
+ * If CSS Color Module Level 4 support is desired, pass {@link CSS_LEVEL4} as
23
+ * 2nd argument.
24
+ *
25
+ * If no direct conversion route for a given source color mode exists, the color
26
+ * will be first converted to sRGB and serialized as such.
27
+ *
11
28
  * @param col - source color
29
+ * @param cssTarget - CSS conversions
12
30
  */
13
- export declare const css: (src: Exclude<MaybeColor, IParsedColor>) => string;
31
+ export declare const css: (src: Exclude<MaybeColor, IParsedColor>, cssTarget?: CSSConversions) => string;
14
32
  //# sourceMappingURL=css.d.ts.map
package/css/css.js CHANGED
@@ -5,22 +5,21 @@ import { hslCss } from "../hsl/hsl-css.js";
5
5
  import { hsvCss } from "../hsv/hsv-css.js";
6
6
  import { intArgb32Css } from "../int/int-css.js";
7
7
  import { intAbgr32Argb32 } from "../int/int-int.js";
8
+ import { labCss } from "../lab/lab-css.js";
9
+ import { labLabD65_50 } from "../lab/lab-lab.js";
8
10
  import { lchLab } from "../lab/lab-lch.js";
9
11
  import { labRgb, labRgbD65 } from "../lab/lab-rgb.js";
12
+ import { lchCss } from "../lch/lch-css.js";
13
+ import { oklabCss } from "../oklab/oklab-css.js";
14
+ import { oklchCss } from "../oklch/oklch-css.js";
10
15
  import { rgbCss } from "../rgb/rgb-css.js";
11
16
  import { rgbSrgb } from "../rgb/rgb-srgb.js";
12
17
  import { srgbCss } from "../srgb/srgb-css.js";
13
- /** @internal */
14
- const CSS_CONVERSIONS = {
18
+ export const CSS_LEVEL3 = {
15
19
  abgr32: (x) => intArgb32Css(intAbgr32Argb32(x[0])),
16
20
  argb32: (x) => intArgb32Css(x[0]),
17
21
  hsl: hslCss,
18
22
  hsv: hsvCss,
19
- // TODO temporarily disabled until CSS L4 is officially supported in browsers
20
- // currently serializing as sRGB CSS
21
- // lab50: labCss,
22
- // lab65: (x) => labCss(labLabD65_50([], x)),
23
- // lch: lchCss,
24
23
  lab50: (src) => srgbCss(rgbSrgb(null, labRgb([], src))),
25
24
  lab65: (src) => srgbCss(rgbSrgb(null, labRgbD65([], src))),
26
25
  lch: (src) => srgbCss(rgbSrgb(null, labRgb(null, lchLab([], src)))),
@@ -28,25 +27,47 @@ const CSS_CONVERSIONS = {
28
27
  srgb: srgbCss,
29
28
  };
30
29
  /**
31
- * Takes a color in one of the following formats and tries to convert it
32
- * to a CSS string:
30
+ * Extended set of direct CSS conversions for use with CSS Color Module Level 4.
31
+ * Based on {@link CSS_LEVEL3}.
32
+ */
33
+ export const CSS_LEVEL4 = {
34
+ ...CSS_LEVEL3,
35
+ lab50: labCss,
36
+ lab65: (x) => labCss(labLabD65_50([], x)),
37
+ lch: lchCss,
38
+ oklab: oklabCss,
39
+ oklch: oklchCss,
40
+ };
41
+ /**
42
+ * Takes a color in one of the following formats and tries to convert it to a
43
+ * CSS string.
44
+ *
45
+ * @remarks
46
+ * The following input formats are supported:
33
47
  *
34
48
  * - any {@link TypedColor} instance
35
49
  * - raw sRGB(A) vector
36
50
  * - number (packed 0xaarrggbb int, MUST provide alpha channel)
37
51
  * - string (passthrough)
38
52
  *
53
+ * If CSS Color Module Level 4 support is desired, pass {@link CSS_LEVEL4} as
54
+ * 2nd argument.
55
+ *
56
+ * If no direct conversion route for a given source color mode exists, the color
57
+ * will be first converted to sRGB and serialized as such.
58
+ *
39
59
  * @param col - source color
60
+ * @param cssTarget - CSS conversions
40
61
  */
41
- export const css = (src) => {
62
+ export const css = (src, cssTarget = CSS_LEVEL3) => {
42
63
  let asCss;
43
64
  return isString(src)
44
65
  ? src
45
66
  : isNumber(src)
46
67
  ? intArgb32Css(src)
47
68
  : src.mode
48
- ? (asCss = CSS_CONVERSIONS[src.mode])
69
+ ? (asCss = cssTarget[src.mode])
49
70
  ? asCss(src)
50
- : CSS_CONVERSIONS.rgb(convert([], src, "rgb", src.mode))
71
+ : cssTarget.rgb(convert([], src, "rgb", src.mode))
51
72
  : srgbCss(src);
52
73
  };
@@ -19,11 +19,21 @@ import { IParsedColor } from "../api.js";
19
19
  * - `hsl(h,s%,l%)`
20
20
  * - `hsla(h,s%,l%,a)`
21
21
  * - `lab(l a b / alpha?)`
22
+ * - `lab(l% a% b% / alpha?)`
22
23
  * - `lch(l c h / alpha?)`
24
+ * - `lch(l% c% h / alpha?)`
25
+ * - `oklab(l a b / alpha?)`
26
+ * - `oklab(l% a% b% / alpha?)`
27
+ * - `oklch(l c h / alpha?)`
28
+ * - `oklch(l% c% h / alpha?)`
23
29
  *
24
30
  * Hue values can be given according to CSS Color L4 spec (raw, deg, rad, grad,
25
31
  * turn): https://www.w3.org/TR/css-color-4/#typedef-hue
26
32
  *
33
+ * For (ok)lab/(ok)lch color channel values given as percentages, the scale
34
+ * ranges defined in the spec are used:
35
+ * https://www.w3.org/TR/css-color-4/#specifying-lab-lch
36
+ *
27
37
  * If no alpha channel is given, it will default to 1.0 (fully opaque).
28
38
  *
29
39
  * Note that any named or system CSS colors, hex colors and any RGB colors will
@@ -36,5 +46,20 @@ import { IParsedColor } from "../api.js";
36
46
  * @param src -
37
47
  */
38
48
  export declare const parseCss: (src: string | IDeref<string>) => IParsedColor;
49
+ /**
50
+ * Parses a CSS hex color string into an uint32. Throws an error if given string
51
+ * doesn't conform to any of the supported formats.
52
+ *
53
+ * @remarks
54
+ * Supports the following input formats (`#` always optional and each letter a
55
+ * hex digit):
56
+ *
57
+ * - `#rgb`
58
+ * - `#rgba`
59
+ * - `#rrggbb`
60
+ * - `#rrggbbaa`
61
+ *
62
+ * @param src
63
+ */
39
64
  export declare const parseHex: (src: string) => number;
40
65
  //# sourceMappingURL=parse-css.d.ts.map