saturon 0.2.3 → 0.3.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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2025 Ganemede Labs
1
+ Copyright © 2026 Ganemede Labs
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
package/README.md CHANGED
@@ -22,7 +22,7 @@ A runtime-extensible JavaScript library for parsing, converting, and manipulatin
22
22
  - Infinite nested color functions (e.g. `color-mix(...)` inside `light-dark(...)`)
23
23
  - Converts between all modern color spaces (OKLab, Display-P3, Rec.2020, etc.)
24
24
  - High-precision color math for serious colorimetry
25
- - Powerful plugin system for custom color spaces and functions
25
+ - Powerful plugin system for custom color spaces and syntaxes
26
26
  - Supports complex color syntaxes like `color(from hsl(240 none calc(-infinity) / 0.5) display-p3 r calc(g + b) 100 / alpha)`
27
27
 
28
28
  ## 🔧 Installation
@@ -77,14 +77,15 @@ console.log(hwb.toString()); // → hwb(100 7 20)
77
77
 
78
78
  ```js
79
79
  const red = Color.from("hsl(0, 100%, 50%)");
80
- const mixed = red.mix("hsl(120, 100%, 50%)");
80
+ const green = Color.from("hsl(120, 100%, 50%)");
81
+ const mixed = Color.mix({ in: "hsl", colors: [{ color: red }, { color: green }] });
81
82
  console.log(mixed.toString()); // → hsl(60 100 50)
82
83
  ```
83
84
 
84
85
  ### New Named Color Registration
85
86
 
86
87
  ```js
87
- registerNamedColor("sunsetblush", [255, 94, 77]);
88
+ register("named-color", [{ name: "sunsetblush", value: [255, 94, 77] }]);
88
89
  const rgb = Color.from("rgb(255, 94, 77)");
89
90
  console.log(rgb.to("named-color")); // → sunsetblush
90
91
  ```
@@ -103,7 +104,7 @@ const converter = {
103
104
  fromBridge: (rgb: number[]) => [/* i, ct, cp */],
104
105
  };
105
106
 
106
- registerColorFunction("ictcp", converter);
107
+ register("color-function", [{ name: "ictcp", value: converter }]);
107
108
  const ictcp = Color.from("ictcp(0.2 0.2 -0.1)");
108
109
  console.log(ictcp.to("rgb")); // → rgb(6 7 90)
