styimat 1.4.0 → 1.6.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/README.md +263 -24
- package/package.json +1 -1
- package/styimat.js +1451 -1380
- package/styimat.min.js +154 -126
package/styimat.min.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* MIT License
|
|
3
|
+
* Copyright (c) 2025 王小玗
|
|
4
|
+
*/
|
|
1
5
|
/**
|
|
2
6
|
* CSS 变量预处理库 - 增强版
|
|
3
7
|
* 支持 CSS 变量预处理、嵌套选择器和嵌套变量
|
|
@@ -19,15 +23,15 @@ mathPrecision:6};
|
|
|
19
23
|
// 全局P3支持检测结果
|
|
20
24
|
let p3Supported=null;
|
|
21
25
|
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
* 检测浏览器是否支持 Display P3
|
|
27
|
+
* @returns {boolean} 是否支持P3
|
|
28
|
+
*/function detectP3Support(){if(p3Supported!==null)return p3Supported;if(typeof window==="undefined"||!window.CSS){p3Supported=false;return false}try{p3Supported=CSS.supports("color","color(display-p3 1 0 0)")}catch(error){console.warn("P3支持检测失败:",error);p3Supported=false}return p3Supported}
|
|
25
29
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
* 解析一行CSS(可能多个语句在同一行,可能最后一个语句没有分号)
|
|
31
|
+
* 返回格式:[{属性名:值}, {属性名:值}, ...]
|
|
32
|
+
* @param {string} cssString - 要解析的CSS字符串
|
|
33
|
+
* @returns {Array} 包含属性名值对象的数组
|
|
34
|
+
*/function parseSingleLineCSS(cssString){
|
|
31
35
|
// 移除首尾空白字符
|
|
32
36
|
let str=cssString.trim();
|
|
33
37
|
// 如果以分号结尾,移除最后一个分号
|
|
@@ -60,20 +64,20 @@ if(value.endsWith(";")){value=value.slice(0,-1).trim()}
|
|
|
60
64
|
// 添加到结果数组
|
|
61
65
|
result.push({[property]:value})}return result}
|
|
62
66
|
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
* 查找不在引号内的第一个冒号位置
|
|
68
|
+
* @param {string} str
|
|
69
|
+
* @returns {number}
|
|
70
|
+
*/function findFirstColonOutsideQuotes(str){let inQuotes=false;let quoteChar="";for(let i=0;i<str.length;i++){const char=str[i];
|
|
67
71
|
// 处理引号
|
|
68
72
|
if((char==='"'||char==="'")&&!inQuotes){inQuotes=true;quoteChar=char}else if(char===quoteChar&&inQuotes){inQuotes=false;quoteChar=""}
|
|
69
73
|
// 如果找到冒号且不在引号内,返回位置
|
|
70
74
|
if(char===":"&&!inQuotes){return i}}return-1}
|
|
71
75
|
/**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
* 增强的数学表达式解析和计算
|
|
77
|
+
* @param {string} expression - 数学表达式
|
|
78
|
+
* @param {Object} config - 配置对象
|
|
79
|
+
* @returns {string} 计算结果
|
|
80
|
+
*/function evaluateMathExpression(expression,config){
|
|
77
81
|
// 如果禁用math()增强,则返回原始表达式
|
|
78
82
|
if(!config.enableMath){return`math(${expression})`}try{
|
|
79
83
|
// 清理表达式:移除空白字符
|
|
@@ -87,21 +91,21 @@ return processUnitExpression(cleanExpr,result)}else{
|
|
|
87
91
|
// 纯数字表达式,直接计算结果
|
|
88
92
|
return roundNumber(result,config.mathPrecision)}}catch(error){console.warn("math()表达式解析失败:",expression,error);return`math(${expression})`}}
|
|
89
93
|
/**
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
* 解析数学表达式
|
|
95
|
+
* @param {string} expr - 清理后的表达式
|
|
96
|
+
* @param {Object} config - 配置对象
|
|
97
|
+
* @returns {number} 计算结果
|
|
98
|
+
*/function parseMathExpression(expr,config){
|
|
95
99
|
// 处理括号
|
|
96
100
|
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
101
|
// 现在expr应该没有括号了
|
|
98
102
|
return evaluateSimpleExpression(expr,config)}
|
|
99
103
|
/**
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
* 评估简单表达式(无括号)
|
|
105
|
+
* @param {string} expr - 简单表达式
|
|
106
|
+
* @param {Object} config - 配置对象
|
|
107
|
+
* @returns {number} 计算结果
|
|
108
|
+
*/function evaluateSimpleExpression(expr,config){
|
|
105
109
|
// 处理操作符优先级:乘除优先于加减
|
|
106
110
|
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
111
|
// 按照优先级处理操作符
|
|
@@ -113,23 +117,23 @@ if(expr!==lastExpr){return evaluateSimpleExpression(expr,config)}
|
|
|
113
117
|
// 解析最终结果
|
|
114
118
|
const parsed=parseValueWithUnit(expr);return parsed.value}
|
|
115
119
|
/**
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
* 解析带单位的数值
|
|
121
|
+
* @param {string} str - 字符串值
|
|
122
|
+
* @returns {Object} {value: number, unit: string}
|
|
123
|
+
*/function parseValueWithUnit(str){
|
|
120
124
|
// 匹配数值和单位
|
|
121
125
|
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
126
|
/**
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
* 检查表达式是否包含单位
|
|
128
|
+
* @param {string} expr - 表达式
|
|
129
|
+
* @returns {boolean} 是否包含单位
|
|
130
|
+
*/function hasUnits(expr){return/[a-zA-Z%]/.test(expr)}
|
|
127
131
|
/**
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
* 处理带单位的表达式
|
|
133
|
+
* @param {string} originalExpr - 原始表达式
|
|
134
|
+
* @param {number} result - 计算结果
|
|
135
|
+
* @returns {string} 处理后的表达式
|
|
136
|
+
*/function processUnitExpression(originalExpr,result){
|
|
133
137
|
// 提取原始表达式中的单位
|
|
134
138
|
const unitMatch=originalExpr.match(/([a-zA-Z%]+)(?!.*[a-zA-Z%])/);if(unitMatch){return result+unitMatch[1]}
|
|
135
139
|
// 如果没有明确单位,检查是否为百分比
|
|
@@ -151,19 +155,19 @@ return{value:`${a.value}${a.unit}+${b.value}${b.unit}`,unit:""}}function subtrac
|
|
|
151
155
|
// 单位不匹配,返回原始表达式
|
|
152
156
|
return{value:`${a.value}${a.unit}-${b.value}${b.unit}`,unit:""}}
|
|
153
157
|
/**
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
* 四舍五入到指定精度
|
|
159
|
+
* @param {number} num - 要四舍五入的数字
|
|
160
|
+
* @param {number} precision - 精度
|
|
161
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
162
|
+
*/function roundNumber(num,precision=6){const factor=Math.pow(10,precision);const rounded=Math.round(num*factor)/factor;
|
|
159
163
|
// 移除不必要的尾随零
|
|
160
164
|
const str=rounded.toString();if(str.includes(".")){return str.replace(/(\.\d*?)0+$/,"$1").replace(/\.$/,"")}return str}
|
|
161
165
|
/**
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
* 处理所有的math()函数
|
|
167
|
+
* @param {string} cssValue - CSS属性值
|
|
168
|
+
* @param {Object} config - 配置对象
|
|
169
|
+
* @returns {string} 转换后的CSS值
|
|
170
|
+
*/function processMathFunctions(cssValue,config){if(!config.enableMath){return cssValue}let result=cssValue;
|
|
167
171
|
// 匹配math()函数
|
|
168
172
|
const mathRegex=/math\(([^)]+)\)/gi;
|
|
169
173
|
// 递归处理嵌套的math()函数
|
|
@@ -171,11 +175,11 @@ const processMath=str=>str.replace(mathRegex,(match,expression)=>evaluateMathExp
|
|
|
171
175
|
// 递归处理,直到没有更多math()函数
|
|
172
176
|
let lastResult;do{lastResult=result;result=processMath(result)}while(result!==lastResult&&result.includes("math("));return result}
|
|
173
177
|
/**
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
* 解析并转换所有的 Lab 和 LCH 颜色(全局一次性处理)
|
|
179
|
+
* @param {string} cssValue - CSS属性值
|
|
180
|
+
* @param {Object} config - 配置对象
|
|
181
|
+
* @returns {string} 转换后的CSS值
|
|
182
|
+
*/function convertAllLabLchColors(cssValue,config){if(!config.convertLabToRGB&&!config.convertLchToRGB){return cssValue}let result=cssValue;
|
|
179
183
|
// 首先处理特殊的十六进制格式
|
|
180
184
|
result=parseHexColorFormats(result,config);
|
|
181
185
|
// 一次性处理所有的 lab() 和 lch() 函数
|
|
@@ -193,11 +197,11 @@ processedColors.set(match,converted);return converted});
|
|
|
193
197
|
// 递归处理,直到没有更多颜色函数
|
|
194
198
|
let lastResult;do{lastResult=result;result=processColorFunctions(result)}while(result!==lastResult);return result}
|
|
195
199
|
/**
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
* 解析十六进制颜色格式:lab#L16A16B16 或 lch#L16C16H
|
|
201
|
+
* @param {string} value - 颜色值
|
|
202
|
+
* @param {Object} config - 配置对象
|
|
203
|
+
* @returns {string} 转换后的CSS颜色
|
|
204
|
+
*/function parseHexColorFormats(value,config){let result=value;
|
|
201
205
|
// 使用正则表达式一次性匹配所有 lab# 和 lch# 格式
|
|
202
206
|
const hexLabRegex=/lab#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/gi;const hexLchRegex=/lch#([0-9a-f]{2})([0-9a-f]{2})(\d{1,3})/gi;
|
|
203
207
|
// 存储处理过的十六进制颜色,避免重复处理
|
|
@@ -217,11 +221,11 @@ const C=parseInt(C_hex,16)/255*150;// 0-150
|
|
|
217
221
|
const H=parseInt(H_dec)/100*360;// 0-360
|
|
218
222
|
const lab=lchToLab(L,C,H);const converted=generateColorString(lab.L,lab.a,lab.b,config);processedHexColors.set(match,converted);return converted}catch(error){console.warn(`无法解析lch#十六进制颜色: ${match}`,error);return match}});return result}
|
|
219
223
|
/**
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
* 转换单个 lab() 颜色函数
|
|
225
|
+
* @param {string} labString - lab() 颜色字符串
|
|
226
|
+
* @param {Object} config - 配置对象
|
|
227
|
+
* @returns {string} 转换后的颜色字符串
|
|
228
|
+
*/function convertSingleLabColor(labString,config){
|
|
225
229
|
// 使用更精确的正则匹配 lab() 函数
|
|
226
230
|
const labRegex=/lab\(\s*([\d.]+)(%?)\s+([\d.-]+)\s+([\d.-]+)(?:\s*\/\s*([\d.%]+))?\s*\)/i;const match=labString.match(labRegex);if(!match){return labString}try{
|
|
227
231
|
// 转换为数字
|
|
@@ -234,11 +238,11 @@ if(L<0)L=0;if(L>100)L=100}const A=parseFloat(match[3]);const B=parseFloat(match[
|
|
|
234
238
|
// 处理 alpha 通道(如果有)
|
|
235
239
|
const alphaValue=match[5]!==undefined?match[5].includes("%")?parseFloat(match[5])/100:parseFloat(match[5]):null;return generateColorString(L,A,B,config,alphaValue)}catch(error){console.warn(`无法转换LAB颜色: ${labString}`,error);return labString}}
|
|
236
240
|
/**
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
241
|
+
* 转换单个 lch() 颜色函数
|
|
242
|
+
* @param {string} lchString - lch() 颜色字符串
|
|
243
|
+
* @param {Object} config - 配置对象
|
|
244
|
+
* @returns {string} 转换后的颜色字符串
|
|
245
|
+
*/function convertSingleLchColor(lchString,config){
|
|
242
246
|
// 使用更精确的正则匹配 lch() 函数
|
|
243
247
|
const lchRegex=/lch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)(deg)?(?:\s*\/\s*([\d.%]+))?\s*\)/i;const match=lchString.match(lchRegex);if(!match){return lchString}try{
|
|
244
248
|
// 转换为数字
|
|
@@ -257,12 +261,12 @@ const lab=lchToLab(L,C,H);
|
|
|
257
261
|
// 处理 alpha 通道(如果有)
|
|
258
262
|
const alphaValue=match[6]!==undefined?match[6].includes("%")?parseFloat(match[6])/100:parseFloat(match[6]):null;return generateColorString(lab.L,lab.a,lab.b,config,alphaValue)}catch(error){console.warn(`无法转换LCH颜色: ${lchString}`,error);return lchString}}
|
|
259
263
|
/**
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
* LCH 转换为 Lab (CSS标准)
|
|
265
|
+
* @param {number} L - 明度 0-100 或 0%-100%
|
|
266
|
+
* @param {number} C - 色度 >=0
|
|
267
|
+
* @param {number} H - 色相角 0-360 度
|
|
268
|
+
* @returns {Object} Lab 值 {L, a, b}
|
|
269
|
+
*/function lchToLab(L,C,H){
|
|
266
270
|
// 角度转换为弧度
|
|
267
271
|
const H_rad=H*Math.PI/180;
|
|
268
272
|
// LCH -> Lab 转换公式
|
|
@@ -286,12 +290,12 @@ const[X,Y,Z]=labToXyz(L,a,b);const[linearR,linearG,linearB]=xyzToLinearRgb(X,Y,Z
|
|
|
286
290
|
// 返回钳制后的 RGB 值
|
|
287
291
|
return{r:clamp(r),g:clamp(g),b:clamp(bOut)}}
|
|
288
292
|
/**
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
* Lab -> Display P3 转换
|
|
294
|
+
* @param {number} L - 明度 0-100
|
|
295
|
+
* @param {number} a - a分量
|
|
296
|
+
* @param {number} b - b分量
|
|
297
|
+
* @returns {Object} P3颜色 {r, g, b}
|
|
298
|
+
*/function labToP3(L,a,b){
|
|
295
299
|
// 1. Lab -> XYZ (使用与RGB相同的转换)
|
|
296
300
|
const labToXyz=(L,a,b)=>{const refX=.95047;const refY=1;const refZ=1.08883;const epsilon=.008856;const kappa=903.3;const fy=(L+16)/116;const fx=a/500+fy;const fz=fy-b/200;const xr=fx**3>epsilon?fx**3:(116*fx-16)/kappa;const yr=L>kappa*epsilon?((L+16)/116)**3:L/kappa;const zr=fz**3>epsilon?fz**3:(116*fz-16)/kappa;return[xr*refX,yr*refY,zr*refZ]};
|
|
297
301
|
// 2. XYZ -> Linear P3
|
|
@@ -307,24 +311,24 @@ try{const[X,Y,Z]=labToXyz(L,a,b);const[linearR,linearG,linearB]=xyzToLinearP3(X,
|
|
|
307
311
|
// 转换为0-1范围的浮点数用于P3颜色格式
|
|
308
312
|
return{r:Math.max(0,Math.min(1,r)),g:Math.max(0,Math.min(1,g)),b:Math.max(0,Math.min(1,bOut))}}catch(error){console.warn("P3转换失败:",error);const rgb=preciseLabToRGB(L,a,b);return{r:rgb.r/255,g:rgb.g/255,b:rgb.b/255}}}
|
|
309
313
|
/**
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
314
|
+
* 生成颜色字符串(根据P3支持情况输出P3或RGB)
|
|
315
|
+
* @param {number} L - Lab L值
|
|
316
|
+
* @param {number} a - Lab a值
|
|
317
|
+
* @param {number} b - Lab b值
|
|
318
|
+
* @param {Object} config - 配置对象
|
|
319
|
+
* @param {number|null} alpha - 透明度值
|
|
320
|
+
* @returns {string} CSS颜色字符串
|
|
321
|
+
*/function generateColorString(L,a,b,config,alpha=null){if(!config.enableP3||!detectP3Support()){
|
|
318
322
|
// 使用RGB
|
|
319
323
|
const rgb=preciseLabToRGB(L,a,b);if(alpha!==null){return`rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`}return`rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`}else{
|
|
320
324
|
// 使用P3
|
|
321
325
|
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)})`}}
|
|
322
326
|
/**
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
327
|
+
* 处理CSS值,根据配置转换LAB、LCH颜色和math()函数
|
|
328
|
+
* @param {string} value - CSS属性值
|
|
329
|
+
* @param {Object} config - 配置对象
|
|
330
|
+
* @returns {string} 处理后的值
|
|
331
|
+
*/function processCSSValue(value,config){let result=value;
|
|
328
332
|
// 1. 首先处理math()函数
|
|
329
333
|
if(config.enableMath){result=processMathFunctions(result,config)}
|
|
330
334
|
// 2. 然后处理LAB和LCH颜色
|
|
@@ -435,52 +439,76 @@ detectP3Support:detectP3Support,
|
|
|
435
439
|
// 数学计算工具方法
|
|
436
440
|
math:{
|
|
437
441
|
/**
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
+
* 计算数学表达式
|
|
443
|
+
* @param {string} expression - 数学表达式
|
|
444
|
+
* @returns {string} 计算结果
|
|
445
|
+
*/
|
|
442
446
|
evaluate:function(expression){return evaluateMathExpression(expression,defaultConfig)},
|
|
443
447
|
/**
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
+
* 解析带单位的数值
|
|
449
|
+
* @param {string} value - 带单位的字符串
|
|
450
|
+
* @returns {Object} {value: number, unit: string}
|
|
451
|
+
*/
|
|
448
452
|
parseUnit:parseValueWithUnit,
|
|
449
453
|
/**
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
454
|
+
* 四舍五入数字
|
|
455
|
+
* @param {number} num - 要四舍五入的数字
|
|
456
|
+
* @param {number} precision - 精度
|
|
457
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
458
|
+
*/
|
|
455
459
|
round:roundNumber,
|
|
456
460
|
/**
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
461
|
+
* 测试数学表达式
|
|
462
|
+
* @param {string} expression - 要测试的表达式
|
|
463
|
+
* @param {Object} testConfig - 测试配置
|
|
464
|
+
* @returns {Object} 测试结果
|
|
465
|
+
*/
|
|
462
466
|
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}}}},
|
|
463
467
|
// 颜色转换工具方法
|
|
464
468
|
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)},
|
|
465
469
|
/**
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
470
|
+
* 生成颜色字符串(根据P3支持情况)
|
|
471
|
+
* @param {number} L - Lab L值
|
|
472
|
+
* @param {number} a - Lab a值
|
|
473
|
+
* @param {number} b - Lab b值
|
|
474
|
+
* @param {number|null} alpha - 透明度
|
|
475
|
+
* @param {boolean} useP3 - 是否使用P3(自动检测)
|
|
476
|
+
* @returns {string} CSS颜色字符串
|
|
477
|
+
*/
|
|
474
478
|
generateColor:function(L,a,b,alpha=null,useP3=true){return generateColorString(L,a,b,{enableP3:useP3},alpha)},
|
|
475
479
|
/**
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
+
* 解析CSS颜色字符串
|
|
481
|
+
* @param {string} colorString - CSS颜色字符串
|
|
482
|
+
* @returns {Object} 包含原始Lab值和颜色字符串的对象
|
|
483
|
+
*/
|
|
480
484
|
parseColor:function(colorString){try{
|
|
481
485
|
// 尝试解析lab()函数格式
|
|
482
486
|
const labMatch=colorString.match(/lab\(\s*([\d.]+)(%?)\s+([\d.-]+)\s+([\d.-]+)(?:\s*\/\s*([\d.%]+))?\s*\)/i);if(labMatch){let L=parseFloat(labMatch[1]);const A=parseFloat(labMatch[3]);const B=parseFloat(labMatch[4]);const alpha=labMatch[5]?labMatch[5].includes("%")?parseFloat(labMatch[5])/100:parseFloat(labMatch[5]):null;const colorStr=generateColorString(L,A,B,defaultConfig,alpha);return{L:L,A:A,B:B,alpha:alpha,rgb:preciseLabToRGB(L,A,B),p3:labToP3(L,A,B),colorString:colorStr}}
|
|
483
487
|
// 尝试解析lch()函数格式
|
|
484
488
|
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}}}};
|
|
489
|
+
// 创建一个可调用的主函数
|
|
490
|
+
const styimat=function(...args){
|
|
491
|
+
// 检查是否是模板字符串调用(标签函数)
|
|
492
|
+
if(args.length>1||args[0]&&args[0].raw){
|
|
493
|
+
// 处理模板字符串
|
|
494
|
+
return handleTemplateTag(...args)}
|
|
495
|
+
// 获取第一个参数
|
|
496
|
+
const firstArg=args[0];
|
|
497
|
+
// 如果传入CSS文本,则编译并返回结果
|
|
498
|
+
if(typeof firstArg==="string"){return convert(firstArg,{...defaultConfig,...args[1]})}
|
|
499
|
+
// 如果传入配置对象,则应用配置
|
|
500
|
+
if(typeof firstArg==="object"&&firstArg!==null){defaultConfig={...defaultConfig,...firstArg};return styimat}
|
|
501
|
+
// 如果没有参数,执行自动处理
|
|
502
|
+
if(args.length===0){return apply()}return styimat};
|
|
503
|
+
// 处理模板字符串的函数
|
|
504
|
+
function handleTemplateTag(strings,...values){
|
|
505
|
+
// 拼接模板字符串
|
|
506
|
+
let cssText=strings[0];for(let i=0;i<values.length;i++){
|
|
507
|
+
// 处理插值(支持字符串、数字、函数等)
|
|
508
|
+
const value=values[i];let result="";if(typeof value==="function"){result=value()}else if(Array.isArray(value)){result=value.join(" ")}else{result=String(value!=null?value:"")}cssText+=result+strings[i+1]}
|
|
509
|
+
// 使用convert函数处理
|
|
510
|
+
return convert(cssText,defaultConfig)}
|
|
511
|
+
// 将API的所有方法复制到主函数上
|
|
512
|
+
Object.assign(styimat,api);Object.setPrototypeOf(styimat,Function.prototype);
|
|
485
513
|
// 自动初始化
|
|
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
|
|
514
|
+
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},apply(target,thisArg,argumentsList){const prop=argumentsList[0];const value=argumentsList[1];const varName=prop.startsWith("--")?prop:`--${prop}`;if(value===undefined)return element.style.getPropertyValue(varName);element.style.setProperty(varName,value)}})}})}return styimat});
|