@hzab/utils 1.1.1 → 1.1.3

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/src/color.ts CHANGED
@@ -1,302 +1,302 @@
1
- /**
2
- * 计算颜色的亮度
3
- * @param r
4
- * @param g
5
- * @param b
6
- * @returns
7
- */
8
- export function luminance(r, g, b) {
9
- const a = [r, g, b].map((v) => {
10
- v /= 255;
11
- return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
12
- });
13
- return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
14
- }
15
-
16
- /**
17
- * 计算两个颜色之间的对比度
18
- * @param l1
19
- * @param l2
20
- * @returns
21
- */
22
- export function contrast(l1, l2) {
23
- const brightest = Math.max(l1, l2);
24
- const darkest = Math.min(l1, l2);
25
- return (brightest + 0.05) / (darkest + 0.05);
26
- }
27
-
28
- /**
29
- * 计算对比度
30
- * @param luminance1
31
- * @param luminance2
32
- * @returns
33
- */
34
- export function contrastRatio(luminance1, luminance2) {
35
- return (Math.max(luminance1, luminance2) + 0.05) / (Math.min(luminance1, luminance2) + 0.05);
36
- }
37
-
38
- /**
39
- * 十六进制颜色转 RGB
40
- * @param hex
41
- * @returns
42
- */
43
- export function hexToRGB(hex) {
44
- hex = hex.replace("#", "");
45
- if (hex.length === 3) {
46
- hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
47
- }
48
- const r = parseInt(hex.substring(0, 2), 16);
49
- const g = parseInt(hex.substring(2, 4), 16);
50
- const b = parseInt(hex.substring(4, 6), 16);
51
- return [r, g, b];
52
- }
53
-
54
- /**
55
- * rgb 数值限制
56
- * @param val
57
- * @returns
58
- */
59
- export function rgbNumLimit(val) {
60
- if (val > 250) {
61
- return 250;
62
- }
63
- if (val < 0) {
64
- return 0;
65
- }
66
- return val;
67
- }
68
-
69
- /**
70
- * RGB 转十六进制颜色
71
- * @param r
72
- * @param g
73
- * @param b
74
- * @returns
75
- */
76
- export function rgbToHex(r, g, b) {
77
- return (
78
- "#" +
79
- [r, g, b]
80
- .map((x) => {
81
- const hex = x.toString(16);
82
- return hex.length === 1 ? "0" + hex : hex;
83
- })
84
- .join("")
85
- );
86
- }
87
-
88
- /**
89
- * RGB 转 HSL
90
- * @param r
91
- * @param g
92
- * @param b
93
- * @returns
94
- */
95
- export function rgbToHsl(r, g, b) {
96
- r /= 255;
97
- g /= 255;
98
- b /= 255;
99
- const max = Math.max(r, g, b);
100
- const min = Math.min(r, g, b);
101
- let h,
102
- s,
103
- l = (max + min) / 2;
104
-
105
- if (max === min) {
106
- h = s = 0;
107
- } else {
108
- const d = max - min;
109
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
110
- switch (max) {
111
- case r:
112
- h = (g - b) / d + (g < b ? 6 : 0);
113
- break;
114
- case g:
115
- h = (b - r) / d + 2;
116
- break;
117
- case b:
118
- h = (r - g) / d + 4;
119
- break;
120
- }
121
- h /= 6;
122
- }
123
- return [h * 360, s * 100, l * 100];
124
- }
125
-
126
- /**
127
- * HSL 转 RGB
128
- * @param h
129
- * @param s
130
- * @param l
131
- * @returns
132
- */
133
- export function hslToRgb(h, s, l) {
134
- h /= 360;
135
- s /= 100;
136
- l /= 100;
137
- let r, g, b;
138
-
139
- if (s === 0) {
140
- r = g = b = l;
141
- } else {
142
- const hue2rgb = (p, q, t) => {
143
- if (t < 0) t += 1;
144
- if (t > 1) t -= 1;
145
- if (t < 1 / 6) return p + (q - p) * 6 * t;
146
- if (t < 1 / 2) return q;
147
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
148
- return p;
149
- };
150
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
151
- const p = 2 * l - q;
152
- r = hue2rgb(p, q, h + 1 / 3);
153
- g = hue2rgb(p, q, h);
154
- b = hue2rgb(p, q, h - 1 / 3);
155
- }
156
- return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
157
- }
158
-
159
- /**
160
- * 判断是否为灰色背景
161
- * @param r
162
- * @param g
163
- * @param b
164
- * @returns
165
- */
166
- export function isGray(r, g, b, opt = { tolerance: 10 }) {
167
- const {
168
- /**
169
- * 允许的误差范围
170
- */
171
- tolerance = 10,
172
- } = opt || {}; //
173
- return Math.abs(r - g) <= tolerance && Math.abs(g - b) <= tolerance && Math.abs(r - b) <= tolerance;
174
- }
175
-
176
- /**
177
- * 根据背景颜色选择合适的文本颜色(十六进制格式)
178
- * @param backgroundColor
179
- * @returns
180
- */
181
- export function getTextColor(backgroundColor) {
182
- let [r, g, b] = [0, 0, 0];
183
- if (backgroundColor.startsWith("#")) {
184
- [r, g, b] = hexToRGB(backgroundColor);
185
- } else {
186
- const div = document.createElement("div");
187
- div.style.color = backgroundColor;
188
- document.body.appendChild(div);
189
- const cs = getComputedStyle(div);
190
- const rgb = cs.color.match(/\d+/g).map(Number);
191
- document.body.removeChild(div);
192
- [r, g, b] = rgb;
193
- }
194
- const bgLuminance = luminance(r, g, b);
195
- const whiteLuminance = luminance(255, 255, 255);
196
- const blackLuminance = luminance(0, 0, 0);
197
- const whiteContrast = contrast(bgLuminance, whiteLuminance);
198
- const blackContrast = contrast(bgLuminance, blackLuminance);
199
- return whiteContrast > blackContrast ? "#ffffff" : "#000000";
200
- }
201
-
202
- /**
203
- * 根据背景亮度调整文字颜色深浅
204
- * @param bgR
205
- * @param bgG
206
- * @param bgB
207
- * @returns
208
- */
209
- export function adjustTextColor(hexColor) {
210
- const [bgR, bgG, bgB] = hexToRGB(hexColor);
211
- const bgLuminance = luminance(bgR, bgG, bgB);
212
- let textR, textG, textB;
213
- const targetContrast = 4.5; // WCAG AA 标准
214
-
215
- if (bgR === 0 && bgG === 0 && bgB === 0) {
216
- // 黑色背景
217
- let textR = 255,
218
- textG = 255,
219
- textB = 255;
220
- let textLuminance = luminance(textR, textG, textB);
221
- let ratio = contrastRatio(bgLuminance, textLuminance);
222
- if (ratio < targetContrast) {
223
- textR = 230;
224
- textG = 230;
225
- textB = 230;
226
- }
227
- return rgbToHex(textR, textG, textB);
228
- } else if (bgR === 255 && bgG === 255 && bgB === 255) {
229
- // 白色背景
230
- let textR = 0,
231
- textG = 0,
232
- textB = 0;
233
- let textLuminance = luminance(textR, textG, textB);
234
- let ratio = contrastRatio(bgLuminance, textLuminance);
235
- if (ratio < targetContrast) {
236
- textR = 20;
237
- textG = 20;
238
- textB = 20;
239
- }
240
- return rgbToHex(textR, textG, textB);
241
- } else if (isGray(bgR, bgG, bgB)) {
242
- // 灰色背景
243
- if (bgLuminance < 0.4) {
244
- // 深色灰色背景,使用白色文字
245
- let textR = 255,
246
- textG = 255,
247
- textB = 255;
248
- let textLuminance = luminance(textR, textG, textB);
249
- let ratio = contrastRatio(bgLuminance, textLuminance);
250
- if (ratio < targetContrast) {
251
- textR = 230;
252
- textG = 230;
253
- textB = 230;
254
- }
255
- return rgbToHex(textR, textG, textB);
256
- } else {
257
- // 浅色灰色背景,使用黑色文字
258
- let textR = 0,
259
- textG = 0,
260
- textB = 0;
261
- let textLuminance = luminance(textR, textG, textB);
262
- let ratio = contrastRatio(bgLuminance, textLuminance);
263
- if (ratio < targetContrast) {
264
- textR = 20;
265
- textG = 20;
266
- textB = 20;
267
- }
268
- return rgbToHex(textR, textG, textB);
269
- }
270
- }
271
-
272
- // 非黑白灰背景,使用差值颜色
273
- const adjustNum = 150;
274
- if (bgLuminance > 0.5) {
275
- // 背景较亮,文字颜色调深
276
- textR = Math.max(0, bgR - adjustNum);
277
- textG = Math.max(0, bgG - adjustNum);
278
- textB = Math.max(0, bgB - adjustNum);
279
- } else {
280
- // 背景较暗,文字颜色调亮
281
- textR = Math.min(255, bgR + adjustNum);
282
- textG = Math.min(255, bgG + adjustNum);
283
- textB = Math.min(255, bgB + adjustNum);
284
- }
285
- return rgbToHex(textR, textG, textB);
286
- }
287
-
288
- /**
289
- * 调整颜色深浅
290
- * @param hexColor
291
- * @param amount
292
- * @returns
293
- */
294
- export function adjustColor(hexColor, amount) {
295
- const [r, g, b] = hexToRGB(hexColor);
296
-
297
- const newR = rgbNumLimit(r + amount);
298
- const newG = rgbNumLimit(g + amount);
299
- const newB = rgbNumLimit(b + amount);
300
-
301
- return rgbToHex(newR, newG, newB);
302
- }
1
+ /**
2
+ * 计算颜色的亮度
3
+ * @param r
4
+ * @param g
5
+ * @param b
6
+ * @returns
7
+ */
8
+ export function luminance(r, g, b) {
9
+ const a = [r, g, b].map((v) => {
10
+ v /= 255;
11
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
12
+ });
13
+ return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
14
+ }
15
+
16
+ /**
17
+ * 计算两个颜色之间的对比度
18
+ * @param l1
19
+ * @param l2
20
+ * @returns
21
+ */
22
+ export function contrast(l1, l2) {
23
+ const brightest = Math.max(l1, l2);
24
+ const darkest = Math.min(l1, l2);
25
+ return (brightest + 0.05) / (darkest + 0.05);
26
+ }
27
+
28
+ /**
29
+ * 计算对比度
30
+ * @param luminance1
31
+ * @param luminance2
32
+ * @returns
33
+ */
34
+ export function contrastRatio(luminance1, luminance2) {
35
+ return (Math.max(luminance1, luminance2) + 0.05) / (Math.min(luminance1, luminance2) + 0.05);
36
+ }
37
+
38
+ /**
39
+ * 十六进制颜色转 RGB
40
+ * @param hex
41
+ * @returns
42
+ */
43
+ export function hexToRGB(hex) {
44
+ hex = hex.replace("#", "");
45
+ if (hex.length === 3) {
46
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
47
+ }
48
+ const r = parseInt(hex.substring(0, 2), 16);
49
+ const g = parseInt(hex.substring(2, 4), 16);
50
+ const b = parseInt(hex.substring(4, 6), 16);
51
+ return [r, g, b];
52
+ }
53
+
54
+ /**
55
+ * rgb 数值限制
56
+ * @param val
57
+ * @returns
58
+ */
59
+ export function rgbNumLimit(val) {
60
+ if (val > 250) {
61
+ return 250;
62
+ }
63
+ if (val < 0) {
64
+ return 0;
65
+ }
66
+ return val;
67
+ }
68
+
69
+ /**
70
+ * RGB 转十六进制颜色
71
+ * @param r
72
+ * @param g
73
+ * @param b
74
+ * @returns
75
+ */
76
+ export function rgbToHex(r, g, b) {
77
+ return (
78
+ "#" +
79
+ [r, g, b]
80
+ .map((x) => {
81
+ const hex = x.toString(16);
82
+ return hex.length === 1 ? "0" + hex : hex;
83
+ })
84
+ .join("")
85
+ );
86
+ }
87
+
88
+ /**
89
+ * RGB 转 HSL
90
+ * @param r
91
+ * @param g
92
+ * @param b
93
+ * @returns
94
+ */
95
+ export function rgbToHsl(r, g, b) {
96
+ r /= 255;
97
+ g /= 255;
98
+ b /= 255;
99
+ const max = Math.max(r, g, b);
100
+ const min = Math.min(r, g, b);
101
+ let h,
102
+ s,
103
+ l = (max + min) / 2;
104
+
105
+ if (max === min) {
106
+ h = s = 0;
107
+ } else {
108
+ const d = max - min;
109
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
110
+ switch (max) {
111
+ case r:
112
+ h = (g - b) / d + (g < b ? 6 : 0);
113
+ break;
114
+ case g:
115
+ h = (b - r) / d + 2;
116
+ break;
117
+ case b:
118
+ h = (r - g) / d + 4;
119
+ break;
120
+ }
121
+ h /= 6;
122
+ }
123
+ return [h * 360, s * 100, l * 100];
124
+ }
125
+
126
+ /**
127
+ * HSL 转 RGB
128
+ * @param h
129
+ * @param s
130
+ * @param l
131
+ * @returns
132
+ */
133
+ export function hslToRgb(h, s, l) {
134
+ h /= 360;
135
+ s /= 100;
136
+ l /= 100;
137
+ let r, g, b;
138
+
139
+ if (s === 0) {
140
+ r = g = b = l;
141
+ } else {
142
+ const hue2rgb = (p, q, t) => {
143
+ if (t < 0) t += 1;
144
+ if (t > 1) t -= 1;
145
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
146
+ if (t < 1 / 2) return q;
147
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
148
+ return p;
149
+ };
150
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
151
+ const p = 2 * l - q;
152
+ r = hue2rgb(p, q, h + 1 / 3);
153
+ g = hue2rgb(p, q, h);
154
+ b = hue2rgb(p, q, h - 1 / 3);
155
+ }
156
+ return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
157
+ }
158
+
159
+ /**
160
+ * 判断是否为灰色背景
161
+ * @param r
162
+ * @param g
163
+ * @param b
164
+ * @returns
165
+ */
166
+ export function isGray(r, g, b, opt = { tolerance: 10 }) {
167
+ const {
168
+ /**
169
+ * 允许的误差范围
170
+ */
171
+ tolerance = 10,
172
+ } = opt || {}; //
173
+ return Math.abs(r - g) <= tolerance && Math.abs(g - b) <= tolerance && Math.abs(r - b) <= tolerance;
174
+ }
175
+
176
+ /**
177
+ * 根据背景颜色选择合适的文本颜色(十六进制格式)
178
+ * @param backgroundColor
179
+ * @returns
180
+ */
181
+ export function getTextColor(backgroundColor) {
182
+ let [r, g, b] = [0, 0, 0];
183
+ if (backgroundColor.startsWith("#")) {
184
+ [r, g, b] = hexToRGB(backgroundColor);
185
+ } else {
186
+ const div = document.createElement("div");
187
+ div.style.color = backgroundColor;
188
+ document.body.appendChild(div);
189
+ const cs = getComputedStyle(div);
190
+ const rgb = cs.color.match(/\d+/g).map(Number);
191
+ document.body.removeChild(div);
192
+ [r, g, b] = rgb;
193
+ }
194
+ const bgLuminance = luminance(r, g, b);
195
+ const whiteLuminance = luminance(255, 255, 255);
196
+ const blackLuminance = luminance(0, 0, 0);
197
+ const whiteContrast = contrast(bgLuminance, whiteLuminance);
198
+ const blackContrast = contrast(bgLuminance, blackLuminance);
199
+ return whiteContrast > blackContrast ? "#ffffff" : "#000000";
200
+ }
201
+
202
+ /**
203
+ * 根据背景亮度调整文字颜色深浅
204
+ * @param bgR
205
+ * @param bgG
206
+ * @param bgB
207
+ * @returns
208
+ */
209
+ export function adjustTextColor(hexColor) {
210
+ const [bgR, bgG, bgB] = hexToRGB(hexColor);
211
+ const bgLuminance = luminance(bgR, bgG, bgB);
212
+ let textR, textG, textB;
213
+ const targetContrast = 4.5; // WCAG AA 标准
214
+
215
+ if (bgR === 0 && bgG === 0 && bgB === 0) {
216
+ // 黑色背景
217
+ let textR = 255,
218
+ textG = 255,
219
+ textB = 255;
220
+ let textLuminance = luminance(textR, textG, textB);
221
+ let ratio = contrastRatio(bgLuminance, textLuminance);
222
+ if (ratio < targetContrast) {
223
+ textR = 230;
224
+ textG = 230;
225
+ textB = 230;
226
+ }
227
+ return rgbToHex(textR, textG, textB);
228
+ } else if (bgR === 255 && bgG === 255 && bgB === 255) {
229
+ // 白色背景
230
+ let textR = 0,
231
+ textG = 0,
232
+ textB = 0;
233
+ let textLuminance = luminance(textR, textG, textB);
234
+ let ratio = contrastRatio(bgLuminance, textLuminance);
235
+ if (ratio < targetContrast) {
236
+ textR = 20;
237
+ textG = 20;
238
+ textB = 20;
239
+ }
240
+ return rgbToHex(textR, textG, textB);
241
+ } else if (isGray(bgR, bgG, bgB)) {
242
+ // 灰色背景
243
+ if (bgLuminance < 0.4) {
244
+ // 深色灰色背景,使用白色文字
245
+ let textR = 255,
246
+ textG = 255,
247
+ textB = 255;
248
+ let textLuminance = luminance(textR, textG, textB);
249
+ let ratio = contrastRatio(bgLuminance, textLuminance);
250
+ if (ratio < targetContrast) {
251
+ textR = 230;
252
+ textG = 230;
253
+ textB = 230;
254
+ }
255
+ return rgbToHex(textR, textG, textB);
256
+ } else {
257
+ // 浅色灰色背景,使用黑色文字
258
+ let textR = 0,
259
+ textG = 0,
260
+ textB = 0;
261
+ let textLuminance = luminance(textR, textG, textB);
262
+ let ratio = contrastRatio(bgLuminance, textLuminance);
263
+ if (ratio < targetContrast) {
264
+ textR = 20;
265
+ textG = 20;
266
+ textB = 20;
267
+ }
268
+ return rgbToHex(textR, textG, textB);
269
+ }
270
+ }
271
+
272
+ // 非黑白灰背景,使用差值颜色
273
+ const adjustNum = 150;
274
+ if (bgLuminance > 0.5) {
275
+ // 背景较亮,文字颜色调深
276
+ textR = Math.max(0, bgR - adjustNum);
277
+ textG = Math.max(0, bgG - adjustNum);
278
+ textB = Math.max(0, bgB - adjustNum);
279
+ } else {
280
+ // 背景较暗,文字颜色调亮
281
+ textR = Math.min(255, bgR + adjustNum);
282
+ textG = Math.min(255, bgG + adjustNum);
283
+ textB = Math.min(255, bgB + adjustNum);
284
+ }
285
+ return rgbToHex(textR, textG, textB);
286
+ }
287
+
288
+ /**
289
+ * 调整颜色深浅
290
+ * @param hexColor
291
+ * @param amount
292
+ * @returns
293
+ */
294
+ export function adjustColor(hexColor, amount) {
295
+ const [r, g, b] = hexToRGB(hexColor);
296
+
297
+ const newR = rgbNumLimit(r + amount);
298
+ const newG = rgbNumLimit(g + amount);
299
+ const newB = rgbNumLimit(b + amount);
300
+
301
+ return rgbToHex(newR, newG, newB);
302
+ }
package/src/empty-val.ts CHANGED
@@ -1,40 +1,40 @@
1
- export interface ICheckEmptyOpt {
2
- /** 【废弃】空值占位符 */
3
- emptyStr?: string;
4
- /** 空值占位符 */
5
- emptySymbol?: string;
6
- checkEmptyArr?: boolean;
7
- }
8
- export interface IHandleEmptyValOpt extends ICheckEmptyOpt {}
9
-
10
- /**
11
- * 空数据判断
12
- * @param {*} val
13
- * @param {*} opt
14
- * @returns
15
- */
16
- export function checkEmpty(val, opt: ICheckEmptyOpt = {}) {
17
- const { checkEmptyArr = true } = opt || {};
18
- if (val === "" || val === null || val === undefined) {
19
- return true;
20
- }
21
- if (checkEmptyArr && Array.isArray(val) && Array.length === 0) {
22
- return true;
23
- }
24
- return false;
25
- }
26
-
27
- /**
28
- * 处理空数据显示占位符
29
- * @param val
30
- * @param opt
31
- * @returns
32
- */
33
- export const handleEmptyVal = (val, opt: IHandleEmptyValOpt = {}) => {
34
- const { emptyStr = "--" } = opt || {};
35
- const emptySymbol = opt?.emptySymbol ?? emptyStr;
36
- if (checkEmpty(val, opt)) {
37
- return emptySymbol;
38
- }
39
- return val;
40
- };
1
+ export interface ICheckEmptyOpt {
2
+ /** 【废弃】空值占位符 */
3
+ emptyStr?: string;
4
+ /** 空值占位符 */
5
+ emptySymbol?: string;
6
+ checkEmptyArr?: boolean;
7
+ }
8
+ export interface IHandleEmptyValOpt extends ICheckEmptyOpt {}
9
+
10
+ /**
11
+ * 空数据判断
12
+ * @param {*} val
13
+ * @param {*} opt
14
+ * @returns
15
+ */
16
+ export function checkEmpty(val, opt: ICheckEmptyOpt = {}) {
17
+ const { checkEmptyArr = true } = opt || {};
18
+ if (val === "" || val === null || val === undefined) {
19
+ return true;
20
+ }
21
+ if (checkEmptyArr && Array.isArray(val) && Array.length === 0) {
22
+ return true;
23
+ }
24
+ return false;
25
+ }
26
+
27
+ /**
28
+ * 处理空数据显示占位符
29
+ * @param val
30
+ * @param opt
31
+ * @returns
32
+ */
33
+ export const handleEmptyVal = (val, opt: IHandleEmptyValOpt = {}) => {
34
+ const { emptyStr = "--" } = opt || {};
35
+ const emptySymbol = opt?.emptySymbol ?? emptyStr;
36
+ if (checkEmpty(val, opt)) {
37
+ return emptySymbol;
38
+ }
39
+ return val;
40
+ };