@etsoo/shared 1.1.14 → 1.1.17

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/README.md CHANGED
@@ -18,6 +18,22 @@ $ yarn add @etsoo/shared
18
18
  ## storage
19
19
  Storage interface and browser storage implementation
20
20
 
21
+ ## EColor
22
+ Etsoo implmented Color
23
+
24
+ |Name|Description|
25
+ |---:|---|
26
+ |static getColors|Get HEX or RGB colors|
27
+ |static getEColors|Get EColors|
28
+ |static parse|Parse HTML color to EColor|
29
+ |clone|Clone color with adjustments|
30
+ |getContrastRatio|Get contrast ratio, a value between 0 and 1|
31
+ |getDeltaValue|Get Delta value (perceptible by human eyes)|
32
+ |getLuminance|Get luminance|
33
+ |toHEXColor|To HEX color string|
34
+ |toLabValue|To Lab value|
35
+ |toRGBColor|To RGB color string|
36
+
21
37
  ## Keyboard
22
38
  Keyboard keys and codes
23
39
 
@@ -0,0 +1,25 @@
1
+ import { EColor } from '../src/types/EColor';
2
+
3
+ test('Tests for parse', () => {
4
+ // Arrange & act
5
+ const colorShort = EColor.parse('#000');
6
+ const color = EColor.parse('#e21821');
7
+ const colorRgb = EColor.parse('RGB(226, 24, 33)');
8
+
9
+ // Assert
10
+ expect(colorShort?.toRGBColor()).toBe('RGB(0, 0, 0)');
11
+ expect(color?.toRGBColor()).toBe('RGB(226, 24, 33)');
12
+ expect(colorRgb?.toHEXColor()).toBe('#e21821');
13
+ });
14
+
15
+ test('Tests for getColors', () => {
16
+ const colors = EColor.getColors(undefined, 128);
17
+ expect(colors.length).toBe(8);
18
+ });
19
+
20
+ test('Tests for toRGBColor', () => {
21
+ const color = new EColor(0, 0, 0);
22
+ expect(color.toRGBColor()).toBe('RGB(0, 0, 0)');
23
+ expect(color.toRGBColor(0.1)).toBe('RGBA(0, 0, 0, 0.1)');
24
+ expect(color.alpha).toBeUndefined();
25
+ });
@@ -1,5 +1,6 @@
1
- export * from './types/FormData';
2
1
  export * from './types/DelayedExecutorType';
2
+ export * from './types/EColor';
3
+ export * from './types/FormData';
3
4
  export * from './storage/IStorage';
4
5
  export * from './storage/WindowStorage';
5
6
  export * from './DataTypes';
package/lib/cjs/index.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -10,8 +14,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
15
  };
12
16
  Object.defineProperty(exports, "__esModule", { value: true });
13
- __exportStar(require("./types/FormData"), exports);
14
17
  __exportStar(require("./types/DelayedExecutorType"), exports);
18
+ __exportStar(require("./types/EColor"), exports);
19
+ __exportStar(require("./types/FormData"), exports);
15
20
  __exportStar(require("./storage/IStorage"), exports);
16
21
  __exportStar(require("./storage/WindowStorage"), exports);
