@master/css-runtime 2.0.0-rc.63 → 2.0.0-rc.64
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 +3 -3
- package/dist/global.min.js +1 -1
- package/dist/index.cjs +91 -125
- package/dist/index.development.cjs +119 -128
- package/dist/index.development.mjs +119 -128
- package/dist/index.mjs +91 -125
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,10 @@ class RuntimeLayer extends css.Layer {
|
|
|
45
45
|
return this.native.cssRules.item(insertedIndex);
|
|
46
46
|
} catch (error) {
|
|
47
47
|
console.error(error, rule);
|
|
48
|
+
/**
|
|
49
|
+
* If the rule is invalid, remove it from the rules array.
|
|
50
|
+
* It's important to note that the rule may break the entire CSS runtime,
|
|
51
|
+
*/ this.rules.splice(insertedIndex, 1);
|
|
48
52
|
return;
|
|
49
53
|
}
|
|
50
54
|
};
|
|
@@ -110,20 +114,19 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
110
114
|
customConfig;
|
|
111
115
|
static instances = new WeakMap();
|
|
112
116
|
host;
|
|
113
|
-
observing;
|
|
114
|
-
progressive;
|
|
115
117
|
container;
|
|
116
|
-
observer;
|
|
117
118
|
baseLayer;
|
|
118
119
|
themeLayer;
|
|
119
120
|
presetLayer;
|
|
120
121
|
componentsLayer;
|
|
121
122
|
generalLayer;
|
|
122
123
|
classCounts;
|
|
124
|
+
observer;
|
|
125
|
+
progressive;
|
|
126
|
+
observing;
|
|
123
127
|
constructor(root = document, customConfig = css.config){
|
|
124
|
-
super(customConfig), this.root = root, this.customConfig = customConfig, this.
|
|
125
|
-
|
|
126
|
-
if (rootConstructorName === 'HTMLDocument' || rootConstructorName === 'Document') {
|
|
128
|
+
super(customConfig), this.root = root, this.customConfig = customConfig, this.baseLayer = new RuntimeSyntaxLayer('base', this), this.themeLayer = new RuntimeLayer('theme', this), this.presetLayer = new RuntimeSyntaxLayer('preset', this), this.componentsLayer = new RuntimeSyntaxLayer('components', this), this.generalLayer = new RuntimeSyntaxLayer('general', this), this.classCounts = new Map(), this.progressive = false, this.observing = false;
|
|
129
|
+
if (this.root instanceof Document || this.root instanceof HTMLDocument) {
|
|
127
130
|
this.root.defaultView.globalThis.cssRuntime = this;
|
|
128
131
|
this.container = this.root.head;
|
|
129
132
|
this.host = this.root.documentElement;
|
|
@@ -142,36 +145,44 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
142
145
|
* @returns this
|
|
143
146
|
*/ observe() {
|
|
144
147
|
if (this.observing) return this;
|
|
145
|
-
//
|
|
146
|
-
if (this.root.styleSheets)
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
// Detect prerendered stylesheet
|
|
149
|
+
if (this.root.styleSheets) {
|
|
150
|
+
for (const sheet of this.root.styleSheets){
|
|
151
|
+
const { ownerNode } = sheet;
|
|
152
|
+
if (ownerNode instanceof HTMLStyleElement && ownerNode.id === 'master') {
|
|
153
|
+
this.style = ownerNode;
|
|
154
|
+
if (this.style.sheet?.cssRules.length) {
|
|
155
|
+
this.progressive = true;
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
153
158
|
}
|
|
154
|
-
break;
|
|
155
159
|
}
|
|
156
160
|
}
|
|
157
|
-
//
|
|
161
|
+
// Prepare snapshot map
|
|
162
|
+
const elementClasses = new WeakMap();
|
|
163
|
+
// Initial scan and populate counts + snapshot
|
|
158
164
|
const connectedNames = new Set();
|
|
159
165
|
const increaseClassCount = (className)=>{
|
|
160
166
|
const count = this.classCounts.get(className) || 0;
|
|
161
|
-
if (!count)
|
|
162
|
-
connectedNames.add(className);
|
|
163
|
-
}
|
|
167
|
+
if (!count) connectedNames.add(className);
|
|
164
168
|
this.classCounts.set(className, count + 1);
|
|
165
169
|
};
|
|
166
|
-
this.
|
|
167
|
-
|
|
168
|
-
|
|
170
|
+
const rootEl = this.root instanceof Document || this.root instanceof HTMLDocument ? this.root : this.container;
|
|
171
|
+
const elementsWithClass = rootEl.querySelectorAll('[class]');
|
|
172
|
+
elementsWithClass.forEach((el)=>{
|
|
173
|
+
const clsList = el.classList;
|
|
174
|
+
if (clsList) {
|
|
175
|
+
el.classList.forEach(increaseClassCount);
|
|
176
|
+
}
|
|
177
|
+
elementClasses.set(el, new Set(clsList));
|
|
178
|
+
});
|
|
179
|
+
// Hydration or style creation
|
|
169
180
|
if (this.progressive) {
|
|
170
181
|
const hydrateResult = this.hydrate(this.style.sheet.cssRules);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
for (const cls of connectedNames){
|
|
183
|
+
if (!hydrateResult.allSyntaxRules.find((r)=>(r.fixedClass || r.name) === cls)) {
|
|
184
|
+
this.add(cls);
|
|
185
|
+
}
|
|
175
186
|
}
|
|
176
187
|
} else {
|
|
177
188
|
this.style = document.createElement('style');
|
|
@@ -179,125 +190,81 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
179
190
|
this.container.append(this.style);
|
|
180
191
|
this.style.sheet.insertRule(this.layerStatementRule.text);
|
|
181
192
|
this.layerStatementRule.native = this.style.sheet.cssRules.item(0);
|
|
182
|
-
|
|
183
|
-
this.add(eachConnectedName);
|
|
184
|
-
}
|
|
193
|
+
connectedNames.forEach((cls)=>this.add(cls));
|
|
185
194
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
this.observer = new MutationObserver((records)=>{
|
|
196
|
+
const deltaCounts = new Map();
|
|
197
|
+
const nodeMap = new Map();
|
|
198
|
+
const attrRecords = new Set();
|
|
199
|
+
const visited = new WeakSet();
|
|
200
|
+
const updateDelta = (cls, delta)=>deltaCounts.set(cls, (deltaCounts.get(cls) || 0) + delta);
|
|
201
|
+
const diffAndSnapshot = (el)=>{
|
|
202
|
+
const prev = new Set(elementClasses.get(el) || []);
|
|
203
|
+
const next = new Set(el.classList);
|
|
204
|
+
for (const c of next)if (!prev.has(c)) updateDelta(c, 1);
|
|
205
|
+
for (const c of prev)if (!next.has(c)) updateDelta(c, -1);
|
|
206
|
+
elementClasses.set(el, next);
|
|
195
207
|
};
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const status = map.get(target);
|
|
200
|
-
if (status) {
|
|
201
|
-
status.change += adding ? 1 : -1;
|
|
202
|
-
status.mutationRecord = mutationRecord;
|
|
203
|
-
} else {
|
|
204
|
-
map.set(target, {
|
|
205
|
-
change: adding ? 1 : -1,
|
|
206
|
-
mutationRecord
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
for (const child of target.children){
|
|
210
|
-
if ('classList' in child) {
|
|
211
|
-
recordStatus(child, mutationRecord, map, adding);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
208
|
+
const removeSnapshot = (el)=>{
|
|
209
|
+
for (const c of elementClasses.get(el) || [])updateDelta(c, -1);
|
|
210
|
+
elementClasses.delete(el);
|
|
214
211
|
};
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
break;
|
|
223
|
-
case 'childList':
|
|
224
|
-
const targetStatusMap = target.isConnected ? connectedStatusMap : disconnectedStatusMap;
|
|
225
|
-
mutationRecord.addedNodes.forEach((node)=>'classList' in node && recordStatus(node, mutationRecord, targetStatusMap, true));
|
|
226
|
-
mutationRecord.removedNodes.forEach((node)=>'classList' in node && recordStatus(node, mutationRecord, targetStatusMap, false));
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
const updateTarget = (target, adding)=>{
|
|
231
|
-
const firstAttrMutationRecord = targetFirstAttrMutationRecord.get(target);
|
|
232
|
-
if (firstAttrMutationRecord) {
|
|
233
|
-
targetFirstAttrMutationRecord.delete(target);
|
|
212
|
+
for (const record of records){
|
|
213
|
+
if (record.type === 'childList') {
|
|
214
|
+
for (const node of record.addedNodes)if (node instanceof Element && node.isConnected) nodeMap.set(node, (nodeMap.get(node) || 0) + 1);
|
|
215
|
+
for (const node of record.removedNodes)if (node instanceof Element && !node.isConnected) nodeMap.set(node, (nodeMap.get(node) || 0) - 1);
|
|
216
|
+
} else if (record.type === 'attributes' && record.attributeName === 'class') {
|
|
217
|
+
attrRecords.add(record.target);
|
|
234
218
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
219
|
+
}
|
|
220
|
+
const traverseIncludingSelf = (el, fn, visited)=>{
|
|
221
|
+
if (!visited.has(el)) {
|
|
222
|
+
visited.add(el);
|
|
223
|
+
fn(el);
|
|
224
|
+
for (const child of el.children){
|
|
225
|
+
traverseIncludingSelf(child, fn, visited);
|
|
242
226
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
updateTarget(disconnectedTarget, disconnectedTargetStatus.change > 0);
|
|
246
|
-
}
|
|
247
|
-
});
|
|
227
|
+
} else {
|
|
228
|
+
nodeMap.delete(el);
|
|
248
229
|
}
|
|
249
230
|
};
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const addedClasses = [];
|
|
256
|
-
newClassList.forEach((c)=>{
|
|
257
|
-
if (!oldClassList.includes(c)) addedClasses.push(c);
|
|
258
|
-
});
|
|
259
|
-
const removedClasses = oldClassList.filter((c)=>!newClassList.contains(c));
|
|
260
|
-
if (addedClasses.length) {
|
|
261
|
-
updateClassCount(addedClasses, true);
|
|
231
|
+
for (const [node, count] of nodeMap){
|
|
232
|
+
if (count > 0) {
|
|
233
|
+
traverseIncludingSelf(node, diffAndSnapshot, visited);
|
|
234
|
+
} else if (count < 0 && !node.isConnected) {
|
|
235
|
+
traverseIncludingSelf(node, removeSnapshot, visited);
|
|
262
236
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
this.classCounts.set(className, newCount);
|
|
274
|
-
if (currentCount === 0) {
|
|
275
|
-
this.add(className);
|
|
276
|
-
}
|
|
237
|
+
}
|
|
238
|
+
for (const el of attrRecords){
|
|
239
|
+
if (!visited.has(el)) diffAndSnapshot(el);
|
|
240
|
+
}
|
|
241
|
+
for (const [cls, change] of deltaCounts){
|
|
242
|
+
const current = this.classCounts.get(cls) || 0;
|
|
243
|
+
const next = current + change;
|
|
244
|
+
if (next > 0) {
|
|
245
|
+
this.classCounts.set(cls, next);
|
|
246
|
+
if (current === 0) this.add(cls);
|
|
277
247
|
} else {
|
|
278
|
-
this.classCounts.delete(
|
|
279
|
-
this.remove(
|
|
248
|
+
this.classCounts.delete(cls);
|
|
249
|
+
this.remove(cls);
|
|
280
250
|
}
|
|
281
|
-
}
|
|
251
|
+
}
|
|
282
252
|
globalThis.__MASTER_CSS_DEVTOOLS_HOOK__?.emit('runtime:mutated', {
|
|
283
|
-
records
|
|
284
|
-
classCounts:
|
|
253
|
+
records,
|
|
254
|
+
classCounts: deltaCounts,
|
|
285
255
|
cssRuntime: this
|
|
286
256
|
});
|
|
287
257
|
});
|
|
288
258
|
this.observer.observe(this.root, {
|
|
259
|
+
childList: true,
|
|
289
260
|
attributes: true,
|
|
290
|
-
attributeOldValue: true,
|
|
291
261
|
attributeFilter: [
|
|
292
262
|
'class'
|
|
293
263
|
],
|
|
294
|
-
|
|
264
|
+
attributeOldValue: true,
|
|
295
265
|
subtree: true
|
|
296
266
|
});
|
|
297
|
-
if (!this.progressive)
|
|
298
|
-
this.host.removeAttribute('hidden');
|
|
299
|
-
}
|
|
300
|
-
// @ts-ignore
|
|
267
|
+
if (!this.progressive) this.host.removeAttribute('hidden');
|
|
301
268
|
this.observing = true;
|
|
302
269
|
globalThis.__MASTER_CSS_DEVTOOLS_HOOK__?.emit('runtime:observed', {
|
|
303
270
|
cssRuntime: this
|
|
@@ -440,7 +407,6 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
440
407
|
if (!this.observing) return;
|
|
441
408
|
if (this.observer) {
|
|
442
409
|
this.observer.disconnect();
|
|
443
|
-
// @ts-expect-error readonly
|
|
444
410
|
this.observer = undefined;
|
|
445
411
|
}
|
|
446
412
|
// @ts-ignore
|
|
@@ -59,10 +59,36 @@ function registerClassCountDebugger() {
|
|
|
59
59
|
});
|
|
60
60
|
if (errored) {
|
|
61
61
|
log.debug('Records:', records);
|
|
62
|
+
log.debug('Serialized Records:', serializeMutations(records));
|
|
62
63
|
log.debug('Counts:', classCounts);
|
|
63
64
|
}
|
|
64
65
|
});
|
|
65
66
|
}
|
|
67
|
+
function serializeMutations(mutations) {
|
|
68
|
+
return mutations.map((m)=>{
|
|
69
|
+
const target = m.target;
|
|
70
|
+
return {
|
|
71
|
+
type: m.type,
|
|
72
|
+
attributeName: m.attributeName,
|
|
73
|
+
oldValue: m.oldValue,
|
|
74
|
+
target: {
|
|
75
|
+
tagName: target.tagName,
|
|
76
|
+
id: target.id,
|
|
77
|
+
classList: Array.from(target.classList)
|
|
78
|
+
},
|
|
79
|
+
added: Array.from(m.addedNodes).filter((n)=>n.nodeType === 1).map((el)=>({
|
|
80
|
+
tagName: el.tagName,
|
|
81
|
+
id: el.id,
|
|
82
|
+
classList: Array.from(el.classList)
|
|
83
|
+
})),
|
|
84
|
+
removed: Array.from(m.removedNodes).filter((n)=>n.nodeType === 1).map((el)=>({
|
|
85
|
+
tagName: el.tagName,
|
|
86
|
+
id: el.id,
|
|
87
|
+
classList: Array.from(el.classList)
|
|
88
|
+
}))
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}
|
|
66
92
|
|
|
67
93
|
function registerLifecycleDebugger() {
|
|
68
94
|
const hook = globalThis.__MASTER_CSS_DEVTOOLS_HOOK__;
|
|
@@ -141,6 +167,10 @@ class RuntimeLayer extends css.Layer {
|
|
|
141
167
|
return this.native.cssRules.item(insertedIndex);
|
|
142
168
|
} catch (error) {
|
|
143
169
|
console.error(error, rule);
|
|
170
|
+
/**
|
|
171
|
+
* If the rule is invalid, remove it from the rules array.
|
|
172
|
+
* It's important to note that the rule may break the entire CSS runtime,
|
|
173
|
+
*/ this.rules.splice(insertedIndex, 1);
|
|
144
174
|
return;
|
|
145
175
|
}
|
|
146
176
|
};
|
|
@@ -206,20 +236,19 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
206
236
|
customConfig;
|
|
207
237
|
static instances = new WeakMap();
|
|
208
238
|
host;
|
|
209
|
-
observing;
|
|
210
|
-
progressive;
|
|
211
239
|
container;
|
|
212
|
-
observer;
|
|
213
240
|
baseLayer;
|
|
214
241
|
themeLayer;
|
|
215
242
|
presetLayer;
|
|
216
243
|
componentsLayer;
|
|
217
244
|
generalLayer;
|
|
218
245
|
classCounts;
|
|
246
|
+
observer;
|
|
247
|
+
progressive;
|
|
248
|
+
observing;
|
|
219
249
|
constructor(root = document, customConfig = css.config){
|
|
220
|
-
super(customConfig), this.root = root, this.customConfig = customConfig, this.
|
|
221
|
-
|
|
222
|
-
if (rootConstructorName === 'HTMLDocument' || rootConstructorName === 'Document') {
|
|
250
|
+
super(customConfig), this.root = root, this.customConfig = customConfig, this.baseLayer = new RuntimeSyntaxLayer('base', this), this.themeLayer = new RuntimeLayer('theme', this), this.presetLayer = new RuntimeSyntaxLayer('preset', this), this.componentsLayer = new RuntimeSyntaxLayer('components', this), this.generalLayer = new RuntimeSyntaxLayer('general', this), this.classCounts = new Map(), this.progressive = false, this.observing = false;
|
|
251
|
+
if (this.root instanceof Document || this.root instanceof HTMLDocument) {
|
|
223
252
|
this.root.defaultView.globalThis.cssRuntime = this;
|
|
224
253
|
this.container = this.root.head;
|
|
225
254
|
this.host = this.root.documentElement;
|
|
@@ -238,39 +267,46 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
238
267
|
* @returns this
|
|
239
268
|
*/ observe() {
|
|
240
269
|
if (this.observing) return this;
|
|
241
|
-
//
|
|
242
|
-
if (this.root.styleSheets)
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
270
|
+
// Detect prerendered stylesheet
|
|
271
|
+
if (this.root.styleSheets) {
|
|
272
|
+
for (const sheet of this.root.styleSheets){
|
|
273
|
+
const { ownerNode } = sheet;
|
|
274
|
+
if (ownerNode instanceof HTMLStyleElement && ownerNode.id === 'master') {
|
|
275
|
+
this.style = ownerNode;
|
|
276
|
+
if (this.style.sheet?.cssRules.length) {
|
|
277
|
+
this.progressive = true;
|
|
278
|
+
}
|
|
279
|
+
break;
|
|
249
280
|
}
|
|
250
|
-
break;
|
|
251
281
|
}
|
|
252
282
|
}
|
|
253
|
-
//
|
|
283
|
+
// Prepare snapshot map
|
|
284
|
+
const elementClasses = new WeakMap();
|
|
285
|
+
// Initial scan and populate counts + snapshot
|
|
254
286
|
const connectedNames = new Set();
|
|
255
287
|
const increaseClassCount = (className)=>{
|
|
256
288
|
const count = this.classCounts.get(className) || 0;
|
|
257
|
-
if (!count)
|
|
258
|
-
connectedNames.add(className);
|
|
259
|
-
}
|
|
289
|
+
if (!count) connectedNames.add(className);
|
|
260
290
|
this.classCounts.set(className, count + 1);
|
|
261
291
|
};
|
|
262
|
-
this.
|
|
263
|
-
|
|
264
|
-
|
|
292
|
+
const rootEl = this.root instanceof Document || this.root instanceof HTMLDocument ? this.root : this.container;
|
|
293
|
+
const elementsWithClass = rootEl.querySelectorAll('[class]');
|
|
294
|
+
elementsWithClass.forEach((el)=>{
|
|
295
|
+
const clsList = el.classList;
|
|
296
|
+
if (clsList) {
|
|
297
|
+
el.classList.forEach(increaseClassCount);
|
|
298
|
+
}
|
|
299
|
+
elementClasses.set(el, new Set(clsList));
|
|
300
|
+
});
|
|
301
|
+
// Hydration or style creation
|
|
265
302
|
if (this.progressive) {
|
|
266
303
|
const hydrateResult = this.hydrate(this.style.sheet.cssRules);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
console.debug(`The class \`${eachConnectedName}\` was added via script before calling hydrate, or the corresponding CSS rule were not properly pre-rendered.`);
|
|
304
|
+
for (const cls of connectedNames){
|
|
305
|
+
if (!hydrateResult.allSyntaxRules.find((r)=>(r.fixedClass || r.name) === cls)) {
|
|
306
|
+
this.add(cls);
|
|
307
|
+
{
|
|
308
|
+
console.debug(`Missing prerendered rule for class \`${cls}\``);
|
|
309
|
+
}
|
|
274
310
|
}
|
|
275
311
|
}
|
|
276
312
|
} else {
|
|
@@ -279,125 +315,81 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
279
315
|
this.container.append(this.style);
|
|
280
316
|
this.style.sheet.insertRule(this.layerStatementRule.text);
|
|
281
317
|
this.layerStatementRule.native = this.style.sheet.cssRules.item(0);
|
|
282
|
-
|
|
283
|
-
this.add(eachConnectedName);
|
|
284
|
-
}
|
|
318
|
+
connectedNames.forEach((cls)=>this.add(cls));
|
|
285
319
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
320
|
+
this.observer = new MutationObserver((records)=>{
|
|
321
|
+
const deltaCounts = new Map();
|
|
322
|
+
const nodeMap = new Map();
|
|
323
|
+
const attrRecords = new Set();
|
|
324
|
+
const visited = new WeakSet();
|
|
325
|
+
const updateDelta = (cls, delta)=>deltaCounts.set(cls, (deltaCounts.get(cls) || 0) + delta);
|
|
326
|
+
const diffAndSnapshot = (el)=>{
|
|
327
|
+
const prev = new Set(elementClasses.get(el) || []);
|
|
328
|
+
const next = new Set(el.classList);
|
|
329
|
+
for (const c of next)if (!prev.has(c)) updateDelta(c, 1);
|
|
330
|
+
for (const c of prev)if (!next.has(c)) updateDelta(c, -1);
|
|
331
|
+
elementClasses.set(el, next);
|
|
295
332
|
};
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const status = map.get(target);
|
|
300
|
-
if (status) {
|
|
301
|
-
status.change += adding ? 1 : -1;
|
|
302
|
-
status.mutationRecord = mutationRecord;
|
|
303
|
-
} else {
|
|
304
|
-
map.set(target, {
|
|
305
|
-
change: adding ? 1 : -1,
|
|
306
|
-
mutationRecord
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
for (const child of target.children){
|
|
310
|
-
if ('classList' in child) {
|
|
311
|
-
recordStatus(child, mutationRecord, map, adding);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
333
|
+
const removeSnapshot = (el)=>{
|
|
334
|
+
for (const c of elementClasses.get(el) || [])updateDelta(c, -1);
|
|
335
|
+
elementClasses.delete(el);
|
|
314
336
|
};
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
break;
|
|
323
|
-
case 'childList':
|
|
324
|
-
const targetStatusMap = target.isConnected ? connectedStatusMap : disconnectedStatusMap;
|
|
325
|
-
mutationRecord.addedNodes.forEach((node)=>'classList' in node && recordStatus(node, mutationRecord, targetStatusMap, true));
|
|
326
|
-
mutationRecord.removedNodes.forEach((node)=>'classList' in node && recordStatus(node, mutationRecord, targetStatusMap, false));
|
|
327
|
-
break;
|
|
337
|
+
for (const record of records){
|
|
338
|
+
if (record.type === 'childList') {
|
|
339
|
+
for (const node of record.addedNodes)if (node instanceof Element && node.isConnected) nodeMap.set(node, (nodeMap.get(node) || 0) + 1);
|
|
340
|
+
for (const node of record.removedNodes)if (node instanceof Element && !node.isConnected) nodeMap.set(node, (nodeMap.get(node) || 0) - 1);
|
|
341
|
+
} else if (record.type === 'attributes' && record.attributeName === 'class') {
|
|
342
|
+
attrRecords.add(record.target);
|
|
328
343
|
}
|
|
329
|
-
}
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
updateClassCount(target.classList, adding);
|
|
337
|
-
} else {
|
|
338
|
-
if (firstAttrMutationRecord) {
|
|
339
|
-
updateClassCount(firstAttrMutationRecord.oldValue ? firstAttrMutationRecord.oldValue.split(/\s+/) : [], adding);
|
|
340
|
-
} else {
|
|
341
|
-
updateClassCount(target.classList, adding);
|
|
344
|
+
}
|
|
345
|
+
const traverseIncludingSelf = (el, fn, visited)=>{
|
|
346
|
+
if (!visited.has(el)) {
|
|
347
|
+
visited.add(el);
|
|
348
|
+
fn(el);
|
|
349
|
+
for (const child of el.children){
|
|
350
|
+
traverseIncludingSelf(child, fn, visited);
|
|
342
351
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
updateTarget(disconnectedTarget, disconnectedTargetStatus.change > 0);
|
|
346
|
-
}
|
|
347
|
-
});
|
|
352
|
+
} else {
|
|
353
|
+
nodeMap.delete(el);
|
|
348
354
|
}
|
|
349
355
|
};
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const addedClasses = [];
|
|
356
|
-
newClassList.forEach((c)=>{
|
|
357
|
-
if (!oldClassList.includes(c)) addedClasses.push(c);
|
|
358
|
-
});
|
|
359
|
-
const removedClasses = oldClassList.filter((c)=>!newClassList.contains(c));
|
|
360
|
-
if (addedClasses.length) {
|
|
361
|
-
updateClassCount(addedClasses, true);
|
|
362
|
-
}
|
|
363
|
-
if (removedClasses.length) {
|
|
364
|
-
updateClassCount(removedClasses, false);
|
|
356
|
+
for (const [node, count] of nodeMap){
|
|
357
|
+
if (count > 0) {
|
|
358
|
+
traverseIncludingSelf(node, diffAndSnapshot, visited);
|
|
359
|
+
} else if (count < 0 && !node.isConnected) {
|
|
360
|
+
traverseIncludingSelf(node, removeSnapshot, visited);
|
|
365
361
|
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
362
|
+
}
|
|
363
|
+
for (const el of attrRecords){
|
|
364
|
+
if (!visited.has(el)) diffAndSnapshot(el);
|
|
365
|
+
}
|
|
366
|
+
for (const [cls, change] of deltaCounts){
|
|
367
|
+
const current = this.classCounts.get(cls) || 0;
|
|
368
|
+
const next = current + change;
|
|
369
|
+
if (next > 0) {
|
|
370
|
+
this.classCounts.set(cls, next);
|
|
371
|
+
if (current === 0) this.add(cls);
|
|
377
372
|
} else {
|
|
378
|
-
this.classCounts.delete(
|
|
379
|
-
this.remove(
|
|
373
|
+
this.classCounts.delete(cls);
|
|
374
|
+
this.remove(cls);
|
|
380
375
|
}
|
|
381
|
-
}
|
|
376
|
+
}
|
|
382
377
|
globalThis.__MASTER_CSS_DEVTOOLS_HOOK__?.emit('runtime:mutated', {
|
|
383
|
-
records
|
|
384
|
-
classCounts:
|
|
378
|
+
records,
|
|
379
|
+
classCounts: deltaCounts,
|
|
385
380
|
cssRuntime: this
|
|
386
381
|
});
|
|
387
382
|
});
|
|
388
383
|
this.observer.observe(this.root, {
|
|
384
|
+
childList: true,
|
|
389
385
|
attributes: true,
|
|
390
|
-
attributeOldValue: true,
|
|
391
386
|
attributeFilter: [
|
|
392
387
|
'class'
|
|
393
388
|
],
|
|
394
|
-
|
|
389
|
+
attributeOldValue: true,
|
|
395
390
|
subtree: true
|
|
396
391
|
});
|
|
397
|
-
if (!this.progressive)
|
|
398
|
-
this.host.removeAttribute('hidden');
|
|
399
|
-
}
|
|
400
|
-
// @ts-ignore
|
|
392
|
+
if (!this.progressive) this.host.removeAttribute('hidden');
|
|
401
393
|
this.observing = true;
|
|
402
394
|
globalThis.__MASTER_CSS_DEVTOOLS_HOOK__?.emit('runtime:observed', {
|
|
403
395
|
cssRuntime: this
|
|
@@ -543,7 +535,6 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
543
535
|
if (!this.observing) return;
|
|
544
536
|
if (this.observer) {
|
|
545
537
|
this.observer.disconnect();
|
|
546
|
-
// @ts-expect-error readonly
|
|
547
538
|
this.observer = undefined;
|
|
548
539
|
}
|
|
549
540
|
// @ts-ignore
|