styimat 1.3.0 → 1.4.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/package.json +2 -2
- package/styimat.js +333 -27
- package/styimat.min.js +153 -22
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "styimat",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "一个高效的CSS变量预处理库,支持Lab/LCH颜色空间自动转换、嵌套选择器和Display P3广色域,让现代CSS开发更简洁强大。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
7
7
|
"preprocessor",
|
package/styimat.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 支持 Lab 和 LCH 颜色空间转换为 RGB(CSS标准格式)
|
|
5
5
|
* 支持 lab# 和 lch# 十六进制语法
|
|
6
6
|
* 支持 Display P3 广色域显示器
|
|
7
|
+
* 增强 math() 函数,支持复杂数学计算
|
|
7
8
|
*/
|
|
8
9
|
(function(root, factory) {
|
|
9
10
|
if (typeof define === 'function' && define.amd) {
|
|
@@ -26,9 +27,11 @@
|
|
|
26
27
|
enableNesting: true,
|
|
27
28
|
autoProcessStyleTags: true,
|
|
28
29
|
styleTagAttribute: 'e',
|
|
29
|
-
convertLabToRGB: true,
|
|
30
|
-
convertLchToRGB: true,
|
|
31
|
-
enableP3: true,
|
|
30
|
+
convertLabToRGB: true,
|
|
31
|
+
convertLchToRGB: true,
|
|
32
|
+
enableP3: true,
|
|
33
|
+
enableMath: true, // 启用math()函数增强
|
|
34
|
+
mathPrecision: 6, // 数学计算精度
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
// 全局P3支持检测结果
|
|
@@ -181,6 +184,252 @@
|
|
|
181
184
|
return -1;
|
|
182
185
|
}
|
|
183
186
|
|
|
187
|
+
/**
|
|
188
|
+
* 增强的数学表达式解析和计算
|
|
189
|
+
* @param {string} expression - 数学表达式
|
|
190
|
+
* @param {Object} config - 配置对象
|
|
191
|
+
* @returns {string} 计算结果
|
|
192
|
+
*/
|
|
193
|
+
function evaluateMathExpression(expression, config) {
|
|
194
|
+
// 如果禁用math()增强,则返回原始表达式
|
|
195
|
+
if (!config.enableMath) {
|
|
196
|
+
return `math(${expression})`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
// 清理表达式:移除空白字符
|
|
201
|
+
let cleanExpr = expression.replace(/\s+/g, '');
|
|
202
|
+
|
|
203
|
+
// 解析数学表达式
|
|
204
|
+
const result = parseMathExpression(cleanExpr, config);
|
|
205
|
+
|
|
206
|
+
// 如果结果包含单位,保留原始格式
|
|
207
|
+
if (hasUnits(cleanExpr)) {
|
|
208
|
+
// 处理带单位的表达式
|
|
209
|
+
return processUnitExpression(cleanExpr, result);
|
|
210
|
+
} else {
|
|
211
|
+
// 纯数字表达式,直接计算结果
|
|
212
|
+
return roundNumber(result, config.mathPrecision);
|
|
213
|
+
}
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.warn('math()表达式解析失败:', expression, error);
|
|
216
|
+
return `math(${expression})`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 解析数学表达式
|
|
222
|
+
* @param {string} expr - 清理后的表达式
|
|
223
|
+
* @param {Object} config - 配置对象
|
|
224
|
+
* @returns {number} 计算结果
|
|
225
|
+
*/
|
|
226
|
+
function parseMathExpression(expr, config) {
|
|
227
|
+
// 处理括号
|
|
228
|
+
while (expr.includes('(') && expr.includes(')')) {
|
|
229
|
+
const start = expr.lastIndexOf('(');
|
|
230
|
+
const end = expr.indexOf(')', start);
|
|
231
|
+
|
|
232
|
+
if (end === -1) break;
|
|
233
|
+
|
|
234
|
+
const inner = expr.substring(start + 1, end);
|
|
235
|
+
const innerResult = parseMathExpression(inner, config);
|
|
236
|
+
|
|
237
|
+
expr = expr.substring(0, start) + innerResult + expr.substring(end + 1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 现在expr应该没有括号了
|
|
241
|
+
return evaluateSimpleExpression(expr, config);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 评估简单表达式(无括号)
|
|
246
|
+
* @param {string} expr - 简单表达式
|
|
247
|
+
* @param {Object} config - 配置对象
|
|
248
|
+
* @returns {number} 计算结果
|
|
249
|
+
*/
|
|
250
|
+
function evaluateSimpleExpression(expr, config) {
|
|
251
|
+
// 处理操作符优先级:乘除优先于加减
|
|
252
|
+
const operators = [
|
|
253
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)\*([\d.]+(?:[a-zA-Z%]+)?)/, handler: multiply },
|
|
254
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)\/([\d.]+(?:[a-zA-Z%]+)?)/, handler: divide },
|
|
255
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)\+([\d.]+(?:[a-zA-Z%]+)?)/, handler: add },
|
|
256
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)-([\d.]+(?:[a-zA-Z%]+)?)/, handler: subtract }
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
let lastExpr = expr;
|
|
260
|
+
|
|
261
|
+
// 按照优先级处理操作符
|
|
262
|
+
for (const op of operators) {
|
|
263
|
+
let match;
|
|
264
|
+
while ((match = expr.match(op.regex)) !== null) {
|
|
265
|
+
const left = parseValueWithUnit(match[1]);
|
|
266
|
+
const right = parseValueWithUnit(match[2]);
|
|
267
|
+
const result = op.handler(left, right);
|
|
268
|
+
|
|
269
|
+
// 替换匹配的部分
|
|
270
|
+
expr = expr.substring(0, match.index) +
|
|
271
|
+
result.value +
|
|
272
|
+
expr.substring(match.index + match[0].length);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// 如果表达式无法进一步简化,尝试解析为数字
|
|
277
|
+
if (expr !== lastExpr) {
|
|
278
|
+
return evaluateSimpleExpression(expr, config);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 解析最终结果
|
|
282
|
+
const parsed = parseValueWithUnit(expr);
|
|
283
|
+
return parsed.value;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* 解析带单位的数值
|
|
288
|
+
* @param {string} str - 字符串值
|
|
289
|
+
* @returns {Object} {value: number, unit: string}
|
|
290
|
+
*/
|
|
291
|
+
function parseValueWithUnit(str) {
|
|
292
|
+
// 匹配数值和单位
|
|
293
|
+
const match = str.match(/^([\d.]+)([a-zA-Z%]*)$/);
|
|
294
|
+
|
|
295
|
+
if (!match) {
|
|
296
|
+
throw new Error(`无法解析值: ${str}`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const value = parseFloat(match[1]);
|
|
300
|
+
const unit = match[2] || '';
|
|
301
|
+
|
|
302
|
+
return { value, unit };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 检查表达式是否包含单位
|
|
307
|
+
* @param {string} expr - 表达式
|
|
308
|
+
* @returns {boolean} 是否包含单位
|
|
309
|
+
*/
|
|
310
|
+
function hasUnits(expr) {
|
|
311
|
+
return /[a-zA-Z%]/.test(expr);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* 处理带单位的表达式
|
|
316
|
+
* @param {string} originalExpr - 原始表达式
|
|
317
|
+
* @param {number} result - 计算结果
|
|
318
|
+
* @returns {string} 处理后的表达式
|
|
319
|
+
*/
|
|
320
|
+
function processUnitExpression(originalExpr, result) {
|
|
321
|
+
// 提取原始表达式中的单位
|
|
322
|
+
const unitMatch = originalExpr.match(/([a-zA-Z%]+)(?!.*[a-zA-Z%])/);
|
|
323
|
+
|
|
324
|
+
if (unitMatch) {
|
|
325
|
+
return result + unitMatch[1];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// 如果没有明确单位,检查是否为百分比
|
|
329
|
+
if (originalExpr.includes('%')) {
|
|
330
|
+
return result + '%';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// 默认为像素
|
|
334
|
+
return result + 'px';
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 数学运算函数
|
|
338
|
+
function multiply(a, b) {
|
|
339
|
+
if (a.unit === b.unit || (!a.unit && !b.unit)) {
|
|
340
|
+
return { value: a.value * b.value, unit: a.unit || b.unit };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 单位不匹配,返回原始表达式
|
|
344
|
+
return { value: `${a.value}${a.unit}*${b.value}${b.unit}`, unit: '' };
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function divide(a, b) {
|
|
348
|
+
if (b.value === 0) {
|
|
349
|
+
throw new Error('除以零');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (a.unit && !b.unit) {
|
|
353
|
+
// 如 100px / 2
|
|
354
|
+
return { value: a.value / b.value, unit: a.unit };
|
|
355
|
+
} else if (a.unit === b.unit) {
|
|
356
|
+
// 如 100px / 2px
|
|
357
|
+
return { value: a.value / b.value, unit: '' };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// 单位不匹配,返回原始表达式
|
|
361
|
+
return { value: `${a.value}${a.unit}/${b.value}${b.unit}`, unit: '' };
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function add(a, b) {
|
|
365
|
+
if (a.unit === b.unit) {
|
|
366
|
+
return { value: a.value + b.value, unit: a.unit };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 单位不匹配,返回原始表达式
|
|
370
|
+
return { value: `${a.value}${a.unit}+${b.value}${b.unit}`, unit: '' };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function subtract(a, b) {
|
|
374
|
+
if (a.unit === b.unit) {
|
|
375
|
+
return { value: a.value - b.value, unit: a.unit };
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// 单位不匹配,返回原始表达式
|
|
379
|
+
return { value: `${a.value}${a.unit}-${b.value}${b.unit}`, unit: '' };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* 四舍五入到指定精度
|
|
384
|
+
* @param {number} num - 要四舍五入的数字
|
|
385
|
+
* @param {number} precision - 精度
|
|
386
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
387
|
+
*/
|
|
388
|
+
function roundNumber(num, precision = 6) {
|
|
389
|
+
const factor = Math.pow(10, precision);
|
|
390
|
+
const rounded = Math.round(num * factor) / factor;
|
|
391
|
+
|
|
392
|
+
// 移除不必要的尾随零
|
|
393
|
+
const str = rounded.toString();
|
|
394
|
+
if (str.includes('.')) {
|
|
395
|
+
return str.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
|
|
396
|
+
}
|
|
397
|
+
return str;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* 处理所有的math()函数
|
|
402
|
+
* @param {string} cssValue - CSS属性值
|
|
403
|
+
* @param {Object} config - 配置对象
|
|
404
|
+
* @returns {string} 转换后的CSS值
|
|
405
|
+
*/
|
|
406
|
+
function processMathFunctions(cssValue, config) {
|
|
407
|
+
if (!config.enableMath) {
|
|
408
|
+
return cssValue;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
let result = cssValue;
|
|
412
|
+
|
|
413
|
+
// 匹配math()函数
|
|
414
|
+
const mathRegex = /math\(([^)]+)\)/gi;
|
|
415
|
+
|
|
416
|
+
// 递归处理嵌套的math()函数
|
|
417
|
+
const processMath = (str) => {
|
|
418
|
+
return str.replace(mathRegex, (match, expression) => {
|
|
419
|
+
return evaluateMathExpression(expression, config);
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// 递归处理,直到没有更多math()函数
|
|
424
|
+
let lastResult;
|
|
425
|
+
do {
|
|
426
|
+
lastResult = result;
|
|
427
|
+
result = processMath(result);
|
|
428
|
+
} while (result !== lastResult && result.includes('math('));
|
|
429
|
+
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
|
|
184
433
|
/**
|
|
185
434
|
* 解析并转换所有的 Lab 和 LCH 颜色(全局一次性处理)
|
|
186
435
|
* @param {string} cssValue - CSS属性值
|
|
@@ -616,21 +865,32 @@
|
|
|
616
865
|
}
|
|
617
866
|
|
|
618
867
|
/**
|
|
619
|
-
* 处理CSS值,根据配置转换LAB
|
|
868
|
+
* 处理CSS值,根据配置转换LAB、LCH颜色和math()函数
|
|
620
869
|
* @param {string} value - CSS属性值
|
|
621
870
|
* @param {Object} config - 配置对象
|
|
622
871
|
* @returns {string} 处理后的值
|
|
623
872
|
*/
|
|
624
873
|
function processCSSValue(value, config) {
|
|
625
|
-
|
|
626
|
-
|
|
874
|
+
let result = value;
|
|
875
|
+
|
|
876
|
+
// 1. 首先处理math()函数
|
|
877
|
+
if (config.enableMath) {
|
|
878
|
+
result = processMathFunctions(result, config);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// 2. 然后处理LAB和LCH颜色
|
|
882
|
+
if (config.convertLabToRGB || config.convertLchToRGB) {
|
|
883
|
+
result = convertAllLabLchColors(result, config);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
return result;
|
|
627
887
|
}
|
|
628
888
|
|
|
629
889
|
// 私有方法:提取变量定义并移除(支持嵌套作用域)
|
|
630
890
|
function extractVariablesAndCSS(cssText, config) {
|
|
631
891
|
const lines = cssText.split('\n');
|
|
632
892
|
const globalVariables = {};
|
|
633
|
-
const selectorVariables = new Map();
|
|
893
|
+
const selectorVariables = new Map();
|
|
634
894
|
let cssWithoutVars = '';
|
|
635
895
|
let currentSelector = null;
|
|
636
896
|
let inSelectorBlock = false;
|
|
@@ -644,8 +904,8 @@
|
|
|
644
904
|
|
|
645
905
|
if (varMatch) {
|
|
646
906
|
const [, varName, varValue] = varMatch;
|
|
647
|
-
//
|
|
648
|
-
const processedValue =
|
|
907
|
+
// 处理变量值中的数学表达式和颜色转换
|
|
908
|
+
const processedValue = processCSSValue(
|
|
649
909
|
replaceVariableUsesInValue(varValue.trim(), {
|
|
650
910
|
...globalVariables,
|
|
651
911
|
...(currentSelector ? selectorVariables.get(currentSelector) || {} : {})
|
|
@@ -764,11 +1024,11 @@
|
|
|
764
1024
|
if (!trimmed.includes('{') && !trimmed.includes('}') && trimmed.includes(':')) {
|
|
765
1025
|
if (stack.length > 0) {
|
|
766
1026
|
const currentRule = stack[stack.length - 1];
|
|
767
|
-
// 处理属性值中的
|
|
1027
|
+
// 处理属性值中的math()函数和颜色转换
|
|
768
1028
|
const parsed = parseSingleLineCSS(trimmed);
|
|
769
1029
|
parsed.forEach(obj => {
|
|
770
1030
|
const key = Object.keys(obj)[0];
|
|
771
|
-
const value =
|
|
1031
|
+
const value = processCSSValue(obj[key], config);
|
|
772
1032
|
currentRule.properties.push(`${key}: ${value}`);
|
|
773
1033
|
});
|
|
774
1034
|
}
|
|
@@ -821,11 +1081,11 @@
|
|
|
821
1081
|
if (rule.properties.length > 0) {
|
|
822
1082
|
result += (isAt ? "" : fullSelector) + ' {\n';
|
|
823
1083
|
for (const prop of rule.properties) {
|
|
824
|
-
// 再次处理属性值(确保
|
|
1084
|
+
// 再次处理属性值(确保math()函数和颜色被转换)
|
|
825
1085
|
const parsed = parseSingleLineCSS(prop);
|
|
826
1086
|
parsed.forEach(obj => {
|
|
827
1087
|
const key = Object.keys(obj)[0];
|
|
828
|
-
const value =
|
|
1088
|
+
const value = processCSSValue(obj[key], config);
|
|
829
1089
|
result += (isParentAt ? ' ' : '') + ` ${key}: ${value};\n`;
|
|
830
1090
|
});
|
|
831
1091
|
}
|
|
@@ -870,10 +1130,8 @@
|
|
|
870
1130
|
return `var(--${varName})`;
|
|
871
1131
|
});
|
|
872
1132
|
|
|
873
|
-
// 最后处理所有的LAB
|
|
874
|
-
|
|
875
|
-
result = convertAllLabLchColors(result, config);
|
|
876
|
-
}
|
|
1133
|
+
// 最后处理所有的LAB、LCH颜色和math()函数
|
|
1134
|
+
result = processCSSValue(result, config);
|
|
877
1135
|
|
|
878
1136
|
return result;
|
|
879
1137
|
}
|
|
@@ -886,7 +1144,7 @@
|
|
|
886
1144
|
|
|
887
1145
|
const declarations = Object.entries(variables)
|
|
888
1146
|
.map(([name, value]) => {
|
|
889
|
-
const processedValue =
|
|
1147
|
+
const processedValue = processCSSValue(
|
|
890
1148
|
replaceVariableUsesInValue(value, variables),
|
|
891
1149
|
config
|
|
892
1150
|
);
|
|
@@ -922,12 +1180,8 @@
|
|
|
922
1180
|
currentSelector = null;
|
|
923
1181
|
}
|
|
924
1182
|
|
|
925
|
-
//
|
|
926
|
-
|
|
927
|
-
result += convertAllLabLchColors(line, config) + '\n';
|
|
928
|
-
} else {
|
|
929
|
-
result += line + '\n';
|
|
930
|
-
}
|
|
1183
|
+
// 使用全局处理函数处理所有math()和颜色
|
|
1184
|
+
result += processCSSValue(line, config) + '\n';
|
|
931
1185
|
}
|
|
932
1186
|
|
|
933
1187
|
return result.trim();
|
|
@@ -1024,7 +1278,7 @@
|
|
|
1024
1278
|
convert,
|
|
1025
1279
|
apply,
|
|
1026
1280
|
config,
|
|
1027
|
-
version: '1.
|
|
1281
|
+
version: '1.9.0',
|
|
1028
1282
|
|
|
1029
1283
|
// 检测P3支持
|
|
1030
1284
|
supportsP3: detectP3Support(),
|
|
@@ -1032,6 +1286,58 @@
|
|
|
1032
1286
|
// 重新检测P3支持(如果配置变化)
|
|
1033
1287
|
detectP3Support: detectP3Support,
|
|
1034
1288
|
|
|
1289
|
+
// 数学计算工具方法
|
|
1290
|
+
math: {
|
|
1291
|
+
/**
|
|
1292
|
+
* 计算数学表达式
|
|
1293
|
+
* @param {string} expression - 数学表达式
|
|
1294
|
+
* @returns {string} 计算结果
|
|
1295
|
+
*/
|
|
1296
|
+
evaluate: function(expression) {
|
|
1297
|
+
return evaluateMathExpression(expression, defaultConfig);
|
|
1298
|
+
},
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* 解析带单位的数值
|
|
1302
|
+
* @param {string} value - 带单位的字符串
|
|
1303
|
+
* @returns {Object} {value: number, unit: string}
|
|
1304
|
+
*/
|
|
1305
|
+
parseUnit: parseValueWithUnit,
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* 四舍五入数字
|
|
1309
|
+
* @param {number} num - 要四舍五入的数字
|
|
1310
|
+
* @param {number} precision - 精度
|
|
1311
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
1312
|
+
*/
|
|
1313
|
+
round: roundNumber,
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* 测试数学表达式
|
|
1317
|
+
* @param {string} expression - 要测试的表达式
|
|
1318
|
+
* @param {Object} testConfig - 测试配置
|
|
1319
|
+
* @returns {Object} 测试结果
|
|
1320
|
+
*/
|
|
1321
|
+
test: function(expression, testConfig = {}) {
|
|
1322
|
+
const config = { ...defaultConfig, ...testConfig };
|
|
1323
|
+
try {
|
|
1324
|
+
const result = evaluateMathExpression(expression, config);
|
|
1325
|
+
return {
|
|
1326
|
+
success: true,
|
|
1327
|
+
expression,
|
|
1328
|
+
result,
|
|
1329
|
+
parsed: parseValueWithUnit(result.replace(/^calc\(|\)$/g, ''))
|
|
1330
|
+
};
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
return {
|
|
1333
|
+
success: false,
|
|
1334
|
+
expression,
|
|
1335
|
+
error: error.message
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
},
|
|
1340
|
+
|
|
1035
1341
|
// 颜色转换工具方法
|
|
1036
1342
|
colorUtils: {
|
|
1037
1343
|
labToRGB: preciseLabToRGB,
|
|
@@ -1152,12 +1458,12 @@
|
|
|
1152
1458
|
const element = this;
|
|
1153
1459
|
return new Proxy({}, {
|
|
1154
1460
|
get(target, prop) {
|
|
1155
|
-
const varName = prop.startsWith('
|
|
1461
|
+
const varName = prop.startsWith('--') ? prop : `--${prop}`;
|
|
1156
1462
|
return element.style.getPropertyValue(varName);
|
|
1157
1463
|
},
|
|
1158
1464
|
|
|
1159
1465
|
set(target, prop, value) {
|
|
1160
|
-
const varName = prop.startsWith('
|
|
1466
|
+
const varName = prop.startsWith('--') ? prop : `--${prop}`;
|
|
1161
1467
|
element.style.setProperty(varName, value);
|
|
1162
1468
|
return true;
|
|
1163
1469
|
}
|
package/styimat.min.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 支持 Lab 和 LCH 颜色空间转换为 RGB(CSS标准格式)
|
|
5
5
|
* 支持 lab# 和 lch# 十六进制语法
|
|
6
6
|
* 支持 Display P3 广色域显示器
|
|
7
|
+
* 增强 math() 函数,支持复杂数学计算
|
|
7
8
|
*/
|
|
8
9
|
(function(root,factory){if(typeof define==="function"&&define.amd){
|
|
9
10
|
// AMD 支持 (RequireJS)
|
|
@@ -13,9 +14,8 @@ module.exports=factory()}else{
|
|
|
13
14
|
// 浏览器全局变量
|
|
14
15
|
root.styimat=factory()}})(typeof self!=="undefined"?self:this,function(){
|
|
15
16
|
// 默认配置
|
|
16
|
-
let defaultConfig={rootSelector:":root",variablePrefix:"--",preserveOriginal:false,indentSize:2,enableNesting:true,autoProcessStyleTags:true,styleTagAttribute:"e",convertLabToRGB:true,//
|
|
17
|
-
|
|
18
|
-
enableP3:true};
|
|
17
|
+
let defaultConfig={rootSelector:":root",variablePrefix:"--",preserveOriginal:false,indentSize:2,enableNesting:true,autoProcessStyleTags:true,styleTagAttribute:"e",convertLabToRGB:true,convertLchToRGB:true,enableP3:true,enableMath:true,// 启用math()函数增强
|
|
18
|
+
mathPrecision:6};
|
|
19
19
|
// 全局P3支持检测结果
|
|
20
20
|
let p3Supported=null;
|
|
21
21
|
/**
|
|
@@ -68,6 +68,108 @@ result.push({[property]:value})}return result}
|
|
|
68
68
|
if((char==='"'||char==="'")&&!inQuotes){inQuotes=true;quoteChar=char}else if(char===quoteChar&&inQuotes){inQuotes=false;quoteChar=""}
|
|
69
69
|
// 如果找到冒号且不在引号内,返回位置
|
|
70
70
|
if(char===":"&&!inQuotes){return i}}return-1}
|
|
71
|
+
/**
|
|
72
|
+
* 增强的数学表达式解析和计算
|
|
73
|
+
* @param {string} expression - 数学表达式
|
|
74
|
+
* @param {Object} config - 配置对象
|
|
75
|
+
* @returns {string} 计算结果
|
|
76
|
+
*/function evaluateMathExpression(expression,config){
|
|
77
|
+
// 如果禁用math()增强,则返回原始表达式
|
|
78
|
+
if(!config.enableMath){return`math(${expression})`}try{
|
|
79
|
+
// 清理表达式:移除空白字符
|
|
80
|
+
let cleanExpr=expression.replace(/\s+/g,"");
|
|
81
|
+
// 解析数学表达式
|
|
82
|
+
const result=parseMathExpression(cleanExpr,config);
|
|
83
|
+
// 如果结果包含单位,保留原始格式
|
|
84
|
+
if(hasUnits(cleanExpr)){
|
|
85
|
+
// 处理带单位的表达式
|
|
86
|
+
return processUnitExpression(cleanExpr,result)}else{
|
|
87
|
+
// 纯数字表达式,直接计算结果
|
|
88
|
+
return roundNumber(result,config.mathPrecision)}}catch(error){console.warn("math()表达式解析失败:",expression,error);return`math(${expression})`}}
|
|
89
|
+
/**
|
|
90
|
+
* 解析数学表达式
|
|
91
|
+
* @param {string} expr - 清理后的表达式
|
|
92
|
+
* @param {Object} config - 配置对象
|
|
93
|
+
* @returns {number} 计算结果
|
|
94
|
+
*/function parseMathExpression(expr,config){
|
|
95
|
+
// 处理括号
|
|
96
|
+
while(expr.includes("(")&&expr.includes(")")){const start=expr.lastIndexOf("(");const end=expr.indexOf(")",start);if(end===-1)break;const inner=expr.substring(start+1,end);const innerResult=parseMathExpression(inner,config);expr=expr.substring(0,start)+innerResult+expr.substring(end+1)}
|
|
97
|
+
// 现在expr应该没有括号了
|
|
98
|
+
return evaluateSimpleExpression(expr,config)}
|
|
99
|
+
/**
|
|
100
|
+
* 评估简单表达式(无括号)
|
|
101
|
+
* @param {string} expr - 简单表达式
|
|
102
|
+
* @param {Object} config - 配置对象
|
|
103
|
+
* @returns {number} 计算结果
|
|
104
|
+
*/function evaluateSimpleExpression(expr,config){
|
|
105
|
+
// 处理操作符优先级:乘除优先于加减
|
|
106
|
+
const operators=[{regex:/([\d.]+(?:[a-zA-Z%]+)?)\*([\d.]+(?:[a-zA-Z%]+)?)/,handler:multiply},{regex:/([\d.]+(?:[a-zA-Z%]+)?)\/([\d.]+(?:[a-zA-Z%]+)?)/,handler:divide},{regex:/([\d.]+(?:[a-zA-Z%]+)?)\+([\d.]+(?:[a-zA-Z%]+)?)/,handler:add},{regex:/([\d.]+(?:[a-zA-Z%]+)?)-([\d.]+(?:[a-zA-Z%]+)?)/,handler:subtract}];let lastExpr=expr;
|
|
107
|
+
// 按照优先级处理操作符
|
|
108
|
+
for(const op of operators){let match;while((match=expr.match(op.regex))!==null){const left=parseValueWithUnit(match[1]);const right=parseValueWithUnit(match[2]);const result=op.handler(left,right);
|
|
109
|
+
// 替换匹配的部分
|
|
110
|
+
expr=expr.substring(0,match.index)+result.value+expr.substring(match.index+match[0].length)}}
|
|
111
|
+
// 如果表达式无法进一步简化,尝试解析为数字
|
|
112
|
+
if(expr!==lastExpr){return evaluateSimpleExpression(expr,config)}
|
|
113
|
+
// 解析最终结果
|
|
114
|
+
const parsed=parseValueWithUnit(expr);return parsed.value}
|
|
115
|
+
/**
|
|
116
|
+
* 解析带单位的数值
|
|
117
|
+
* @param {string} str - 字符串值
|
|
118
|
+
* @returns {Object} {value: number, unit: string}
|
|
119
|
+
*/function parseValueWithUnit(str){
|
|
120
|
+
// 匹配数值和单位
|
|
121
|
+
const match=str.match(/^([\d.]+)([a-zA-Z%]*)$/);if(!match){throw new Error(`无法解析值: ${str}`)}const value=parseFloat(match[1]);const unit=match[2]||"";return{value:value,unit:unit}}
|
|
122
|
+
/**
|
|
123
|
+
* 检查表达式是否包含单位
|
|
124
|
+
* @param {string} expr - 表达式
|
|
125
|
+
* @returns {boolean} 是否包含单位
|
|
126
|
+
*/function hasUnits(expr){return/[a-zA-Z%]/.test(expr)}
|
|
127
|
+
/**
|
|
128
|
+
* 处理带单位的表达式
|
|
129
|
+
* @param {string} originalExpr - 原始表达式
|
|
130
|
+
* @param {number} result - 计算结果
|
|
131
|
+
* @returns {string} 处理后的表达式
|
|
132
|
+
*/function processUnitExpression(originalExpr,result){
|
|
133
|
+
// 提取原始表达式中的单位
|
|
134
|
+
const unitMatch=originalExpr.match(/([a-zA-Z%]+)(?!.*[a-zA-Z%])/);if(unitMatch){return result+unitMatch[1]}
|
|
135
|
+
// 如果没有明确单位,检查是否为百分比
|
|
136
|
+
if(originalExpr.includes("%")){return result+"%"}
|
|
137
|
+
// 默认为像素
|
|
138
|
+
return result+"px"}
|
|
139
|
+
// 数学运算函数
|
|
140
|
+
function multiply(a,b){if(a.unit===b.unit||!a.unit&&!b.unit){return{value:a.value*b.value,unit:a.unit||b.unit}}
|
|
141
|
+
// 单位不匹配,返回原始表达式
|
|
142
|
+
return{value:`${a.value}${a.unit}*${b.value}${b.unit}`,unit:""}}function divide(a,b){if(b.value===0){throw new Error("除以零")}if(a.unit&&!b.unit){
|
|
143
|
+
// 如 100px / 2
|
|
144
|
+
return{value:a.value/b.value,unit:a.unit}}else if(a.unit===b.unit){
|
|
145
|
+
// 如 100px / 2px
|
|
146
|
+
return{value:a.value/b.value,unit:""}}
|
|
147
|
+
// 单位不匹配,返回原始表达式
|
|
148
|
+
return{value:`${a.value}${a.unit}/${b.value}${b.unit}`,unit:""}}function add(a,b){if(a.unit===b.unit){return{value:a.value+b.value,unit:a.unit}}
|
|
149
|
+
// 单位不匹配,返回原始表达式
|
|
150
|
+
return{value:`${a.value}${a.unit}+${b.value}${b.unit}`,unit:""}}function subtract(a,b){if(a.unit===b.unit){return{value:a.value-b.value,unit:a.unit}}
|
|
151
|
+
// 单位不匹配,返回原始表达式
|
|
152
|
+
return{value:`${a.value}${a.unit}-${b.value}${b.unit}`,unit:""}}
|
|
153
|
+
/**
|
|
154
|
+
* 四舍五入到指定精度
|
|
155
|
+
* @param {number} num - 要四舍五入的数字
|
|
156
|
+
* @param {number} precision - 精度
|
|
157
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
158
|
+
*/function roundNumber(num,precision=6){const factor=Math.pow(10,precision);const rounded=Math.round(num*factor)/factor;
|
|
159
|
+
// 移除不必要的尾随零
|
|
160
|
+
const str=rounded.toString();if(str.includes(".")){return str.replace(/(\.\d*?)0+$/,"$1").replace(/\.$/,"")}return str}
|
|
161
|
+
/**
|
|
162
|
+
* 处理所有的math()函数
|
|
163
|
+
* @param {string} cssValue - CSS属性值
|
|
164
|
+
* @param {Object} config - 配置对象
|
|
165
|
+
* @returns {string} 转换后的CSS值
|
|
166
|
+
*/function processMathFunctions(cssValue,config){if(!config.enableMath){return cssValue}let result=cssValue;
|
|
167
|
+
// 匹配math()函数
|
|
168
|
+
const mathRegex=/math\(([^)]+)\)/gi;
|
|
169
|
+
// 递归处理嵌套的math()函数
|
|
170
|
+
const processMath=str=>str.replace(mathRegex,(match,expression)=>evaluateMathExpression(expression,config));
|
|
171
|
+
// 递归处理,直到没有更多math()函数
|
|
172
|
+
let lastResult;do{lastResult=result;result=processMath(result)}while(result!==lastResult&&result.includes("math("));return result}
|
|
71
173
|
/**
|
|
72
174
|
* 解析并转换所有的 Lab 和 LCH 颜色(全局一次性处理)
|
|
73
175
|
* @param {string} cssValue - CSS属性值
|
|
@@ -218,20 +320,21 @@ const rgb=preciseLabToRGB(L,a,b);if(alpha!==null){return`rgba(${rgb.r}, ${rgb.g}
|
|
|
218
320
|
// 使用P3
|
|
219
321
|
const p3=labToP3(L,a,b);if(alpha!==null){return`color(display-p3 ${p3.r.toFixed(4)} ${p3.g.toFixed(4)} ${p3.b.toFixed(4)} / ${alpha})`}return`color(display-p3 ${p3.r.toFixed(4)} ${p3.g.toFixed(4)} ${p3.b.toFixed(4)})`}}
|
|
220
322
|
/**
|
|
221
|
-
* 处理CSS值,根据配置转换LAB
|
|
323
|
+
* 处理CSS值,根据配置转换LAB、LCH颜色和math()函数
|
|
222
324
|
* @param {string} value - CSS属性值
|
|
223
325
|
* @param {Object} config - 配置对象
|
|
224
326
|
* @returns {string} 处理后的值
|
|
225
|
-
*/function processCSSValue(value,config){
|
|
226
|
-
//
|
|
227
|
-
|
|
327
|
+
*/function processCSSValue(value,config){let result=value;
|
|
328
|
+
// 1. 首先处理math()函数
|
|
329
|
+
if(config.enableMath){result=processMathFunctions(result,config)}
|
|
330
|
+
// 2. 然后处理LAB和LCH颜色
|
|
331
|
+
if(config.convertLabToRGB||config.convertLchToRGB){result=convertAllLabLchColors(result,config)}return result}
|
|
228
332
|
// 私有方法:提取变量定义并移除(支持嵌套作用域)
|
|
229
|
-
function extractVariablesAndCSS(cssText,config){const lines=cssText.split("\n");const globalVariables={};const selectorVariables=new Map
|
|
230
|
-
let cssWithoutVars="";let currentSelector=null;let inSelectorBlock=false;let currentIndent=0;for(let line of lines){const trimmed=line.trim();
|
|
333
|
+
function extractVariablesAndCSS(cssText,config){const lines=cssText.split("\n");const globalVariables={};const selectorVariables=new Map;let cssWithoutVars="";let currentSelector=null;let inSelectorBlock=false;let currentIndent=0;for(let line of lines){const trimmed=line.trim();
|
|
231
334
|
// 检查是否是变量定义
|
|
232
335
|
const varMatch=trimmed.match(/^\$([a-zA-Z0-9_-]+)\s*:\s*(.+?);?$/);if(varMatch){const[,varName,varValue]=varMatch;
|
|
233
|
-
//
|
|
234
|
-
const processedValue=
|
|
336
|
+
// 处理变量值中的数学表达式和颜色转换
|
|
337
|
+
const processedValue=processCSSValue(replaceVariableUsesInValue(varValue.trim(),{...globalVariables,...currentSelector?selectorVariables.get(currentSelector)||{}:{}}),config);if(currentSelector){
|
|
235
338
|
// 选择器内部的变量
|
|
236
339
|
if(!selectorVariables.has(currentSelector)){selectorVariables.set(currentSelector,{})}selectorVariables.get(currentSelector)[varName]=processedValue}else{
|
|
237
340
|
// 全局变量(:root 中)
|
|
@@ -263,8 +366,8 @@ const rule={selector:selector,properties:[],children:[],indentLevel:indentLevel}
|
|
|
263
366
|
stack.push(rule);continue}
|
|
264
367
|
// 处理属性行(不包含 { 或 } 的行)
|
|
265
368
|
if(!trimmed.includes("{")&&!trimmed.includes("}")&&trimmed.includes(":")){if(stack.length>0){const currentRule=stack[stack.length-1];
|
|
266
|
-
// 处理属性值中的
|
|
267
|
-
const parsed=parseSingleLineCSS(trimmed);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=
|
|
369
|
+
// 处理属性值中的math()函数和颜色转换
|
|
370
|
+
const parsed=parseSingleLineCSS(trimmed);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=processCSSValue(obj[key],config);currentRule.properties.push(`${key}: ${value}`)})}continue}}
|
|
268
371
|
// 处理栈中剩余规则
|
|
269
372
|
while(stack.length>0){const rule=stack.pop();if(stack.length===0){rootRules.push(rule)}else{const parent=stack[stack.length-1];if(!parent.children)parent.children=[];parent.children.push(rule)}}
|
|
270
373
|
// 将规则树转换为CSS字符串
|
|
@@ -277,8 +380,8 @@ const isAt=rule.selector.startsWith("@");let fullSelector=(isParentAt?" ":"")+r
|
|
|
277
380
|
if(fullSelector.includes("&")){fullSelector=fullSelector.replace(/&/g,parentSelector)}else if(fullSelector.trim().startsWith(":")){fullSelector=parentSelector+fullSelector}else{fullSelector=parentSelector+(isParentAt?"":" ")+fullSelector}}
|
|
278
381
|
// 如果有属性,生成规则块
|
|
279
382
|
if(rule.properties.length>0){result+=(isAt?"":fullSelector)+" {\n";for(const prop of rule.properties){
|
|
280
|
-
// 再次处理属性值(确保
|
|
281
|
-
const parsed=parseSingleLineCSS(prop);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=
|
|
383
|
+
// 再次处理属性值(确保math()函数和颜色被转换)
|
|
384
|
+
const parsed=parseSingleLineCSS(prop);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=processCSSValue(obj[key],config);result+=(isParentAt?" ":"")+` ${key}: ${value};\n`})}result+=isParentAt?" }\n":"}\n\n"}
|
|
282
385
|
// 递归处理子规则
|
|
283
386
|
if(rule.children&&rule.children.length>0){result+=convertRulesToCSS(rule.children,config,fullSelector)}if(isParentAt){result+="}\n\n"}}return result.trim()+(isParentAt?"\n\n":"")}
|
|
284
387
|
// 替换变量值中的变量引用
|
|
@@ -289,16 +392,16 @@ function replaceVariableUses(cssText,globalVariables,selectorVariables,config){l
|
|
|
289
392
|
for(const[varName,varValue]of Object.entries(globalVariables)){const varRegex=new RegExp(`\\$${varName}(?![a-zA-Z0-9_-])`,"g");result=result.replace(varRegex,`var(--${varName})`)}
|
|
290
393
|
// 然后处理选择器特定的变量
|
|
291
394
|
result=result.replace(/\$([a-zA-Z0-9_-]+)/g,(match,varName)=>`var(--${varName})`);
|
|
292
|
-
// 最后处理所有的LAB
|
|
293
|
-
|
|
395
|
+
// 最后处理所有的LAB、LCH颜色和math()函数
|
|
396
|
+
result=processCSSValue(result,config);return result}
|
|
294
397
|
// 生成根规则
|
|
295
|
-
function generateRootRule(variables,config){if(Object.keys(variables).length===0){return""}const declarations=Object.entries(variables).map(([name,value])=>{const processedValue=
|
|
398
|
+
function generateRootRule(variables,config){if(Object.keys(variables).length===0){return""}const declarations=Object.entries(variables).map(([name,value])=>{const processedValue=processCSSValue(replaceVariableUsesInValue(value,variables),config);return` --${name}: ${processedValue};`}).join("\n");return`${config.rootSelector} {\n${declarations}\n}\n\n`}
|
|
296
399
|
// 处理选择器内部的变量
|
|
297
400
|
function injectSelectorVariables(cssText,selectorVariables,config){let result="";const lines=cssText.split("\n");let currentSelector=null;for(let line of lines){const trimmed=line.trim();if(trimmed.endsWith("{")){currentSelector=trimmed.slice(0,-1).trim()}if(trimmed==="}"&¤tSelector){
|
|
298
401
|
// 在选择器结束前插入变量声明
|
|
299
402
|
if(selectorVariables.has(currentSelector)){const vars=selectorVariables.get(currentSelector);const indent=line.match(/^(\s*)/)[0];for(const[varName,varValue]of Object.entries(vars)){result+=indent+" --"+varName+": "+varValue+";\n"}}currentSelector=null}
|
|
300
|
-
//
|
|
301
|
-
|
|
403
|
+
// 使用全局处理函数处理所有math()和颜色
|
|
404
|
+
result+=processCSSValue(line,config)+"\n"}return result.trim()}
|
|
302
405
|
// 主转换函数
|
|
303
406
|
function convert(cssText,customConfig={}){const config={...defaultConfig,...customConfig};
|
|
304
407
|
// 1. 提取变量定义(区分全局和选择器局部)
|
|
@@ -324,11 +427,39 @@ if(!config.preserveOriginal){styleTag.remove()}else{styleTag.style.display="none
|
|
|
324
427
|
// 初始化自动处理
|
|
325
428
|
function apply(cssText,customConfig={}){const config={...defaultConfig,...customConfig};if(cssText){const converted=convert(cssText,config);const styleEl=document.createElement("style");styleEl.textContent=converted;document.head.appendChild(styleEl);return styleEl}else{if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",()=>{autoProcessStyleTags(config)})}else{autoProcessStyleTags(config)}}}
|
|
326
429
|
// 返回公共 API
|
|
327
|
-
const api={convert:convert,apply:apply,config:config,version:"1.
|
|
430
|
+
const api={convert:convert,apply:apply,config:config,version:"1.9.0",
|
|
328
431
|
// 检测P3支持
|
|
329
432
|
supportsP3:detectP3Support(),
|
|
330
433
|
// 重新检测P3支持(如果配置变化)
|
|
331
434
|
detectP3Support:detectP3Support,
|
|
435
|
+
// 数学计算工具方法
|
|
436
|
+
math:{
|
|
437
|
+
/**
|
|
438
|
+
* 计算数学表达式
|
|
439
|
+
* @param {string} expression - 数学表达式
|
|
440
|
+
* @returns {string} 计算结果
|
|
441
|
+
*/
|
|
442
|
+
evaluate:function(expression){return evaluateMathExpression(expression,defaultConfig)},
|
|
443
|
+
/**
|
|
444
|
+
* 解析带单位的数值
|
|
445
|
+
* @param {string} value - 带单位的字符串
|
|
446
|
+
* @returns {Object} {value: number, unit: string}
|
|
447
|
+
*/
|
|
448
|
+
parseUnit:parseValueWithUnit,
|
|
449
|
+
/**
|
|
450
|
+
* 四舍五入数字
|
|
451
|
+
* @param {number} num - 要四舍五入的数字
|
|
452
|
+
* @param {number} precision - 精度
|
|
453
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
454
|
+
*/
|
|
455
|
+
round:roundNumber,
|
|
456
|
+
/**
|
|
457
|
+
* 测试数学表达式
|
|
458
|
+
* @param {string} expression - 要测试的表达式
|
|
459
|
+
* @param {Object} testConfig - 测试配置
|
|
460
|
+
* @returns {Object} 测试结果
|
|
461
|
+
*/
|
|
462
|
+
test:function(expression,testConfig={}){const config={...defaultConfig,...testConfig};try{const result=evaluateMathExpression(expression,config);return{success:true,expression:expression,result:result,parsed:parseValueWithUnit(result.replace(/^calc\(|\)$/g,""))}}catch(error){return{success:false,expression:expression,error:error.message}}}},
|
|
332
463
|
// 颜色转换工具方法
|
|
333
464
|
colorUtils:{labToRGB:preciseLabToRGB,lchToLab:lchToLab,lchToRGB:function(L,C,H){const lab=lchToLab(L,C,H);return preciseLabToRGB(lab.L,lab.a,lab.b)},labToP3:labToP3,lchToP3:function(L,C,H){const lab=lchToLab(L,C,H);return labToP3(lab.L,lab.a,lab.b)},parseHexLab:function(hexString){const match=hexString.match(/lab#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i);if(!match)return null;const L_hex=match[1];const A_hex=match[2];const B_hex=match[3];const L=parseInt(L_hex,16)/255*100;const A=(parseInt(A_hex,16)-128)*1.5;const B=(parseInt(B_hex,16)-128)*1.5;return preciseLabToRGB(L,A,B)},parseHexLch:function(hexString){const match=hexString.match(/lch#([0-9a-f]{2})([0-9a-f]{2})(\d{1,3})/i);if(!match)return null;const L_hex=match[1];const C_hex=match[2];const H_dec=match[3];const L=parseInt(L_hex,16)/255*100;const C=parseInt(C_hex,16)/255*150;const H=parseInt(H_dec)/100*360;const lab=lchToLab(L,C,H);return preciseLabToRGB(lab.L,lab.a,lab.b)},
|
|
334
465
|
/**
|
|
@@ -352,4 +483,4 @@ const labMatch=colorString.match(/lab\(\s*([\d.]+)(%?)\s+([\d.-]+)\s+([\d.-]+)(?
|
|
|
352
483
|
// 尝试解析lch()函数格式
|
|
353
484
|
const lchMatch=colorString.match(/lch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)(deg)?(?:\s*\/\s*([\d.%]+))?\s*\)/i);if(lchMatch){let L=parseFloat(lchMatch[1]);const C=parseFloat(lchMatch[3]);let H=parseFloat(lchMatch[4]);const alpha=lchMatch[6]?lchMatch[6].includes("%")?parseFloat(lchMatch[6])/100:parseFloat(lchMatch[6]):null;const lab=lchToLab(L,C,H);const colorStr=generateColorString(lab.L,lab.a,lab.b,defaultConfig,alpha);return{L:L,C:C,H:H,alpha:alpha,lab:lab,rgb:preciseLabToRGB(lab.L,lab.a,lab.b),p3:labToP3(lab.L,lab.a,lab.b),colorString:colorStr}}return null}catch(error){console.warn("无法解析颜色:",colorString,error);return null}}}};
|
|
354
485
|
// 自动初始化
|
|
355
|
-
if(typeof window!=="undefined"){apply();Object.defineProperty(window.HTMLElement.prototype,"cssVar",{get(){const element=this;return new Proxy({},{get(target,prop){const varName=prop.startsWith("
|
|
486
|
+
if(typeof window!=="undefined"){apply();Object.defineProperty(window.HTMLElement.prototype,"cssVar",{get(){const element=this;return new Proxy({},{get(target,prop){const varName=prop.startsWith("--")?prop:`--${prop}`;return element.style.getPropertyValue(varName)},set(target,prop,value){const varName=prop.startsWith("--")?prop:`--${prop}`;element.style.setProperty(varName,value);return true}})}})}return api});
|