@esmalley/ts-utils 3.0.0 → 5.0.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/dist/cjs/index.js +17 -27
- package/dist/cjs/index.js.map +7 -0
- package/dist/esm/index.js +17 -11
- package/dist/esm/index.js.map +7 -0
- package/dist/{cjs → types}/Kontororu/Socket.d.ts +8 -3
- package/dist/types/Kontororu/Socket.d.ts.map +1 -0
- package/dist/{esm/Text.d.ts → types/Textor.d.ts} +2 -2
- package/dist/types/Textor.d.ts.map +1 -0
- package/dist/{cjs → types}/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +9 -7
- package/dist/cjs/Arithmetic.js +0 -9
- package/dist/cjs/Arrayifier.js +0 -69
- package/dist/cjs/CSV.js +0 -39
- package/dist/cjs/Color.js +0 -348
- package/dist/cjs/Dates.js +0 -358
- package/dist/cjs/Kontororu/Socket.d.ts.map +0 -1
- package/dist/cjs/Kontororu/Socket.js +0 -221
- package/dist/cjs/Kontororu.js +0 -27
- package/dist/cjs/Objector.js +0 -124
- package/dist/cjs/Sorter.js +0 -32
- package/dist/cjs/Style.js +0 -475
- package/dist/cjs/Text.d.ts +0 -5
- package/dist/cjs/Text.d.ts.map +0 -1
- package/dist/cjs/Text.js +0 -39
- package/dist/cjs/Theme.js +0 -507
- package/dist/cjs/Toaster.js +0 -49
- package/dist/cjs/index.d.ts.map +0 -1
- package/dist/esm/Arithmetic.d.ts +0 -4
- package/dist/esm/Arithmetic.d.ts.map +0 -1
- package/dist/esm/Arithmetic.js +0 -5
- package/dist/esm/Arrayifier.d.ts +0 -29
- package/dist/esm/Arrayifier.d.ts.map +0 -1
- package/dist/esm/Arrayifier.js +0 -65
- package/dist/esm/CSV.d.ts +0 -10
- package/dist/esm/CSV.d.ts.map +0 -1
- package/dist/esm/CSV.js +0 -35
- package/dist/esm/Color.d.ts +0 -93
- package/dist/esm/Color.d.ts.map +0 -1
- package/dist/esm/Color.js +0 -344
- package/dist/esm/Dates.d.ts +0 -51
- package/dist/esm/Dates.d.ts.map +0 -1
- package/dist/esm/Dates.js +0 -354
- package/dist/esm/Kontororu/Socket.d.ts +0 -44
- package/dist/esm/Kontororu/Socket.d.ts.map +0 -1
- package/dist/esm/Kontororu/Socket.js +0 -218
- package/dist/esm/Kontororu.d.ts +0 -8
- package/dist/esm/Kontororu.d.ts.map +0 -1
- package/dist/esm/Kontororu.js +0 -23
- package/dist/esm/Objector.d.ts +0 -32
- package/dist/esm/Objector.d.ts.map +0 -1
- package/dist/esm/Objector.js +0 -120
- package/dist/esm/Sorter.d.ts +0 -8
- package/dist/esm/Sorter.d.ts.map +0 -1
- package/dist/esm/Sorter.js +0 -28
- package/dist/esm/Style.d.ts +0 -63
- package/dist/esm/Style.d.ts.map +0 -1
- package/dist/esm/Style.js +0 -471
- package/dist/esm/Text.d.ts.map +0 -1
- package/dist/esm/Text.js +0 -35
- package/dist/esm/Theme.d.ts +0 -1413
- package/dist/esm/Theme.d.ts.map +0 -1
- package/dist/esm/Theme.js +0 -503
- package/dist/esm/Toaster.d.ts +0 -24
- package/dist/esm/Toaster.d.ts.map +0 -1
- package/dist/esm/Toaster.js +0 -46
- package/dist/esm/index.d.ts +0 -12
- package/dist/esm/index.d.ts.map +0 -1
- /package/dist/{cjs → types}/Arithmetic.d.ts +0 -0
- /package/dist/{cjs → types}/Arithmetic.d.ts.map +0 -0
- /package/dist/{cjs → types}/Arrayifier.d.ts +0 -0
- /package/dist/{cjs → types}/Arrayifier.d.ts.map +0 -0
- /package/dist/{cjs → types}/CSV.d.ts +0 -0
- /package/dist/{cjs → types}/CSV.d.ts.map +0 -0
- /package/dist/{cjs → types}/Color.d.ts +0 -0
- /package/dist/{cjs → types}/Color.d.ts.map +0 -0
- /package/dist/{cjs → types}/Dates.d.ts +0 -0
- /package/dist/{cjs → types}/Dates.d.ts.map +0 -0
- /package/dist/{cjs → types}/Kontororu.d.ts +0 -0
- /package/dist/{cjs → types}/Kontororu.d.ts.map +0 -0
- /package/dist/{cjs → types}/Objector.d.ts +0 -0
- /package/dist/{cjs → types}/Objector.d.ts.map +0 -0
- /package/dist/{cjs → types}/Sorter.d.ts +0 -0
- /package/dist/{cjs → types}/Sorter.d.ts.map +0 -0
- /package/dist/{cjs → types}/Style.d.ts +0 -0
- /package/dist/{cjs → types}/Style.d.ts.map +0 -0
- /package/dist/{cjs → types}/Theme.d.ts +0 -0
- /package/dist/{cjs → types}/Theme.d.ts.map +0 -0
- /package/dist/{cjs → types}/Toaster.d.ts +0 -0
- /package/dist/{cjs → types}/Toaster.d.ts.map +0 -0
package/dist/cjs/Color.js
DELETED
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/* eslint-disable no-mixed-operators */
|
|
3
|
-
/* eslint-disable no-bitwise */
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.Color = void 0;
|
|
6
|
-
class Color {
|
|
7
|
-
// constructor() {
|
|
8
|
-
// }
|
|
9
|
-
/**
|
|
10
|
-
* A linear interpolator for hexadecimal colors
|
|
11
|
-
* @param {string} a
|
|
12
|
-
* @param {string} b
|
|
13
|
-
* @param {number} amount
|
|
14
|
-
* @example
|
|
15
|
-
* // returns #7F7F7F
|
|
16
|
-
* lerpColor('#000000', '#ffffff', 0.5)
|
|
17
|
-
* @return {string}
|
|
18
|
-
*/
|
|
19
|
-
static lerpColor(a, b, amount) {
|
|
20
|
-
const ah = +a.replace('#', '0x');
|
|
21
|
-
const ar = ah >> 16;
|
|
22
|
-
const ag = ah >> 8 & 0xff;
|
|
23
|
-
const ab = ah & 0xff;
|
|
24
|
-
const bh = +b.replace('#', '0x');
|
|
25
|
-
const br = bh >> 16;
|
|
26
|
-
const bg = bh >> 8 & 0xff;
|
|
27
|
-
const bb = bh & 0xff;
|
|
28
|
-
const rr = ar + amount * (br - ar);
|
|
29
|
-
const rg = ag + amount * (bg - ag);
|
|
30
|
-
const rb = ab + amount * (bb - ab);
|
|
31
|
-
return `#${((1 << 24) + (rr << 16) + (rg << 8) + rb | 0).toString(16).slice(1)}`;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Get a color that will look readable based on a background color
|
|
35
|
-
*/
|
|
36
|
-
static getTextColor(color, backgroundColor, debug = false) {
|
|
37
|
-
// Convert hex colors to RGB
|
|
38
|
-
/*
|
|
39
|
-
let [r1, g1, b1] = Color.hexToRgb(color);
|
|
40
|
-
const [r2, g2, b2] = Color.hexToRgb(backgroundColor);
|
|
41
|
-
|
|
42
|
-
const brightnessBg = Color.calculateBrightness(r2, g2, b2);
|
|
43
|
-
|
|
44
|
-
const targetBrightness = brightnessBg > 128 ? 50 : 150; // target brightness threshold for contrast
|
|
45
|
-
|
|
46
|
-
while (true) {
|
|
47
|
-
const brightnessColor = Color.calculateBrightness(r1, g1, b1);
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
(brightnessBg > 128 && brightnessColor < targetBrightness) ||
|
|
51
|
-
(brightnessBg <= 128 && brightnessColor > targetBrightness)
|
|
52
|
-
) {
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (brightnessBg > 128) {
|
|
57
|
-
r1 = Math.max(0, r1 - 25);
|
|
58
|
-
g1 = Math.max(0, g1 - 25);
|
|
59
|
-
b1 = Math.max(0, b1 - 25);
|
|
60
|
-
} else {
|
|
61
|
-
r1 = Math.min(255, r1 + 25);
|
|
62
|
-
g1 = Math.min(255, g1 + 25);
|
|
63
|
-
b1 = Math.min(255, b1 + 25);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if ((r1 === 0 && g1 === 0 && b1 === 0) || (r1 === 255 && g1 === 255 && b1 === 255)) {
|
|
67
|
-
break; // avoid infinite loop
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Convert back to hex
|
|
72
|
-
return Color.rgbToHex(r1, g1, b1);
|
|
73
|
-
*/
|
|
74
|
-
let [r, g, b] = Color.hexToRgb(color);
|
|
75
|
-
const [br, bg, bb] = Color.hexToRgb(backgroundColor);
|
|
76
|
-
const contrastTarget = 4.5;
|
|
77
|
-
if (debug) {
|
|
78
|
-
console.log('Color.getContrastRatio([r, g, b], [br, bg, bb])', Color.getContrastRatio([r, g, b], [br, bg, bb]));
|
|
79
|
-
}
|
|
80
|
-
if (Color.getContrastRatio([r, g, b], [br, bg, bb]) >= contrastTarget) {
|
|
81
|
-
return Color.rgbToHex(r, g, b);
|
|
82
|
-
}
|
|
83
|
-
const contrastToBlack = Color.getContrastRatio([0, 0, 0], [br, bg, bb]);
|
|
84
|
-
const contrastToWhite = Color.getContrastRatio([255, 255, 255], [br, bg, bb]);
|
|
85
|
-
const direction = contrastToWhite > contrastToBlack ? 'lighter' : 'darker';
|
|
86
|
-
if (debug) {
|
|
87
|
-
console.log('contrastToBlack', contrastToBlack);
|
|
88
|
-
console.log('contrastToWhite', contrastToWhite);
|
|
89
|
-
console.log('direction', direction);
|
|
90
|
-
}
|
|
91
|
-
const adjust = (c, lighter) => {
|
|
92
|
-
return lighter ? Math.min(255, c + 10) : Math.max(0, c - 10);
|
|
93
|
-
};
|
|
94
|
-
for (let i = 0; i < 25; i++) {
|
|
95
|
-
r = adjust(r, direction === 'lighter');
|
|
96
|
-
g = adjust(g, direction === 'lighter');
|
|
97
|
-
b = adjust(b, direction === 'lighter');
|
|
98
|
-
if (debug) {
|
|
99
|
-
console.log('Color.getContrastRatio([r, g, b], [br, bg, bb]) 2', Color.getContrastRatio([r, g, b], [br, bg, bb]));
|
|
100
|
-
}
|
|
101
|
-
if (Color.getContrastRatio([r, g, b], [br, bg, bb]) >= contrastTarget) {
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return Color.rgbToHex(r, g, b);
|
|
106
|
-
}
|
|
107
|
-
static getContrastRatio(rgb1, rgb2) {
|
|
108
|
-
const luminance = (r, g, b) => {
|
|
109
|
-
const a = [r, g, b].map((v) => {
|
|
110
|
-
v /= 255;
|
|
111
|
-
return v <= 0.03928
|
|
112
|
-
? v / 12.92
|
|
113
|
-
: Math.pow((v + 0.055) / 1.055, 2.4);
|
|
114
|
-
});
|
|
115
|
-
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
116
|
-
};
|
|
117
|
-
const lum1 = luminance(...rgb1) + 0.05;
|
|
118
|
-
const lum2 = luminance(...rgb2) + 0.05;
|
|
119
|
-
return lum1 > lum2 ? lum1 / lum2 : lum2 / lum1;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Take a hex (#fff) and an amount and darken the color, return a hex
|
|
123
|
-
* @param {string} hex
|
|
124
|
-
* @param {number} amount
|
|
125
|
-
* @return {string} hex
|
|
126
|
-
*/
|
|
127
|
-
// public static darken(hex: string, amount: number = 0.02): string {
|
|
128
|
-
// const [r, g, b] = this.hexToRgb(hex);
|
|
129
|
-
// const [h, s, l] = this.rgbToHsl(r, g, b);
|
|
130
|
-
// const newL = Math.max(0, (l / 100) - amount) * 100;
|
|
131
|
-
// const [r2, g2, b2] = this.hslToRgb(h, s, newL);
|
|
132
|
-
// return this.rgbToHex(r2, g2, b2);
|
|
133
|
-
// }
|
|
134
|
-
/**
|
|
135
|
-
* Take a hex (#fff) and an amount and lighten the color, return a hex
|
|
136
|
-
* @param {string} hex
|
|
137
|
-
* @param {number} amount
|
|
138
|
-
* @return {string} hex
|
|
139
|
-
*/
|
|
140
|
-
// public static lighten(hex: string, amount: number = 0.02): string {
|
|
141
|
-
// const [r, g, b] = this.hexToRgb(hex);
|
|
142
|
-
// const [h, s, l] = this.rgbToHsl(r, g, b);
|
|
143
|
-
// const newL = Math.min(1, (l / 100) + amount) * 100;
|
|
144
|
-
// const [r2, g2, b2] = this.hslToRgb(h, s, newL);
|
|
145
|
-
// return this.rgbToHex(r2, g2, b2);
|
|
146
|
-
// }
|
|
147
|
-
/**
|
|
148
|
-
* Mixes the color with black to create a Shade.
|
|
149
|
-
* Prevents the "muddy/brown" look of HSL darkening.
|
|
150
|
-
* @param {string} hex - The color to darken
|
|
151
|
-
* @param {number} amount - 0 to 1 (e.g. 0.1 is 10% darker)
|
|
152
|
-
* @return {string} hex
|
|
153
|
-
*/
|
|
154
|
-
static darken(hex, amount = 0.1) {
|
|
155
|
-
const [r, g, b] = this.hexToRgb(hex);
|
|
156
|
-
// Calculate new color by mixing with black (0)
|
|
157
|
-
// Formula: Current * (1 - amount)
|
|
158
|
-
const remaining = 1 - amount;
|
|
159
|
-
const r2 = Math.round(r * remaining);
|
|
160
|
-
const g2 = Math.round(g * remaining);
|
|
161
|
-
const b2 = Math.round(b * remaining);
|
|
162
|
-
return this.rgbToHex(r2, g2, b2);
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Mixes the color with white to create a Tint.
|
|
166
|
-
* cleaner and less "washed out" than HSL lightness adjustment.
|
|
167
|
-
* @param {string} hex - The color to lighten
|
|
168
|
-
* @param {number} amount - 0 to 1 (e.g. 0.1 is 10% lighter)
|
|
169
|
-
* @return {string} hex
|
|
170
|
-
*/
|
|
171
|
-
static lighten(hex, amount = 0.1) {
|
|
172
|
-
const [r, g, b] = this.hexToRgb(hex);
|
|
173
|
-
// Calculate new color by mixing with white (255)
|
|
174
|
-
// Formula: Current + ((Target - Current) * amount)
|
|
175
|
-
const r2 = Math.round(r + (255 - r) * amount);
|
|
176
|
-
const g2 = Math.round(g + (255 - g) * amount);
|
|
177
|
-
const b2 = Math.round(b + (255 - b) * amount);
|
|
178
|
-
return this.rgbToHex(r2, g2, b2);
|
|
179
|
-
}
|
|
180
|
-
static shadeColor(hex, percent) {
|
|
181
|
-
let [r, g, b] = Color.hexToRgb(hex);
|
|
182
|
-
r = Math.min(255, Math.max(0, Math.round(r + (r * (percent / 100)))));
|
|
183
|
-
g = Math.min(255, Math.max(0, Math.round(g + (g * (percent / 100)))));
|
|
184
|
-
b = Math.min(255, Math.max(0, Math.round(b + (b * (percent / 100)))));
|
|
185
|
-
return Color.rgbToHex(r, g, b);
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Are 2 colors similar to each other?
|
|
189
|
-
* @param {string} color1
|
|
190
|
-
* @param {string} color2
|
|
191
|
-
* @param {number} threshold
|
|
192
|
-
* @return {boolean}
|
|
193
|
-
*/
|
|
194
|
-
static areColorsSimilar(color1, color2, threshold = 50) {
|
|
195
|
-
const distance = Color.colorDistance(color1, color2);
|
|
196
|
-
return distance < threshold;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Inverts a hex color
|
|
200
|
-
* @param {string} hex
|
|
201
|
-
* @return {string} hex
|
|
202
|
-
*/
|
|
203
|
-
static invertColor(hex) {
|
|
204
|
-
const [r, g, b] = Color.hexToRgb(hex);
|
|
205
|
-
// Invert each color component
|
|
206
|
-
const invertedR = 255 - r;
|
|
207
|
-
const invertedG = 255 - g;
|
|
208
|
-
const invertedB = 255 - b;
|
|
209
|
-
return Color.rgbToHex(invertedR, invertedG, invertedB);
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Takes a hex (#fff) and returns an rgba with the provided alpha
|
|
213
|
-
* @param {string} hex
|
|
214
|
-
* @param {number} alpha
|
|
215
|
-
* @return {string} rgba()
|
|
216
|
-
*/
|
|
217
|
-
static alphaColor(hex, alpha) {
|
|
218
|
-
const [r, g, b] = this.hexToRgb(hex);
|
|
219
|
-
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Gets analogous colors
|
|
223
|
-
* @param {string} hex
|
|
224
|
-
* @return {Array<string>}
|
|
225
|
-
*/
|
|
226
|
-
static getAnalogousColors(hex) {
|
|
227
|
-
const [r, g, b] = Color.hexToRgb(hex);
|
|
228
|
-
const [h, s, l] = Color.rgbToHsl(r, g, b);
|
|
229
|
-
const analogousColors = [];
|
|
230
|
-
const offset = 30; // Offset for analogous colors, usually 30 degrees
|
|
231
|
-
for (let i = -1; i <= 1; i++) {
|
|
232
|
-
if (i !== 0) {
|
|
233
|
-
const newHue = (h + i * offset + 360) % 360;
|
|
234
|
-
const [newR, newG, newB] = Color.hslToRgb(newHue, s, l);
|
|
235
|
-
analogousColors.push(Color.rgbToHex(newR, newG, newB));
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return analogousColors;
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Convert hex to rgb
|
|
242
|
-
* @param {string} hex
|
|
243
|
-
* @return {Array} rgb
|
|
244
|
-
*/
|
|
245
|
-
static hexToRgb(hex) {
|
|
246
|
-
// Remove the hash at the start if it's there
|
|
247
|
-
let h = hex.replace(/^#/, '');
|
|
248
|
-
// Handle 3-character hex codes by expanding them to 6-character
|
|
249
|
-
if (h.length === 3) {
|
|
250
|
-
h = h.split('').map((char) => { return char + char; }).join('');
|
|
251
|
-
}
|
|
252
|
-
// Ensure it's a valid 6-character hex code
|
|
253
|
-
if (h.length !== 6) {
|
|
254
|
-
throw new Error(`Invalid hex color format: ${hex}`);
|
|
255
|
-
}
|
|
256
|
-
// Parse r, g, b values
|
|
257
|
-
const bigint = parseInt(h, 16);
|
|
258
|
-
const r = (bigint >> 16) & 255;
|
|
259
|
-
const g = (bigint >> 8) & 255;
|
|
260
|
-
const b = bigint & 255;
|
|
261
|
-
return [r, g, b];
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Convert rgb to hex
|
|
265
|
-
* @param {number} r
|
|
266
|
-
* @param {number} g
|
|
267
|
-
* @param {number} b
|
|
268
|
-
* @return {string}
|
|
269
|
-
*/
|
|
270
|
-
static rgbToHex(r, g, b) {
|
|
271
|
-
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()}`;
|
|
272
|
-
}
|
|
273
|
-
static rgbToHsl(r, g, b) {
|
|
274
|
-
r /= 255;
|
|
275
|
-
g /= 255;
|
|
276
|
-
b /= 255;
|
|
277
|
-
const max = Math.max(r, g, b);
|
|
278
|
-
const min = Math.min(r, g, b);
|
|
279
|
-
let h = 0;
|
|
280
|
-
let s = 0;
|
|
281
|
-
const l = (max + min) / 2;
|
|
282
|
-
if (max === min) {
|
|
283
|
-
h = s = 0; // achromatic
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
const d = max - min;
|
|
287
|
-
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
288
|
-
switch (max) {
|
|
289
|
-
case r:
|
|
290
|
-
h = (g - b) / d + (g < b ? 6 : 0);
|
|
291
|
-
break;
|
|
292
|
-
case g:
|
|
293
|
-
h = (b - r) / d + 2;
|
|
294
|
-
break;
|
|
295
|
-
case b:
|
|
296
|
-
h = (r - g) / d + 4;
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
|
-
h /= 6;
|
|
300
|
-
}
|
|
301
|
-
return [h * 360, s * 100, l * 100];
|
|
302
|
-
}
|
|
303
|
-
static hslToRgb(h, s, l) {
|
|
304
|
-
let r;
|
|
305
|
-
let g;
|
|
306
|
-
let b;
|
|
307
|
-
h /= 360;
|
|
308
|
-
s /= 100;
|
|
309
|
-
l /= 100;
|
|
310
|
-
if (s === 0) {
|
|
311
|
-
r = g = b = l; // achromatic
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
const hue2rgb = (p, q, t) => {
|
|
315
|
-
if (t < 0)
|
|
316
|
-
t += 1;
|
|
317
|
-
if (t > 1)
|
|
318
|
-
t -= 1;
|
|
319
|
-
if (t < 1 / 6)
|
|
320
|
-
return p + (q - p) * 6 * t;
|
|
321
|
-
if (t < 1 / 3)
|
|
322
|
-
return q;
|
|
323
|
-
if (t < 1 / 2)
|
|
324
|
-
return p + (q - p) * (2 / 3 - t) * 6;
|
|
325
|
-
return p;
|
|
326
|
-
};
|
|
327
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
328
|
-
const p = 2 * l - q;
|
|
329
|
-
r = hue2rgb(p, q, h + 1 / 3);
|
|
330
|
-
g = hue2rgb(p, q, h);
|
|
331
|
-
b = hue2rgb(p, q, h - 1 / 3);
|
|
332
|
-
}
|
|
333
|
-
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
|
334
|
-
}
|
|
335
|
-
static calculateBrightness(r, g, b) {
|
|
336
|
-
// Calculate the brightness of the color
|
|
337
|
-
return (r * 299 + g * 587 + b * 114) / 1000;
|
|
338
|
-
}
|
|
339
|
-
static colorDistance(color1, color2) {
|
|
340
|
-
const [r1, g1, b1] = Color.hexToRgb(color1);
|
|
341
|
-
const [r2, g2, b2] = Color.hexToRgb(color2);
|
|
342
|
-
const dr = r1 - r2;
|
|
343
|
-
const dg = g1 - g2;
|
|
344
|
-
const db = b1 - b2;
|
|
345
|
-
return Math.sqrt(dr * dr + dg * dg + db * db);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
exports.Color = Color;
|
package/dist/cjs/Dates.js
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/* eslint-disable one-var-declaration-per-line */
|
|
3
|
-
/* eslint-disable one-var */
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.Dates = void 0;
|
|
6
|
-
class Dates {
|
|
7
|
-
// constructor() {
|
|
8
|
-
// }
|
|
9
|
-
/*
|
|
10
|
-
* Robust Date Parsing
|
|
11
|
-
* Handles:
|
|
12
|
-
* - Date Objects / Numbers (Timestamps)
|
|
13
|
-
* - ISO Strings (2025-01-01) -> Forces Local Midnight
|
|
14
|
-
* - US Formats (01/05/2026)
|
|
15
|
-
* - Mixed Time Formats (23:00 pm, 5:00pm, 14:30:00)
|
|
16
|
-
*/
|
|
17
|
-
static parse(str, utc = false) {
|
|
18
|
-
// 1. Handle Null / Undefined -> Return Now
|
|
19
|
-
if (!str) {
|
|
20
|
-
return new Date();
|
|
21
|
-
}
|
|
22
|
-
// 2. Handle Existing Date Objects -> Return Copy
|
|
23
|
-
if (str instanceof Date) {
|
|
24
|
-
return new Date(str.getTime());
|
|
25
|
-
}
|
|
26
|
-
// 3. Handle Timestamps (Numbers)
|
|
27
|
-
if (typeof str === 'number') {
|
|
28
|
-
return new Date(str);
|
|
29
|
-
}
|
|
30
|
-
// 4. Handle Strings
|
|
31
|
-
if (typeof str === 'string') {
|
|
32
|
-
const input = str.trim();
|
|
33
|
-
// CASE A: Strict ISO Date "YYYY-MM-DD"
|
|
34
|
-
// Native JS parses this as UTC Midnight, which often shows as
|
|
35
|
-
// previous day 7pm EST. We force "T00:00:00" to make it Local Midnight.
|
|
36
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(input)) {
|
|
37
|
-
return new Date(`${input}T00:00:00`);
|
|
38
|
-
}
|
|
39
|
-
// CASE B: Manual Parsing for Complex Strings
|
|
40
|
-
// This handles "2026-01-05 23:03:19 pm", "01/05/2026", etc.
|
|
41
|
-
// Step 1: Extract Date Part (YYYY-MM-DD or MM/DD/YYYY)
|
|
42
|
-
// Regex looks for: (Group 1: Year/Month) -or/ (Group 2: Month/Day) -or/ (Group 3: Day/Year)
|
|
43
|
-
let year, month, day, timePart = '';
|
|
44
|
-
// Match YYYY-MM-DD or YYYY/MM/DD
|
|
45
|
-
const isoMatch = input.match(/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})(.*)$/);
|
|
46
|
-
// Match MM/DD/YYYY or MM-DD-YYYY
|
|
47
|
-
const usMatch = input.match(/^(\d{1,2})[-/](\d{1,2})[-/](\d{4})(.*)$/);
|
|
48
|
-
if (isoMatch) {
|
|
49
|
-
year = parseInt(isoMatch[1], 10);
|
|
50
|
-
month = parseInt(isoMatch[2], 10) - 1; // JS Months are 0-11
|
|
51
|
-
day = parseInt(isoMatch[3], 10);
|
|
52
|
-
timePart = isoMatch[4];
|
|
53
|
-
}
|
|
54
|
-
else if (usMatch) {
|
|
55
|
-
year = parseInt(usMatch[3], 10);
|
|
56
|
-
month = parseInt(usMatch[1], 10) - 1;
|
|
57
|
-
day = parseInt(usMatch[2], 10);
|
|
58
|
-
timePart = usMatch[4];
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
// Fallback: Let the browser try its best if our regex fails
|
|
62
|
-
const d = new Date(input);
|
|
63
|
-
return isNaN(d.getTime()) ? new Date() : d;
|
|
64
|
-
}
|
|
65
|
-
// Step 2: Extract Time Part
|
|
66
|
-
let hours = 0;
|
|
67
|
-
let minutes = 0;
|
|
68
|
-
let seconds = 0;
|
|
69
|
-
// Look for HH:MM(:SS) and optional AM/PM in the remaining string
|
|
70
|
-
if (timePart && timePart.trim().length > 0) {
|
|
71
|
-
// Matches: 23:03, 23:03:19, 5:00pm, 5:00 pm
|
|
72
|
-
const timeMatch = timePart.match(/(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?\s*(am|pm|AM|PM)?/);
|
|
73
|
-
if (timeMatch) {
|
|
74
|
-
hours = parseInt(timeMatch[1], 10);
|
|
75
|
-
minutes = parseInt(timeMatch[2], 10);
|
|
76
|
-
seconds = timeMatch[3] ? parseInt(timeMatch[3], 10) : 0;
|
|
77
|
-
const meridiem = timeMatch[4] ? timeMatch[4].toLowerCase() : null;
|
|
78
|
-
// Step 3: Normalize Hours (12h to 24h)
|
|
79
|
-
if (meridiem === 'pm' && hours < 12) {
|
|
80
|
-
hours += 12;
|
|
81
|
-
}
|
|
82
|
-
if (meridiem === 'am' && hours === 12) {
|
|
83
|
-
hours = 0;
|
|
84
|
-
}
|
|
85
|
-
// Note: If input is "23:00 pm", we ignore the 'pm' because 23 > 12.
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (utc) {
|
|
89
|
-
return new Date(Date.UTC(year, month, day, hours, minutes, seconds));
|
|
90
|
-
}
|
|
91
|
-
// Step 4: Construct Date in Local Time
|
|
92
|
-
return new Date(year, month, day, hours, minutes, seconds);
|
|
93
|
-
}
|
|
94
|
-
return new Date();
|
|
95
|
-
}
|
|
96
|
-
static utc(date) {
|
|
97
|
-
const d = this.parse(date);
|
|
98
|
-
return new Date(d.getTime() + (d.getTimezoneOffset() * 60000));
|
|
99
|
-
}
|
|
100
|
-
static getMonthsShort() {
|
|
101
|
-
return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
102
|
-
}
|
|
103
|
-
static getMonths() {
|
|
104
|
-
return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
105
|
-
}
|
|
106
|
-
static getDaysShort() {
|
|
107
|
-
return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
108
|
-
}
|
|
109
|
-
static getDays() {
|
|
110
|
-
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Format a date using php syntax
|
|
114
|
-
*
|
|
115
|
-
| Token | Meaning | Example |
|
|
116
|
-
| ----- | ------------------------- | ------- |
|
|
117
|
-
| `Y` | 4-digit year | 2025 |
|
|
118
|
-
| `y` | 2-digit year | 25 |
|
|
119
|
-
| `m` | 2-digit month | 03 |
|
|
120
|
-
| `n` | month (no leading zero) | 3 |
|
|
121
|
-
| `d` | day (2-digit) | 09 |
|
|
122
|
-
| `j` | day (no leading zero) | 9 |
|
|
123
|
-
| `S` | Ordinal suffix | th |
|
|
124
|
-
| `H` | 24-hour | 14 |
|
|
125
|
-
| `G` | 24-hour (no leading zero) | 14 |
|
|
126
|
-
| `h` | 12-hour | 02 |
|
|
127
|
-
| `g` | 12-hour (no leading zero) | 2 |
|
|
128
|
-
| `i` | minutes | 05 |
|
|
129
|
-
| `s` | seconds | 09 |
|
|
130
|
-
| `A` | AM/PM | PM |
|
|
131
|
-
| `a` | am/pm | pm |
|
|
132
|
-
| `w` | day of week (0–6) | 1 |
|
|
133
|
-
| `N` | day of week (1–7) | 2 |
|
|
134
|
-
| `M` | short month name | Mar |
|
|
135
|
-
| `F` | full month name | March |
|
|
136
|
-
| `D` | short weekday | Mon |
|
|
137
|
-
| `l` | full weekday | Monday |
|
|
138
|
-
*/
|
|
139
|
-
static format(dateInput, format) {
|
|
140
|
-
const date = this.parse(dateInput);
|
|
141
|
-
const pad = (n) => String(n).padStart(2, '0');
|
|
142
|
-
const monthsShort = this.getMonthsShort();
|
|
143
|
-
const monthsLong = this.getMonths();
|
|
144
|
-
const daysShort = this.getDaysShort();
|
|
145
|
-
const daysLong = this.getDays();
|
|
146
|
-
/*
|
|
147
|
-
const Y = date.getUTCFullYear();
|
|
148
|
-
const y = String(Y).slice(-2);
|
|
149
|
-
const month = date.getUTCMonth(); // 0-11
|
|
150
|
-
const dateNum = date.getUTCDate(); // 1-31
|
|
151
|
-
const day = date.getUTCDay(); // 0-6, Sun = 0
|
|
152
|
-
const hours = date.getUTCHours(); // 0-23
|
|
153
|
-
const minutes = date.getUTCMinutes();
|
|
154
|
-
const seconds = date.getUTCSeconds();
|
|
155
|
-
*/
|
|
156
|
-
const Y = date.getFullYear();
|
|
157
|
-
const y = String(Y).slice(-2);
|
|
158
|
-
const month = date.getMonth(); // 0-11
|
|
159
|
-
const dateNum = date.getDate(); // 1-31
|
|
160
|
-
const day = date.getDay(); // 0-6, Sun = 0
|
|
161
|
-
const hours = date.getHours(); // 0-23
|
|
162
|
-
const minutes = date.getMinutes();
|
|
163
|
-
const seconds = date.getSeconds();
|
|
164
|
-
// Logic for ordinal suffix (st, nd, rd, th)
|
|
165
|
-
const getOrdinalSuffix = (n) => {
|
|
166
|
-
const v = n % 100;
|
|
167
|
-
// 11th, 12th, 13th are exceptions to the 1st, 2nd, 3rd rule
|
|
168
|
-
if (v >= 11 && v <= 13) {
|
|
169
|
-
return 'th';
|
|
170
|
-
}
|
|
171
|
-
switch (n % 10) {
|
|
172
|
-
case 1: {
|
|
173
|
-
return 'st';
|
|
174
|
-
}
|
|
175
|
-
case 2: {
|
|
176
|
-
return 'nd';
|
|
177
|
-
}
|
|
178
|
-
case 3: {
|
|
179
|
-
return 'rd';
|
|
180
|
-
}
|
|
181
|
-
default: {
|
|
182
|
-
return 'th';
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
const tokens = {
|
|
187
|
-
/// Year
|
|
188
|
-
Y: String(Y),
|
|
189
|
-
y,
|
|
190
|
-
// Month
|
|
191
|
-
m: pad(month + 1),
|
|
192
|
-
n: String(month + 1),
|
|
193
|
-
M: monthsShort[month],
|
|
194
|
-
F: monthsLong[month],
|
|
195
|
-
// Day
|
|
196
|
-
d: pad(dateNum),
|
|
197
|
-
j: String(dateNum),
|
|
198
|
-
D: daysShort[day],
|
|
199
|
-
l: daysLong[day],
|
|
200
|
-
w: String(day), // 0 (Sun) - 6
|
|
201
|
-
N: String(day === 0 ? 7 : day), // 1 (Mon) - 7 (Sun)
|
|
202
|
-
S: getOrdinalSuffix(dateNum),
|
|
203
|
-
// Time
|
|
204
|
-
H: pad(hours),
|
|
205
|
-
G: String(hours),
|
|
206
|
-
h: pad(((hours + 11) % 12) + 1),
|
|
207
|
-
g: String(((hours + 11) % 12) + 1),
|
|
208
|
-
i: pad(minutes),
|
|
209
|
-
s: pad(seconds),
|
|
210
|
-
// AM/PM
|
|
211
|
-
A: hours < 12 ? 'AM' : 'PM',
|
|
212
|
-
a: hours < 12 ? 'am' : 'pm',
|
|
213
|
-
};
|
|
214
|
-
// Replace tokens using regex
|
|
215
|
-
return format.replace(/\\(.)|([a-zA-Z])/g, (_, esc, token) => {
|
|
216
|
-
if (esc) {
|
|
217
|
-
// literal escaped char like \H or \Y → return the raw letter
|
|
218
|
-
return esc;
|
|
219
|
-
}
|
|
220
|
-
return tokens[token] ?? token;
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
static add(date, amount, unit) {
|
|
224
|
-
const d = this.parse(date);
|
|
225
|
-
if (unit === 'years') {
|
|
226
|
-
const originalDay = d.getDate();
|
|
227
|
-
d.setFullYear(d.getFullYear() + amount);
|
|
228
|
-
// Handle Leap Year Rollover:
|
|
229
|
-
// Feb 29, 2024 + 1 year -> Mar 1, 2025 (Standard JS behavior)
|
|
230
|
-
// If strict "same day or last day of month" logic is desired (turning it into Feb 28):
|
|
231
|
-
if (d.getDate() !== originalDay) {
|
|
232
|
-
d.setDate(0); // Set to last day of previous month (Feb 28)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
else if (unit === 'months') {
|
|
236
|
-
const originalDay = d.getDate();
|
|
237
|
-
d.setMonth(d.getMonth() + amount);
|
|
238
|
-
// Handle rollover: Jan 31 + 1 month -> Feb 28/29
|
|
239
|
-
if (d.getDate() !== originalDay) {
|
|
240
|
-
d.setDate(0); // Set to last day of previous month
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
else if (unit === 'days') {
|
|
244
|
-
// Use setDate to be DST safe (24h addition via ms is unsafe across DST)
|
|
245
|
-
d.setDate(d.getDate() + amount);
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
const map = {
|
|
249
|
-
hours: amount * 60 * 60 * 1000,
|
|
250
|
-
minutes: amount * 60 * 1000,
|
|
251
|
-
};
|
|
252
|
-
// Use getTime() for day/hour/minute units for simple millisecond addition
|
|
253
|
-
d.setTime(d.getTime() + map[unit]);
|
|
254
|
-
}
|
|
255
|
-
return d;
|
|
256
|
-
}
|
|
257
|
-
static subtract(date, amount, unit) {
|
|
258
|
-
return this.add(date, -amount, unit);
|
|
259
|
-
}
|
|
260
|
-
static fromNow(date) {
|
|
261
|
-
const d = this.parse(date);
|
|
262
|
-
const diff = Date.now() - d.getTime();
|
|
263
|
-
const mins = Math.floor(diff / 60000);
|
|
264
|
-
if (Math.abs(mins) < 1) {
|
|
265
|
-
return 'just now';
|
|
266
|
-
}
|
|
267
|
-
// Handle future dates roughly
|
|
268
|
-
if (mins < 0) {
|
|
269
|
-
return 'in the future';
|
|
270
|
-
}
|
|
271
|
-
if (mins < 60) {
|
|
272
|
-
return `${mins}m ago`;
|
|
273
|
-
}
|
|
274
|
-
const hours = Math.floor(mins / 60);
|
|
275
|
-
if (hours < 24) {
|
|
276
|
-
return `${hours}h ago`;
|
|
277
|
-
}
|
|
278
|
-
const days = Math.floor(hours / 24);
|
|
279
|
-
return `${days}d ago`;
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Find the closest date in an array of dates
|
|
283
|
-
*/
|
|
284
|
-
static getClosestDate(dateToMatch, datesArray) {
|
|
285
|
-
if (!datesArray.length) {
|
|
286
|
-
return null;
|
|
287
|
-
}
|
|
288
|
-
const matchDate = this.parse(dateToMatch).getTime();
|
|
289
|
-
let closestDate = null;
|
|
290
|
-
let closestDist = Infinity;
|
|
291
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
292
|
-
for (const dateStr of datesArray) {
|
|
293
|
-
const currDate = this.parse(dateStr).getTime();
|
|
294
|
-
const dist = Math.abs(currDate - matchDate);
|
|
295
|
-
if (dist < closestDist) {
|
|
296
|
-
closestDist = dist;
|
|
297
|
-
closestDate = dateStr;
|
|
298
|
-
}
|
|
299
|
-
else if (dist === closestDist) {
|
|
300
|
-
// Tie-breaker: Prefer the date that is in the future relative to the matchDate
|
|
301
|
-
// Or if both are same direction, just keep the current one (or implementation defined)
|
|
302
|
-
// Requirement: "Both 17th and 19th have same dist. It should pick 19th"
|
|
303
|
-
if (currDate > matchDate) {
|
|
304
|
-
closestDate = dateStr;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return closestDate;
|
|
309
|
-
}
|
|
310
|
-
static getTodayEST() {
|
|
311
|
-
return this.format(new Date().toLocaleString('en-US', { timeZone: 'America/New_York' }), 'Y-m-d');
|
|
312
|
-
}
|
|
313
|
-
static getStartOfDay(date) {
|
|
314
|
-
const d = this.parse(date);
|
|
315
|
-
d.setHours(0, 0, 0, 0);
|
|
316
|
-
return d;
|
|
317
|
-
}
|
|
318
|
-
static getStartOfMonth(date) {
|
|
319
|
-
const d = this.parse(date);
|
|
320
|
-
d.setDate(1);
|
|
321
|
-
d.setHours(0, 0, 0, 0);
|
|
322
|
-
return d;
|
|
323
|
-
}
|
|
324
|
-
static getStartOfGrid(date) {
|
|
325
|
-
const d = this.getStartOfMonth(date);
|
|
326
|
-
const dayOfWeek = d.getDay(); // 0 (Sunday) is the start in standard JS
|
|
327
|
-
// Move back to the beginning of the week
|
|
328
|
-
const result = this.parse(d);
|
|
329
|
-
// Subtract days to get to the start of the week (Sunday)
|
|
330
|
-
result.setDate(d.getDate() - dayOfWeek);
|
|
331
|
-
return result;
|
|
332
|
-
}
|
|
333
|
-
static isSameDay(date1, date2) {
|
|
334
|
-
if (!date1 || !date2) {
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
const d1 = this.parse(date1);
|
|
338
|
-
const d2 = this.parse(date2);
|
|
339
|
-
return (d1.getFullYear() === d2.getFullYear() &&
|
|
340
|
-
d1.getMonth() === d2.getMonth() &&
|
|
341
|
-
d1.getDate() === d2.getDate());
|
|
342
|
-
}
|
|
343
|
-
// Helper to check if one date is before another (ignoring time)
|
|
344
|
-
static isBeforeDay(date1, date2) {
|
|
345
|
-
if (!date1 || !date2) {
|
|
346
|
-
return false;
|
|
347
|
-
}
|
|
348
|
-
return this.getStartOfDay(date1).getTime() < this.getStartOfDay(date2).getTime();
|
|
349
|
-
}
|
|
350
|
-
// Helper to check if one date is after another (ignoring time)
|
|
351
|
-
static isAfterDay(date1, date2) {
|
|
352
|
-
if (!date1 || !date2) {
|
|
353
|
-
return false;
|
|
354
|
-
}
|
|
355
|
-
return this.getStartOfDay(date1).getTime() > this.getStartOfDay(date2).getTime();
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
exports.Dates = Dates;
|