@master/css-runtime 2.0.0-rc.47 → 2.0.0-rc.49

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/index.cjs CHANGED
@@ -14,7 +14,8 @@ class RuntimeCSS extends css.MasterCSS {
14
14
  observer;
15
15
  constructor(root = document, customConfig = css.config){
16
16
  super(customConfig), this.root = root, this.customConfig = customConfig, this.observing = false, this.progressive = false;
17
- if (!root) this.root = document;
17
+ const existingRuntimeCSS = globalThis.runtimeCSSs.find((eachCSS)=>eachCSS.root === this.root);
18
+ if (existingRuntimeCSS) throw new Error('Cannot create multiple RuntimeCSS instances for the same root element.');
18
19
  const rootConstructorName = this.root?.constructor.name;
19
20
  if (rootConstructorName === 'HTMLDocument' || rootConstructorName === 'Document') {
20
21
  // @ts-ignore
@@ -31,340 +32,353 @@ class RuntimeCSS extends css.MasterCSS {
31
32
  * Observe the DOM for changes and update the running stylesheet. (browser only)
32
33
  * @param options mutation observer options
33
34
  * @returns this
34
- */ observe(options = {
35
- subtree: true,
36
- childList: true
37
- }) {
38
- if (this.observing || !this.root) return this;
39
- if (runtimeCSSs.find((eachRuntimeCSS)=>eachRuntimeCSS !== this && eachRuntimeCSS.root === this.root)) {
40
- console.warn('Cannot observe the same root element repeatedly.');
41
- return this;
42
- }
43
- if (this.root?.styleSheets) for (const sheet of this.root.styleSheets){
35
+ */ observe() {
36
+ if (this.observing) return this;
37
+ if (this.root.styleSheets) for (const sheet of this.root.styleSheets){
44
38
  const { ownerNode } = sheet;
45
39
  if (ownerNode && ownerNode.id === 'master') {
46
- // @ts-ignore
47
40
  this.style = ownerNode;
48
41
  // @ts-ignore
49
42
  this.progressive = true;
50
43
  break;
51
44
  }
52
45
  }
53
- if (this.style?.sheet) {
54
- let index = 0;
55
- for(; index < this.style.sheet.cssRules.length; index++){
56
- const eachCSSRule = this.style.sheet.cssRules[index];
57
- switch(eachCSSRule.constructor.name){
58
- case 'CSSKeyframesRule':
59
- continue;
60
- case 'CSSMediaRule':
61
- const result = /\(prefers-color-scheme: ?(.*?)\)/.exec(eachCSSRule.conditionText);
62
- if (result) {
63
- const firstCSSRule = eachCSSRule.cssRules[0];
64
- if (firstCSSRule?.constructor.name === 'CSSStyleRule' && firstCSSRule.selectorText === ':root') {
65
- this.pushVariableNativeRule(result[1], firstCSSRule);
66
- continue;
67
- }
68
- }
69
- break;
70
- case 'CSSStyleRule':
71
- const selectorText = eachCSSRule.selectorText;
72
- if (eachCSSRule.style.length) {
73
- let isVariablesRule = true;
74
- // eslint-disable-next-line @typescript-eslint/prefer-for-of
75
- for(let i = 0; i < eachCSSRule.style.length; i++){
76
- if (!eachCSSRule.style[i]?.startsWith('--')) {
77
- isVariablesRule = false;
78
- break;
79
- }
80
- }
81
- if (isVariablesRule) {
82
- if (selectorText === ':root') {
83
- this.pushVariableNativeRule('', eachCSSRule);
84
- continue;
85
- } else {
86
- const result = /:host(.*?)/.exec(selectorText);
87
- if (result) {
88
- this.pushVariableNativeRule(result[1], eachCSSRule);
89
- continue;
90
- } else if (!selectorText.startsWith('.\\$')) {
91
- const [mode] = selectorText.split(',');
92
- this.pushVariableNativeRule(mode.slice(1), eachCSSRule);
93
- continue;
94
- }
95
- }
96
- }
97
- }
98
- break;
99
- }
100
- break;
101
- }
102
- for(; index < this.style.sheet.cssRules.length; index++){
103
- const getRule = (cssRule)=>{
104
- if (cssRule.selectorText) {
105
- const selectorTexts = cssRule.selectorText.split(', ');
106
- const escapedClassNames = selectorTexts[0].split(' ');
107
- for (const eachSelectorText of escapedClassNames){
108
- if (eachSelectorText[0] === '.') {
109
- const escapedClassName = eachSelectorText.slice(1);
110
- let className = '';
111
- for(let j = 0; j < escapedClassName.length; j++){
112
- const char = escapedClassName[j];
113
- const nextChar = escapedClassName[j + 1];
114
- if (char === '\\') {
115
- j++;
116
- if (nextChar !== '\\') {
117
- className += nextChar;
118
- continue;
119
- }
120
- } else if ([
121
- ',',
122
- '.',
123
- '#',
124
- '[',
125
- '!',
126
- '*',
127
- '>',
128
- '+',
129
- '~',
130
- ':',
131
- '@'
132
- ].includes(char)) {
133
- break;
134
- }
135
- className += char;
136
- }
137
- if (!Object.prototype.hasOwnProperty.call(this.ruleBy, className) && !Object.prototype.hasOwnProperty.call(this.styles, className)) {
138
- const currentRule = this.generate(className)[0];
139
- if (currentRule) return currentRule;
140
- }
141
- }
142
- }
143
- } else if (cssRule.cssRules) {
144
- for (const rule of cssRule.cssRules){
145
- const currentRule = getRule(rule);
146
- if (currentRule) return currentRule;
147
- }
148
- }
149
- };
150
- const rule = getRule(this.style.sheet.cssRules[index]);
151
- if (rule) {
152
- this.syntaxes.push(rule);
153
- this.ruleBy[rule.className] = rule;
154
- for(let i = 0; i < rule.natives.length; i++){
155
- rule.natives[i].cssRule = this.style.sheet.cssRules[index + i];
156
- }
157
- index += rule.natives.length - 1;
158
- // variables
159
- this.handleRuleWithVariableNames(rule, true);
160
- // animations
161
- this.handleRuleWithAnimationNames(rule, true);
162
- rule.definition.insert?.call(rule);
163
- }
164
- }
46
+ if (this.progressive) {
47
+ this.hydrate(this.style.sheet.cssRules);
165
48
  } else {
166
- // @ts-ignore
167
49
  this.style = document.createElement('style');
168
50
  this.style.id = 'master';
169
51
  this.container.append(this.style);
52
+ this.style.sheet.insertRule(this.layerStatementRule.text);
53
+ this.layerStatementRule.nodes[0].native = this.style.sheet.cssRules.item(0);
170
54
  }
171
- const handleClassList = (classList)=>{
172
- classList.forEach((className)=>{
173
- if (Object.prototype.hasOwnProperty.call(this.classesUsage, className)) {
174
- this.classesUsage[className]++;
55
+ const firstConnectedElementsClasses = new Map();
56
+ const addClasses = (element)=>{
57
+ element.classList.forEach((className)=>{
58
+ if (this.classUsages.has(className)) {
59
+ this.classUsages.set(className, this.classUsages.get(className) + 1);
175
60
  } else {
176
- this.classesUsage[className] = 1;
61
+ this.classUsages.set(className, 1);
177
62
  this.add(className);
178
63
  }
64
+ const classes = firstConnectedElementsClasses.get(element);
65
+ if (classes) {
66
+ classes.push(className);
67
+ } else {
68
+ firstConnectedElementsClasses.set(element, [
69
+ className
70
+ ]);
71
+ }
179
72
  });
180
73
  };
181
- handleClassList(this.host.classList);
182
- if (options.subtree) {
183
- /**
184
- * 待所有 DOM 結構完成解析後,開始繪製 Rule 樣式
185
- */ (this.root.constructor.name === 'HTMLDocument' ? this.host : this.container).querySelectorAll('[class]').forEach((element)=>handleClassList(element.classList));
186
- }
74
+ addClasses(this.host);
75
+ /**
76
+ * 待所有 DOM 結構完成解析後,開始繪製 Rule 樣式
77
+ */ (this.root.constructor.name === 'HTMLDocument' ? this.host : this.container).querySelectorAll('[class]').forEach((element)=>{
78
+ addClasses(element);
79
+ });
80
+ // @ts-expect-error readonly
187
81
  this.observer = new MutationObserver((mutationRecords)=>{
188
- // console.time('css engine');
189
- const correctionOfClassName = {};
190
- const attributeMutationRecords = [];
191
- const updatedElements = [];
192
- const unchangedElements = [];
193
- /**
194
- * 取得所有深層後代的 class names
195
- */ const handleClassNameDeeply = (element, remove)=>{
196
- if (remove) {
197
- element.classList.forEach(removeClassName);
198
- } else {
199
- element.classList.forEach(addClassName);
200
- }
201
- const children = element.children;
202
- for (const eachChildren of children){
203
- if (eachChildren.classList && !updatedElements.includes(eachChildren)) {
204
- updatedElements.push(eachChildren);
205
- handleClassNameDeeply(eachChildren, remove);
206
- }
207
- }
82
+ // console.clear()
83
+ // console.log('-----------')
84
+ // const test = 'swiper-slide-next'
85
+ // console.log(`${test}: ${this.classUsages.get(test)}`)
86
+ const eachClassUsages = new Map();
87
+ const updatedAttrElements = new Set();
88
+ const updatedConnectedElements = new Set();
89
+ const updatedElements = new Set();
90
+ const updateClassUsage = (classes, isAdding = false)=>{
91
+ const usage = isAdding ? 1 : -1;
92
+ classes.forEach((className)=>{
93
+ // if (className === test) console.log(` ${isAdding ? '+' : '-'} ${className} ${(eachClassUsages.get(className) || 0) + usage}`, target)
94
+ eachClassUsages.set(className, (eachClassUsages.get(className) || 0) + usage);
95
+ });
208
96
  };
209
- const addClassName = (className)=>{
210
- if (Object.prototype.hasOwnProperty.call(correctionOfClassName, className)) {
211
- correctionOfClassName[className]++;
212
- } else {
213
- correctionOfClassName[className] = 1;
97
+ const updateElementTree = (element, adding)=>{
98
+ if (element.isConnected) {
99
+ updatedConnectedElements.add(element);
214
100
  }
215
- };
216
- const removeClassName = (className)=>{
217
- if (Object.prototype.hasOwnProperty.call(correctionOfClassName, className)) {
218
- correctionOfClassName[className]--;
219
- } else if (Object.prototype.hasOwnProperty.call(this.classesUsage, className)) {
220
- correctionOfClassName[className] = -1;
101
+ updatedElements.add(element);
102
+ updateClassUsage(element.classList, adding);
103
+ for (const child of element.children){
104
+ updateElementTree(child, adding);
221
105
  }
222
106
  };
223
- const handleNodes = (nodes, remove)=>{
224
- for (const eachNode of nodes){
225
- if (eachNode.classList && !updatedElements.includes(eachNode) && !unchangedElements.includes(eachNode)) {
226
- if (eachNode.isConnected !== remove) {
227
- updatedElements.push(eachNode);
228
- handleClassNameDeeply(eachNode, remove);
229
- } else {
230
- unchangedElements.push(eachNode);
231
- }
232
- }
107
+ // console.log('///')
108
+ mutationRecords.forEach((mutation)=>{
109
+ const target = mutation.target;
110
+ switch(mutation.type){
111
+ case 'attributes':
112
+ const oldClassList = mutation.oldValue ? mutation.oldValue.split(/\s+/) : [];
113
+ const newClassList = target.classList;
114
+ newClassList.forEach((c)=>{
115
+ if (!oldClassList.includes(c)) ;
116
+ });
117
+ break;
233
118
  }
234
- };
235
- for (const mutationRecord of mutationRecords){
236
- const { addedNodes, removedNodes, type, target } = mutationRecord;
237
- if (type === 'attributes') {
238
- /**
239
- * 防止同樣的 MutationRecord 重複執行
240
- * According to this history,
241
- * MutationObserver was designed to work that way.
242
- * Any call to setAttribute triggers a mutation,
243
- * regardless of whether the value is being changed or set to the current value
244
- */ if (attributeMutationRecords.find((eachAttributeMutationRecord)=>eachAttributeMutationRecord.target === target)) {
245
- continue;
246
- } else {
119
+ });
120
+ // console.log('///')
121
+ mutationRecords.forEach((mutation)=>{
122
+ const target = mutation.target;
123
+ switch(mutation.type){
124
+ case 'attributes':
247
125
  /**
248
- * 第一個匹配到的 oldValue 一定是該批變動前的原始狀態值
249
- */ attributeMutationRecords.push(mutationRecord);
250
- }
251
- } else {
252
- // 先判斷節點新增或移除
253
- handleNodes(addedNodes, false);
254
- // 忽略處理新元素的已刪除子節點
255
- if (!target.isConnected || !updatedElements.includes(target)) {
256
- handleNodes(removedNodes, true);
257
- }
126
+ * We only need to determine the first attribute record of the same target,
127
+ * because the first record has the original old class name.
128
+ *
129
+ * The target is skipped if it is contained in the unhandled childList.
130
+ */ if (updatedAttrElements.has(target) || updatedElements.has(target)) return;
131
+ updatedAttrElements.add(target);
132
+ const oldClassList = mutation.oldValue ? mutation.oldValue.split(/\s+/) : [];
133
+ const newClassList = target.classList;
134
+ const addedClasses = [];
135
+ newClassList.forEach((c)=>{
136
+ if (!oldClassList.includes(c)) addedClasses.push(c);
137
+ });
138
+ const removedClasses = oldClassList.filter((c)=>!newClassList.contains(c));
139
+ // if (addedClasses.length) console.log('[attribute]', '[add]', addedClasses, target)
140
+ if (addedClasses.length) updateClassUsage(addedClasses, true);
141
+ // if (removedClasses.length) console.log('[attribute]', '[remove]', removedClasses, target)
142
+ if (removedClasses.length) updateClassUsage(removedClasses, false);
143
+ break;
144
+ case 'childList':
145
+ if (updatedConnectedElements.has(target)) return;
146
+ // if (mutation.addedNodes.length) console.log('[childList]', '[add]', mutation.addedNodes)
147
+ mutation.addedNodes.forEach((node)=>'classList' in node && updateElementTree(node, true));
148
+ // if (mutation.removedNodes.length) console.log('[childList]', '[remove]', mutation.removedNodes)
149
+ mutation.removedNodes.forEach((node)=>'classList' in node && updateElementTree(node, false));
150
+ break;
258
151
  }
259
- }
260
- if (!attributeMutationRecords.length && !Object.keys(correctionOfClassName).length) {
261
- // console.timeEnd('css engine');
262
- return;
263
- }
264
- for (const { oldValue, target } of attributeMutationRecords){
265
- /**
266
- * 如果被操作的元素中包含了屬性變更的目標,
267
- * 則將該目標從 existedAttributeMutationTargets 中移除,
268
- * 以防止執行接下來的屬性變更處理
269
- *
270
- * 該批 mutationRecords 中,某個 target 同時有 attribute 及 childList 的變更,
271
- * 則以 childList 節點插入及移除的 target.className 為主
272
- */ const updated = updatedElements.includes(target);
273
- const classNames = target.classList;
274
- const oldClassNames = oldValue ? oldValue.split(' ') : [];
275
- if (updated) {
276
- if (target.isConnected) {
277
- continue;
278
- } else {
279
- for (const oldClassName of oldClassNames){
280
- if (!classNames.contains(oldClassName)) {
281
- removeClassName(oldClassName);
282
- }
283
- }
284
- }
285
- } else if (target.isConnected) {
286
- classNames.forEach((className)=>{
287
- if (!oldClassNames.includes(className)) {
288
- addClassName(className);
289
- }
290
- });
291
- for (const oldClassName of oldClassNames){
292
- if (!classNames.contains(oldClassName)) {
293
- removeClassName(oldClassName);
294
- }
152
+ });
153
+ /**
154
+ * Merge the class usage changes into the current class usage map.
155
+ */ eachClassUsages.forEach((countChange, className)=>{
156
+ let currentCount = this.classUsages.get(className) || 0;
157
+ let newCount = currentCount + countChange;
158
+ if (newCount > 0) {
159
+ this.classUsages.set(className, newCount);
160
+ if (currentCount === 0) {
161
+ this.add(className);
295
162
  }
296
- }
297
- }
298
- for(const className in correctionOfClassName){
299
- const correction = correctionOfClassName[className];
300
- const count = (this.classesUsage[className] || 0) + correction;
301
- if (count === 0) {
302
- // remove
303
- delete this.classesUsage[className];
304
- /**
305
- * class name 從 DOM tree 中被移除,
306
- * 匹配並刪除對應的 rule
307
- */ this.delete(className);
308
163
  } else {
309
- if (!Object.prototype.hasOwnProperty.call(this.classesUsage, className)) {
310
- // add
311
- /**
312
- * 新 class name 被 connected 至 DOM tree,
313
- * 匹配並創建對應的 Rule
314
- */ this.add(className);
315
- }
316
- this.classesUsage[className] = count;
164
+ this.classUsages.delete(className);
165
+ this.remove(className);
317
166
  }
318
- }
167
+ });
168
+ // start: debug
169
+ // const safeClassUsages: any = {};
170
+ // ((this.root.constructor.name === 'HTMLDocument') ? this.host : this.container)
171
+ // .querySelectorAll('[class]')
172
+ // .forEach((element) => {
173
+ // element.classList.forEach((className) => {
174
+ // if (Object.prototype.hasOwnProperty.call(safeClassUsages, className)) {
175
+ // safeClassUsages[className]++
176
+ // } else {
177
+ // safeClassUsages[className] = 1
178
+ // }
179
+ // })
180
+ // })
181
+ // this.host.classList.forEach((className) => {
182
+ // if (Object.prototype.hasOwnProperty.call(safeClassUsages, className)) {
183
+ // safeClassUsages[className]++
184
+ // } else {
185
+ // safeClassUsages[className] = 1
186
+ // }
187
+ // })
188
+ // // 與 this.classUsages 比較並且打印不同的部分
189
+ // for (const className in safeClassUsages) {
190
+ // if (this.classUsages.get(className) !== safeClassUsages[className]) {
191
+ // throw new Error(`[css] ${className} ${this.classUsages.get(className)} (correct: ${safeClassUsages[className]})`)
192
+ // }
193
+ // }
194
+ // end: debug
319
195
  });
320
196
  this.observer.observe(this.root, {
321
- ...options,
322
197
  attributes: true,
323
198
  attributeOldValue: true,
324
199
  attributeFilter: [
325
200
  'class'
326
- ]
201
+ ],
202
+ childList: true,
203
+ subtree: true
327
204
  });
328
- this.host.style.removeProperty('display');
205
+ if (!this.progressive) {
206
+ this.host.style.removeProperty('display');
207
+ }
329
208
  // @ts-ignore
330
209
  this.observing = true;
331
210
  return this;
332
211
  }
333
- refresh(customConfig = this.customConfig) {
334
- // remove all CSS rules
335
- // todo: e2e test
336
- const sheet = this.style?.sheet;
337
- if (sheet?.cssRules) {
338
- for(let i = sheet.cssRules.length - 1; i >= 0; i--){
339
- sheet.deleteRule(i);
212
+ hydrate(nativeCSSRules) {
213
+ const cssSyntaxLayerBlockRules = [];
214
+ for(let i = 0; i < nativeCSSRules.length; i++){
215
+ const eachNativeCSSRule = nativeCSSRules[i];
216
+ if (eachNativeCSSRule.constructor.name === 'CSSLayerBlockRule') {
217
+ const cssLayerBlockRule = eachNativeCSSRule;
218
+ if (eachNativeCSSRule.name === 'theme') {
219
+ this.themeLayer.native = cssLayerBlockRule;
220
+ let variableRule;
221
+ let lastVariableName;
222
+ for(let j = 0; j < cssLayerBlockRule.cssRules.length; j++){
223
+ const cssRule = cssLayerBlockRule.cssRules[j];
224
+ const variableCSSRule = cssRule.constructor.name === 'CSSMediaRule' ? cssRule.cssRules[0] : cssRule;
225
+ const variableName = variableCSSRule.style[0].slice(2);
226
+ if (variableName !== lastVariableName) {
227
+ lastVariableName = variableName;
228
+ variableRule = new css.Rule(variableName);
229
+ this.themeLayer.rules.push(variableRule);
230
+ this.themeLayer.usages[variableRule.name] = 0;
231
+ }
232
+ variableRule?.nodes.push({
233
+ native: cssRule,
234
+ text: cssRule.cssText
235
+ });
236
+ }
237
+ if (this.themeLayer.rules.length) this.rules.push(this.themeLayer);
238
+ } else {
239
+ cssSyntaxLayerBlockRules.push(cssLayerBlockRule);
240
+ }
241
+ } else if (eachNativeCSSRule.constructor.name === 'CSSLayerStatementRule') {
242
+ this.layerStatementRule.nodes[0].native = eachNativeCSSRule;
243
+ } else if (eachNativeCSSRule.constructor.name === 'CSSKeyframesRule') {
244
+ const keyframsRule = eachNativeCSSRule;
245
+ const animationRule = new css.Rule(keyframsRule.name, [
246
+ {
247
+ native: keyframsRule,
248
+ text: keyframsRule.cssText
249
+ }
250
+ ]);
251
+ this.animationsNonLayer.rules.push(animationRule);
252
+ this.rules.push(animationRule);
253
+ this.animationsNonLayer.usages[animationRule.name] = 0;
340
254
  }
341
255
  }
342
- super.refresh(customConfig);
343
- return this;
344
- }
345
- reset() {
346
- super.reset();
347
- const sheet = this.style?.sheet;
348
- if (sheet?.cssRules) {
349
- for(let i = sheet.cssRules.length - 1; i >= 0; i--){
350
- sheet.deleteRule(i);
256
+ for (const cssLayerBlockRule of cssSyntaxLayerBlockRules){
257
+ const handleSyntaxLayer = (layer)=>{
258
+ layer.native = cssLayerBlockRule;
259
+ for(let j = 0; j < cssLayerBlockRule.cssRules.length; j++){
260
+ const cssRule = cssLayerBlockRule.cssRules[j];
261
+ const createSyntaxRule = (cssRule)=>{
262
+ if (cssRule.selectorText) {
263
+ const syntaxRule = this.createFromSelectorText(cssRule.selectorText)[0];
264
+ if (syntaxRule) return syntaxRule;
265
+ } else if (cssRule.cssRules) {
266
+ for (const eachCSSRule of cssRule.cssRules){
267
+ const syntaxRule = createSyntaxRule(eachCSSRule);
268
+ if (syntaxRule) return syntaxRule;
269
+ }
270
+ }
271
+ };
272
+ const syntaxRule = createSyntaxRule(cssRule);
273
+ if (syntaxRule) {
274
+ layer.rules.push(syntaxRule);
275
+ layer.insertVariables(syntaxRule);
276
+ layer.insertAnimations(syntaxRule);
277
+ for (const eachNode of syntaxRule.nodes){
278
+ if (!eachNode.native) eachNode.native = cssRule;
279
+ }
280
+ } else {
281
+ cssLayerBlockRule.deleteRule?.(j--);
282
+ console.error(`Cannot recognize the CSS rule in the ${layer.name} layer. \`${cssRule.cssText}\` (https://rc.css.master.co/messages/hydration-errors)`);
283
+ }
284
+ }
285
+ for (const eachRule of layer.rules){
286
+ for(let k = eachRule.nodes.length - 1; k >= 0; k--){
287
+ if (!eachRule.nodes[k].native) {
288
+ eachRule.nodes.splice(k, 1);
289
+ }
290
+ }
291
+ }
292
+ if (layer.rules.length) this.rules.push(layer);
293
+ };
294
+ switch(cssLayerBlockRule.name){
295
+ case 'base':
296
+ handleSyntaxLayer(this.baseLayer);
297
+ break;
298
+ case 'preset':
299
+ handleSyntaxLayer(this.presetLayer);
300
+ break;
301
+ case 'components':
302
+ this.componentsLayer.native = cssLayerBlockRule;
303
+ let stylePreText;
304
+ const createSyntaxRules = (cssRule)=>{
305
+ if (cssRule.selectorText) {
306
+ const syntaxRules = this.createFromSelectorText(cssRule.selectorText);
307
+ if (syntaxRules.length) {
308
+ stylePreText = cssRule.selectorText + '{';
309
+ return syntaxRules;
310
+ }
311
+ } else if (cssRule.cssRules) {
312
+ for (const eachCSSRule of cssRule.cssRules){
313
+ const syntaxRules = this.createFromSelectorText(eachCSSRule.selectorText);
314
+ if (syntaxRules) return syntaxRules;
315
+ }
316
+ }
317
+ };
318
+ for(let j = 0; j < cssLayerBlockRule.cssRules.length; j++){
319
+ const cssRule = cssLayerBlockRule.cssRules[j];
320
+ const syntaxRules = createSyntaxRules(cssRule);
321
+ if (syntaxRules) {
322
+ let matched = false;
323
+ for (const eachSyntaxRule of syntaxRules){
324
+ for (const node of eachSyntaxRule.nodes){
325
+ if (!node.native && node.text.includes(stylePreText)) {
326
+ node.native = cssRule;
327
+ if (!this.componentsLayer.rules.includes(eachSyntaxRule)) {
328
+ this.componentsLayer.rules.push(eachSyntaxRule);
329
+ this.componentsLayer.insertVariables(eachSyntaxRule);
330
+ this.componentsLayer.insertAnimations(eachSyntaxRule);
331
+ }
332
+ matched = true;
333
+ break;
334
+ }
335
+ }
336
+ if (matched) break;
337
+ }
338
+ } else {
339
+ cssLayerBlockRule?.deleteRule?.(j--);
340
+ console.error(`Cannot recognize the CSS rule in the components layer. \`${cssRule.cssText}\` (https://rc.css.master.co/messages/hydration-errors)`);
341
+ }
342
+ }
343
+ for (const eachRule of this.componentsLayer.rules){
344
+ for(let k = eachRule.nodes.length - 1; k >= 0; k--){
345
+ if (!eachRule.nodes[k].native) {
346
+ eachRule.nodes.splice(k, 1);
347
+ }
348
+ }
349
+ }
350
+ if (this.componentsLayer.rules.length) this.rules.push(this.componentsLayer);
351
+ break;
352
+ case 'general':
353
+ handleSyntaxLayer(this.generalLayer);
354
+ break;
351
355
  }
352
356
  }
353
- if (!this.progressive) {
354
- this.style?.remove();
355
- // @ts-ignore
356
- this.style = null;
357
- }
358
- return this;
359
357
  }
360
358
  disconnect() {
359
+ if (!this.observing) return;
361
360
  if (this.observer) {
362
361
  this.observer.disconnect();
363
- this.observer = null;
362
+ // @ts-expect-error readonly
363
+ this.observer = undefined;
364
364
  }
365
365
  // @ts-ignore
366
366
  this.observing = false;
367
367
  this.reset();
368
+ // @ts-expect-error
369
+ this.classUsages = {};
370
+ if (!this.progressive) {
371
+ this.style?.remove();
372
+ this.style = null;
373
+ }
374
+ return this;
375
+ }
376
+ refresh(customConfig = this.customConfig) {
377
+ if (!this.observing || !this.style.sheet) return this;
378
+ for(let i = 1; i <= this.style.sheet.cssRules.length - 1; i++){
379
+ this.style.sheet.deleteRule(i);
380
+ }
381
+ super.refresh(customConfig);
368
382
  return this;
369
383
  }
370
384
  destroy() {