17
22
  __exportStar(require("./DataTypes"), exports);
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Etsoo implmented Color
3
+ */
4
+ export declare class EColor {
5
+ readonly r: number;
6
+ readonly g: number;
7
+ readonly b: number;
8
+ readonly alpha?: number | undefined;
9
+ /**
10
+ * Adjust value
11
+ * @param value Current value
12
+ * @param adjust Adjust value
13
+ * @returns Adjusted value
14
+ */
15
+ static adjust(value: number, adjust?: number): number;
16
+ /**
17
+ * Get HEX or RGB colors
18
+ * @param init Initial color
19
+ * @param factor Increase factor
20
+ * @param adjustOrder Adjust order to increase difference
21
+ * @param hex to HEX or not
22
+ * @returns Result
23
+ */
24
+ static getColors(init?: string, factor?: number, adjustOrder?: boolean, hex?: boolean): string[];
25
+ /**
26
+ * Get EColors
27
+ * @param init Initial color
28
+ * @param factor Increase factor
29
+ * @param adjustOrder Adjust order to increase difference
30
+ * @returns Result
31
+ */
32
+ static getEColors(init?: string, factor?: number, adjustOrder?: boolean): EColor[];
33
+ /**
34
+ * HEX string to integer value
35
+ * @param hex HEX string
36
+ * @returns Integer value
37
+ */
38
+ static hexTo(hex: string): number;
39
+ /**
40
+ * Format value to 16 radix string
41
+ * @param num Int value
42
+ * @returns Result
43
+ */
44
+ static toHex(num: number): string;
45
+ /**
46
+ * Parse HTML color to EColor
47
+ * @param htmlColor HTML color
48
+ * @returns EColor
49
+ */
50
+ static parse(htmlColor?: string | null): EColor | undefined;
51
+ /**
52
+ * Constructor
53
+ * @param r Reg
54
+ * @param g Green
55
+ * @param b Blue
56
+ * @param alpha Alpha
57
+ */
58
+ constructor(r: number, g: number, b: number, alpha?: number | undefined);
59
+ /**
60
+ * Clone color with adjustments
61
+ * @param adjustR Adjust R value
62
+ * @param adjustG Adjust G value
63
+ * @param adjustB Adjust B value
64
+ * @param alpha New alpha value
65
+ */
66
+ clone(adjustR?: number, adjustG?: number, adjustB?: number, alpha?: number): EColor | undefined;
67
+ /**
68
+ * Get contrast ratio, a value between 0 and 1
69
+ * @param color Contrast color
70
+ */
71
+ getContrastRatio(color: EColor): number;
72
+ /**
73
+ * Get Delta value (perceptible by human eyes)
74
+ * <= 1, Not perceptible by human eyes
75
+ * 1 - 2, Perceptible through close observation
76
+ * 2 - 10, Perceptible at a glance
77
+ * 11 - 49, Colors are more similar than opposite
78
+ * 100+, Colors are exact opposite
79
+ * @param color Contrast color
80
+ * @returns Value
81
+ */
82
+ getDeltaValue(color: EColor): number;
83
+ /**
84
+ * Get luminance
85
+ * Darker one has higher luminance
86
+ * https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
87
+ */
88
+ getLuminance(): number;
89
+ /**
90
+ * To HEX color string
91
+ * @returns HEX color string
92
+ */
93
+ toHEXColor(): string;
94
+ /**
95
+ * To Lab value
96
+ * @returns Lab value
97
+ */
98
+ toLabValue(): [number, number, number];
99
+ /**
100
+ * To RGB color string
101
+ * @param alpha Alpha value, false means ignore it
102
+ * @returns RGB color string
103
+ */
104
+ toRGBColor(alpha?: boolean | number): string;
105
+ }
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EColor = void 0;
4
+ /**
5
+ * Etsoo implmented Color
6
+ */
7
+ class EColor {
8
+ /**
9
+ * Constructor
10
+ * @param r Reg
11
+ * @param g Green
12
+ * @param b Blue
13
+ * @param alpha Alpha
14
+ */
15
+ constructor(r, g, b, alpha) {
16
+ this.r = r;
17
+ this.g = g;
18
+ this.b = b;
19
+ this.alpha = alpha;
20
+ }
21
+ /**
22
+ * Adjust value
23
+ * @param value Current value
24
+ * @param adjust Adjust value
25
+ * @returns Adjusted value
26
+ */
27
+ static adjust(value, adjust) {
28
+ if (adjust == null)
29
+ return value;
30
+ value = Math.abs(value + adjust);
31
+ if (value > 255)
32
+ return value % 255;
33
+ return value;
34
+ }
35
+ /**
36
+ * Get HEX or RGB colors
37
+ * @param init Initial color
38
+ * @param factor Increase factor
39
+ * @param adjustOrder Adjust order to increase difference
40
+ * @param hex to HEX or not
41
+ * @returns Result
42
+ */
43
+ static getColors(init = '#000', factor = 51, adjustOrder = true, hex = true) {
44
+ return EColor.getEColors(init, factor, adjustOrder).map((c) => hex ? c.toHEXColor() : c.toRGBColor());
45
+ }
46
+ /**
47
+ * Get EColors
48
+ * @param init Initial color
49
+ * @param factor Increase factor
50
+ * @param adjustOrder Adjust order to increase difference
51
+ * @returns Result
52
+ */
53
+ static getEColors(init = '#000', factor = 51, adjustOrder = true) {
54
+ var _a;
55
+ // Init color
56
+ const initColor = (_a = EColor.parse(init)) !== null && _a !== void 0 ? _a : new EColor(0, 0, 0);
57
+ // Factors elements
58
+ // 51 = '00', '33', '66', '99', 'cc', 'ff'
59
+ const factors = [];
60
+ let f = 0;
61
+ while (f <= 255) {
62
+ factors.push(f);
63
+ f += factor;
64
+ }
65
+ // RGB loop
66
+ const colors = [initColor];
67
+ for (const r of factors) {
68
+ for (const g of factors) {
69
+ for (const b of factors) {
70
+ colors.push(initColor.clone(r, g, b));
71
+ }
72
+ }
73
+ }
74
+ // Non-nullable colors
75
+ const nColors = colors.filter((color) => color != null);
76
+ // Adjust order
77
+ if (adjustOrder) {
78
+ const firstColor = nColors.shift();
79
+ if (firstColor) {
80
+ let color = firstColor;
81
+ const newColors = [color];
82
+ while (nColors.length > 0) {
83
+ const result = nColors.reduce((p, c, index) => {
84
+ const delta = color.getDeltaValue(c);
85
+ if (delta != null && delta > p.delta) {
86
+ p.delta = delta;
87
+ p.color = c;
88
+ p.index = index;
89
+ }
90
+ return p;
91
+ }, { delta: 0, color, index: -1 });
92
+ if (result.delta > 0) {
93
+ color = result.color;
94
+ newColors.push(color);
95
+ nColors.splice(result.index, 1);
96
+ }
97
+ }
98
+ return newColors;
99
+ }
100
+ }
101
+ return nColors;
102
+ }
103
+ /**
104
+ * HEX string to integer value
105
+ * @param hex HEX string
106
+ * @returns Integer value
107
+ */
108
+ static hexTo(hex) {
109
+ return parseInt(hex, 16);
110
+ }
111
+ /**
112
+ * Format value to 16 radix string
113
+ * @param num Int value
114
+ * @returns Result
115
+ */
116
+ static toHex(num) {
117
+ return num.toString(16).padStart(2, '0');
118
+ }
119
+ /**
120
+ * Parse HTML color to EColor
121
+ * @param htmlColor HTML color
122
+ * @returns EColor
123
+ */
124
+ static parse(htmlColor) {
125
+ // Null
126
+ if (htmlColor == null)
127
+ return undefined;
128
+ htmlColor = htmlColor.toUpperCase();
129
+ // HEX color
130
+ if (htmlColor.startsWith('#')) {
131
+ htmlColor = htmlColor.substring(1);
132
+ if (htmlColor.length === 3)
133
+ htmlColor = Array.from(htmlColor)
134
+ .map((c) => c + c)
135
+ .join('');
136
+ if (htmlColor.length === 6) {
137
+ return new EColor(EColor.hexTo(htmlColor.substring(0, 2)), EColor.hexTo(htmlColor.substring(2, 4)), EColor.hexTo(htmlColor.substring(4, 6)));
138
+ }
139
+ return undefined;
140
+ }
141
+ // For RGB and RGBA
142
+ const reg = /^RGBA?\(([0-9,\s\.]+)\)$/;
143
+ const result = htmlColor.match(reg);
144
+ if (result != null && result.length == 2) {
145
+ const parts = result[1].split(/\s*,\s*/);
146
+ if (parts.length === 3 || parts.length === 4) {
147
+ const alpha = parts[3];
148
+ return new EColor(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]), alpha == null ? undefined : parseFloat(alpha));
149
+ }
150
+ }
151
+ return undefined;
152
+ }
153
+ /**
154
+ * Clone color with adjustments
155
+ * @param adjustR Adjust R value
156
+ * @param adjustG Adjust G value
157
+ * @param adjustB Adjust B value
158
+ * @param alpha New alpha value
159
+ */
160
+ clone(adjustR, adjustG, adjustB, alpha) {
161
+ const r = EColor.adjust(this.r, adjustR);
162
+ const g = EColor.adjust(this.g, adjustG);
163
+ const b = EColor.adjust(this.b, adjustB);
164
+ if (r === this.r &&
165
+ g === this.g &&
166
+ b === this.b &&
167
+ (alpha == null || alpha === this.alpha))
168
+ return undefined;
169
+ return new EColor(r, g, b, alpha);
170
+ }
171
+ /**
172
+ * Get contrast ratio, a value between 0 and 1
173
+ * @param color Contrast color
174
+ */
175
+ getContrastRatio(color) {
176
+ const lum1 = this.getLuminance();
177
+ const lum2 = color.getLuminance();
178
+ const brightest = Math.max(lum1, lum2);
179
+ const darkest = Math.min(lum1, lum2);
180
+ return (brightest + 0.05) / (darkest + 0.05);
181
+ }
182
+ /**
183
+ * Get Delta value (perceptible by human eyes)
184
+ * <= 1, Not perceptible by human eyes
185
+ * 1 - 2, Perceptible through close observation
186
+ * 2 - 10, Perceptible at a glance
187
+ * 11 - 49, Colors are more similar than opposite
188
+ * 100+, Colors are exact opposite
189
+ * @param color Contrast color
190
+ * @returns Value
191
+ */
192
+ getDeltaValue(color) {
193
+ const labA = this.toLabValue();
194
+ const labB = color.toLabValue();
195
+ const deltaL = labA[0] - labB[0];
196
+ const deltaA = labA[1] - labB[1];
197
+ const deltaB = labA[2] - labB[2];
198
+ const c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
199
+ const c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
200
+ const deltaC = c1 - c2;
201
+ let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
202
+ deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
203
+ const sc = 1.0 + 0.045 * c1;
204
+ const sh = 1.0 + 0.015 * c1;
205
+ const deltaLKlsl = deltaL / 1.0;
206
+ const deltaCkcsc = deltaC / sc;
207
+ const deltaHkhsh = deltaH / sh;
208
+ const i = deltaLKlsl * deltaLKlsl +
209
+ deltaCkcsc * deltaCkcsc +
210
+ deltaHkhsh * deltaHkhsh;
211
+ return i < 0 ? 0 : Math.sqrt(i);
212
+ }
213
+ /**
214
+ * Get luminance
215
+ * Darker one has higher luminance
216
+ * https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
217
+ */
218
+ getLuminance() {
219
+ const a = [this.r, this.g, this.b].map((v) => {
220
+ v /= 255;
221
+ return v <= 0.03928
222
+ ? v / 12.92
223
+ : Math.pow((v + 0.055) / 1.055, 2.4);
224
+ });
225
+ return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
226
+ }
227
+ /**
228
+ * To HEX color string
229
+ * @returns HEX color string
230
+ */
231
+ toHEXColor() {
232
+ return `#${EColor.toHex(this.r)}${EColor.toHex(this.g)}${EColor.toHex(this.b)}`;
233
+ }
234
+ /**
235
+ * To Lab value
236
+ * @returns Lab value
237
+ */
238
+ toLabValue() {
239
+ let r = this.r / 255, g = this.g / 255, b = this.b / 255, x, y, z;
240
+ r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
241
+ g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
242
+ b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
243
+ x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
244
+ y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0;
245
+ z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
246
+ x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
247
+ y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
248
+ z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
249
+ return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
250
+ }
251
+ /**
252
+ * To RGB color string
253
+ * @param alpha Alpha value, false means ignore it
254
+ * @returns RGB color string
255
+ */
256
+ toRGBColor(alpha) {
257
+ // Decide
258
+ let includeAlpha, alphaValue = this.alpha;
259
+ if (typeof alpha === 'number') {
260
+ alphaValue = alpha;
261
+ includeAlpha = true;
262
+ }
263
+ else if (alpha == null) {
264
+ includeAlpha = this.alpha != null;
265
+ }
266
+ else {
267
+ includeAlpha = alpha;
268
+ }
269
+ if (includeAlpha)
270
+ return `RGBA(${this.r}, ${this.g}, ${this.b}, ${alphaValue !== null && alphaValue !== void 0 ? alphaValue : 1})`;
271
+ return `RGB(${this.r}, ${this.g}, ${this.b})`;
272
+ }
273
+ }
274
+ exports.EColor = EColor;
@@ -1,5 +1,6 @@
1
- export * from './types/FormData';
2
1
  export * from './types/DelayedExecutorType';
