adaptive-extender 0.2.13 → 0.5.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 +16 -2
- package/README.md +9 -0
- package/{core → dist/core}/array.d.ts +2 -2
- package/{core → dist/core}/array.js +2 -0
- package/dist/core/array.js.map +1 -0
- package/{core → dist/core}/boolean.js +2 -0
- package/dist/core/boolean.js.map +1 -0
- package/{core → dist/core}/color.d.ts +2 -20
- package/dist/core/color.js +524 -0
- package/dist/core/color.js.map +1 -0
- package/{core → dist/core}/date.js +2 -0
- package/dist/core/date.js.map +1 -0
- package/dist/core/engine.d.ts +30 -0
- package/dist/core/engine.js +4 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/error.d.ts +38 -0
- package/{core → dist/core}/error.js +14 -0
- package/dist/core/error.js.map +1 -0
- package/{core → dist/core}/global.js +1 -0
- package/dist/core/global.js.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.js +21 -0
- package/dist/core/index.js.map +1 -0
- package/{core → dist/core}/math.d.ts +27 -14
- package/{core → dist/core}/math.js +20 -12
- package/dist/core/math.js.map +1 -0
- package/{core → dist/core}/number.js +2 -2
- package/dist/core/number.js.map +1 -0
- package/{core → dist/core}/object.d.ts +0 -10
- package/{core → dist/core}/object.js +1 -7
- package/dist/core/object.js.map +1 -0
- package/{core → dist/core}/primitives.d.ts +1 -1
- package/dist/core/primitives.js +4 -0
- package/dist/core/primitives.js.map +1 -0
- package/{core → dist/core}/promise.d.ts +5 -2
- package/{core → dist/core}/promise.js +1 -0
- package/dist/core/promise.js.map +1 -0
- package/{core → dist/core}/random.d.ts +0 -1
- package/{core → dist/core}/random.js +18 -27
- package/dist/core/random.js.map +1 -0
- package/{core → dist/core}/string.d.ts +14 -21
- package/{core → dist/core}/string.js +2 -7
- package/dist/core/string.js.map +1 -0
- package/dist/core/timespan.d.ts +140 -0
- package/dist/core/timespan.js +269 -0
- package/dist/core/timespan.js.map +1 -0
- package/dist/core/vector-1.d.ts +17 -0
- package/dist/core/vector-1.js +57 -0
- package/dist/core/vector-1.js.map +1 -0
- package/dist/core/vector-2.d.ts +19 -0
- package/dist/core/vector-2.js +63 -0
- package/dist/core/vector-2.js.map +1 -0
- package/dist/core/vector-3.d.ts +20 -0
- package/dist/core/vector-3.js +68 -0
- package/dist/core/vector-3.js.map +1 -0
- package/dist/core/vector.d.ts +42 -0
- package/dist/core/vector.js +176 -0
- package/dist/core/vector.js.map +1 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +3 -0
- package/dist/node/index.js.map +1 -0
- package/dist/web/index.d.ts +1 -0
- package/dist/web/index.js +3 -0
- package/dist/web/index.js.map +1 -0
- package/package.json +65 -50
- package/core/array.js.map +0 -1
- package/core/boolean.js.map +0 -1
- package/core/color.js +0 -537
- package/core/color.js.map +0 -1
- package/core/date.js.map +0 -1
- package/core/error.d.ts +0 -20
- package/core/error.js.map +0 -1
- package/core/global.js.map +0 -1
- package/core/index.d.ts +0 -17
- package/core/index.js +0 -16
- package/core/index.js.map +0 -1
- package/core/math.js.map +0 -1
- package/core/number.js.map +0 -1
- package/core/object.js.map +0 -1
- package/core/primitives.js +0 -3
- package/core/primitives.js.map +0 -1
- package/core/promise.js.map +0 -1
- package/core/random.js.map +0 -1
- package/core/string.js.map +0 -1
- package/core.d.ts +0 -1
- package/core.js +0 -2
- package/core.js.map +0 -1
- package/node/index.d.ts +0 -8
- package/node/index.js +0 -7
- package/node/index.js.map +0 -1
- package/node.d.ts +0 -1
- package/node.js +0 -2
- package/node.js.map +0 -1
- package/web/index.d.ts +0 -8
- package/web/index.js +0 -7
- package/web/index.js.map +0 -1
- package/web.d.ts +0 -1
- package/web.js +0 -2
- package/web.js.map +0 -1
- /package/{core → dist/core}/boolean.d.ts +0 -0
- /package/{core → dist/core}/date.d.ts +0 -0
- /package/{core → dist/core}/global.d.ts +0 -0
- /package/{core → dist/core}/number.d.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
## 0.
|
|
2
|
-
- Added
|
|
1
|
+
## 0.5.0 (19.09.2025)
|
|
2
|
+
- Added [timespan]() module.
|
|
3
|
+
- Improved module separation.
|
|
4
|
+
- Optimized `Color.newBlack`.
|
|
5
|
+
- Added tests.
|
|
6
|
+
- Fixed multiple bugs.
|
|
7
|
+
- Improved documentation and function descriptions.
|
|
8
|
+
- Split many functions into overloads for optimal usage.
|
|
9
|
+
|
|
10
|
+
## 0.4.0 (26.08.2025)
|
|
11
|
+
- Improved package structure.
|
|
12
|
+
- Configured package for the latest stable ES version.
|
|
13
|
+
- Added modules [vector](), [vector-1](), [vector-2](), [vector-3]().
|
|
14
|
+
|
|
15
|
+
## 0.2.14 (20.08.2025)
|
|
16
|
+
- Added import support for `CommonJS` modules.
|
|
3
17
|
|
|
4
18
|
## 0.2.8 (16.08.2025)
|
|
5
19
|
- Fixed root import error.
|
package/README.md
CHANGED
|
@@ -18,11 +18,11 @@ declare global {
|
|
|
18
18
|
/**
|
|
19
19
|
* Combines elements from multiple iterables into tuples.
|
|
20
20
|
* Iteration stops when the shortest iterable is exhausted.
|
|
21
|
-
* @returns
|
|
21
|
+
* @returns An iterator yielding tuples.
|
|
22
22
|
*/
|
|
23
23
|
zip<T extends unknown[]>(...iterables: {
|
|
24
24
|
[K in keyof T]: Iterable<T[K]>;
|
|
25
|
-
}):
|
|
25
|
+
}): IteratorObject<T, void>;
|
|
26
26
|
}
|
|
27
27
|
interface Array<T> {
|
|
28
28
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.js","sourceRoot":"","sources":["../../src/core/array.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,aAAa,CAAC;AAErB,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;AA2CvB,KAAK,CAAC,MAAM,GAAG,UAAU,MAAW,EAAE,OAAe,UAAU;IAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,+BAA+B,IAAI,YAAY,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxH,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,KAAK,CAAC,KAAK,GAAG,UAAU,GAAW,EAAE,GAAW;IAC/C,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACjB,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACjB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEF,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC,EAAsB,GAAG,SAA6C;IAC1F,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzE,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3D,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,MAAM;QAC/C,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAM,CAAC;IAChD,CAAC;AACF,CAAC,CAAC;AAEF,KAAK,CAAC,SAAS,CAAC,IAAI,GAAG,UAAU,MAAc,EAAE,MAAc;IAC9D,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;AAC1B,CAAC,CAAC;AAEF,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,UAAwB,MAAc,EAAE,QAAW;IAC3E,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACrB,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AACF,YAAY;AAEZ,OAAO,EAAG,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boolean.js","sourceRoot":"","sources":["../../src/core/boolean.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,aAAa,CAAC;AAgBrB,OAAO,CAAC,MAAM,GAAG,UAAU,MAAW,EAAE,OAAe,UAAU;IAChE,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,SAAS;QAAE,MAAM,IAAI,SAAS,CAAC,iCAAiC,IAAI,YAAY,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjI,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AACzB,CAAC,CAAC;AACF,YAAY;AAEZ,OAAO,EAAG,CAAC"}
|
|
@@ -160,92 +160,74 @@ declare class Color {
|
|
|
160
160
|
toString(options: Partial<ColorProperties>): string;
|
|
161
161
|
/**
|
|
162
162
|
* Transparent color preset.
|
|
163
|
-
* @readonly
|
|
164
163
|
*/
|
|
165
164
|
static get newTransparent(): Color;
|
|
166
165
|
/**
|
|
167
166
|
* Maroon color preset.
|
|
168
|
-
* @readonly
|
|
169
167
|
*/
|
|
170
168
|
static get newMaroon(): Color;
|
|
171
169
|
/**
|
|
172
170
|
* Red color preset.
|
|
173
|
-
* @readonly
|
|
174
171
|
*/
|
|
175
172
|
static get newRed(): Color;
|
|
176
173
|
/**
|
|
177
174
|
* Orange color preset.
|
|
178
|
-
* @readonly
|
|
179
175
|
*/
|
|
180
176
|
static get newOrange(): Color;
|
|
181
177
|
/**
|
|
182
178
|
* Yellow color preset.
|
|
183
|
-
* @readonly
|
|
184
179
|
*/
|
|
185
180
|
static get newYellow(): Color;
|
|
186
181
|
/**
|
|
187
182
|
* Olive color preset.
|
|
188
|
-
* @readonly
|
|
189
183
|
*/
|
|
190
184
|
static get newOlive(): Color;
|
|
191
185
|
/**
|
|
192
186
|
* Green color preset.
|
|
193
|
-
* @readonly
|
|
194
187
|
*/
|
|
195
188
|
static get newGreen(): Color;
|
|
196
189
|
/**
|
|
197
190
|
* Purple color preset.
|
|
198
|
-
* @readonly
|
|
199
191
|
*/
|
|
200
192
|
static get newPurple(): Color;
|
|
201
193
|
/**
|
|
202
194
|
* Fuchsia color preset.
|
|
203
|
-
* @readonly
|
|
204
195
|
*/
|
|
205
196
|
static get newFuchsia(): Color;
|
|
206
197
|
/**
|
|
207
198
|
* Lime color preset.
|
|
208
|
-
* @readonly
|
|
209
199
|
*/
|
|
210
200
|
static get newLime(): Color;
|
|
211
201
|
/**
|
|
212
202
|
* Teal color preset.
|
|
213
|
-
* @readonly
|
|
214
203
|
*/
|
|
215
204
|
static get newTeal(): Color;
|
|
216
205
|
/**
|
|
217
206
|
* Aqua color preset.
|
|
218
|
-
* @readonly
|
|
219
207
|
*/
|
|
220
208
|
static get newAqua(): Color;
|
|
221
209
|
/**
|
|
222
210
|
* Blue color preset.
|
|
223
|
-
* @readonly
|
|
224
211
|
*/
|
|
225
212
|
static get newBlue(): Color;
|
|
226
213
|
/**
|
|
227
214
|
* Navy color preset.
|
|
228
|
-
* @readonly
|
|
229
215
|
*/
|
|
230
216
|
static get newNavy(): Color;
|
|
231
217
|
/**
|
|
232
218
|
* Black color preset.
|
|
233
|
-
* @readonly
|
|
234
219
|
*/
|
|
235
220
|
static get newBlack(): Color;
|
|
236
221
|
/**
|
|
237
222
|
* Gray color preset.
|
|
238
|
-
* @readonly
|
|
239
223
|
*/
|
|
240
224
|
static get newGray(): Color;
|
|
241
225
|
/**
|
|
242
226
|
* Silver color preset.
|
|
243
|
-
* @readonly
|
|
244
227
|
*/
|
|
245
228
|
static get newSilver(): Color;
|
|
246
229
|
/**
|
|
247
230
|
* White color preset.
|
|
248
|
-
* @readonly
|
|
249
231
|
*/
|
|
250
232
|
static get newWhite(): Color;
|
|
251
233
|
/**
|
|
@@ -365,5 +347,5 @@ declare class Color {
|
|
|
365
347
|
*/
|
|
366
348
|
pass(scale: number): Color;
|
|
367
349
|
}
|
|
368
|
-
export {
|
|
369
|
-
export {
|
|
350
|
+
export { ColorFormats };
|
|
351
|
+
export { type ColorProperties, Color };
|
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import "./number.js";
|
|
3
|
+
import "./string.js";
|
|
4
|
+
const { min, max, trunc, abs } = Math;
|
|
5
|
+
//#region Color formats
|
|
6
|
+
/**
|
|
7
|
+
* Represents available color formats.
|
|
8
|
+
*/
|
|
9
|
+
var ColorFormats;
|
|
10
|
+
(function (ColorFormats) {
|
|
11
|
+
ColorFormats["rgb"] = "RGB";
|
|
12
|
+
ColorFormats["hsl"] = "HSL";
|
|
13
|
+
ColorFormats["hex"] = "HEX";
|
|
14
|
+
})(ColorFormats || (ColorFormats = {}));
|
|
15
|
+
/**
|
|
16
|
+
* Represents a color in RGB, HSL, or HEX format with support for alpha channel,
|
|
17
|
+
* conversion between formats, creation from components, and parsing from strings.
|
|
18
|
+
*/
|
|
19
|
+
class Color {
|
|
20
|
+
//#region Properties
|
|
21
|
+
#rgb = new Uint8ClampedArray([0, 0, 0]);
|
|
22
|
+
/**
|
|
23
|
+
* Gets the red color component.
|
|
24
|
+
*/
|
|
25
|
+
get red() {
|
|
26
|
+
return this.#rgb[0];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Sets the red color component.
|
|
30
|
+
*/
|
|
31
|
+
set red(value) {
|
|
32
|
+
if (!Number.isFinite(value))
|
|
33
|
+
return;
|
|
34
|
+
this.#rgb[0] = value;
|
|
35
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Gets the green color component.
|
|
39
|
+
*/
|
|
40
|
+
get green() {
|
|
41
|
+
return this.#rgb[1];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sets the green color component.
|
|
45
|
+
*/
|
|
46
|
+
set green(value) {
|
|
47
|
+
if (!Number.isFinite(value))
|
|
48
|
+
return;
|
|
49
|
+
this.#rgb[1] = value;
|
|
50
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Gets the blue color component.
|
|
54
|
+
*/
|
|
55
|
+
get blue() {
|
|
56
|
+
return this.#rgb[2];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Sets the blue color component.
|
|
60
|
+
*/
|
|
61
|
+
set blue(value) {
|
|
62
|
+
if (!Number.isFinite(value))
|
|
63
|
+
return;
|
|
64
|
+
this.#rgb[2] = value;
|
|
65
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
66
|
+
}
|
|
67
|
+
#hsl = new Uint16Array([0, 0, 0]);
|
|
68
|
+
/**
|
|
69
|
+
* Gets the hue color component.
|
|
70
|
+
*/
|
|
71
|
+
get hue() {
|
|
72
|
+
return this.#hsl[0];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Sets the hue color component.
|
|
76
|
+
*/
|
|
77
|
+
set hue(value) {
|
|
78
|
+
if (!Number.isFinite(value))
|
|
79
|
+
return;
|
|
80
|
+
this.#hsl[0] = value.mod(360);
|
|
81
|
+
Color.#HSLtoRGB(this.#hsl, this.#rgb);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Gets the saturation color component.
|
|
85
|
+
*/
|
|
86
|
+
get saturation() {
|
|
87
|
+
return this.#hsl[1];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Sets the saturation color component.
|
|
91
|
+
*/
|
|
92
|
+
set saturation(value) {
|
|
93
|
+
if (!Number.isFinite(value))
|
|
94
|
+
return;
|
|
95
|
+
this.#hsl[1] = value.clamp(0, 100);
|
|
96
|
+
Color.#HSLtoRGB(this.#hsl, this.#rgb);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Gets the lightness color component.
|
|
100
|
+
*/
|
|
101
|
+
get lightness() {
|
|
102
|
+
return this.#hsl[2];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Sets the lightness color component.
|
|
106
|
+
*/
|
|
107
|
+
set lightness(value) {
|
|
108
|
+
if (!Number.isFinite(value))
|
|
109
|
+
return;
|
|
110
|
+
this.#hsl[2] = value.clamp(0, 100);
|
|
111
|
+
Color.#HSLtoRGB(this.#hsl, this.#rgb);
|
|
112
|
+
}
|
|
113
|
+
#alpha = 1;
|
|
114
|
+
/**
|
|
115
|
+
* Gets the alpha color component.
|
|
116
|
+
*/
|
|
117
|
+
get alpha() {
|
|
118
|
+
return this.#alpha;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Sets the alpha color component.
|
|
122
|
+
*/
|
|
123
|
+
set alpha(value) {
|
|
124
|
+
if (!Number.isFinite(value))
|
|
125
|
+
return;
|
|
126
|
+
this.#alpha = value.clamp(0, 1);
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region Builders
|
|
130
|
+
static #patternRGB = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
|
|
131
|
+
static #patternRGBA = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\S+)\s*\)$/i;
|
|
132
|
+
static #patternHSL = /^hsl\(\s*(\d+)(?:deg)?\s*,\s*(\d+)(?:%)?\s*,\s*(\d+)(?:%)?\s*\)$/i;
|
|
133
|
+
static #patternHSLA = /^hsla\(\s*(\d+)(?:deg)?\s*,\s*(\d+)(?:%)?\s*,\s*(\d+)(?:%)?\s*,\s*(\S+)\s*\)$/i;
|
|
134
|
+
static #patternHEX = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
|
|
135
|
+
static #patternHEXA = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
|
|
136
|
+
static #variations = Object.values(ColorFormats).flatMap(format => [{ format, deep: false }, { format, deep: true }]);
|
|
137
|
+
constructor(source) {
|
|
138
|
+
if (!(source instanceof Color))
|
|
139
|
+
return;
|
|
140
|
+
this.#rgb = Uint8ClampedArray.from(source.#rgb);
|
|
141
|
+
this.#hsl = Uint16Array.from(source.#hsl);
|
|
142
|
+
this.#alpha = source.#alpha;
|
|
143
|
+
}
|
|
144
|
+
static fromRGB(red, green, blue, alpha = 1) {
|
|
145
|
+
if (!Number.isFinite(red))
|
|
146
|
+
throw new Error(`The red ${red} must be a finite number`);
|
|
147
|
+
if (!Number.isFinite(green))
|
|
148
|
+
throw new Error(`The green ${green} must be a finite number`);
|
|
149
|
+
if (!Number.isFinite(blue))
|
|
150
|
+
throw new Error(`The blue ${blue} must be a finite number`);
|
|
151
|
+
if (!Number.isFinite(alpha))
|
|
152
|
+
throw new Error(`The alpha ${alpha} must be a finite number`);
|
|
153
|
+
const color = new Color();
|
|
154
|
+
color.#rgb[0] = red;
|
|
155
|
+
color.#rgb[1] = green;
|
|
156
|
+
color.#rgb[2] = blue;
|
|
157
|
+
color.#alpha = alpha.clamp(0, 1);
|
|
158
|
+
Color.#RGBtoHSL(color.#rgb, color.#hsl);
|
|
159
|
+
return color;
|
|
160
|
+
}
|
|
161
|
+
static fromHSL(hue, saturation, lightness, alpha = 1) {
|
|
162
|
+
if (!Number.isFinite(hue))
|
|
163
|
+
throw new Error(`The hue ${hue} must be a finite number`);
|
|
164
|
+
if (!Number.isFinite(saturation))
|
|
165
|
+
throw new Error(`The saturation ${saturation} must be a finite number`);
|
|
166
|
+
if (!Number.isFinite(lightness))
|
|
167
|
+
throw new Error(`The lightness ${lightness} must be a finite number`);
|
|
168
|
+
if (!Number.isFinite(alpha))
|
|
169
|
+
throw new Error(`The alpha ${alpha} must be a finite number`);
|
|
170
|
+
const color = new Color();
|
|
171
|
+
hue %= 360;
|
|
172
|
+
if (hue < 0)
|
|
173
|
+
hue += 360;
|
|
174
|
+
color.#hsl[0] = hue;
|
|
175
|
+
color.#hsl[1] = saturation.clamp(0, 100);
|
|
176
|
+
color.#hsl[2] = lightness.clamp(0, 100);
|
|
177
|
+
color.#alpha = alpha.clamp(0, 1);
|
|
178
|
+
Color.#HSLtoRGB(color.#hsl, color.#rgb);
|
|
179
|
+
return color;
|
|
180
|
+
}
|
|
181
|
+
static #parse(string, deep, format) {
|
|
182
|
+
switch (format) {
|
|
183
|
+
case ColorFormats.rgb:
|
|
184
|
+
{
|
|
185
|
+
const regex = (deep ? Color.#patternRGBA : Color.#patternRGB);
|
|
186
|
+
const match = regex.exec(string.trim());
|
|
187
|
+
if (match === null)
|
|
188
|
+
throw new SyntaxError(`Invalid ${format} color '${string}' syntax`);
|
|
189
|
+
const [, red, green, blue, alpha] = match.map(part => Number(part));
|
|
190
|
+
return Color.fromRGB(red, green, blue, deep ? alpha : 1);
|
|
191
|
+
}
|
|
192
|
+
;
|
|
193
|
+
case ColorFormats.hsl:
|
|
194
|
+
{
|
|
195
|
+
const regex = (deep ? Color.#patternHSLA : Color.#patternHSL);
|
|
196
|
+
const match = regex.exec(string.trim());
|
|
197
|
+
if (match === null)
|
|
198
|
+
throw new SyntaxError(`Invalid ${format} color '${string}' syntax`);
|
|
199
|
+
const [, hue, saturation, lightness, alpha] = match.map(part => Number(part));
|
|
200
|
+
return Color.fromHSL(hue, saturation, lightness, deep ? alpha : 1);
|
|
201
|
+
}
|
|
202
|
+
;
|
|
203
|
+
case ColorFormats.hex:
|
|
204
|
+
{
|
|
205
|
+
const regex = (deep ? Color.#patternHEXA : Color.#patternHEX);
|
|
206
|
+
const match = regex.exec(string.trim());
|
|
207
|
+
if (match === null)
|
|
208
|
+
throw new SyntaxError(`Invalid ${format} color '${string}' syntax`);
|
|
209
|
+
const [, red, green, blue, alpha] = match.map(part => Number.parseInt(part, 16));
|
|
210
|
+
return Color.fromRGB(red, green, blue, deep ? (alpha / 255) : 1);
|
|
211
|
+
}
|
|
212
|
+
;
|
|
213
|
+
default: throw new Error(`Invalid '${format}' format for color`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
static tryParse(string, options = {}) {
|
|
217
|
+
let variations = Color.#variations;
|
|
218
|
+
for (const key in options) {
|
|
219
|
+
const value = Reflect.get(options, key);
|
|
220
|
+
if (value === undefined)
|
|
221
|
+
continue;
|
|
222
|
+
variations = variations.filter(properties => Reflect.get(properties, key) === value);
|
|
223
|
+
}
|
|
224
|
+
for (const { format, deep } of variations) {
|
|
225
|
+
try {
|
|
226
|
+
return Color.#parse(string, deep, format);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
static parse(string, options = {}) {
|
|
235
|
+
const color = Color.tryParse(string, options);
|
|
236
|
+
if (color === null)
|
|
237
|
+
throw new SyntaxError(`Unable to parse '${string}' of any selected variation`);
|
|
238
|
+
return color;
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region Converters
|
|
242
|
+
static #toChannel(offset, hue, saturation, lightness) {
|
|
243
|
+
const sector = (offset + hue) % 12;
|
|
244
|
+
return lightness - (saturation * min(lightness, 1 - lightness)) * min(sector - 3, 9 - sector).clamp(-1, 1);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* @param hsl [0 - 360], [0 - 100], [0 - 100]
|
|
248
|
+
* @param rgb [0 - 255], [0 - 255], [0 - 255]
|
|
249
|
+
*/
|
|
250
|
+
static #HSLtoRGB(hsl, rgb) {
|
|
251
|
+
const hue = hsl[0] / 30;
|
|
252
|
+
const saturation = hsl[1] / 100;
|
|
253
|
+
const lightness = hsl[2] / 100;
|
|
254
|
+
rgb[0] = Color.#toChannel(0, hue, saturation, lightness) * 255;
|
|
255
|
+
rgb[1] = Color.#toChannel(8, hue, saturation, lightness) * 255;
|
|
256
|
+
rgb[2] = Color.#toChannel(4, hue, saturation, lightness) * 255;
|
|
257
|
+
}
|
|
258
|
+
static #toHue(maximum, red, green, blue, difference) {
|
|
259
|
+
switch (maximum) {
|
|
260
|
+
case red: return (green - blue) / difference + 0;
|
|
261
|
+
case green: return (blue - red) / difference + 2;
|
|
262
|
+
case blue: return (red - green) / difference + 4;
|
|
263
|
+
default: throw new Error(`Invalid '${maximum}' maximum for colors`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* @param rgb [0 - 255], [0 - 255], [0 - 255]
|
|
268
|
+
* @param hsl [0 - 360], [0 - 100], [0 - 100]
|
|
269
|
+
*/
|
|
270
|
+
static #RGBtoHSL(rgb, hsl) {
|
|
271
|
+
const red = rgb[0] / 255;
|
|
272
|
+
const green = rgb[1] / 255;
|
|
273
|
+
const blue = rgb[2] / 255;
|
|
274
|
+
const minimum = min(red, green, blue);
|
|
275
|
+
const maximum = max(red, green, blue);
|
|
276
|
+
const difference = maximum - minimum;
|
|
277
|
+
let hue = Color.#toHue(maximum, red, green, blue, difference);
|
|
278
|
+
hue = difference && hue;
|
|
279
|
+
if (hue < 0)
|
|
280
|
+
hue += 6;
|
|
281
|
+
hsl[0] = hue * 60;
|
|
282
|
+
const median = 1 - abs(maximum + minimum - 1);
|
|
283
|
+
hsl[1] = (median && (difference / median)) * 100;
|
|
284
|
+
hsl[2] = (maximum + minimum) / 2 * 100;
|
|
285
|
+
}
|
|
286
|
+
static #toHEXString(byte) {
|
|
287
|
+
return byte.toString(16).padStart(2, "0");
|
|
288
|
+
}
|
|
289
|
+
toString(options = {}) {
|
|
290
|
+
let { format, deep } = options;
|
|
291
|
+
format ??= ColorFormats.rgb;
|
|
292
|
+
deep ??= true;
|
|
293
|
+
switch (format) {
|
|
294
|
+
case ColorFormats.rgb: return `rgb${deep ? "a" : String.empty}(${this.red}, ${this.green}, ${this.blue}${deep ? `, ${this.alpha}` : String.empty})`;
|
|
295
|
+
case ColorFormats.hsl: return `hsl${deep ? "a" : String.empty}(${this.hue}deg, ${this.saturation}%, ${this.lightness}%${deep ? `, ${this.alpha}` : String.empty})`;
|
|
296
|
+
case ColorFormats.hex: return `#${Color.#toHEXString(this.red)}${Color.#toHEXString(this.green)}${Color.#toHEXString(this.blue)}${deep ? Color.#toHEXString(trunc(this.alpha * 255)) : String.empty}`;
|
|
297
|
+
default: throw new Error(`Invalid '${format}' format for color`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region Presets
|
|
302
|
+
/**
|
|
303
|
+
* Transparent color preset.
|
|
304
|
+
*/
|
|
305
|
+
static get newTransparent() { return Color.fromRGB(0, 0, 0, 0); }
|
|
306
|
+
;
|
|
307
|
+
/**
|
|
308
|
+
* Maroon color preset.
|
|
309
|
+
*/
|
|
310
|
+
static get newMaroon() { return Color.fromRGB(128, 0, 0); }
|
|
311
|
+
;
|
|
312
|
+
/**
|
|
313
|
+
* Red color preset.
|
|
314
|
+
*/
|
|
315
|
+
static get newRed() { return Color.fromRGB(255, 0, 0); }
|
|
316
|
+
;
|
|
317
|
+
/**
|
|
318
|
+
* Orange color preset.
|
|
319
|
+
*/
|
|
320
|
+
static get newOrange() { return Color.fromRGB(255, 165, 0); }
|
|
321
|
+
;
|
|
322
|
+
/**
|
|
323
|
+
* Yellow color preset.
|
|
324
|
+
*/
|
|
325
|
+
static get newYellow() { return Color.fromRGB(255, 255, 0); }
|
|
326
|
+
;
|
|
327
|
+
/**
|
|
328
|
+
* Olive color preset.
|
|
329
|
+
*/
|
|
330
|
+
static get newOlive() { return Color.fromRGB(128, 128, 0); }
|
|
331
|
+
;
|
|
332
|
+
/**
|
|
333
|
+
* Green color preset.
|
|
334
|
+
*/
|
|
335
|
+
static get newGreen() { return Color.fromRGB(0, 128, 0); }
|
|
336
|
+
;
|
|
337
|
+
/**
|
|
338
|
+
* Purple color preset.
|
|
339
|
+
*/
|
|
340
|
+
static get newPurple() { return Color.fromRGB(128, 0, 128); }
|
|
341
|
+
;
|
|
342
|
+
/**
|
|
343
|
+
* Fuchsia color preset.
|
|
344
|
+
*/
|
|
345
|
+
static get newFuchsia() { return Color.fromRGB(255, 0, 255); }
|
|
346
|
+
;
|
|
347
|
+
/**
|
|
348
|
+
* Lime color preset.
|
|
349
|
+
*/
|
|
350
|
+
static get newLime() { return Color.fromRGB(0, 255, 0); }
|
|
351
|
+
;
|
|
352
|
+
/**
|
|
353
|
+
* Teal color preset.
|
|
354
|
+
*/
|
|
355
|
+
static get newTeal() { return Color.fromRGB(0, 128, 128); }
|
|
356
|
+
;
|
|
357
|
+
/**
|
|
358
|
+
* Aqua color preset.
|
|
359
|
+
*/
|
|
360
|
+
static get newAqua() { return Color.fromRGB(0, 255, 255); }
|
|
361
|
+
;
|
|
362
|
+
/**
|
|
363
|
+
* Blue color preset.
|
|
364
|
+
*/
|
|
365
|
+
static get newBlue() { return Color.fromRGB(0, 0, 255); }
|
|
366
|
+
;
|
|
367
|
+
/**
|
|
368
|
+
* Navy color preset.
|
|
369
|
+
*/
|
|
370
|
+
static get newNavy() { return Color.fromRGB(0, 0, 128); }
|
|
371
|
+
;
|
|
372
|
+
/**
|
|
373
|
+
* Black color preset.
|
|
374
|
+
*/
|
|
375
|
+
static get newBlack() { return new Color(); }
|
|
376
|
+
;
|
|
377
|
+
/**
|
|
378
|
+
* Gray color preset.
|
|
379
|
+
*/
|
|
380
|
+
static get newGray() { return Color.fromRGB(128, 128, 128); }
|
|
381
|
+
;
|
|
382
|
+
/**
|
|
383
|
+
* Silver color preset.
|
|
384
|
+
*/
|
|
385
|
+
static get newSilver() { return Color.fromRGB(192, 192, 192); }
|
|
386
|
+
;
|
|
387
|
+
/**
|
|
388
|
+
* White color preset.
|
|
389
|
+
*/
|
|
390
|
+
static get newWhite() { return Color.fromRGB(255, 255, 255); }
|
|
391
|
+
;
|
|
392
|
+
static mix(first, second, ratio = 0.5) {
|
|
393
|
+
if (!Number.isFinite(ratio))
|
|
394
|
+
throw new Error(`The ratio ${ratio} must be a finite number`);
|
|
395
|
+
ratio = ratio.clamp(0, 1);
|
|
396
|
+
const red = first.red + (second.red - first.red) * ratio;
|
|
397
|
+
const green = first.green + (second.green - first.green) * ratio;
|
|
398
|
+
const blue = first.blue + (second.blue - first.blue) * ratio;
|
|
399
|
+
const alpha = first.alpha + (second.alpha - first.alpha) * ratio;
|
|
400
|
+
return Color.fromRGB(red, green, blue, alpha);
|
|
401
|
+
}
|
|
402
|
+
grayscale(scale = 1) {
|
|
403
|
+
if (!Number.isFinite(scale))
|
|
404
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
405
|
+
scale = scale.clamp(0, 1);
|
|
406
|
+
const { red, green, blue } = this;
|
|
407
|
+
const achromatic = (red + green + blue) / 3;
|
|
408
|
+
this.#rgb[0] = red + (achromatic - red) * scale;
|
|
409
|
+
this.#rgb[1] = green + (achromatic - green) * scale;
|
|
410
|
+
this.#rgb[2] = blue + (achromatic - blue) * scale;
|
|
411
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
412
|
+
return this;
|
|
413
|
+
}
|
|
414
|
+
redEmphasis(scale = 1) {
|
|
415
|
+
if (!Number.isFinite(scale))
|
|
416
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
417
|
+
scale = scale.clamp(0, 1);
|
|
418
|
+
const { green, blue } = this;
|
|
419
|
+
const average = (green + blue) / 2;
|
|
420
|
+
this.#rgb[1] = green + (average - green) * scale;
|
|
421
|
+
this.#rgb[2] = blue + (average - blue) * scale;
|
|
422
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
423
|
+
return this;
|
|
424
|
+
}
|
|
425
|
+
greenEmphasis(scale = 1) {
|
|
426
|
+
if (!Number.isFinite(scale))
|
|
427
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
428
|
+
scale = scale.clamp(0, 1);
|
|
429
|
+
const { red, blue } = this;
|
|
430
|
+
const average = (red + blue) / 2;
|
|
431
|
+
this.#rgb[0] = red + (average - red) * scale;
|
|
432
|
+
this.#rgb[2] = blue + (average - blue) * scale;
|
|
433
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
434
|
+
return this;
|
|
435
|
+
}
|
|
436
|
+
blueEmphasis(scale = 1) {
|
|
437
|
+
if (!Number.isFinite(scale))
|
|
438
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
439
|
+
scale = scale.clamp(0, 1);
|
|
440
|
+
const { red, green } = this;
|
|
441
|
+
const average = (red + green) / 2;
|
|
442
|
+
this.#rgb[0] = red + (average - red) * scale;
|
|
443
|
+
this.#rgb[1] = green + (average - green) * scale;
|
|
444
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
445
|
+
return this;
|
|
446
|
+
}
|
|
447
|
+
invert(scale = 1) {
|
|
448
|
+
if (!Number.isFinite(scale))
|
|
449
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
450
|
+
scale = scale.clamp(0, 1);
|
|
451
|
+
const { red, green, blue } = this;
|
|
452
|
+
this.#rgb[0] = red + ((255 - red) - red) * scale;
|
|
453
|
+
this.#rgb[1] = green + ((255 - green) - green) * scale;
|
|
454
|
+
this.#rgb[2] = blue + ((255 - blue) - blue) * scale;
|
|
455
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
456
|
+
return this;
|
|
457
|
+
}
|
|
458
|
+
sepia(scale = 1) {
|
|
459
|
+
if (!Number.isFinite(scale))
|
|
460
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
461
|
+
scale = scale.clamp(0, 1);
|
|
462
|
+
const { red, green, blue } = this;
|
|
463
|
+
const redness = (red * 0.393) + (green * 0.769) + (blue * 0.189);
|
|
464
|
+
const greenness = (red * 0.349) + (green * 0.686) + (blue * 0.168);
|
|
465
|
+
const blueness = (red * 0.272) + (green * 0.534) + (blue * 0.131);
|
|
466
|
+
this.#rgb[0] = red + (redness - red) * scale;
|
|
467
|
+
this.#rgb[1] = green + (greenness - green) * scale;
|
|
468
|
+
this.#rgb[2] = blue + (blueness - blue) * scale;
|
|
469
|
+
Color.#RGBtoHSL(this.#rgb, this.#hsl);
|
|
470
|
+
return this;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Rotates the hue of the current color by the given angle in degrees.
|
|
474
|
+
* @param angle Rotation angle in degrees.
|
|
475
|
+
* @returns The modified current color.
|
|
476
|
+
* @throws {Error} If `angle` is not a finite number.
|
|
477
|
+
*/
|
|
478
|
+
rotate(angle) {
|
|
479
|
+
if (!Number.isFinite(angle))
|
|
480
|
+
throw new Error(`The angle ${angle} must be a finite number`);
|
|
481
|
+
this.hue += angle;
|
|
482
|
+
return this;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Sets the saturation of the current color by scale.
|
|
486
|
+
* @param scale Saturation scale [0 - 1].
|
|
487
|
+
* @returns The modified current color.
|
|
488
|
+
* @throws {Error} If `scale` is not a finite number.
|
|
489
|
+
*/
|
|
490
|
+
saturate(scale) {
|
|
491
|
+
if (!Number.isFinite(scale))
|
|
492
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
493
|
+
this.saturation = 100 * scale;
|
|
494
|
+
return this;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Sets the lightness of the current color by scale.
|
|
498
|
+
* @param scale Lightness scale [0 - 1].
|
|
499
|
+
* @returns The modified current color.
|
|
500
|
+
* @throws {Error} If `scale` is not a finite number.
|
|
501
|
+
*/
|
|
502
|
+
illuminate(scale) {
|
|
503
|
+
if (!Number.isFinite(scale))
|
|
504
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
505
|
+
this.lightness = 100 * scale;
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Sets the alpha of the current color.
|
|
510
|
+
* @param scale Alpha value [0 - 1].
|
|
511
|
+
* @returns The modified current color.
|
|
512
|
+
* @throws {Error} If `scale` is not a finite number.
|
|
513
|
+
*/
|
|
514
|
+
pass(scale) {
|
|
515
|
+
if (!Number.isFinite(scale))
|
|
516
|
+
throw new Error(`The scale ${scale} must be a finite number`);
|
|
517
|
+
this.alpha = scale;
|
|
518
|
+
return this;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
522
|
+
export { ColorFormats };
|
|
523
|
+
export { Color };
|
|
524
|
+
//# sourceMappingURL=color.js.map
|