@master/css-runtime 2.0.0-rc.53 → 2.0.0-rc.55

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
@@ -3,45 +3,40 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var css = require('@master/css');
6
+ var cssDevtoolsHook = require('@master/css-devtools-hook');
6
7
 
7
- class RuntimeCSS extends css.MasterCSS {
8
+ function registerGlobal(CSSRuntime) {
9
+ if (!globalThis.CSSRuntime) globalThis.CSSRuntime = CSSRuntime;
10
+ cssDevtoolsHook.installHook();
11
+ }
12
+
13
+ class CSSRuntime extends css.MasterCSS {
8
14
  root;
9
15
  customConfig;
10
- // @ts-expect-error
16
+ static instances = new WeakMap();
11
17
  host;
12
18
  observing;
13
19
  progressive;
14
- // @ts-expect-error
15
20
  container;
16
21
  observer;
17
22
  constructor(root = document, customConfig = css.config){
18
23
  super(customConfig), this.root = root, this.customConfig = customConfig, this.observing = false, this.progressive = false;
19
- this.init();
20
- this.supportVendors = new Set();
21
- const styleDeclaration = document.documentElement.style;
22
- if ('webkitTransform' in styleDeclaration) this.supportVendors.add('webkit');
23
- if ('MozTransform' in styleDeclaration) this.supportVendors.add('moz');
24
- if ('msTransform' in styleDeclaration) this.supportVendors.add('ms');
25
- if ('OTransform' in styleDeclaration) this.supportVendors.add('o');
26
- }
27
- init() {
28
- const existingRuntimeCSS = globalThis.runtimeCSSs.find((eachCSS)=>eachCSS.root === this.root);
29
- if (existingRuntimeCSS) throw new Error('Cannot create multiple RuntimeCSS instances for the same root element.');
30
- const rootConstructorName = this.root?.constructor.name;
24
+ const rootConstructorName = root?.constructor.name;
31
25
  if (rootConstructorName === 'HTMLDocument' || rootConstructorName === 'Document') {
32
- // @ts-ignore
33
- this.root.defaultView.globalThis.runtimeCSS = this;
34
- // @ts-ignore readonly
26
+ this.root.defaultView.globalThis.cssRuntime = this;
35
27
  this.container = this.root.head;
36
- // @ts-ignore readonly
37
28
  this.host = this.root.documentElement;
38
29
  } else {
39
- // @ts-ignore readonly
40
30
  this.container = this.root;
41
- // @ts-ignore readonly
42
31
  this.host = this.root.host;
43
32
  }
44
- runtimeCSSs.push(this);
33
+ this.supportVendors = new Set();
34
+ const styleDeclaration = document.documentElement.style;
35
+ if ('webkitTransform' in styleDeclaration) this.supportVendors.add('webkit');
36
+ if ('MozTransform' in styleDeclaration) this.supportVendors.add('moz');
37
+ if ('msTransform' in styleDeclaration) this.supportVendors.add('ms');
38
+ if ('OTransform' in styleDeclaration) this.supportVendors.add('o');
39
+ globalThis.CSSRuntime.instances.set(this.root, this);
45
40
  }
46
41
  /**
47
42
  * Observe the DOM for changes and update the running stylesheet. (browser only)
@@ -70,10 +65,10 @@ class RuntimeCSS extends css.MasterCSS {
70
65
  const firstConnectedElementsClasses = new Map();
71
66
  const addClasses = (element)=>{
72
67
  element.classList.forEach((className)=>{
73
- if (this.classUsages.has(className)) {
74
- this.classUsages.set(className, this.classUsages.get(className) + 1);
68
+ if (this.classCounts.has(className)) {
69
+ this.classCounts.set(className, this.classCounts.get(className) + 1);
75
70
  } else {
76
- this.classUsages.set(className, 1);
71
+ this.classCounts.set(className, 1);
77
72
  this.add(className);
78
73
  }
79
74
  const classes = firstConnectedElementsClasses.get(element);
@@ -98,14 +93,14 @@ class RuntimeCSS extends css.MasterCSS {
98
93
  // const test = ''
99
94
  // if (test) {
100
95
  // console.log('')
101
- // console.log(`${test}: ${this.classUsages.get(test)}`)
96
+ // console.log(`${test}: ${this.classCounts.get(test)}`)
102
97
  // }
103
- const eachClassUsages = new Map();
98
+ const eachClassCounts = new Map();
104
99
  const targetFirstAttrMutationRecord = new Map();
105
- const updateClassUsage = (classes, isAdding = false)=>{
100
+ const updateClassCount = (classes, isAdding = false)=>{
106
101
  const usage = isAdding ? 1 : -1;
107
102
  classes.forEach((className)=>{
108
- eachClassUsages.set(className, (eachClassUsages.get(className) || 0) + usage);
103
+ eachClassCounts.set(className, (eachClassCounts.get(className) || 0) + usage);
109
104
  });
110
105
  };
111
106
  const connectedStatusMap = new Map();
@@ -148,12 +143,12 @@ class RuntimeCSS extends css.MasterCSS {
148
143
  targetFirstAttrMutationRecord.delete(target);
149
144
  }
150
145
  if (adding) {
151
- updateClassUsage(target.classList, adding);
146
+ updateClassCount(target.classList, adding);
152
147
  } else {
153
148
  if (firstAttrMutationRecord) {
154
- updateClassUsage(firstAttrMutationRecord.oldValue ? firstAttrMutationRecord.oldValue.split(/\s+/) : [], adding);
149
+ updateClassCount(firstAttrMutationRecord.oldValue ? firstAttrMutationRecord.oldValue.split(/\s+/) : [], adding);
155
150
  } else {
156
- updateClassUsage(target.classList, adding);
151
+ updateClassCount(target.classList, adding);
157
152
  }
158
153
  disconnectedStatusMap.forEach((disconnectedTargetStatus, disconnectedTarget)=>{
159
154
  if (disconnectedTargetStatus.mutationRecord.target === target && disconnectedTargetStatus.change !== 0) {
@@ -178,59 +173,33 @@ class RuntimeCSS extends css.MasterCSS {
178
173
  const removedClasses = oldClassList.filter((c)=>!newClassList.contains(c));
179
174
  if (addedClasses.length) {
180
175
  // console.log('[attribute]', '[add] ', addedClasses, target)
181
- updateClassUsage(addedClasses, true);
176
+ updateClassCount(addedClasses, true);
182
177
  }
183
178
  if (removedClasses.length) {
184
179
  // console.log('[attribute]', '[remove]', removedClasses, target)
185
- updateClassUsage(removedClasses, false);
180
+ updateClassCount(removedClasses, false);
186
181
  }
187
182
  });
188
183
  /**
189
184
  * Merge the class usage changes into the current class usage map.
190
- */ eachClassUsages.forEach((countChange, className)=>{
191
- let currentCount = this.classUsages.get(className) || 0;
185
+ */ eachClassCounts.forEach((countChange, className)=>{
186
+ let currentCount = this.classCounts.get(className) || 0;
192
187
  let newCount = currentCount + countChange;
193
188
  if (newCount > 0) {
194
- this.classUsages.set(className, newCount);
189
+ this.classCounts.set(className, newCount);
195
190
  if (currentCount === 0) {
196
191
  this.add(className);
197
192
  }
198
193
  } else {
199
- this.classUsages.delete(className);
194
+ this.classCounts.delete(className);
200
195
  this.remove(className);
201
196
  }
202
197
  });
203
- // start: debug
204
- // const safeClassUsages: any = {};
205
- // ((this.root.constructor.name === 'HTMLDocument') ? this.host : this.container)
206
- // .querySelectorAll('[class]')
207
- // .forEach((element) => {
208
- // element.classList.forEach((className) => {
209
- // if (Object.prototype.hasOwnProperty.call(safeClassUsages, className)) {
210
- // safeClassUsages[className]++
211
- // } else {
212
- // safeClassUsages[className] = 1
213
- // }
214
- // })
215
- // })
216
- // this.host.classList.forEach((className) => {
217
- // if (Object.prototype.hasOwnProperty.call(safeClassUsages, className)) {
218
- // safeClassUsages[className]++
219
- // } else {
220
- // safeClassUsages[className] = 1
221
- // }
222
- // })
223
- // for (const className in safeClassUsages) {
224
- // if (this.classUsages.get(className) !== safeClassUsages[className]) {
225
- // throw new Error(`[css] ${className} ${this.classUsages.get(className)} (correct: ${safeClassUsages[className]})`)
226
- // }
227
- // }
228
- // this.classUsages.forEach((count, className) => {
229
- // if (!Object.prototype.hasOwnProperty.call(safeClassUsages, className)) {
230
- // throw new Error(`[css] ${className} ${count} (correct: 0)`)
231
- // }
232
- // })
233
- // end: debug
198
+ globalThis.__MASTER_CSS_DEVTOOLS_HOOK__?.emit('mutated', {
199
+ records: mutationRecords,
200
+ classCounts: eachClassCounts,
201
+ cssRuntime: this
202
+ });
234
203
  });
235
204
  this.observer.observe(this.root, {
236
205
  attributes: true,
@@ -248,10 +217,11 @@ class RuntimeCSS extends css.MasterCSS {
248
217
  this.observing = true;
249
218
  return this;
250
219
  }
251
- hydrate(nativeCSSRules) {
220
+ hydrate(nativeLayerRules) {
252
221
  const cssLayerRules = [];
253
- for(let i = 0; i < nativeCSSRules.length; i++){
254
- const eachNativeCSSRule = nativeCSSRules[i];
222
+ const checkSheet = new CSSStyleSheet();
223
+ for(let i = 0; i < nativeLayerRules.length; i++){
224
+ const eachNativeCSSRule = nativeLayerRules[i];
255
225
  if (eachNativeCSSRule.constructor.name === 'CSSLayerBlockRule') {
256
226
  const eachCSSLayerRule = eachNativeCSSRule;
257
227
  if (eachNativeCSSRule.name === 'theme') {
@@ -292,20 +262,8 @@ class RuntimeCSS extends css.MasterCSS {
292
262
  this.animationsNonLayer.usages[animationRule.name] = 0;
293
263
  }
294
264
  }
295
- const createSyntaxRules = (cssRule)=>{
296
- if (cssRule.selectorText) {
297
- return this.createFromSelectorText(cssRule.selectorText);
298
- } else if (cssRule.cssRules) {
299
- for (const eachCSSRule of cssRule.cssRules){
300
- const syntaxRules = createSyntaxRules(eachCSSRule);
301
- if (syntaxRules?.length) {
302
- return syntaxRules;
303
- }
304
- }
305
- }
306
- };
307
265
  for (const eachCSSLayerRule of cssLayerRules){
308
- const eachCSSRules = Array.from(eachCSSLayerRule.cssRules);
266
+ const nativeLayerRules = Array.from(eachCSSLayerRule.cssRules);
309
267
  let layer;
310
268
  switch(eachCSSLayerRule.name){
311
269
  case 'base':
@@ -322,62 +280,46 @@ class RuntimeCSS extends css.MasterCSS {
322
280
  break;
323
281
  }
324
282
  layer.native = eachCSSLayerRule;
325
- eachCSSRules.forEach((eachCSSRule)=>{
326
- const syntaxRules = createSyntaxRules(eachCSSRule);
327
- if (syntaxRules) {
328
- const retrieveNative = (selectorText)=>{
329
- for(let eachTargetCSSRuleIndex = 0; eachTargetCSSRuleIndex < eachCSSRules.length; eachTargetCSSRuleIndex++){
330
- const eachTargetCSSRule = eachCSSRules[eachTargetCSSRuleIndex];
331
- const matchSelector = (eachSelectorText)=>{
332
- if (eachSelectorText.replace(/,\s+/g, ',') === selectorText) {
333
- eachCSSRules.splice(eachTargetCSSRuleIndex, 1);
334
- return true;
335
- }
336
- return false;
337
- };
338
- if (eachTargetCSSRule instanceof CSSStyleRule) {
339
- if (matchSelector(eachTargetCSSRule.selectorText)) {
340
- return eachTargetCSSRule;
341
- }
342
- } else if (eachTargetCSSRule instanceof CSSMediaRule) {
343
- for(let eachMediaChildRuleIndex = 0; eachMediaChildRuleIndex < eachTargetCSSRule.cssRules.length; eachMediaChildRuleIndex++){
344
- const eachMediaChildRule = eachTargetCSSRule.cssRules[eachMediaChildRuleIndex];
345
- if (eachMediaChildRule instanceof CSSStyleRule) {
346
- if (matchSelector(eachMediaChildRule.selectorText)) {
347
- return eachTargetCSSRule;
348
- }
283
+ for (const eachNativeRule of nativeLayerRules){
284
+ const selectorText = this.getSelectorText(eachNativeRule);
285
+ if (!selectorText) {
286
+ console.error(`Cannot get the selector text from \`${eachNativeRule.cssText}\`. (${layer.name}) (https://rc.css.master.co/messages/hydration-errors)`);
287
+ continue;
288
+ }
289
+ const createdRules = this.createFromSelectorText(selectorText);
290
+ if (createdRules) {
291
+ for (const createdRule of createdRules){
292
+ layer.rules.push(createdRule);
293
+ layer.insertVariables(createdRule);
294
+ layer.insertAnimations(createdRule);
295
+ createdRule.nodes.forEach((node)=>{
296
+ const createdNodeNativeRule = checkSheet.cssRules.item(checkSheet.insertRule(node.text));
297
+ if (createdNodeNativeRule) {
298
+ for (const eachFindingNativeRule of nativeLayerRules){
299
+ if (createdNodeNativeRule.cssText === eachFindingNativeRule.cssText) {
300
+ node.native = eachFindingNativeRule;
301
+ nativeLayerRules.splice(nativeLayerRules.indexOf(eachFindingNativeRule), 1);
302
+ return;
349
303
  }
350
304
  }
351
305
  }
352
- }
353
- };
354
- for (const syntaxRule of syntaxRules){
355
- layer.rules.push(syntaxRule);
356
- layer.insertVariables(syntaxRule);
357
- layer.insertAnimations(syntaxRule);
358
- syntaxRule.nodes.forEach((node)=>{
359
- const native = retrieveNative(node.selectorText);
360
- if (native) {
361
- node.native = native;
362
- } else {
363
- console.error(`Cannot retrieve the CSS rule for \`${node.selectorText}\`. (${layer.name}) (https://rc.css.master.co/messages/hydration-errors)`);
364
- }
306
+ console.error(`Cannot retrieve CSS rule for \`${node.selectorText}\`. (${layer.name}) (https://rc.css.master.co/messages/hydration-errors)`);
365
307
  });
366
308
  }
367
309
  } else {
368
- console.error(`Cannot recognize the CSS rule \`${eachCSSRule.cssText}\`. (${layer.name}) (https://rc.css.master.co/messages/hydration-errors)`);
369
- }
370
- });
371
- for (const eachRule of layer.rules){
372
- for(let k = eachRule.nodes.length - 1; k >= 0; k--){
373
- if (!eachRule.nodes[k].native) {
374
- eachRule.nodes.splice(k, 1);
375
- }
310
+ console.error(`Cannot recognize \`${eachNativeRule.cssText}\`. (${layer.name}) (https://rc.css.master.co/messages/hydration-errors)`);
376
311
  }
377
312
  }
378
313
  if (layer.rules.length) this.rules.push(layer);
379
314
  }
380
315
  }
316
+ getSelectorText(cssRule) {
317
+ if ('selectorText' in cssRule) {
318
+ return cssRule.selectorText;
319
+ } else if ('cssRules' in cssRule) {
320
+ return this.getSelectorText(cssRule.cssRules.item(0));
321
+ }
322
+ }
381
323
  disconnect() {
382
324
  if (!this.observing) return;
383
325
  if (this.observer) {
@@ -388,7 +330,7 @@ class RuntimeCSS extends css.MasterCSS {
388
330
  // @ts-ignore
389
331
  this.observing = false;
390
332
  this.reset();
391
- this.classUsages.clear();
333
+ this.classCounts.clear();
392
334
  if (!this.progressive) {
393
335
  this.style?.remove();
394
336
  this.style = null;
@@ -405,25 +347,28 @@ class RuntimeCSS extends css.MasterCSS {
405
347
  }
406
348
  destroy() {
407
349
  this.disconnect();
408
- runtimeCSSs.splice(runtimeCSSs.indexOf(this), 1);
350
+ globalThis.CSSRuntime.instances.delete(this.root);
409
351
  return this;
410
352
  }
411
353
  }
412
- const runtimeCSSs = [];
413
- (()=>{
414
- globalThis.RuntimeCSS = RuntimeCSS;
415
- globalThis.runtimeCSSs = runtimeCSSs;
416
- })();
354
+ (function(CSSRuntime) {
355
+ registerGlobal(CSSRuntime);
356
+ })(CSSRuntime);
417
357
 
418
358
  /**
419
- * Initialize a new RuntimeCSS instance and observe the target root
359
+ * Initialize a new CSSRuntime instance and observe the target root
420
360
  * @param config master css config
421
- * @param targetRoot target root to observe
361
+ * @param root target root to observe
362
+ * @param autoObserve auto observe the target root
422
363
  * @returns master css instance
423
- */ function initCSSRuntime(config) {
424
- return new RuntimeCSS(document, config).observe();
364
+ */ function initCSSRuntime(config, root = document, autoObserve = true) {
365
+ let cssRuntime = globalThis.CSSRuntime.instances.get(root);
366
+ if (cssRuntime) return cssRuntime;
367
+ cssRuntime = new CSSRuntime(document, config);
368
+ if (autoObserve) cssRuntime.observe();
369
+ return cssRuntime;
425
370
  }
426
371
 
427
- exports.RuntimeCSS = RuntimeCSS;
428
- exports.default = RuntimeCSS;
372
+ exports.CSSRuntime = CSSRuntime;
373
+ exports.default = CSSRuntime;
429
374
  exports.initCSSRuntime = initCSSRuntime;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { RuntimeCSS, RuntimeCSS as default } from './core';
2
- export { default as initCSSRuntime } from './init-css-runtime';
1
+ export { default as CSSRuntime, default } from './core';
2
+ export { default as initCSSRuntime } from './init';