2
+ export * from './types/EColor';
3
+ export * from './types/FormData';
3
4
  export * from './storage/IStorage';
4
5
  export * from './storage/WindowStorage';
5
6
  export * from './DataTypes';
package/lib/mjs/index.js CHANGED
@@ -1,5 +1,6 @@
1
- export * from './types/FormData';
2
1
  export * from './types/DelayedExecutorType';
2
+ export * from './types/EColor';
3
+ export * from './types/FormData';
3
4
  export * from './storage/IStorage';
4
5
  export * from './storage/WindowStorage';
5
6
  export * from './DataTypes';
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Etsoo implmented Color
3
+ */
4
+ export declare class EColor {
5
+ readonly r: number;
6
+ readonly g: number;
7
+ readonly b: number;
8
+ readonly alpha?: number | undefined;
9
+ /**
10
+ * Adjust value
11
+ * @param value Current value
12
+ * @param adjust Adjust value
13
+ * @returns Adjusted value
14
+ */
15
+ static adjust(value: number, adjust?: number): number;
16
+ /**
17
+ * Get HEX or RGB colors
18
+ * @param init Initial color
19
+ * @param factor Increase factor
20
+ * @param adjustOrder Adjust order to increase difference
21
+ * @param hex to HEX or not
22
+ * @returns Result
23
+ */
24
+ static getColors(init?: string, factor?: number, adjustOrder?: boolean, hex?: boolean): string[];
25
+ /**
26
+ * Get EColors
27
+ * @param init Initial color
28
+ * @param factor Increase factor
29
+ * @param adjustOrder Adjust order to increase difference
30
+ * @returns Result
31
+ */
32
+ static getEColors(init?: string, factor?: number, adjustOrder?: boolean): EColor[];
33
+ /**
34
+ * HEX string to integer value
35
+ * @param hex HEX string
36
+ * @returns Integer value
37
+ */
38
+ static hexTo(hex: string): number;
39
+ /**
40
+ * Format value to 16 radix string
41
+ * @param num Int value
42
+ * @returns Result
43
+ */
44
+ static toHex(num: number): string;
45
+ /**
46
+ * Parse HTML color to EColor
47
+ * @param htmlColor HTML color
48
+ * @returns EColor
49
+ */
50
+ static parse(htmlColor?: string | null): EColor | undefined;
51
+ /**
52
+ * Constructor
53
+ * @param r Reg
54
+ * @param g Green
55
+ * @param b Blue
56
+ * @param alpha Alpha
57
+ */
58
+ constructor(r: number, g: number, b: number, alpha?: number | undefined);
59
+ /**
60
+ * Clone color with adjustments
61
+ * @param adjustR Adjust R value
62
+ * @param adjustG Adjust G value
63
+ * @param adjustB Adjust B value
64
+ * @param alpha New alpha value
65
+ */
66
+ clone(adjustR?: number, adjustG?: number, adjustB?: number, alpha?: number): EColor | undefined;
67
+ /**
68
+ * Get contrast ratio, a value between 0 and 1
69
+ * @param color Contrast color
70
+ */
71
+ getContrastRatio(color: EColor): number;
72
+ /**
73
+ * Get Delta value (perceptible by human eyes)
74
+ * <= 1, Not perceptible by human eyes
75
+ * 1 - 2, Perceptible through close observation
76
+ * 2 - 10, Perceptible at a glance
77
+ * 11 - 49, Colors are more similar than opposite
78
+ * 100+, Colors are exact opposite
79
+ * @param color Contrast color
80
+ * @returns Value
81
+ */
82
+ getDeltaValue(color: EColor): number;
83
+ /**
84
+ * Get luminance
85
+ * Darker one has higher luminance
86
+ * https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
87
+ */
88
+ getLuminance(): number;
89
+ /**
90
+ * To HEX color string
91
+ * @returns HEX color string
92
+ */
93
+ toHEXColor(): string;
94
+ /**
95
+ * To Lab value
96
+ * @returns Lab value
97
+ */
98
+ toLabValue(): [number, number, number];
99
+ /**
100
+ * To RGB color string
101
+ * @param alpha Alpha value, false means ignore it
102
+ * @returns RGB color string
103
+ */
104
+ toRGBColor(alpha?: boolean | number): string;
105
+ }
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Etsoo implmented Color
3
+ */
4
+ export class EColor {
5
+ /**
6
+ * Constructor
7
+ * @param r Reg
8
+ * @param g Green
9
+ * @param b Blue
10
+ * @param alpha Alpha
11
+ */
12
+ constructor(r, g, b, alpha) {
13
+ this.r = r;
14
+ this.g = g;
15
+ this.b = b;
16
+ this.alpha = alpha;
17
+ }
18
+ /**
19
+ * Adjust value
20
+ * @param value Current value
21
+ * @param adjust Adjust value
22
+ * @returns Adjusted value
23
+ */
24
+ static adjust(value, adjust) {
25
+ if (adjust == null)
26
+ return value;
27
+ value = Math.abs(value + adjust);
28
+ if (value > 255)
29
+ return value % 255;
30
+ return value;
31
+ }
32
+ /**
33
+ * Get HEX or RGB colors
34
+ * @param init Initial color
35
+ * @param factor Increase factor
36
+ * @param adjustOrder Adjust order to increase difference
37
+ * @param hex to HEX or not
38
+ * @returns Result
39
+ */
40
+ static getColors(init = '#000', factor = 51, adjustOrder = true, hex = true) {
41
+ return EColor.getEColors(init, factor, adjustOrder).map((c) => hex ? c.toHEXColor() : c.toRGBColor());
42
+ }
43
+ /**
44
+ * Get EColors
45
+ * @param init Initial color
46
+ * @param factor Increase factor
47
+ * @param adjustOrder Adjust order to increase difference
48
+ * @returns Result
49
+ */
50
+ static getEColors(init = '#000', factor = 51, adjustOrder = true) {
51
+ var _a;
52
+ // Init color
53
+ const initColor = (_a = EColor.parse(init)) !== null && _a !== void 0 ? _a : new EColor(0, 0, 0);
54
+ // Factors elements
55
+ // 51 = '00', '33', '66', '99', 'cc', 'ff'
56
+ const factors = [];
57
+ let f = 0;
58
+ while (f <= 255) {
59
+ factors.push(f);
60
+ f += factor;
61
+ }
62
+ // RGB loop
63
+ const colors = [initColor];
64
+ for (const r of factors) {
65
+ for (const g of factors) {
66
+ for (const b of factors) {
67
+ colors.push(initColor.clone(r, g, b));
68
+ }
69
+ }
70
+ }
71
+ // Non-nullable colors
72
+ const nColors = colors.filter((color) => color != null);
73
+ // Adjust order
74
+ if (adjustOrder) {
75
+ const firstColor = nColors.shift();
76
+ if (firstColor) {
77
+ let color = firstColor;
78
+ const newColors = [color];
79
+ while (nColors.length > 0) {
80
+ const result = nColors.reduce((p, c, index) => {
81
+ const delta = color.getDeltaValue(c);
82
+ if (delta != null && delta > p.delta) {
83
+ p.delta = delta;
84
+ p.color = c;
85
+ p.index = index;
86
+ }
87
+ return p;
88
+ }, { delta: 0, color, index: -1 });
89
+ if (result.delta > 0) {
90
+ color = result.color;
91
+ newColors.push(color);
92
+ nColors.splice(result.index, 1);
93
+ }
94
+ }
95
+ return newColors;
96
+ }
97
+ }
98
+ return nColors;
99
+ }
100
+ /**
101
+ * HEX string to integer value
102
+ * @param hex HEX string
103
+ * @returns Integer value
104
+ */
105
+ static hexTo(hex) {
106
+ return parseInt(hex, 16);
107
+ }
108
+ /**
109
+ * Format value to 16 radix string
110
+ * @param num Int value
111
+ * @returns Result
112
+ */
113
+ static toHex(num) {
114
+ return num.toString(16).padStart(2, '0');
115
+ }
116
+ /**
117
+ * Parse HTML color to EColor
118
+ * @param htmlColor HTML color
119
+ * @returns EColor
120
+ */
121
+ static parse(htmlColor) {
122
+ // Null
123
+ if (htmlColor == null)
124
+ return undefined;
125
+ htmlColor = htmlColor.toUpperCase();
126
+ // HEX color
127
+ if (htmlColor.startsWith('#')) {
128
+ htmlColor = htmlColor.substring(1);
129
+ if (htmlColor.length === 3)
130
+ htmlColor = Array.from(htmlColor)
131
+ .map((c) => c + c)
132
+ .join('');
133
+ if (htmlColor.length === 6) {
134
+ return new EColor(EColor.hexTo(htmlColor.substring(0, 2)), EColor.hexTo(htmlColor.substring(2, 4)), EColor.hexTo(htmlColor.substring(4, 6)));
135
+ }
136
+ return undefined;
137
+ }
138
+ // For RGB and RGBA
139
+ const reg = /^RGBA?\(([0-9,\s\.]+)\)$/;
140
+ const result = htmlColor.match(reg);
141
+ if (result != null && result.length == 2) {
142
+ const parts = result[1].split(/\s*,\s*/);
143
+ if (parts.length === 3 || parts.length === 4) {
144
+ const alpha = parts[3];
145
+ return new EColor(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]), alpha == null ? undefined : parseFloat(alpha));
146
+ }
147
+ }
148
+ return undefined;
149
+ }
150
+ /**
151
+ * Clone color with adjustments
152
+ * @param adjustR Adjust R value
153
+ * @param adjustG Adjust G value
154
+ * @param adjustB Adjust B value
155
+ * @param alpha New alpha value
156
+ */
157
+ clone(adjustR, adjustG, adjustB, alpha) {
158
+ const r = EColor.adjust(this.r, adjustR);
159
+ const g = EColor.adjust(this.g, adjustG);
160
+ const b = EColor.adjust(this.b, adjustB);
161
+ if (r === this.r &&
162
+ g === this.g &&
163
+ b === this.b &&
164
+ (alpha == null || alpha === this.alpha))
165
+ return undefined;
166
+ return new EColor(r, g, b, alpha);
167
+ }
168
+ /**
169
+ * Get contrast ratio, a value between 0 and 1
170
+ * @param color Contrast color
171
+ */
172
+ getContrastRatio(color) {
173
+ const lum1 = this.getLuminance();
174
+ const lum2 = color.getLuminance();
175
+ const brightest = Math.max(lum1, lum2);
176
+ const darkest = Math.min(lum1, lum2);
177
+ return (brightest + 0.05) / (darkest + 0.05);
178
+ }
179
+ /**
180
+ * Get Delta value (perceptible by human eyes)
181
+ * <= 1, Not perceptible by human eyes
182
+ * 1 - 2, Perceptible through close observation
183
+ * 2 - 10, Perceptible at a glance
184
+ * 11 - 49, Colors are more similar than opposite
185
+ * 100+, Colors are exact opposite
186
+ * @param color Contrast color
187
+ * @returns Value
188
+ */
189
+ getDeltaValue(color) {
190
+ const labA = this.toLabValue();
191
+ const labB = color.toLabValue();
192
+ const deltaL = labA[0] - labB[0];
193
+ const deltaA = labA[1] - labB[1];
194
+ const deltaB = labA[2] - labB[2];
195
+ const c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
196
+ const c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
197
+ const deltaC = c1 - c2;
198
+ let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
199
+ deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
200
+ const sc = 1.0 + 0.045 * c1;
201
+ const sh = 1.0 + 0.015 * c1;
202
+ const deltaLKlsl = deltaL / 1.0;
203
+ const deltaCkcsc = deltaC / sc;
204
+ const deltaHkhsh = deltaH / sh;
205
+ const i = deltaLKlsl * deltaLKlsl +
206
+ deltaCkcsc * deltaCkcsc +
207
+ deltaHkhsh * deltaHkhsh;
208
+ return i < 0 ? 0 : Math.sqrt(i);
209
+ }
210
+ /**
211
+ * Get luminance
212
+ * Darker one has higher luminance
213
+ * https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
214
+ */
215
+ getLuminance() {
216
+ const a = [this.r, this.g, this.b].map((v) => {
217
+ v /= 255;
218
+ return v <= 0.03928
219
+ ? v / 12.92
220
+ : Math.pow((v + 0.055) / 1.055, 2.4);
221
+ });
222
+ return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
223
+ }
224
+ /**
225
+ * To HEX color string
226
+ * @returns HEX color string
227
+ */
228
+ toHEXColor() {
229
+ return `#${EColor.toHex(this.r)}${EColor.toHex(this.g)}${EColor.toHex(this.b)}`;
230
+ }
231
+ /**
232
+ * To Lab value
233
+ * @returns Lab value
234
+ */
235
+ toLabValue() {
236
+ let r = this.r / 255, g = this.g / 255, b = this.b / 255, x, y, z;
237
+ r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
238
+ g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
239
+ b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
240
+ x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
241
+ y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0;
242
+ z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
243
+ x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
244
+ y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
245
+ z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
246
+ return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
247
+ }
248
+ /**
249
+ * To RGB color string
250
+ * @param alpha Alpha value, false means ignore it
251
+ * @returns RGB color string
252
+ */
253
+ toRGBColor(alpha) {
254
+ // Decide
255
+ let includeAlpha, alphaValue = this.alpha;
256
+ if (typeof alpha === 'number') {
257
+ alphaValue = alpha;
258
+ includeAlpha = true;
259
+ }
260
+ else if (alpha == null) {
261
+ includeAlpha = this.alpha != null;
262
+ }
263
+ else {
264
+ includeAlpha = alpha;
265
+ }
266
+ if (includeAlpha)
267
+ return `RGBA(${this.r}, ${this.g}, ${this.b}, ${alphaValue !== null && alphaValue !== void 0 ? alphaValue : 1})`;
268
+ return `RGB(${this.r}, ${this.g}, ${this.b})`;
269
+ }
270
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/shared",
3
- "version": "1.1.14",
3
+ "version": "1.1.17",
4
4
  "description": "TypeScript shared utilities and functions",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -55,13 +55,13 @@