109
110
  ```
package/dist/Color.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Component, MixOptions, ColorType, OutputType, FormattingOptions, NamedColor, ColorSpace, FitMethod, ColorModel, RandomOptions, ComponentOptions } from "./types.js";
1
+ import type { Component, MixOptions, OutputType, FormattingOptions, NamedColor, ColorSpace, FitMethod, ColorModel, RandomOptions, ComponentOptions, MixItem, IsValidOptions } from "./types.js";
2
2
  /**
3
3
  * The `Color` class represents a dynamic CSS color object, allowing for the manipulation
4
4
  * and retrieval of colors in various formats (e.g., RGB, HEX, HSL).
@@ -23,24 +23,25 @@ export declare class Color<M extends ColorModel = ColorModel> {
23
23
  static from(color: `lch(${string})`): Color<"lch">;
24
24
  static from(color: `oklab(${string})`): Color<"oklab">;
25
25
  static from(color: `oklch(${string})`): Color<"oklch">;
26
+ static from(color: `color(srgb ${string})`): Color<"srgb">;
27
+ static from(color: `color(srgb-linear ${string})`): Color<"srgb-linear">;
28
+ static from(color: `color(display-p3 ${string})`): Color<"display-p3">;
29
+ static from(color: `color(rec2020 ${string})`): Color<"rec2020">;
30
+ static from(color: `color(a98-rgb ${string})`): Color<"a98-rgb">;
31
+ static from(color: `color(prophoto-rgb ${string})`): Color<"prophoto-rgb">;
32
+ static from(color: `color(xyz-d65 ${string})`): Color<"xyz-d65">;
33
+ static from(color: `color(xyz-d50 ${string})`): Color<"xyz-d50">;
34
+ static from(color: `color(xyz ${string})`): Color<"xyz">;
26
35
  static from(color: string): Color<any>;
27
36
  static from<T extends ColorModel = ColorModel>(color: string): Color<T>;
28
37
  /**
29
- * Returns the detected color type, or `undefined` if unrecognized.
30
- *
31
- * @param color - Color string to analyze.
32
- * @param strict - Whether to validate full round-trip conversion.
33
- */
34
- static type(color: string, strict?: boolean): "hex-color" | "rgb" | "xyz-d65" | "xyz-d50" | "lab" | "oklab" | "srgb" | "srgb-linear" | "display-p3" | "rec2020" | "a98-rgb" | "prophoto-rgb" | "xyz" | "hsl" | "hwb" | "lch" | "oklch" | "named-color" | "color-mix" | "transparent" | "currentColor" | "system-color" | "contrast-color" | "device-cmyk" | "light-dark" | undefined;
35
- /**
36
- * Validates a color string, optionally for a specific type.
38
+ * Validates a color string.
37
39
  *
38
40
  * @param color - Color string to check.
39
- * @param type - Optional color type.
41
+ * @param options - Validation options.
40
42
  * @returns `true` if valid, otherwise `false`.
41
43
  */
42
- static isValid(color: string, type?: ColorType): boolean;
43
- static isValid(color: string, type?: string): boolean;
44
+ static isValid(color: string, options?: IsValidOptions): boolean;
44
45
  /**
45
46
  * Generates a random `Color` instance.
46
47
  *
@@ -50,6 +51,15 @@ export declare class Color<M extends ColorModel = ColorModel> {
50
51
  * @throws If an invalid component is specified.
51
52
  */
52
53
  static random<M extends ColorModel = ColorModel>(options?: RandomOptions<M>): Color<M>;
54
+ /**
55
+ * Statically mixes multiple colors together by specified percentages.
56
+ * Fully compliant with CSS Color Module Level 5 specification constraints.
57
+ *
58
+ * @param colors - Array of MixItems containing colors and optional percentages.
59
+ * @param options - Options containing the interpolation space and hue policy.
60
+ * @returns A new `Color` instance representing the mixed color.
61
+ */
62
+ static mix<M extends ColorModel = "oklab">(colors: MixItem[], options: MixOptions<M>): Color<M>;
53
63
  /**
54
64
  * Converts this color to a specified format.
55
65
  *
@@ -79,15 +89,17 @@ export declare class Color<M extends ColorModel = ColorModel> {
79
89
  * Returns the color as an object of component values.
80
90
  *
81
91
  * @param options - Optional retrieval options.
82
- * @returns An object mapping each component (and alpha) to its numeric value.
92
+ * @returns An object mapping each component to its numeric value.
83
93
  * @throws If the model has no defined components.
84
94
  */
85
- toObject(options?: ComponentOptions): { [key in Component<M>]: number; };
95
+ toObject(options?: ComponentOptions): {
96
+ [key in Component<M>]: number;
97
+ };
86
98
  /**
87
99
  * Returns the color as an array of component values, optionally normalized and fitted.
88
100
  *
89
101
  * @param options - Conversion configuration.
90
- * @returns An array of normalized color components and alpha.
102
+ * @returns An array of normalized color components.
91
103
  * @throws If the model has no defined components.
92
104
  */
93
105
  toArray(options?: ComponentOptions): number[];
@@ -136,26 +148,24 @@ export declare class Color<M extends ColorModel = ColorModel> {
136
148
  * - A partial object mapping component names to numbers or update functions
137
149
  * - A function that receives current components and returns partial updates or an array of values
138
150
  * - An array of new values corresponding to component indices
139
- * @param normalize - Whether to normalize component values to their valid ranges. Defaults to `true`.
151
+ * @param normalized - Whether to normalize component values to their valid ranges. Defaults to `true`.
140
152
  * When `false`, values are not clamped or validated against their ranges.
141
153
  * @returns A new Color instance with the updated component values
142
154
  */
143
155
  with(values: Partial<{
144
- [K in Component<M> | "alpha"]: number | ((prev: number) => number);
156
+ [K in Component<M>]: number | ((prev: number) => number);
145
157
  }> | ((components: {
146
- [K in Component<M> | "alpha"]: number;
158
+ [K in Component<M>]: number;
147
159
  }) => Partial<{
148
- [K in Component<M> | "alpha"]: number;
149
- }> | (number | undefined)[]) | (number | undefined)[], normalize?: boolean): Color<M>;
160
+ [K in Component<M>]: number;
161
+ }> | (number | undefined)[]) | (number | undefined)[]): Color<M>;
150
162
  /**
151
- * Mixes this color with another by a specified amount.
163
+ * Creates a new Color instance with values fitted to the color model's gamut.
152
164
  *
153
- * @param other - The color to mix with. Can be a string or a `Color` instance.
154
- * @param options - Options for how the colors are mixed.
155
- * @returns A new `Color` instance representing the mixed color.
156
- * @throws If the color model does not have defined components.
165
+ * @param options - Configuration options for fitting
166
+ * @returns A new Color instance with fitted values
157
167
  */
158
- mix(other: Color<ColorModel> | string, options?: MixOptions): Color<M>;
168
+ fit(options?: ComponentOptions): Color<M>;
159
169
  /**
160
170
  * Fits this color within the specified gamut using a given method.
161
171
  *
@@ -165,28 +175,21 @@ export declare class Color<M extends ColorModel = ColorModel> {
165
175
  * @throws If the gamut is unsupported.
166
176
  */
167
177
  within(gamut: ColorSpace, method?: FitMethod): Color<M>;
168
- /**
169
- * Creates a new Color instance with values fitted to the color model's gamut.
170
- *
171
- * @param options - Configuration options for fitting
172
- * @returns A new Color instance with fitted values
173
- */
174
- fit(options?: ComponentOptions): Color<M>;
175
178
  /**
176
179
  * Calculates the WCAG 2.1 contrast ratio between this color and another.
177
180
  *
178
- * @param other - The comparison color (instance or string).
181
+ * @param other - The comparison Color instance.
179
182
  * @returns Contrast ratio from 1 to 21.
180
183
  *
181
184
  * @remarks
182
185
  * - Ratios ≥ 4.5 are generally accessible for normal text.
183
186
  * - For perceptual accuracy, consider using APCA instead.
184
187
  */
185
- contrast(other: Color<ColorModel> | string): number;
188
+ contrast(other: Color<ColorModel>): number;
186
189
  /**
187
190
  * Calculates the color difference (ΔEOK) between the current color and another color using the OKLAB color space.
188
191
  *
189
- * @param other - The other color to compare against (as a Color instance or string).
192
+ * @param other - The other Color instance to compare against.
190
193
  * @returns A number in range (0-1) (smaller indicates more similar colors).
191
194
  *
192
195
  * @remarks
@@ -194,36 +197,36 @@ export declare class Color<M extends ColorModel = ColorModel> {
194
197
  * OKLAB's perceptual uniformity allows for a straightforward distance calculation without additional weighting.
195
198
  * The result is normalized by a factor of 100 to align with OKLAB's L range (0-1) and approximate the JND scale.
196
199
  */
197
- deltaEOK(other: Color<ColorModel> | string): number;
200
+ deltaEOK(other: Color<ColorModel>): number;
198
201
  /**
199
202
  * Calculates the color difference (ΔE) between two colors using the CIE76 formula.
200
203
  * This is a simple Euclidean distance in LAB color space.
201
204
  *
202
- * @param other - The other color to compare against (as a Color instance or string).
205
+ * @param other - The other Color instance to compare against.
203
206
  * @returns A number in range (0-1) (smaller indicates more similar colors).
204
207
  */
205
- deltaE76(other: Color<ColorModel> | string): number;
208
+ deltaE76(other: Color<ColorModel>): number;
206
209
  /**
207
210
  * Calculates the color difference (ΔE) between two colors using the CIE94 formula.
208
211
  * This method improves perceptual accuracy over CIE76 by applying weighting factors.
209
212
  *
210
- * @param other - The other color to compare against (as a Color instance or string).
213
+ * @param other - The other Color instance to compare against.
211
214
  * @returns A number in range (0-1) (smaller indicates more similar colors).
212
215
  */
213
- deltaE94(other: Color<ColorModel> | string): number;
216
+ deltaE94(other: Color<ColorModel>): number;
214
217
  /**
215
218
  * Calculates the color difference (ΔE) between two colors using the CIEDE2000 formula.
216
219
  * This is the most perceptually accurate method, accounting for interactions between hue, chroma, and lightness.
217
220
  *
218
- * @param other - The other color to compare against (as a Color instance or string).
221
+ * @param other - The other Color instance to compare against.
219
222
  * @returns A number in range (0-1) (smaller indicates more similar colors).
220
223
  */
221
- deltaE2000(other: Color<ColorModel> | string): number;
224
+ deltaE2000(other: Color<ColorModel>): number;
222
225
  /**
223
226
  * Checks numeric equality with another color within a tolerance.
224
227
  *
225
- * @param other - Color or string to compare.
226
- * @param epsilon - Allowed floating-point difference (default: 1e-5).
228
+ * @param other - Color instnace to compare.
229
+ * @param epsilon - Allowed floating-point difference (defaults to the value of `EPSILON` in `"saturon/math"`).
227
230
  * @returns `true` if equal within tolerance.
228
231
  *
229
232
  * @remarks
@@ -237,12 +240,12 @@ export declare class Color<M extends ColorModel = ColorModel> {
237
240
  * - {@link deltaE94} (weighted improvements over LAB)
238
241
  * - {@link deltaE2000} (most accurate, accounts for perceptual interactions)
239
242
  */
240
- equals(other: Color<ColorModel> | string, epsilon?: number): boolean;
243
+ equals(other: Color<ColorModel>, epsilon?: number): boolean;
241
244
  /**
242
245
  * Determines whether this color lies within a given gamut.
243
246
  *
244
247
  * @param gamut - Target color space.
245
- * @param epsilon - Floating-point tolerance (default: 1e-5).
248
+ * @param epsilon - Floating-point tolerance (defaults to the value of `EPSILON` in `"saturon/math"`).
246
249
  * @returns `true` if inside gamut, else `false`.
247
250
  */
248
251
  inGamut(gamut: ColorSpace | string, epsilon?: number): boolean;