@nemigo/helpers 0.13.3 → 1.5.2
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/dist/aggregator.d.ts +33 -0
- package/dist/aggregator.js +44 -0
- package/dist/array.d.ts +33 -0
- package/dist/array.js +24 -0
- package/dist/async/context.d.ts +73 -0
- package/dist/async/context.js +90 -0
- package/dist/async/future.d.ts +54 -0
- package/dist/async/future.js +71 -0
- package/dist/async/index.d.ts +56 -27
- package/dist/async/index.js +63 -58
- package/dist/async/loader.d.ts +67 -0
- package/dist/async/loader.js +101 -0
- package/dist/async/queue.d.ts +51 -0
- package/dist/async/queue.js +84 -0
- package/dist/cases.d.ts +31 -21
- package/dist/cases.js +41 -37
- package/dist/clean.d.ts +44 -26
- package/dist/clean.js +67 -42
- package/dist/color/types.d.ts +31 -0
- package/dist/color/types.js +1 -0
- package/dist/datetime/delta.d.ts +28 -0
- package/dist/datetime/delta.js +65 -0
- package/dist/datetime/format.d.ts +54 -0
- package/dist/datetime/format.js +122 -0
- package/dist/datetime/index.d.ts +6 -0
- package/dist/datetime/index.js +22 -0
- package/dist/datetime/plural.d.ts +77 -0
- package/dist/datetime/plural.js +78 -0
- package/dist/emitter.d.ts +29 -17
- package/dist/emitter.js +35 -21
- package/dist/explorer.d.ts +22 -29
- package/dist/explorer.js +18 -16
- package/dist/files.d.ts +31 -2
- package/dist/files.js +33 -8
- package/dist/fish.d.ts +29 -0
- package/dist/fish.js +70 -0
- package/dist/html/cookie.d.ts +48 -0
- package/dist/html/cookie.js +37 -0
- package/dist/html/events.d.ts +133 -0
- package/dist/html/events.js +139 -0
- package/dist/html/index.d.ts +31 -0
- package/dist/html/index.js +61 -0
- package/dist/index.d.ts +38 -40
- package/dist/index.js +43 -56
- package/dist/jiff/apply.d.ts +93 -0
- package/dist/jiff/apply.js +64 -0
- package/dist/jiff/extract.d.ts +7 -0
- package/dist/jiff/extract.js +82 -0
- package/dist/jiff/types.d.ts +57 -0
- package/dist/jiff/types.js +1 -0
- package/dist/lens.d.ts +20 -31
- package/dist/lens.js +22 -37
- package/dist/msgpack.d.ts +11 -26
- package/dist/msgpack.js +9 -21
- package/dist/mutate.d.ts +70 -0
- package/dist/mutate.js +130 -0
- package/dist/omitter.d.ts +54 -34
- package/dist/omitter.js +33 -25
- package/dist/path.d.ts +20 -1
- package/dist/path.js +21 -2
- package/dist/phymath/format.d.ts +60 -0
- package/dist/phymath/format.js +34 -0
- package/dist/phymath/index.d.ts +30 -30
- package/dist/phymath/index.js +41 -33
- package/dist/promoter.d.ts +20 -12
- package/dist/promoter.js +24 -17
- package/dist/random.d.ts +20 -21
- package/dist/random.js +22 -23
- package/dist/rubles.d.ts +24 -0
- package/dist/rubles.js +24 -0
- package/dist/script.d.ts +60 -13
- package/dist/script.js +46 -10
- package/dist/string.d.ts +46 -92
- package/dist/string.js +46 -171
- package/dist/types.d.ts +144 -25
- package/dist/url/index.d.ts +12 -0
- package/dist/url/index.js +17 -0
- package/dist/url/params.d.ts +141 -0
- package/dist/{url.js → url/params.js} +90 -18
- package/dist/url/slug.d.ts +28 -0
- package/dist/url/slug.js +102 -0
- package/dist/veil.d.ts +14 -0
- package/dist/veil.js +26 -0
- package/dist/xod.d.ts +237 -16
- package/dist/xod.js +192 -18
- package/dist/zipper.d.ts +22 -4
- package/dist/zipper.js +22 -5
- package/package.json +82 -34
- package/dist/async/space.d.ts +0 -8
- package/dist/async/space.js +0 -31
- package/dist/cleanup.d.ts +0 -9
- package/dist/cleanup.js +0 -18
- package/dist/colors.d.ts +0 -539
- package/dist/colors.js +0 -888
- package/dist/cookie.d.ts +0 -60
- package/dist/cookie.js +0 -48
- package/dist/datetime.d.ts +0 -82
- package/dist/datetime.js +0 -161
- package/dist/format.d.ts +0 -36
- package/dist/format.js +0 -26
- package/dist/future.d.ts +0 -51
- package/dist/future.js +0 -71
- package/dist/html.d.ts +0 -145
- package/dist/html.js +0 -205
- package/dist/humanly.d.ts +0 -9
- package/dist/humanly.js +0 -93
- package/dist/lru.d.ts +0 -77
- package/dist/lru.js +0 -128
- package/dist/queue.d.ts +0 -40
- package/dist/queue.js +0 -56
- package/dist/url.d.ts +0 -61
package/dist/colors.js
DELETED
|
@@ -1,888 +0,0 @@
|
|
|
1
|
-
import { clamp, toRound, toZero } from "./phymath/index.js";
|
|
2
|
-
//...
|
|
3
|
-
/**
|
|
4
|
-
* Ограничивает значение RGB-канала в диапазоне 0-255
|
|
5
|
-
*/
|
|
6
|
-
export const clampRgb = (value) => clamp(Math.round(value), 0, 255);
|
|
7
|
-
/**
|
|
8
|
-
* Ограничивает оттенок в диапазоне 0-360
|
|
9
|
-
*/
|
|
10
|
-
export const clampHue = (value) => {
|
|
11
|
-
const v = value % 360;
|
|
12
|
-
return toZero(v < 0 ? v + 360 : v);
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Ограничивает процентное значение в диапазоне 0-100
|
|
16
|
-
*/
|
|
17
|
-
export const clampPercent = (value) => clamp(value, 0, 100);
|
|
18
|
-
/**
|
|
19
|
-
* Ограничивает значение альфа-канала в диапазоне 0-1
|
|
20
|
-
*/
|
|
21
|
-
export const clampAlpha = (value) => clamp(value, 0, 1);
|
|
22
|
-
//...
|
|
23
|
-
/**
|
|
24
|
-
* Проверяет, является ли объект RGB
|
|
25
|
-
*/
|
|
26
|
-
const isRGB = (color) => typeof color === "object" && color !== null && "r" in color && "g" in color && "b" in color;
|
|
27
|
-
/**
|
|
28
|
-
* Проверяет, является ли объект RGBA
|
|
29
|
-
*/
|
|
30
|
-
const isRGBA = (color) => isRGB(color) && "a" in color;
|
|
31
|
-
/**
|
|
32
|
-
* Проверяет, является ли объект HSL
|
|
33
|
-
*/
|
|
34
|
-
const isHSL = (color) => typeof color === "object" && color !== null && "h" in color && "s" in color && "l" in color;
|
|
35
|
-
/**
|
|
36
|
-
* Проверяет, является ли объект HSLA
|
|
37
|
-
*/
|
|
38
|
-
const isHSLA = (color) => isHSL(color) && "a" in color;
|
|
39
|
-
/**
|
|
40
|
-
* Проверяет, является ли объект HSV
|
|
41
|
-
*/
|
|
42
|
-
const isHSV = (color) => typeof color === "object" && color !== null && "h" in color && "s" in color && "v" in color;
|
|
43
|
-
/**
|
|
44
|
-
* Проверяет, является ли объект HSVA
|
|
45
|
-
*/
|
|
46
|
-
const isHSVA = (color) => isHSV(color) && "a" in color;
|
|
47
|
-
//...
|
|
48
|
-
/**
|
|
49
|
-
* Парсит HEX-строку в RGB или RGBA
|
|
50
|
-
*
|
|
51
|
-
* Поддерживаемые форматы:
|
|
52
|
-
* - #RGB
|
|
53
|
-
* - #RRGGBB
|
|
54
|
-
* - #RGBA
|
|
55
|
-
* - #RRGGBBAA
|
|
56
|
-
*
|
|
57
|
-
* @param hex - HEX-строка цвета
|
|
58
|
-
* @returns RGB или RGBA объект, или null если формат неверен
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```typescript
|
|
62
|
-
* parseHex("#ff0000"); // { r: 255, g: 0, b: 0 }
|
|
63
|
-
* parseHex("#f00"); // { r: 255, g: 0, b: 0 }
|
|
64
|
-
* parseHex("#ff0000ff"); // { r: 255, g: 0, b: 0, a: 1 }
|
|
65
|
-
* parseHex("#f00f"); // { r: 255, g: 0, b: 0, a: 1 }
|
|
66
|
-
* parseHex("invalid"); // null
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
export const parseHex = (hex) => {
|
|
70
|
-
const cleaned = hex.trim().replace(/^#/, "");
|
|
71
|
-
// #RGB или #RGBA
|
|
72
|
-
if (cleaned.length === 3 || cleaned.length === 4) {
|
|
73
|
-
const r = parseInt(cleaned[0] + cleaned[0], 16);
|
|
74
|
-
const g = parseInt(cleaned[1] + cleaned[1], 16);
|
|
75
|
-
const b = parseInt(cleaned[2] + cleaned[2], 16);
|
|
76
|
-
if (isNaN(r) || isNaN(g) || isNaN(b))
|
|
77
|
-
return null;
|
|
78
|
-
if (cleaned.length === 4) {
|
|
79
|
-
const a = parseInt(cleaned[3] + cleaned[3], 16) / 255;
|
|
80
|
-
if (isNaN(a))
|
|
81
|
-
return null;
|
|
82
|
-
return { r, g, b, a: toRound(a, 3) };
|
|
83
|
-
}
|
|
84
|
-
return { r, g, b };
|
|
85
|
-
}
|
|
86
|
-
// #RRGGBB или #RRGGBBAA
|
|
87
|
-
if (cleaned.length === 6 || cleaned.length === 8) {
|
|
88
|
-
const r = parseInt(cleaned.substring(0, 2), 16);
|
|
89
|
-
const g = parseInt(cleaned.substring(2, 4), 16);
|
|
90
|
-
const b = parseInt(cleaned.substring(4, 6), 16);
|
|
91
|
-
if (isNaN(r) || isNaN(g) || isNaN(b))
|
|
92
|
-
return null;
|
|
93
|
-
if (cleaned.length === 8) {
|
|
94
|
-
const a = parseInt(cleaned.substring(6, 8), 16) / 255;
|
|
95
|
-
if (isNaN(a))
|
|
96
|
-
return null;
|
|
97
|
-
return { r, g, b, a: toRound(a, 3) };
|
|
98
|
-
}
|
|
99
|
-
return { r, g, b };
|
|
100
|
-
}
|
|
101
|
-
return null;
|
|
102
|
-
};
|
|
103
|
-
/**
|
|
104
|
-
* Парсит RGB/RGBA строку в объект
|
|
105
|
-
*
|
|
106
|
-
* Поддерживаемые форматы:
|
|
107
|
-
* - rgb(r, g, b)
|
|
108
|
-
* - rgba(r, g, b, a)
|
|
109
|
-
* - rgb(r g b)
|
|
110
|
-
* - rgba(r g b / a)
|
|
111
|
-
*
|
|
112
|
-
* @param rgb - RGB/RGBA строка
|
|
113
|
-
* @returns RGB или RGBA объект, или null если формат неверен
|
|
114
|
-
*
|
|
115
|
-
* @example
|
|
116
|
-
* ```typescript
|
|
117
|
-
* parseRgb("rgb(255, 0, 0)"); // { r: 255, g: 0, b: 0 }
|
|
118
|
-
* parseRgb("rgba(255, 0, 0, 0.5)"); // { r: 255, g: 0, b: 0, a: 0.5 }
|
|
119
|
-
* parseRgb("rgb(255 0 0)"); // { r: 255, g: 0, b: 0 }
|
|
120
|
-
* parseRgb("rgba(255 0 0 / 0.5)"); // { r: 255, g: 0, b: 0, a: 0.5 }
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
export const parseRgb = (rgb) => {
|
|
124
|
-
const match = rgb.trim().match(/^rgba?\(\s*([^)]+)\s*\)$/i);
|
|
125
|
-
if (!match)
|
|
126
|
-
return null;
|
|
127
|
-
const parts = match[1]
|
|
128
|
-
.split(/[\s,/]+/)
|
|
129
|
-
.map((v) => v.trim())
|
|
130
|
-
.filter((v) => v !== "");
|
|
131
|
-
if (parts.length < 3 || parts.length > 4)
|
|
132
|
-
return null;
|
|
133
|
-
const r = parseInt(parts[0], 10);
|
|
134
|
-
const g = parseInt(parts[1], 10);
|
|
135
|
-
const b = parseInt(parts[2], 10);
|
|
136
|
-
if (isNaN(r) || isNaN(g) || isNaN(b))
|
|
137
|
-
return null;
|
|
138
|
-
if (parts.length === 4) {
|
|
139
|
-
const a = parseFloat(parts[3]);
|
|
140
|
-
if (isNaN(a))
|
|
141
|
-
return null;
|
|
142
|
-
return { r: clampRgb(r), g: clampRgb(g), b: clampRgb(b), a: clampAlpha(a) };
|
|
143
|
-
}
|
|
144
|
-
return { r: clampRgb(r), g: clampRgb(g), b: clampRgb(b) };
|
|
145
|
-
};
|
|
146
|
-
/**
|
|
147
|
-
* Парсит HSL/HSLA строку в объект
|
|
148
|
-
*
|
|
149
|
-
* Поддерживаемые форматы:
|
|
150
|
-
* - hsl(h, s%, l%)
|
|
151
|
-
* - hsla(h, s%, l%, a)
|
|
152
|
-
* - hsl(h s% l%)
|
|
153
|
-
* - hsla(h s% l% / a)
|
|
154
|
-
*
|
|
155
|
-
* @param hsl - HSL/HSLA строка
|
|
156
|
-
* @returns HSL или HSLA объект, или null если формат неверен
|
|
157
|
-
*
|
|
158
|
-
* @example
|
|
159
|
-
* ```typescript
|
|
160
|
-
* parseHsl("hsl(0, 100%, 50%)"); // { h: 0, s: 100, l: 50 }
|
|
161
|
-
* parseHsl("hsla(0, 100%, 50%, 0.5)"); // { h: 0, s: 100, l: 50, a: 0.5 }
|
|
162
|
-
* parseHsl("hsl(0 100% 50%)"); // { h: 0, s: 100, l: 50 }
|
|
163
|
-
* ```
|
|
164
|
-
*/
|
|
165
|
-
export const parseHsl = (hsl) => {
|
|
166
|
-
const match = hsl.trim().match(/^hsla?\(\s*([^)]+)\s*\)$/i);
|
|
167
|
-
if (!match)
|
|
168
|
-
return null;
|
|
169
|
-
const parts = match[1]
|
|
170
|
-
.split(/[\s,/]+/)
|
|
171
|
-
.map((v) => v.trim())
|
|
172
|
-
.filter((v) => v !== "");
|
|
173
|
-
if (parts.length < 3 || parts.length > 4)
|
|
174
|
-
return null;
|
|
175
|
-
const h = parseFloat(parts[0]);
|
|
176
|
-
const s = parseFloat(parts[1].replace("%", ""));
|
|
177
|
-
const l = parseFloat(parts[2].replace("%", ""));
|
|
178
|
-
if (isNaN(h) || isNaN(s) || isNaN(l))
|
|
179
|
-
return null;
|
|
180
|
-
if (parts.length === 4) {
|
|
181
|
-
const a = parseFloat(parts[3]);
|
|
182
|
-
if (isNaN(a))
|
|
183
|
-
return null;
|
|
184
|
-
return { h: clampHue(h), s: clampPercent(s), l: clampPercent(l), a: clampAlpha(a) };
|
|
185
|
-
}
|
|
186
|
-
return { h: clampHue(h), s: clampPercent(s), l: clampPercent(l) };
|
|
187
|
-
};
|
|
188
|
-
/**
|
|
189
|
-
* Универсальный парсер цвета
|
|
190
|
-
*
|
|
191
|
-
* Пробует распознать формат и парсит соответствующим парсером
|
|
192
|
-
*
|
|
193
|
-
* @param color - Строка цвета в любом поддерживаемом формате
|
|
194
|
-
* @returns RGB или RGBA объект, или null если формат не распознан
|
|
195
|
-
*
|
|
196
|
-
* @example
|
|
197
|
-
* ```typescript
|
|
198
|
-
* parseColor("#ff0000"); // { r: 255, g: 0, b: 0 }
|
|
199
|
-
* parseColor("rgb(255, 0, 0)"); // { r: 255, g: 0, b: 0 }
|
|
200
|
-
* parseColor("hsl(0, 100%, 50%)"); // { r: 255, g: 0, b: 0 }
|
|
201
|
-
* ```
|
|
202
|
-
*/
|
|
203
|
-
export const parseColor = (color) => {
|
|
204
|
-
const trimmed = color.trim();
|
|
205
|
-
// Пробуем HEX
|
|
206
|
-
if (trimmed.startsWith("#")) {
|
|
207
|
-
return parseHex(trimmed);
|
|
208
|
-
}
|
|
209
|
-
// Пробуем RGB/RGBA
|
|
210
|
-
if (trimmed.startsWith("rgb")) {
|
|
211
|
-
return parseRgb(trimmed);
|
|
212
|
-
}
|
|
213
|
-
// Пробуем HSL/HSLA (конвертируем в RGB)
|
|
214
|
-
if (trimmed.startsWith("hsl")) {
|
|
215
|
-
const hsl = parseHsl(trimmed);
|
|
216
|
-
if (hsl)
|
|
217
|
-
return hslToRgb(hsl);
|
|
218
|
-
}
|
|
219
|
-
return null;
|
|
220
|
-
};
|
|
221
|
-
//...
|
|
222
|
-
/**
|
|
223
|
-
* Конвертирует RGB/RGBA в HEX/HEXA строку
|
|
224
|
-
*
|
|
225
|
-
* @param rgb - RGB или RGBA объект
|
|
226
|
-
* @returns HEX строка в формате #RRGGBB или #RRGGBBAA
|
|
227
|
-
*
|
|
228
|
-
* @example
|
|
229
|
-
* ```typescript
|
|
230
|
-
* rgbToHex({ r: 255, g: 0, b: 0 }); // "#ff0000"
|
|
231
|
-
* rgbToHex({ r: 255, g: 0, b: 0, a: 0.5 }); // "#ff000080"
|
|
232
|
-
* ```
|
|
233
|
-
*/
|
|
234
|
-
export const rgbToHex = (rgb) => {
|
|
235
|
-
const r = clampRgb(rgb.r).toString(16).padStart(2, "0");
|
|
236
|
-
const g = clampRgb(rgb.g).toString(16).padStart(2, "0");
|
|
237
|
-
const b = clampRgb(rgb.b).toString(16).padStart(2, "0");
|
|
238
|
-
if (isRGBA(rgb)) {
|
|
239
|
-
const a = Math.round(clampAlpha(rgb.a) * 255)
|
|
240
|
-
.toString(16)
|
|
241
|
-
.padStart(2, "0");
|
|
242
|
-
return `#${r}${g}${b}${a}`;
|
|
243
|
-
}
|
|
244
|
-
return `#${r}${g}${b}`;
|
|
245
|
-
};
|
|
246
|
-
/**
|
|
247
|
-
* Конвертирует HEX строку в RGB/RGBA объект
|
|
248
|
-
*
|
|
249
|
-
* @param hex - HEX строка
|
|
250
|
-
* @returns RGB или RGBA объект
|
|
251
|
-
* @throws {Error} Если формат HEX неверен
|
|
252
|
-
*
|
|
253
|
-
* @example
|
|
254
|
-
* ```typescript
|
|
255
|
-
* hexToRgb("#ff0000"); // { r: 255, g: 0, b: 0 }
|
|
256
|
-
* hexToRgb("#f00"); // { r: 255, g: 0, b: 0 }
|
|
257
|
-
* ```
|
|
258
|
-
*/
|
|
259
|
-
export const hexToRgb = (hex) => {
|
|
260
|
-
const result = parseHex(hex);
|
|
261
|
-
if (!result)
|
|
262
|
-
throw new Error(`Неверный HEX формат: ${hex}`);
|
|
263
|
-
return result;
|
|
264
|
-
};
|
|
265
|
-
/**
|
|
266
|
-
* Конвертирует RGB/RGBA в HSL/HSLA
|
|
267
|
-
*
|
|
268
|
-
* @param rgb - RGB или RGBA объект
|
|
269
|
-
* @returns HSL или HSLA объект
|
|
270
|
-
*
|
|
271
|
-
* @example
|
|
272
|
-
* ```typescript
|
|
273
|
-
* rgbToHsl({ r: 255, g: 0, b: 0 }); // { h: 0, s: 100, l: 50 }
|
|
274
|
-
* rgbToHsl({ r: 255, g: 255, b: 255 }); // { h: 0, s: 0, l: 100 }
|
|
275
|
-
* ```
|
|
276
|
-
*/
|
|
277
|
-
export const rgbToHsl = (rgb) => {
|
|
278
|
-
const r = rgb.r / 255;
|
|
279
|
-
const g = rgb.g / 255;
|
|
280
|
-
const b = rgb.b / 255;
|
|
281
|
-
const max = Math.max(r, g, b);
|
|
282
|
-
const min = Math.min(r, g, b);
|
|
283
|
-
const delta = max - min;
|
|
284
|
-
let h = 0;
|
|
285
|
-
let s = 0;
|
|
286
|
-
const l = (max + min) / 2;
|
|
287
|
-
if (delta !== 0) {
|
|
288
|
-
s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
|
|
289
|
-
switch (max) {
|
|
290
|
-
case r:
|
|
291
|
-
h = ((g - b) / delta + (g < b ? 6 : 0)) / 6;
|
|
292
|
-
break;
|
|
293
|
-
case g:
|
|
294
|
-
h = ((b - r) / delta + 2) / 6;
|
|
295
|
-
break;
|
|
296
|
-
case b:
|
|
297
|
-
h = ((r - g) / delta + 4) / 6;
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
const result = {
|
|
302
|
-
h: toRound(h * 360, 1),
|
|
303
|
-
s: toRound(s * 100, 1),
|
|
304
|
-
l: toRound(l * 100, 1),
|
|
305
|
-
};
|
|
306
|
-
if (isRGBA(rgb)) {
|
|
307
|
-
return { ...result, a: rgb.a };
|
|
308
|
-
}
|
|
309
|
-
return result;
|
|
310
|
-
};
|
|
311
|
-
/**
|
|
312
|
-
* Конвертирует HSL/HSLA в RGB/RGBA
|
|
313
|
-
*
|
|
314
|
-
* @param hsl - HSL или HSLA объект
|
|
315
|
-
* @returns RGB или RGBA объект
|
|
316
|
-
*
|
|
317
|
-
* @example
|
|
318
|
-
* ```typescript
|
|
319
|
-
* hslToRgb({ h: 0, s: 100, l: 50 }); // { r: 255, g: 0, b: 0 }
|
|
320
|
-
* hslToRgb({ h: 0, s: 0, l: 100 }); // { r: 255, g: 255, b: 255 }
|
|
321
|
-
* ```
|
|
322
|
-
*/
|
|
323
|
-
export const hslToRgb = (hsl) => {
|
|
324
|
-
const h = hsl.h / 360;
|
|
325
|
-
const s = hsl.s / 100;
|
|
326
|
-
const l = hsl.l / 100;
|
|
327
|
-
let r, g, b;
|
|
328
|
-
if (s === 0) {
|
|
329
|
-
r = g = b = l;
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
const hue2rgb = (p, q, t) => {
|
|
333
|
-
if (t < 0)
|
|
334
|
-
t += 1;
|
|
335
|
-
if (t > 1)
|
|
336
|
-
t -= 1;
|
|
337
|
-
if (t < 1 / 6)
|
|
338
|
-
return p + (q - p) * 6 * t;
|
|
339
|
-
if (t < 1 / 2)
|
|
340
|
-
return q;
|
|
341
|
-
if (t < 2 / 3)
|
|
342
|
-
return p + (q - p) * (2 / 3 - t) * 6;
|
|
343
|
-
return p;
|
|
344
|
-
};
|
|
345
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
346
|
-
const p = 2 * l - q;
|
|
347
|
-
r = hue2rgb(p, q, h + 1 / 3);
|
|
348
|
-
g = hue2rgb(p, q, h);
|
|
349
|
-
b = hue2rgb(p, q, h - 1 / 3);
|
|
350
|
-
}
|
|
351
|
-
const result = {
|
|
352
|
-
r: Math.round(r * 255),
|
|
353
|
-
g: Math.round(g * 255),
|
|
354
|
-
b: Math.round(b * 255),
|
|
355
|
-
};
|
|
356
|
-
if (isHSLA(hsl)) {
|
|
357
|
-
return { ...result, a: hsl.a };
|
|
358
|
-
}
|
|
359
|
-
return result;
|
|
360
|
-
};
|
|
361
|
-
/**
|
|
362
|
-
* Конвертирует RGB/RGBA в HSV/HSVA
|
|
363
|
-
*
|
|
364
|
-
* @param rgb - RGB или RGBA объект
|
|
365
|
-
* @returns HSV или HSVA объект
|
|
366
|
-
*
|
|
367
|
-
* @example
|
|
368
|
-
* ```typescript
|
|
369
|
-
* rgbToHsv({ r: 255, g: 0, b: 0 }); // { h: 0, s: 100, v: 100 }
|
|
370
|
-
* rgbToHsv({ r: 0, g: 0, b: 0 }); // { h: 0, s: 0, v: 0 }
|
|
371
|
-
* ```
|
|
372
|
-
*/
|
|
373
|
-
export const rgbToHsv = (rgb) => {
|
|
374
|
-
const r = rgb.r / 255;
|
|
375
|
-
const g = rgb.g / 255;
|
|
376
|
-
const b = rgb.b / 255;
|
|
377
|
-
const max = Math.max(r, g, b);
|
|
378
|
-
const min = Math.min(r, g, b);
|
|
379
|
-
const delta = max - min;
|
|
380
|
-
let h = 0;
|
|
381
|
-
let s = 0;
|
|
382
|
-
const v = max;
|
|
383
|
-
if (delta !== 0) {
|
|
384
|
-
s = delta / max;
|
|
385
|
-
switch (max) {
|
|
386
|
-
case r:
|
|
387
|
-
h = ((g - b) / delta + (g < b ? 6 : 0)) / 6;
|
|
388
|
-
break;
|
|
389
|
-
case g:
|
|
390
|
-
h = ((b - r) / delta + 2) / 6;
|
|
391
|
-
break;
|
|
392
|
-
case b:
|
|
393
|
-
h = ((r - g) / delta + 4) / 6;
|
|
394
|
-
break;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
const result = {
|
|
398
|
-
h: toRound(h * 360, 1),
|
|
399
|
-
s: toRound(s * 100, 1),
|
|
400
|
-
v: toRound(v * 100, 1),
|
|
401
|
-
};
|
|
402
|
-
if (isRGBA(rgb)) {
|
|
403
|
-
return { ...result, a: rgb.a };
|
|
404
|
-
}
|
|
405
|
-
return result;
|
|
406
|
-
};
|
|
407
|
-
/**
|
|
408
|
-
* Конвертирует HSV/HSVA в RGB/RGBA
|
|
409
|
-
*
|
|
410
|
-
* @param hsv - HSV или HSVA объект
|
|
411
|
-
* @returns RGB или RGBA объект
|
|
412
|
-
*
|
|
413
|
-
* @example
|
|
414
|
-
* ```typescript
|
|
415
|
-
* hsvToRgb({ h: 0, s: 100, v: 100 }); // { r: 255, g: 0, b: 0 }
|
|
416
|
-
* hsvToRgb({ h: 0, s: 0, v: 0 }); // { r: 0, g: 0, b: 0 }
|
|
417
|
-
* ```
|
|
418
|
-
*/
|
|
419
|
-
export const hsvToRgb = (hsv) => {
|
|
420
|
-
const h = hsv.h / 360;
|
|
421
|
-
const s = hsv.s / 100;
|
|
422
|
-
const v = hsv.v / 100;
|
|
423
|
-
const i = Math.floor(h * 6);
|
|
424
|
-
const f = h * 6 - i;
|
|
425
|
-
const p = v * (1 - s);
|
|
426
|
-
const q = v * (1 - f * s);
|
|
427
|
-
const t = v * (1 - (1 - f) * s);
|
|
428
|
-
let r, g, b;
|
|
429
|
-
switch (i % 6) {
|
|
430
|
-
case 0:
|
|
431
|
-
r = v;
|
|
432
|
-
g = t;
|
|
433
|
-
b = p;
|
|
434
|
-
break;
|
|
435
|
-
case 1:
|
|
436
|
-
r = q;
|
|
437
|
-
g = v;
|
|
438
|
-
b = p;
|
|
439
|
-
break;
|
|
440
|
-
case 2:
|
|
441
|
-
r = p;
|
|
442
|
-
g = v;
|
|
443
|
-
b = t;
|
|
444
|
-
break;
|
|
445
|
-
case 3:
|
|
446
|
-
r = p;
|
|
447
|
-
g = q;
|
|
448
|
-
b = v;
|
|
449
|
-
break;
|
|
450
|
-
case 4:
|
|
451
|
-
r = t;
|
|
452
|
-
g = p;
|
|
453
|
-
b = v;
|
|
454
|
-
break;
|
|
455
|
-
case 5:
|
|
456
|
-
default:
|
|
457
|
-
r = v;
|
|
458
|
-
g = p;
|
|
459
|
-
b = q;
|
|
460
|
-
break;
|
|
461
|
-
}
|
|
462
|
-
const result = {
|
|
463
|
-
r: Math.round(r * 255),
|
|
464
|
-
g: Math.round(g * 255),
|
|
465
|
-
b: Math.round(b * 255),
|
|
466
|
-
};
|
|
467
|
-
if (isHSVA(hsv)) {
|
|
468
|
-
return { ...result, a: hsv.a };
|
|
469
|
-
}
|
|
470
|
-
return result;
|
|
471
|
-
};
|
|
472
|
-
//...
|
|
473
|
-
/**
|
|
474
|
-
* Форматирует RGB/RGBA в CSS-строку
|
|
475
|
-
*
|
|
476
|
-
* @param rgb - RGB или RGBA объект
|
|
477
|
-
* @returns CSS-строка в формате rgb(r, g, b) или rgba(r, g, b, a)
|
|
478
|
-
*
|
|
479
|
-
* @example
|
|
480
|
-
* ```typescript
|
|
481
|
-
* toRgbString({ r: 255, g: 0, b: 0 }); // "rgb(255, 0, 0)"
|
|
482
|
-
* toRgbString({ r: 255, g: 0, b: 0, a: 0.5 }); // "rgba(255, 0, 0, 0.5)"
|
|
483
|
-
* ```
|
|
484
|
-
*/
|
|
485
|
-
export const toRgbString = (rgb) => {
|
|
486
|
-
if (isRGBA(rgb)) {
|
|
487
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${toRound(rgb.a, 3)})`;
|
|
488
|
-
}
|
|
489
|
-
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
|
|
490
|
-
};
|
|
491
|
-
/**
|
|
492
|
-
* Форматирует RGB/RGBA в HEX-строку
|
|
493
|
-
*
|
|
494
|
-
* @param rgb - RGB или RGBA объект
|
|
495
|
-
* @returns HEX-строка в формате #RRGGBB или #RRGGBBAA
|
|
496
|
-
*
|
|
497
|
-
* @example
|
|
498
|
-
* ```typescript
|
|
499
|
-
* toHexString({ r: 255, g: 0, b: 0 }); // "#ff0000"
|
|
500
|
-
* toHexString({ r: 255, g: 0, b: 0, a: 0.5 }); // "#ff000080"
|
|
501
|
-
* ```
|
|
502
|
-
*/
|
|
503
|
-
export const toHexString = (rgb) => rgbToHex(rgb);
|
|
504
|
-
/**
|
|
505
|
-
* Форматирует HSL/HSLA в CSS-строку
|
|
506
|
-
*
|
|
507
|
-
* @param hsl - HSL или HSLA объект
|
|
508
|
-
* @returns CSS-строка в формате hsl(h, s%, l%) или hsla(h, s%, l%, a)
|
|
509
|
-
*
|
|
510
|
-
* @example
|
|
511
|
-
* ```typescript
|
|
512
|
-
* toHslString({ h: 0, s: 100, l: 50 }); // "hsl(0, 100%, 50%)"
|
|
513
|
-
* toHslString({ h: 0, s: 100, l: 50, a: 0.5 }); // "hsla(0, 100%, 50%, 0.5)"
|
|
514
|
-
* ```
|
|
515
|
-
*/
|
|
516
|
-
export const toHslString = (hsl) => {
|
|
517
|
-
if (isHSLA(hsl)) {
|
|
518
|
-
return `hsla(${toRound(hsl.h, 1)}, ${toRound(hsl.s, 1)}%, ${toRound(hsl.l, 1)}%, ${toRound(hsl.a, 3)})`;
|
|
519
|
-
}
|
|
520
|
-
return `hsl(${toRound(hsl.h, 1)}, ${toRound(hsl.s, 1)}%, ${toRound(hsl.l, 1)}%)`;
|
|
521
|
-
};
|
|
522
|
-
//...
|
|
523
|
-
/**
|
|
524
|
-
* Вычисляет относительную яркость цвета по формуле WCAG
|
|
525
|
-
*
|
|
526
|
-
* @param rgb - RGB объект
|
|
527
|
-
* @returns Относительная яркость (0-1)
|
|
528
|
-
*
|
|
529
|
-
* @see https://www.w3.org/TR/WCAG20/#relativeluminancedef
|
|
530
|
-
*
|
|
531
|
-
* @example
|
|
532
|
-
* ```typescript
|
|
533
|
-
* getLuminance({ r: 255, g: 255, b: 255 }); // 1 (белый)
|
|
534
|
-
* getLuminance({ r: 0, g: 0, b: 0 }); // 0 (чёрный)
|
|
535
|
-
* getLuminance({ r: 255, g: 0, b: 0 }); // 0.2126 (красный)
|
|
536
|
-
* ```
|
|
537
|
-
*/
|
|
538
|
-
export const getLuminance = (rgb) => {
|
|
539
|
-
const rsRGB = rgb.r / 255;
|
|
540
|
-
const gsRGB = rgb.g / 255;
|
|
541
|
-
const bsRGB = rgb.b / 255;
|
|
542
|
-
const r = rsRGB <= 0.03928 ? rsRGB / 12.92 : Math.pow((rsRGB + 0.055) / 1.055, 2.4);
|
|
543
|
-
const g = gsRGB <= 0.03928 ? gsRGB / 12.92 : Math.pow((gsRGB + 0.055) / 1.055, 2.4);
|
|
544
|
-
const b = bsRGB <= 0.03928 ? bsRGB / 12.92 : Math.pow((bsRGB + 0.055) / 1.055, 2.4);
|
|
545
|
-
return toRound(0.2126 * r + 0.7152 * g + 0.0722 * b, 4);
|
|
546
|
-
};
|
|
547
|
-
/**
|
|
548
|
-
* Вычисляет контрастность между двумя цветами по формуле WCAG
|
|
549
|
-
*
|
|
550
|
-
* @param rgb1 - Первый RGB объект
|
|
551
|
-
* @param rgb2 - Второй RGB объект
|
|
552
|
-
* @returns Коэффициент контрастности (1-21)
|
|
553
|
-
*
|
|
554
|
-
* @see https://www.w3.org/TR/WCAG20/#contrast-ratiodef
|
|
555
|
-
*
|
|
556
|
-
* @example
|
|
557
|
-
* ```typescript
|
|
558
|
-
* getContrast({ r: 255, g: 255, b: 255 }, { r: 0, g: 0, b: 0 }); // 21 (максимальный контраст)
|
|
559
|
-
* getContrast({ r: 255, g: 255, b: 255 }, { r: 255, g: 255, b: 255 }); // 1 (нет контраста)
|
|
560
|
-
* ```
|
|
561
|
-
*/
|
|
562
|
-
export const getContrast = (rgb1, rgb2) => {
|
|
563
|
-
const lum1 = getLuminance(rgb1);
|
|
564
|
-
const lum2 = getLuminance(rgb2);
|
|
565
|
-
const lighter = Math.max(lum1, lum2);
|
|
566
|
-
const darker = Math.min(lum1, lum2);
|
|
567
|
-
return toRound((lighter + 0.05) / (darker + 0.05), 2);
|
|
568
|
-
};
|
|
569
|
-
//...
|
|
570
|
-
/**
|
|
571
|
-
* Класс для работы с цветами
|
|
572
|
-
*
|
|
573
|
-
* Поддерживает конвертацию между форматами, манипуляции с цветом и вычисление характеристик
|
|
574
|
-
*
|
|
575
|
-
* @example
|
|
576
|
-
* ```typescript
|
|
577
|
-
* const color = new Color("#ff0000");
|
|
578
|
-
* color.rgb; // { r: 255, g: 0, b: 0 }
|
|
579
|
-
* color.hex; // "#ff0000"
|
|
580
|
-
* color.lighten(20).hex; // "#ff6666"
|
|
581
|
-
* color.luminance(); // 0.2126
|
|
582
|
-
* ```
|
|
583
|
-
*/
|
|
584
|
-
export class Color {
|
|
585
|
-
_rgb;
|
|
586
|
-
/**
|
|
587
|
-
* Создаёт экземпляр Color
|
|
588
|
-
*
|
|
589
|
-
* @param color - Строка цвета или RGB/RGBA объект
|
|
590
|
-
* @throws {Error} Если формат цвета не распознан
|
|
591
|
-
*
|
|
592
|
-
* @example
|
|
593
|
-
* ```typescript
|
|
594
|
-
* new Color("#ff0000");
|
|
595
|
-
* new Color("rgb(255, 0, 0)");
|
|
596
|
-
* new Color({ r: 255, g: 0, b: 0 });
|
|
597
|
-
* new Color({ r: 255, g: 0, b: 0, a: 0.5 });
|
|
598
|
-
* ```
|
|
599
|
-
*/
|
|
600
|
-
constructor(color) {
|
|
601
|
-
if (typeof color === "string") {
|
|
602
|
-
const parsed = parseColor(color);
|
|
603
|
-
if (!parsed)
|
|
604
|
-
throw new Error(`Не удалось распознать цвет: ${color}`);
|
|
605
|
-
this._rgb = isRGBA(parsed) ? parsed : { ...parsed, a: 1 };
|
|
606
|
-
}
|
|
607
|
-
else if (isRGBA(color)) {
|
|
608
|
-
this._rgb = {
|
|
609
|
-
r: clampRgb(color.r),
|
|
610
|
-
g: clampRgb(color.g),
|
|
611
|
-
b: clampRgb(color.b),
|
|
612
|
-
a: clampAlpha(color.a),
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
else {
|
|
616
|
-
this._rgb = {
|
|
617
|
-
r: clampRgb(color.r),
|
|
618
|
-
g: clampRgb(color.g),
|
|
619
|
-
b: clampRgb(color.b),
|
|
620
|
-
a: 1,
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Получает RGB представление цвета
|
|
626
|
-
*/
|
|
627
|
-
get rgb() {
|
|
628
|
-
return { r: this._rgb.r, g: this._rgb.g, b: this._rgb.b };
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Получает RGBA представление цвета
|
|
632
|
-
*/
|
|
633
|
-
get rgba() {
|
|
634
|
-
return { ...this._rgb };
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Получает HSL представление цвета
|
|
638
|
-
*/
|
|
639
|
-
get hsl() {
|
|
640
|
-
const result = rgbToHsl(this._rgb);
|
|
641
|
-
if (isHSLA(result)) {
|
|
642
|
-
const { a, ...hsl } = result;
|
|
643
|
-
return hsl;
|
|
644
|
-
}
|
|
645
|
-
return result;
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Получает HSLA представление цвета
|
|
649
|
-
*/
|
|
650
|
-
get hsla() {
|
|
651
|
-
const result = rgbToHsl(this._rgb);
|
|
652
|
-
if (isHSLA(result))
|
|
653
|
-
return result;
|
|
654
|
-
return { ...result, a: this._rgb.a };
|
|
655
|
-
}
|
|
656
|
-
/**
|
|
657
|
-
* Получает HSV представление цвета
|
|
658
|
-
*/
|
|
659
|
-
get hsv() {
|
|
660
|
-
const result = rgbToHsv(this._rgb);
|
|
661
|
-
if (isHSVA(result)) {
|
|
662
|
-
const { a, ...hsv } = result;
|
|
663
|
-
return hsv;
|
|
664
|
-
}
|
|
665
|
-
return result;
|
|
666
|
-
}
|
|
667
|
-
/**
|
|
668
|
-
* Получает HSVA представление цвета
|
|
669
|
-
*/
|
|
670
|
-
get hsva() {
|
|
671
|
-
const result = rgbToHsv(this._rgb);
|
|
672
|
-
if (isHSVA(result))
|
|
673
|
-
return result;
|
|
674
|
-
return { ...result, a: this._rgb.a };
|
|
675
|
-
}
|
|
676
|
-
/**
|
|
677
|
-
* Получает HEX представление цвета
|
|
678
|
-
*/
|
|
679
|
-
get hex() {
|
|
680
|
-
if (this._rgb.a < 1) {
|
|
681
|
-
return rgbToHex(this._rgb);
|
|
682
|
-
}
|
|
683
|
-
return rgbToHex(this.rgb);
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Осветляет цвет
|
|
687
|
-
*
|
|
688
|
-
* @param amount - Процент осветления (0-100)
|
|
689
|
-
* @returns Новый экземпляр Color
|
|
690
|
-
*
|
|
691
|
-
* @example
|
|
692
|
-
* ```typescript
|
|
693
|
-
* new Color("#ff0000").lighten(20).hex; // "#ff6666"
|
|
694
|
-
* ```
|
|
695
|
-
*/
|
|
696
|
-
lighten(amount) {
|
|
697
|
-
const hsl = this.hsla;
|
|
698
|
-
hsl.l = clampPercent(hsl.l + amount);
|
|
699
|
-
return new Color(hslToRgb(hsl));
|
|
700
|
-
}
|
|
701
|
-
/**
|
|
702
|
-
* Затемняет цвет
|
|
703
|
-
*
|
|
704
|
-
* @param amount - Процент затемнения (0-100)
|
|
705
|
-
* @returns Новый экземпляр Color
|
|
706
|
-
*
|
|
707
|
-
* @example
|
|
708
|
-
* ```typescript
|
|
709
|
-
* new Color("#ff0000").darken(20).hex; // "#990000"
|
|
710
|
-
* ```
|
|
711
|
-
*/
|
|
712
|
-
darken(amount) {
|
|
713
|
-
const hsl = this.hsla;
|
|
714
|
-
hsl.l = clampPercent(hsl.l - amount);
|
|
715
|
-
return new Color(hslToRgb(hsl));
|
|
716
|
-
}
|
|
717
|
-
/**
|
|
718
|
-
* Увеличивает насыщенность цвета
|
|
719
|
-
*
|
|
720
|
-
* @param amount - Процент увеличения насыщенности (0-100)
|
|
721
|
-
* @returns Новый экземпляр Color
|
|
722
|
-
*
|
|
723
|
-
* @example
|
|
724
|
-
* ```typescript
|
|
725
|
-
* new Color("#ff6666").saturate(50).hex; // "#ff1a1a"
|
|
726
|
-
* ```
|
|
727
|
-
*/
|
|
728
|
-
saturate(amount) {
|
|
729
|
-
const hsl = this.hsla;
|
|
730
|
-
hsl.s = clampPercent(hsl.s + amount);
|
|
731
|
-
return new Color(hslToRgb(hsl));
|
|
732
|
-
}
|
|
733
|
-
/**
|
|
734
|
-
* Уменьшает насыщенность цвета
|
|
735
|
-
*
|
|
736
|
-
* @param amount - Процент уменьшения насыщенности (0-100)
|
|
737
|
-
* @returns Новый экземпляр Color
|
|
738
|
-
*
|
|
739
|
-
* @example
|
|
740
|
-
* ```typescript
|
|
741
|
-
* new Color("#ff0000").desaturate(50).hex; // "#bf4040"
|
|
742
|
-
* ```
|
|
743
|
-
*/
|
|
744
|
-
desaturate(amount) {
|
|
745
|
-
const hsl = this.hsla;
|
|
746
|
-
hsl.s = clampPercent(hsl.s - amount);
|
|
747
|
-
return new Color(hslToRgb(hsl));
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Устанавливает прозрачность цвета
|
|
751
|
-
*
|
|
752
|
-
* @param alpha - Значение альфа-канала (0-1)
|
|
753
|
-
* @returns Новый экземпляр Color
|
|
754
|
-
*
|
|
755
|
-
* @example
|
|
756
|
-
* ```typescript
|
|
757
|
-
* new Color("#ff0000").opacity(0.5).hex; // "#ff000080"
|
|
758
|
-
* ```
|
|
759
|
-
*/
|
|
760
|
-
opacity(alpha) {
|
|
761
|
-
return new Color({ ...this._rgb, a: clampAlpha(alpha) });
|
|
762
|
-
}
|
|
763
|
-
/**
|
|
764
|
-
* Инвертирует цвет
|
|
765
|
-
*
|
|
766
|
-
* @returns Новый экземпляр Color
|
|
767
|
-
*
|
|
768
|
-
* @example
|
|
769
|
-
* ```typescript
|
|
770
|
-
* new Color("#ff0000").invert().hex; // "#00ffff"
|
|
771
|
-
* ```
|
|
772
|
-
*/
|
|
773
|
-
invert() {
|
|
774
|
-
return new Color({
|
|
775
|
-
r: 255 - this._rgb.r,
|
|
776
|
-
g: 255 - this._rgb.g,
|
|
777
|
-
b: 255 - this._rgb.b,
|
|
778
|
-
a: this._rgb.a,
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Смешивает цвет с другим цветом
|
|
783
|
-
*
|
|
784
|
-
* @param color - Цвет для смешивания
|
|
785
|
-
* @param weight - Вес первого цвета (0-1), по умолчанию 0.5
|
|
786
|
-
* @returns Новый экземпляр Color
|
|
787
|
-
*
|
|
788
|
-
* @example
|
|
789
|
-
* ```typescript
|
|
790
|
-
* new Color("#ff0000").mix(new Color("#0000ff")).hex; // "#800080"
|
|
791
|
-
* new Color("#ff0000").mix(new Color("#0000ff"), 0.75).hex; // "#bf0040"
|
|
792
|
-
* ```
|
|
793
|
-
*/
|
|
794
|
-
mix(color, weight = 0.5) {
|
|
795
|
-
const w = clampAlpha(weight);
|
|
796
|
-
const w1 = w;
|
|
797
|
-
const w2 = 1 - w;
|
|
798
|
-
const rgba1 = this._rgb;
|
|
799
|
-
const rgba2 = color._rgb;
|
|
800
|
-
return new Color({
|
|
801
|
-
r: Math.round(rgba1.r * w1 + rgba2.r * w2),
|
|
802
|
-
g: Math.round(rgba1.g * w1 + rgba2.g * w2),
|
|
803
|
-
b: Math.round(rgba1.b * w1 + rgba2.b * w2),
|
|
804
|
-
a: rgba1.a * w1 + rgba2.a * w2,
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
/**
|
|
808
|
-
* Вычисляет относительную яркость цвета
|
|
809
|
-
*
|
|
810
|
-
* @returns Относительная яркость (0-1)
|
|
811
|
-
*
|
|
812
|
-
* @example
|
|
813
|
-
* ```typescript
|
|
814
|
-
* new Color("#ffffff").luminance(); // 1
|
|
815
|
-
* new Color("#000000").luminance(); // 0
|
|
816
|
-
* ```
|
|
817
|
-
*/
|
|
818
|
-
luminance() {
|
|
819
|
-
return getLuminance(this.rgb);
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* Вычисляет контрастность с другим цветом
|
|
823
|
-
*
|
|
824
|
-
* @param color - Цвет для сравнения
|
|
825
|
-
* @returns Коэффициент контрастности (1-21)
|
|
826
|
-
*
|
|
827
|
-
* @example
|
|
828
|
-
* ```typescript
|
|
829
|
-
* new Color("#ffffff").contrast(new Color("#000000")); // 21
|
|
830
|
-
* new Color("#ffffff").contrast(new Color("#ffffff")); // 1
|
|
831
|
-
* ```
|
|
832
|
-
*/
|
|
833
|
-
contrast(color) {
|
|
834
|
-
return getContrast(this.rgb, color.rgb);
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* Проверяет, является ли цвет светлым
|
|
838
|
-
*
|
|
839
|
-
* @returns true, если яркость > 0.5
|
|
840
|
-
*
|
|
841
|
-
* @example
|
|
842
|
-
* ```typescript
|
|
843
|
-
* new Color("#ffffff").isLight(); // true
|
|
844
|
-
* new Color("#000000").isLight(); // false
|
|
845
|
-
* ```
|
|
846
|
-
*/
|
|
847
|
-
isLight() {
|
|
848
|
-
return this.luminance() > 0.5;
|
|
849
|
-
}
|
|
850
|
-
/**
|
|
851
|
-
* Проверяет, является ли цвет тёмным
|
|
852
|
-
*
|
|
853
|
-
* @returns true, если яркость <= 0.5
|
|
854
|
-
*
|
|
855
|
-
* @example
|
|
856
|
-
* ```typescript
|
|
857
|
-
* new Color("#000000").isDark(); // true
|
|
858
|
-
* new Color("#ffffff").isDark(); // false
|
|
859
|
-
* ```
|
|
860
|
-
*/
|
|
861
|
-
isDark() {
|
|
862
|
-
return !this.isLight();
|
|
863
|
-
}
|
|
864
|
-
/**
|
|
865
|
-
* Преобразует цвет в строку
|
|
866
|
-
*
|
|
867
|
-
* @param format - Формат вывода (hex, rgb, hsl), по умолчанию hex
|
|
868
|
-
* @returns Строковое представление цвета
|
|
869
|
-
*
|
|
870
|
-
* @example
|
|
871
|
-
* ```typescript
|
|
872
|
-
* new Color("#ff0000").toString(); // "#ff0000"
|
|
873
|
-
* new Color("#ff0000").toString("rgb"); // "rgb(255, 0, 0)"
|
|
874
|
-
* new Color("#ff0000").toString("hsl"); // "hsl(0, 100%, 50%)"
|
|
875
|
-
* ```
|
|
876
|
-
*/
|
|
877
|
-
toString(format = "hex") {
|
|
878
|
-
switch (format) {
|
|
879
|
-
case "rgb":
|
|
880
|
-
return toRgbString(this._rgb);
|
|
881
|
-
case "hsl":
|
|
882
|
-
return toHslString(this.hsla);
|
|
883
|
-
case "hex":
|
|
884
|
-
default:
|
|
885
|
-
return this.hex;
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
}
|