55
55
  "dependencies": {},
56
56
  "devDependencies": {
57
57
  "@types/jest": "^27.4.1",
58
- "@typescript-eslint/eslint-plugin": "^5.12.1",
59
- "@typescript-eslint/parser": "^5.12.1",
58
+ "@typescript-eslint/eslint-plugin": "^5.14.0",
59
+ "@typescript-eslint/parser": "^5.14.0",
60
60
  "eslint": "^8.10.0",
61
61
  "eslint-config-airbnb-base": "^15.0.0",
62
62
  "eslint-plugin-import": "^2.25.4",
63
63
  "jest": "^27.5.1",
64
64
  "ts-jest": "^27.1.3",
65
- "typescript": "^4.5.5"
65
+ "typescript": "^4.6.2"
66
66
  }
67
67
  }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
- export * from './types/FormData';
2
1
  export * from './types/DelayedExecutorType';
2
+ export * from './types/EColor';
3
+ export * from './types/FormData';
3
4
 
4
5
  export * from './storage/IStorage';
5
6
  export * from './storage/WindowStorage';
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Etsoo implmented Color
3
+ */
4
+ export class EColor {
5
+ /**
6
+ * Adjust value
7
+ * @param value Current value
8
+ * @param adjust Adjust value
9
+ * @returns Adjusted value
10
+ */
11
+ static adjust(value: number, adjust?: number) {
12
+ if (adjust == null) return value;
13
+ value = Math.abs(value + adjust);
14
+ if (value > 255) return value % 255;
15
+ return value;
16
+ }
17
+
18
+ /**
19
+ * Get HEX or RGB colors
20
+ * @param init Initial color
21
+ * @param factor Increase factor
22
+ * @param adjustOrder Adjust order to increase difference
23
+ * @param hex to HEX or not
24
+ * @returns Result
25
+ */
26
+ static getColors(
27
+ init: string = '#000',
28
+ factor: number = 51,
29
+ adjustOrder: boolean = true,
30
+ hex: boolean = true
31
+ ) {
32
+ return EColor.getEColors(init, factor, adjustOrder).map((c) =>
33
+ hex ? c.toHEXColor() : c.toRGBColor()
34
+ );
35
+ }
36
+
37
+ /**
38
+ * Get EColors
39
+ * @param init Initial color
40
+ * @param factor Increase factor
41
+ * @param adjustOrder Adjust order to increase difference
42
+ * @returns Result
43
+ */
44
+ static getEColors(
45
+ init: string = '#000',
46
+ factor: number = 51,
47
+ adjustOrder: boolean = true
48
+ ): EColor[] {
49
+ // Init color
50
+ const initColor = EColor.parse(init) ?? new EColor(0, 0, 0);
51
+
52
+ // Factors elements
53
+ // 51 = '00', '33', '66', '99', 'cc', 'ff'
54
+ const factors: number[] = [];
55
+ let f = 0;
56
+ while (f <= 255) {
57
+ factors.push(f);
58
+ f += factor;
59
+ }
60
+
61
+ // RGB loop
62
+ const colors: (EColor | undefined)[] = [initColor];
63
+ for (const r of factors) {
64
+ for (const g of factors) {
65
+ for (const b of factors) {
66
+ colors.push(initColor.clone(r, g, b));
67
+ }
68
+ }
69
+ }
70
+
71
+ // Non-nullable colors
72
+ const nColors = colors.filter(
73
+ (color): color is EColor => color != null
74
+ );
75
+
76
+ // Adjust order
77
+ if (adjustOrder) {
78
+ const firstColor = nColors.shift();
79
+ if (firstColor) {
80
+ let color = firstColor;
81
+ const newColors: EColor[] = [color];
82
+
83
+ while (nColors.length > 0) {
84
+ const result = nColors.reduce(
85
+ (p, c, index) => {
86
+ const delta = color.getDeltaValue(c);
87
+ if (delta != null && delta > p.delta) {
88
+ p.delta = delta;
89
+ p.color = c;
90
+ p.index = index;
91
+ }
92
+ return p;
93
+ },
94
+ { delta: 0, color, index: -1 }
95
+ );
96
+
97
+ if (result.delta > 0) {
98
+ color = result.color;
99
+ newColors.push(color);
100
+ nColors.splice(result.index, 1);
101
+ }
102
+ }
103
+
104
+ return newColors;
105
+ }
106
+ }
107
+
108
+ return nColors;
109
+ }
110
+
111
+ /**
112
+ * HEX string to integer value
113
+ * @param hex HEX string
114
+ * @returns Integer value
115
+ */
116
+ static hexTo(hex: string) {
117
+ return parseInt(hex, 16);
118
+ }
119
+
120
+ /**
121
+ * Format value to 16 radix string
122
+ * @param num Int value
123
+ * @returns Result
124
+ */
125
+ static toHex(num: number) {
126
+ return num.toString(16).padStart(2, '0');
127
+ }
128
+
129
+ /**
130
+ * Parse HTML color to EColor
131
+ * @param htmlColor HTML color
132
+ * @returns EColor
133
+ */
134
+ static parse(htmlColor?: string | null): EColor | undefined {
135
+ // Null
136
+ if (htmlColor == null) return undefined;
137
+ htmlColor = htmlColor.toUpperCase();
138
+
139
+ // HEX color
140
+ if (htmlColor.startsWith('#')) {
141
+ htmlColor = htmlColor.substring(1);
142
+ if (htmlColor.length === 3)
143
+ htmlColor = Array.from(htmlColor)
144
+ .map((c) => c + c)
145
+ .join('');
146
+
147
+ if (htmlColor.length === 6) {
148
+ return new EColor(
149
+ EColor.hexTo(htmlColor.substring(0, 2)),
150
+ EColor.hexTo(htmlColor.substring(2, 4)),
151
+ EColor.hexTo(htmlColor.substring(4, 6))
152
+ );
153
+ }
154
+
155
+ return undefined;
156
+ }
157
+
158
+ // For RGB and RGBA
159
+ const reg = /^RGBA?\(([0-9,\s\.]+)\)$/;
160
+ const result = htmlColor.match(reg);
161
+ if (result != null && result.length == 2) {
162
+ const parts = result[1].split(/\s*,\s*/);
163
+ if (parts.length === 3 || parts.length === 4) {
164
+ const alpha = parts[3];
165
+ return new EColor(
166
+ parseInt(parts[0]),
167
+ parseInt(parts[1]),
168
+ parseInt(parts[2]),
169
+ alpha == null ? undefined : parseFloat(alpha)
170
+ );
171
+ }
172
+ }
173
+
174
+ return undefined;
175
+ }
176
+
177
+ /**
178
+ * Constructor
179
+ * @param r Reg
180
+ * @param g Green
181
+ * @param b Blue
182
+ * @param alpha Alpha
183
+ */
184
+ constructor(
185
+ public readonly r: number,
186
+ public readonly g: number,
187
+ public readonly b: number,
188
+ public readonly alpha?: number
189
+ ) {}
190
+
191
+ /**
192
+ * Clone color with adjustments
193
+ * @param adjustR Adjust R value
194
+ * @param adjustG Adjust G value
195
+ * @param adjustB Adjust B value
196
+ * @param alpha New alpha value
197
+ */
198
+ clone(
199
+ adjustR?: number,
200
+ adjustG?: number,
201
+ adjustB?: number,
202
+ alpha?: number
203
+ ) {
204
+ const r = EColor.adjust(this.r, adjustR);
205
+ const g = EColor.adjust(this.g, adjustG);
206
+ const b = EColor.adjust(this.b, adjustB);
207
+ if (
208
+ r === this.r &&
209
+ g === this.g &&
210
+ b === this.b &&
211
+ (alpha == null || alpha === this.alpha)
212
+ )
213
+ return undefined;
214
+ return new EColor(r, g, b, alpha);
215
+ }
216
+
217
+ /**
218
+ * Get contrast ratio, a value between 0 and 1
219
+ * @param color Contrast color
220
+ */
221
+ getContrastRatio(color: EColor) {
222
+ const lum1 = this.getLuminance();
223
+ const lum2 = color.getLuminance();
224
+ const brightest = Math.max(lum1, lum2);
225
+ const darkest = Math.min(lum1, lum2);
226
+ return (brightest + 0.05) / (darkest + 0.05);
227
+ }
228
+
229
+ /**
230
+ * Get Delta value (perceptible by human eyes)
231
+ * <= 1, Not perceptible by human eyes
232
+ * 1 - 2, Perceptible through close observation
233
+ * 2 - 10, Perceptible at a glance
234
+ * 11 - 49, Colors are more similar than opposite
235
+ * 100+, Colors are exact opposite
236
+ * @param color Contrast color
237
+ * @returns Value
238
+ */
239
+ getDeltaValue(color: EColor) {
240
+ const labA = this.toLabValue();
241
+ const labB = color.toLabValue();
242
+ const deltaL = labA[0] - labB[0];
243
+ const deltaA = labA[1] - labB[1];
244
+ const deltaB = labA[2] - labB[2];
245
+ const c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
246
+ const c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
247
+ const deltaC = c1 - c2;
248
+ let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
249
+ deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
250
+ const sc = 1.0 + 0.045 * c1;
251
+ const sh = 1.0 + 0.015 * c1;
252
+ const deltaLKlsl = deltaL / 1.0;
253
+ const deltaCkcsc = deltaC / sc;
254
+ const deltaHkhsh = deltaH / sh;
255
+ const i =
256
+ deltaLKlsl * deltaLKlsl +
257
+ deltaCkcsc * deltaCkcsc +
258
+ deltaHkhsh * deltaHkhsh;
259
+ return i < 0 ? 0 : Math.sqrt(i);
260
+ }
261
+
262
+ /**
263
+ * Get luminance
264
+ * Darker one has higher luminance
265
+ * https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
266
+ */
267
+ getLuminance() {
268
+ const a = [this.r, this.g, this.b].map((v) => {
269
+ v /= 255;
270
+ return v <= 0.03928
271
+ ? v / 12.92
272
+ : Math.pow((v + 0.055) / 1.055, 2.4);
273
+ });
274
+ return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
275
+ }
276
+
277
+ /**
278
+ * To HEX color string
279
+ * @returns HEX color string
280
+ */
281
+ toHEXColor() {
282
+ return `#${EColor.toHex(this.r)}${EColor.toHex(this.g)}${EColor.toHex(
283
+ this.b
284
+ )}`;
285
+ }
286
+
287
+ /**
288
+ * To Lab value
289
+ * @returns Lab value
290
+ */
291
+ toLabValue(): [number, number, number] {
292
+ let r = this.r / 255,
293
+ g = this.g / 255,
294
+ b = this.b / 255,
295
+ x,
296
+ y,
297
+ z;
298
+ r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
299
+ g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
300
+ b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
301
+ x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
302
+ y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0;
303
+ z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
304
+ x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
305
+ y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
306
+ z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
307
+ return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
308
+ }
309
+
310
+ /**
311
+ * To RGB color string
312
+ * @param alpha Alpha value, false means ignore it
313
+ * @returns RGB color string
314
+ */
315
+ toRGBColor(alpha?: boolean | number) {
316
+ // Decide
317
+ let includeAlpha: boolean,
318
+ alphaValue: number | undefined = this.alpha;
319
+
320
+ if (typeof alpha === 'number') {
321
+ alphaValue = alpha;
322
+ includeAlpha = true;
323
+ } else if (alpha == null) {
324
+ includeAlpha = this.alpha != null;
325
+ } else {
326
+ includeAlpha = alpha;
327
+ }
328
+
329
+ if (includeAlpha)
330
+ return `RGBA(${this.r}, ${this.g}, ${this.b}, ${alphaValue ?? 1})`;
331
+
332
+ return `RGB(${this.r}, ${this.g}, ${this.b})`;
333
+ }
334
+ }