@master/css-runtime 2.0.0-rc.63 → 2.0.0-rc.65
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 +103 -132
- package/dist/index.development.cjs +131 -135
- package/dist/index.development.mjs +131 -135
- package/dist/index.mjs +103 -132
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,12 +40,21 @@ class RuntimeLayer extends css.Layer {
|
|
|
40
40
|
const insertedIndex = super.insert(rule, index);
|
|
41
41
|
if (insertedIndex === undefined || !this.native) return;
|
|
42
42
|
const insertRuleSafely = (text, position)=>{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return this.native.cssRules.item(
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
// Checks if the rule is inserted in a native CSS rule with this.attach()
|
|
44
|
+
if (this.rules.length === 1) {
|
|
45
|
+
return this.native.cssRules.item(position);
|
|
46
|
+
} else {
|
|
47
|
+
try {
|
|
48
|
+
const insertedIndex = this.native.insertRule(text, position);
|
|
49
|
+
return this.native.cssRules.item(insertedIndex);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(error, rule);
|
|
52
|
+
/**
|
|
53
|
+
* If the rule is invalid, remove it from the rules array.
|
|
54
|
+
* It's important to note that the rule may break the entire CSS runtime,
|
|
55
|
+
*/ this.rules.splice(insertedIndex, 1);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
49
58
|
}
|
|
50
59
|
};
|
|
51
60
|
if ('nodes' in rule) {
|
|
@@ -55,7 +64,7 @@ class RuntimeLayer extends css.Layer {
|
|
|
55
64
|
if (node.native) currentIndex++;
|
|
56
65
|
});
|
|
57
66
|
} else {
|
|
58
|
-
rule.native = insertRuleSafely(rule.text,
|
|
67
|
+
rule.native = insertRuleSafely(rule.text, insertedIndex);
|
|
59
68
|
}
|
|
60
69
|
return insertedIndex;
|
|
61
70
|
}
|
|
@@ -110,20 +119,19 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
110
119
|
customConfig;
|
|
111
120
|
static instances = new WeakMap();
|
|
112
121
|
host;
|
|
113
|
-
observing;
|
|
114
|
-
progressive;
|
|
115
122
|
container;
|
|
116
|
-
observer;
|
|
117
123
|
baseLayer;
|
|
118
124
|
themeLayer;
|
|
119
125
|
presetLayer;
|
|
120
126
|
componentsLayer;
|
|
121
127
|
generalLayer;
|
|
122
128
|
classCounts;
|
|
129
|
+
observer;
|
|
130
|
+
progressive;
|
|
131
|
+
observing;
|
|
123
132
|
constructor(root = document, customConfig = css.config){
|
|
124
|
-
super(customConfig), this.root = root, this.customConfig = customConfig, this.
|
|
125
|
-
|
|
126
|
-
if (rootConstructorName === 'HTMLDocument' || rootConstructorName === 'Document') {
|
|
133
|
+
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;
|
|
134
|
+
if (this.root instanceof Document || this.root instanceof HTMLDocument) {
|
|
127
135
|
this.root.defaultView.globalThis.cssRuntime = this;
|
|
128
136
|
this.container = this.root.head;
|
|
129
137
|
this.host = this.root.documentElement;
|
|
@@ -142,36 +150,44 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
142
150
|
* @returns this
|
|
143
151
|
*/ observe() {
|
|
144
152
|
if (this.observing) return this;
|
|
145
|
-
//
|
|
146
|
-
if (this.root.styleSheets)
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
// Detect prerendered stylesheet
|
|
154
|
+
if (this.root.styleSheets) {
|
|
155
|
+
for (const sheet of this.root.styleSheets){
|
|
156
|
+
const { ownerNode } = sheet;
|
|
157
|
+
if (ownerNode instanceof HTMLStyleElement && ownerNode.id === 'master') {
|
|
158
|
+
this.style = ownerNode;
|
|
159
|
+
if (this.style.sheet?.cssRules.length) {
|
|
160
|
+
this.progressive = true;
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
153
163
|
}
|
|
154
|
-
break;
|
|
155
164
|
}
|
|
156
165
|
}
|
|
157
|
-
//
|
|
166
|
+
// Prepare snapshot map
|
|
167
|
+
const elementClasses = new WeakMap();
|
|
168
|
+
// Initial scan and populate counts + snapshot
|
|
158
169
|
const connectedNames = new Set();
|
|
159
170
|
const increaseClassCount = (className)=>{
|
|
160
171
|
const count = this.classCounts.get(className) || 0;
|
|
161
|
-
if (!count)
|
|
162
|
-
connectedNames.add(className);
|
|
163
|
-
}
|
|
172
|
+
if (!count) connectedNames.add(className);
|
|
164
173
|
this.classCounts.set(className, count + 1);
|
|
165
174
|
};
|
|
166
|
-
this.
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
const rootEl = this.root instanceof Document || this.root instanceof HTMLDocument ? this.root : this.container;
|
|
176
|
+
const elementsWithClass = rootEl.querySelectorAll('[class]');
|
|
177
|
+
elementsWithClass.forEach((el)=>{
|
|
178
|
+
const clsList = el.classList;
|
|
179
|
+
if (clsList) {
|
|
180
|
+
el.classList.forEach(increaseClassCount);
|
|
181
|
+
}
|
|
182
|
+
elementClasses.set(el, new Set(clsList));
|
|
183
|
+
});
|
|
184
|
+
// Hydration or style creation
|
|
169
185
|
if (this.progressive) {
|
|
170
186
|
const hydrateResult = this.hydrate(this.style.sheet.cssRules);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
187
|
+
for (const cls of connectedNames){
|
|
188
|
+
if (!hydrateResult.allSyntaxRules.find((r)=>(r.fixedClass || r.name) === cls)) {
|
|
189
|
+
this.add(cls);
|
|
190
|
+
}
|
|
175
191
|
}
|
|
176
192
|
} else {
|
|
177
193
|
this.style = document.createElement('style');
|
|
@@ -179,125 +195,81 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
179
195
|
this.container.append(this.style);
|
|
180
196
|
this.style.sheet.insertRule(this.layerStatementRule.text);
|
|
181
197
|
this.layerStatementRule.native = this.style.sheet.cssRules.item(0);
|
|
182
|
-
|
|
183
|
-
this.add(eachConnectedName);
|
|
184
|
-
}
|
|
198
|
+
connectedNames.forEach((cls)=>this.add(cls));
|
|
185
199
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
200
|
+
this.observer = new MutationObserver((records)=>{
|
|
201
|
+
const deltaCounts = new Map();
|
|
202
|
+
const nodeMap = new Map();
|
|
203
|
+
const attrRecords = new Set();
|
|
204
|
+
const visited = new WeakSet();
|
|
205
|
+
const updateDelta = (cls, delta)=>deltaCounts.set(cls, (deltaCounts.get(cls) || 0) + delta);
|
|
206
|
+
const diffAndSnapshot = (el)=>{
|
|
207
|
+
const prev = new Set(elementClasses.get(el) || []);
|
|
208
|
+
const next = new Set(el.classList);
|
|
209
|
+
for (const c of next)if (!prev.has(c)) updateDelta(c, 1);
|
|
210
|
+
for (const c of prev)if (!next.has(c)) updateDelta(c, -1);
|
|
211
|
+
elementClasses.set(el, next);
|
|
195
212
|
};
|
|
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
|
-
}
|
|
213
|
+
const removeSnapshot = (el)=>{
|
|
214
|
+
for (const c of elementClasses.get(el) || [])updateDelta(c, -1);
|
|
215
|
+
elementClasses.delete(el);
|
|
214
216
|
};
|
|
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);
|
|
217
|
+
for (const record of records){
|
|
218
|
+
if (record.type === 'childList') {
|
|
219
|
+
for (const node of record.addedNodes)if (node instanceof Element && node.isConnected) nodeMap.set(node, (nodeMap.get(node) || 0) + 1);
|
|
220
|
+
for (const node of record.removedNodes)if (node instanceof Element && !node.isConnected) nodeMap.set(node, (nodeMap.get(node) || 0) - 1);
|
|
221
|
+
} else if (record.type === 'attributes' && record.attributeName === 'class') {
|
|
222
|
+
attrRecords.add(record.target);
|
|
234
223
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
224
|
+
}
|
|
225
|
+
const traverseIncludingSelf = (el, fn, visited)=>{
|
|
226
|
+
if (!visited.has(el)) {
|
|
227
|
+
visited.add(el);
|
|
228
|
+
fn(el);
|
|
229
|
+
for (const child of el.children){
|
|
230
|
+
traverseIncludingSelf(child, fn, visited);
|
|
242
231
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
updateTarget(disconnectedTarget, disconnectedTargetStatus.change > 0);
|
|
246
|
-
}
|
|
247
|
-
});
|
|
232
|
+
} else {
|
|
233
|
+
nodeMap.delete(el);
|
|
248
234
|
}
|
|
249
235
|
};
|
|
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);
|
|
262
|
-
}
|
|
263
|
-
if (removedClasses.length) {
|
|
264
|
-
updateClassCount(removedClasses, false);
|
|
236
|
+
for (const [node, count] of nodeMap){
|
|
237
|
+
if (count > 0) {
|
|
238
|
+
traverseIncludingSelf(node, diffAndSnapshot, visited);
|
|
239
|
+
} else if (count < 0 && !node.isConnected) {
|
|
240
|
+
traverseIncludingSelf(node, removeSnapshot, visited);
|
|
265
241
|
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
242
|
+
}
|
|
243
|
+
for (const el of attrRecords){
|
|
244
|
+
if (!visited.has(el)) diffAndSnapshot(el);
|
|
245
|
+
}
|
|
246
|
+
for (const [cls, change] of deltaCounts){
|
|
247
|
+
const current = this.classCounts.get(cls) || 0;
|
|
248
|
+
const next = current + change;
|
|
249
|
+
if (next > 0) {
|
|
250
|
+
this.classCounts.set(cls, next);
|
|
251
|
+
if (current === 0) this.add(cls);
|
|
277
252
|
} else {
|
|
278
|
-
this.classCounts.delete(
|
|
279
|
-
this.remove(
|
|
253
|
+
this.classCounts.delete(cls);
|
|
254
|
+
this.remove(cls);
|
|
280
255
|
}
|
|
281
|
-
}
|
|
256
|
+
}
|
|
282
257
|
globalThis.__MASTER_CSS_DEVTOOLS_HOOK__?.emit('runtime:mutated', {
|
|
283
|
-
records
|
|
284
|
-
classCounts:
|
|
258
|
+
records,
|
|
259
|
+
classCounts: deltaCounts,
|
|
285
260
|
cssRuntime: this
|
|
286
261
|
});
|
|
287
262
|
});
|
|
288
263
|
this.observer.observe(this.root, {
|
|
264
|
+
childList: true,
|
|
289
265
|
attributes: true,
|
|
290
|
-
attributeOldValue: true,
|
|
291
266
|
attributeFilter: [
|
|
292
267
|
'class'
|
|
293
268
|
],
|
|
294
|
-
|
|
269
|
+
attributeOldValue: true,
|
|
295
270
|
subtree: true
|
|
296
271
|
});
|
|
297
|
-
if (!this.progressive)
|
|
298
|
-
this.host.removeAttribute('hidden');
|
|
299
|
-
}
|
|
300
|
-
// @ts-ignore
|
|
272
|
+
if (!this.progressive) this.host.removeAttribute('hidden');
|
|
301
273
|
this.observing = true;
|
|
302
274
|
globalThis.__MASTER_CSS_DEVTOOLS_HOOK__?.emit('runtime:observed', {
|
|
303
275
|
cssRuntime: this
|
|
@@ -440,7 +412,6 @@ class CSSRuntime extends css.MasterCSS {
|
|
|
440
412
|
if (!this.observing) return;
|
|
441
413
|
if (this.observer) {
|
|
442
414
|
this.observer.disconnect();
|
|
443
|
-
// @ts-expect-error readonly
|
|
444
415
|
this.observer = undefined;
|
|
445
416
|
}
|
|
446
417
|
// @ts-ignore
|