@master/css-runtime 2.0.0-rc.47 → 2.0.0-rc.48
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/core.d.ts +5 -5
- package/dist/global.min.js +1 -1
- package/dist/index.cjs +165 -144
- package/dist/index.mjs +166 -145
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MasterCSS, config } from '@master/css';
|
|
1
|
+
import { MasterCSS, config, Rule } from '@master/css';
|
|
2
2
|
|
|
3
3
|
class RuntimeCSS extends MasterCSS {
|
|
4
4
|
root;
|
|
@@ -10,7 +10,8 @@ class RuntimeCSS extends MasterCSS {
|
|
|
10
10
|
observer;
|
|
11
11
|
constructor(root = document, customConfig = config){
|
|
12
12
|
super(customConfig), this.root = root, this.customConfig = customConfig, this.observing = false, this.progressive = false;
|
|
13
|
-
|
|
13
|
+
const existingRuntimeCSS = globalThis.runtimeCSSs.find((eachCSS)=>eachCSS.root === this.root);
|
|
14
|
+
if (existingRuntimeCSS) throw new Error('Cannot create multiple RuntimeCSS instances for the same root element.');
|
|
14
15
|
const rootConstructorName = this.root?.constructor.name;
|
|
15
16
|
if (rootConstructorName === 'HTMLDocument' || rootConstructorName === 'Document') {
|
|
16
17
|
// @ts-ignore
|
|
@@ -31,138 +32,24 @@ class RuntimeCSS extends MasterCSS {
|
|
|
31
32
|
subtree: true,
|
|
32
33
|
childList: true
|
|
33
34
|
}) {
|
|
34
|
-
if (this.observing
|
|
35
|
-
if (
|
|
36
|
-
console.warn('Cannot observe the same root element repeatedly.');
|
|
37
|
-
return this;
|
|
38
|
-
}
|
|
39
|
-
if (this.root?.styleSheets) for (const sheet of this.root.styleSheets){
|
|
35
|
+
if (this.observing) return this;
|
|
36
|
+
if (this.root.styleSheets) for (const sheet of this.root.styleSheets){
|
|
40
37
|
const { ownerNode } = sheet;
|
|
41
38
|
if (ownerNode && ownerNode.id === 'master') {
|
|
42
|
-
// @ts-ignore
|
|
43
39
|
this.style = ownerNode;
|
|
44
40
|
// @ts-ignore
|
|
45
41
|
this.progressive = true;
|
|
46
42
|
break;
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
|
-
if (this.
|
|
50
|
-
|
|
51
|
-
for(; index < this.style.sheet.cssRules.length; index++){
|
|
52
|
-
const eachCSSRule = this.style.sheet.cssRules[index];
|
|
53
|
-
switch(eachCSSRule.constructor.name){
|
|
54
|
-
case 'CSSKeyframesRule':
|
|
55
|
-
continue;
|
|
56
|
-
case 'CSSMediaRule':
|
|
57
|
-
const result = /\(prefers-color-scheme: ?(.*?)\)/.exec(eachCSSRule.conditionText);
|
|
58
|
-
if (result) {
|
|
59
|
-
const firstCSSRule = eachCSSRule.cssRules[0];
|
|
60
|
-
if (firstCSSRule?.constructor.name === 'CSSStyleRule' && firstCSSRule.selectorText === ':root') {
|
|
61
|
-
this.pushVariableNativeRule(result[1], firstCSSRule);
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
break;
|
|
66
|
-
case 'CSSStyleRule':
|
|
67
|
-
const selectorText = eachCSSRule.selectorText;
|
|
68
|
-
if (eachCSSRule.style.length) {
|
|
69
|
-
let isVariablesRule = true;
|
|
70
|
-
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
71
|
-
for(let i = 0; i < eachCSSRule.style.length; i++){
|
|
72
|
-
if (!eachCSSRule.style[i]?.startsWith('--')) {
|
|
73
|
-
isVariablesRule = false;
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (isVariablesRule) {
|
|
78
|
-
if (selectorText === ':root') {
|
|
79
|
-
this.pushVariableNativeRule('', eachCSSRule);
|
|
80
|
-
continue;
|
|
81
|
-
} else {
|
|
82
|
-
const result = /:host(.*?)/.exec(selectorText);
|
|
83
|
-
if (result) {
|
|
84
|
-
this.pushVariableNativeRule(result[1], eachCSSRule);
|
|
85
|
-
continue;
|
|
86
|
-
} else if (!selectorText.startsWith('.\\$')) {
|
|
87
|
-
const [mode] = selectorText.split(',');
|
|
88
|
-
this.pushVariableNativeRule(mode.slice(1), eachCSSRule);
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
for(; index < this.style.sheet.cssRules.length; index++){
|
|
99
|
-
const getRule = (cssRule)=>{
|
|
100
|
-
if (cssRule.selectorText) {
|
|
101
|
-
const selectorTexts = cssRule.selectorText.split(', ');
|
|
102
|
-
const escapedClassNames = selectorTexts[0].split(' ');
|
|
103
|
-
for (const eachSelectorText of escapedClassNames){
|
|
104
|
-
if (eachSelectorText[0] === '.') {
|
|
105
|
-
const escapedClassName = eachSelectorText.slice(1);
|
|
106
|
-
let className = '';
|
|
107
|
-
for(let j = 0; j < escapedClassName.length; j++){
|
|
108
|
-
const char = escapedClassName[j];
|
|
109
|
-
const nextChar = escapedClassName[j + 1];
|
|
110
|
-
if (char === '\\') {
|
|
111
|
-
j++;
|
|
112
|
-
if (nextChar !== '\\') {
|
|
113
|
-
className += nextChar;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
} else if ([
|
|
117
|
-
',',
|
|
118
|
-
'.',
|
|
119
|
-
'#',
|
|
120
|
-
'[',
|
|
121
|
-
'!',
|
|
122
|
-
'*',
|
|
123
|
-
'>',
|
|
124
|
-
'+',
|
|
125
|
-
'~',
|
|
126
|
-
':',
|
|
127
|
-
'@'
|
|
128
|
-
].includes(char)) {
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
className += char;
|
|
132
|
-
}
|
|
133
|
-
if (!Object.prototype.hasOwnProperty.call(this.ruleBy, className) && !Object.prototype.hasOwnProperty.call(this.styles, className)) {
|
|
134
|
-
const currentRule = this.generate(className)[0];
|
|
135
|
-
if (currentRule) return currentRule;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
} else if (cssRule.cssRules) {
|
|
140
|
-
for (const rule of cssRule.cssRules){
|
|
141
|
-
const currentRule = getRule(rule);
|
|
142
|
-
if (currentRule) return currentRule;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
const rule = getRule(this.style.sheet.cssRules[index]);
|
|
147
|
-
if (rule) {
|
|
148
|
-
this.syntaxes.push(rule);
|
|
149
|
-
this.ruleBy[rule.className] = rule;
|
|
150
|
-
for(let i = 0; i < rule.natives.length; i++){
|
|
151
|
-
rule.natives[i].cssRule = this.style.sheet.cssRules[index + i];
|
|
152
|
-
}
|
|
153
|
-
index += rule.natives.length - 1;
|
|
154
|
-
// variables
|
|
155
|
-
this.handleRuleWithVariableNames(rule, true);
|
|
156
|
-
// animations
|
|
157
|
-
this.handleRuleWithAnimationNames(rule, true);
|
|
158
|
-
rule.definition.insert?.call(rule);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
45
|
+
if (this.progressive) {
|
|
46
|
+
this.hydrate(this.style.sheet.cssRules);
|
|
161
47
|
} else {
|
|
162
|
-
// @ts-ignore
|
|
163
48
|
this.style = document.createElement('style');
|
|
164
49
|
this.style.id = 'master';
|
|
165
50
|
this.container.append(this.style);
|
|
51
|
+
this.style.sheet.insertRule(this.layerStatementRule.text);
|
|
52
|
+
this.layerStatementRule.nodes[0].native = this.style.sheet.cssRules.item(0);
|
|
166
53
|
}
|
|
167
54
|
const handleClassList = (classList)=>{
|
|
168
55
|
classList.forEach((className)=>{
|
|
@@ -300,7 +187,7 @@ class RuntimeCSS extends MasterCSS {
|
|
|
300
187
|
/**
|
|
301
188
|
* class name 從 DOM tree 中被移除,
|
|
302
189
|
* 匹配並刪除對應的 rule
|
|
303
|
-
*/ this.
|
|
190
|
+
*/ this.remove(className);
|
|
304
191
|
} else {
|
|
305
192
|
if (!Object.prototype.hasOwnProperty.call(this.classesUsage, className)) {
|
|
306
193
|
// add
|
|
@@ -326,34 +213,154 @@ class RuntimeCSS extends MasterCSS {
|
|
|
326
213
|
this.observing = true;
|
|
327
214
|
return this;
|
|
328
215
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
216
|
+
hydrate(nativeCSSRules) {
|
|
217
|
+
const cssSyntaxLayerBlockRules = [];
|
|
218
|
+
for(let i = 0; i < nativeCSSRules.length; i++){
|
|
219
|
+
const eachNativeCSSRule = nativeCSSRules[i];
|
|
220
|
+
if (eachNativeCSSRule.constructor.name === 'CSSLayerBlockRule') {
|
|
221
|
+
const cssLayerBlockRule = eachNativeCSSRule;
|
|
222
|
+
if (eachNativeCSSRule.name === 'theme') {
|
|
223
|
+
this.themeLayer.native = cssLayerBlockRule;
|
|
224
|
+
let variableRule;
|
|
225
|
+
let lastVariableName;
|
|
226
|
+
for(let j = 0; j < cssLayerBlockRule.cssRules.length; j++){
|
|
227
|
+
const cssRule = cssLayerBlockRule.cssRules[j];
|
|
228
|
+
const variableCSSRule = cssRule.constructor.name === 'CSSMediaRule' ? cssRule.cssRules[0] : cssRule;
|
|
229
|
+
const variableName = variableCSSRule.style[0].slice(2);
|
|
230
|
+
if (variableName !== lastVariableName) {
|
|
231
|
+
lastVariableName = variableName;
|
|
232
|
+
variableRule = new Rule(variableName);
|
|
233
|
+
this.themeLayer.rules.push(variableRule);
|
|
234
|
+
this.themeLayer.usages[variableRule.name] = 0;
|
|
235
|
+
}
|
|
236
|
+
variableRule?.nodes.push({
|
|
237
|
+
native: cssRule,
|
|
238
|
+
text: cssRule.cssText
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (this.themeLayer.rules.length) this.rules.push(this.themeLayer);
|
|
242
|
+
} else {
|
|
243
|
+
cssSyntaxLayerBlockRules.push(cssLayerBlockRule);
|
|
244
|
+
}
|
|
245
|
+
} else if (eachNativeCSSRule.constructor.name === 'CSSLayerStatementRule') {
|
|
246
|
+
this.layerStatementRule.nodes[0].native = eachNativeCSSRule;
|
|
247
|
+
} else if (eachNativeCSSRule.constructor.name === 'CSSKeyframesRule') {
|
|
248
|
+
const keyframsRule = eachNativeCSSRule;
|
|
249
|
+
const animationRule = new Rule(keyframsRule.name, [
|
|
250
|
+
{
|
|
251
|
+
native: keyframsRule,
|
|
252
|
+
text: keyframsRule.cssText
|
|
253
|
+
}
|
|
254
|
+
]);
|
|
255
|
+
this.animationsNonLayer.rules.push(animationRule);
|
|
256
|
+
this.rules.push(animationRule);
|
|
257
|
+
this.animationsNonLayer.usages[animationRule.name] = 0;
|
|
336
258
|
}
|
|
337
259
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
260
|
+
for (const cssLayerBlockRule of cssSyntaxLayerBlockRules){
|
|
261
|
+
const handleSyntaxLayer = (layer)=>{
|
|
262
|
+
layer.native = cssLayerBlockRule;
|
|
263
|
+
for(let j = 0; j < cssLayerBlockRule.cssRules.length; j++){
|
|
264
|
+
const cssRule = cssLayerBlockRule.cssRules[j];
|
|
265
|
+
const createSyntaxRule = (cssRule)=>{
|
|
266
|
+
if (cssRule.selectorText) {
|
|
267
|
+
const syntaxRule = this.createFromSelectorText(cssRule.selectorText)[0];
|
|
268
|
+
if (syntaxRule) return syntaxRule;
|
|
269
|
+
} else if (cssRule.cssRules) {
|
|
270
|
+
for (const eachCSSRule of cssRule.cssRules){
|
|
271
|
+
const syntaxRule = createSyntaxRule(eachCSSRule);
|
|
272
|
+
if (syntaxRule) return syntaxRule;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
const syntaxRule = createSyntaxRule(cssRule);
|
|
277
|
+
if (syntaxRule) {
|
|
278
|
+
layer.rules.push(syntaxRule);
|
|
279
|
+
layer.insertVariables(syntaxRule);
|
|
280
|
+
layer.insertAnimations(syntaxRule);
|
|
281
|
+
for (const eachNode of syntaxRule.nodes){
|
|
282
|
+
if (!eachNode.native) eachNode.native = cssRule;
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
cssLayerBlockRule.deleteRule?.(j--);
|
|
286
|
+
console.error(`Cannot recognize the CSS rule in the ${layer.name} layer. \`${cssRule.cssText}\` (https://rc.css.master.co/messages/hydration-errors)`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
for (const eachRule of layer.rules){
|
|
290
|
+
for(let k = eachRule.nodes.length - 1; k >= 0; k--){
|
|
291
|
+
if (!eachRule.nodes[k].native) {
|
|
292
|
+
eachRule.nodes.splice(k, 1);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (layer.rules.length) this.rules.push(layer);
|
|
297
|
+
};
|
|
298
|
+
switch(cssLayerBlockRule.name){
|
|
299
|
+
case 'base':
|
|
300
|
+
handleSyntaxLayer(this.baseLayer);
|
|
301
|
+
break;
|
|
302
|
+
case 'preset':
|
|
303
|
+
handleSyntaxLayer(this.presetLayer);
|
|
304
|
+
break;
|
|
305
|
+
case 'components':
|
|
306
|
+
this.stylesLayer.native = cssLayerBlockRule;
|
|
307
|
+
let stylePreText;
|
|
308
|
+
const createSyntaxRules = (cssRule)=>{
|
|
309
|
+
if (cssRule.selectorText) {
|
|
310
|
+
const syntaxRules = this.createFromSelectorText(cssRule.selectorText);
|
|
311
|
+
if (syntaxRules.length) {
|
|
312
|
+
stylePreText = cssRule.selectorText + '{';
|
|
313
|
+
return syntaxRules;
|
|
314
|
+
}
|
|
315
|
+
} else if (cssRule.cssRules) {
|
|
316
|
+
for (const eachCSSRule of cssRule.cssRules){
|
|
317
|
+
const syntaxRules = this.createFromSelectorText(eachCSSRule.selectorText);
|
|
318
|
+
if (syntaxRules) return syntaxRules;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
for(let j = 0; j < cssLayerBlockRule.cssRules.length; j++){
|
|
323
|
+
const cssRule = cssLayerBlockRule.cssRules[j];
|
|
324
|
+
const syntaxRules = createSyntaxRules(cssRule);
|
|
325
|
+
if (syntaxRules) {
|
|
326
|
+
let matched = false;
|
|
327
|
+
for (const eachSyntaxRule of syntaxRules){
|
|
328
|
+
for (const node of eachSyntaxRule.nodes){
|
|
329
|
+
if (!node.native && node.text.includes(stylePreText)) {
|
|
330
|
+
node.native = cssRule;
|
|
331
|
+
if (!this.stylesLayer.rules.includes(eachSyntaxRule)) {
|
|
332
|
+
this.stylesLayer.rules.push(eachSyntaxRule);
|
|
333
|
+
this.stylesLayer.insertVariables(eachSyntaxRule);
|
|
334
|
+
this.stylesLayer.insertAnimations(eachSyntaxRule);
|
|
335
|
+
}
|
|
336
|
+
matched = true;
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (matched) break;
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
cssLayerBlockRule?.deleteRule?.(j--);
|
|
344
|
+
console.error(`Cannot recognize the CSS rule in the components layer. \`${cssRule.cssText}\` (https://rc.css.master.co/messages/hydration-errors)`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
for (const eachRule of this.stylesLayer.rules){
|
|
348
|
+
for(let k = eachRule.nodes.length - 1; k >= 0; k--){
|
|
349
|
+
if (!eachRule.nodes[k].native) {
|
|
350
|
+
eachRule.nodes.splice(k, 1);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (this.stylesLayer.rules.length) this.rules.push(this.stylesLayer);
|
|
355
|
+
break;
|
|
356
|
+
case 'general':
|
|
357
|
+
handleSyntaxLayer(this.generalLayer);
|
|
358
|
+
break;
|
|
347
359
|
}
|
|
348
360
|
}
|
|
349
|
-
if (!this.progressive) {
|
|
350
|
-
this.style?.remove();
|
|
351
|
-
// @ts-ignore
|
|
352
|
-
this.style = null;
|
|
353
|
-
}
|
|
354
|
-
return this;
|
|
355
361
|
}
|
|
356
362
|
disconnect() {
|
|
363
|
+
if (!this.observing) return;
|
|
357
364
|
if (this.observer) {
|
|
358
365
|
this.observer.disconnect();
|
|
359
366
|
this.observer = null;
|
|
@@ -361,6 +368,20 @@ class RuntimeCSS extends MasterCSS {
|
|
|
361
368
|
// @ts-ignore
|
|
362
369
|
this.observing = false;
|
|
363
370
|
this.reset();
|
|
371
|
+
// @ts-expect-error
|
|
372
|
+
this.classesUsage = {};
|
|
373
|
+
if (!this.progressive) {
|
|
374
|
+
this.style?.remove();
|
|
375
|
+
this.style = null;
|
|
376
|
+
}
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
refresh(customConfig = this.customConfig) {
|
|
380
|
+
if (!this.observing || !this.style.sheet) return this;
|
|
381
|
+
for(let i = 1; i <= this.style.sheet.cssRules.length - 1; i++){
|
|
382
|
+
this.style.sheet.deleteRule(i);
|
|
383
|
+
}
|
|
384
|
+
super.refresh(customConfig);
|
|
364
385
|
return this;
|
|
365
386
|
}
|
|
366
387
|
destroy() {
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@master/css-runtime","type":"module","scripts":{"build":"techor build","dev":"pnpm build --watch","
|
|
1
|
+
{"name":"@master/css-runtime","type":"module","scripts":{"build":"techor build","dev":"pnpm build --watch","e2e":"playwright test","e2e:watch":"PWTEST_WATCH=1 playwright test","test":"vitest","type-check":"tsc --noEmit","lint":"eslint"},"license":"MIT","description":"Run Master CSS right in the browser","author":"Aoyue Design LLC.","funding":"https://rc.css.master.co/sponsor","homepage":"https://css.master.co","bugs":{"url":"https://github.com/master-co/css/issues"},"repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/runtime"},"keywords":["utility","css","lightweight","mastercss","master","runtime","cdn"],"sideEffects":false,"main":"./dist/index.cjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","module":"./dist/index.mjs","browser":"./dist/global.min.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","require":"./dist/index.cjs","import":"./dist/index.mjs"}},"files":["dist"],"publishConfig":{"access":"public","provenance":true},"dependencies":{"@master/css":"^2.0.0-rc.48"},"devDependencies":{"@playwright/test":"^1.49.1","@types/cssom":"^0.4.3","css-tree":"^3.0.1","cssom":"^0.5.0","shared":"^2.0.0-rc.48"},"version":"2.0.0-rc.48"}
|