@master/css 2.0.0-rc.57 → 2.0.0-rc.59

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.mjs CHANGED
@@ -3,10 +3,10 @@ import { config } from './config/index.mjs';
3
3
  import hexToRgb from './utils/hex-to-rgb.mjs';
4
4
  import { flattenObject } from './utils/flatten-object.mjs';
5
5
  import extendConfig from './utils/extend-config.mjs';
6
- import SyntaxLayer from './syntax-layer.mjs';
7
6
  import { Rule } from './rule.mjs';
8
7
  import SyntaxRuleType from './syntax-rule-type.mjs';
9
8
  import Layer from './layer.mjs';
9
+ import SyntaxLayer from './syntax-layer.mjs';
10
10
  import NonLayer from './non-layer.mjs';
11
11
  import registerGlobal from './register-global.mjs';
12
12
 
@@ -15,7 +15,6 @@ class MasterCSS {
15
15
  static config = config;
16
16
  definedRules;
17
17
  config;
18
- classCounts;
19
18
  layerStatementRule;
20
19
  rules;
21
20
  animationsNonLayer;
@@ -24,25 +23,14 @@ class MasterCSS {
24
23
  presetLayer;
25
24
  componentsLayer;
26
25
  generalLayer;
27
- get text() {
28
- return this.rules.sort((a, b)=>{
29
- const order = [
30
- 'layer-statement',
31
- 'base',
32
- 'theme',
33
- 'preset',
34
- 'components',
35
- 'general'
36
- ];
37
- const indexA = order.indexOf(a.name) === -1 ? Infinity : order.indexOf(a.name);
38
- const indexB = order.indexOf(b.name) === -1 ? Infinity : order.indexOf(b.name);
39
- return indexA - indexB;
40
- }).map(({ text })=>text).join('');
41
- }
26
+ components;
27
+ selectors;
28
+ variables;
29
+ at;
30
+ animations;
42
31
  constructor(customConfig){
43
32
  this.customConfig = customConfig;
44
33
  this.definedRules = [];
45
- this.classCounts = new Map();
46
34
  this.layerStatementRule = new Rule('layer-statement', [
47
35
  {
48
36
  text: '@layer base,theme,preset,components,general;'
@@ -57,15 +45,35 @@ class MasterCSS {
57
45
  this.presetLayer = new SyntaxLayer('preset', this);
58
46
  this.componentsLayer = new SyntaxLayer('components', this);
59
47
  this.generalLayer = new SyntaxLayer('general', this);
48
+ this.components = new Map();
49
+ this.selectors = new Map();
50
+ this.variables = new Map();
51
+ this.at = new Map();
52
+ this.animations = new Map();
60
53
  this.config = customConfig?.override ? extendConfig(customConfig) : extendConfig(config, customConfig);
61
54
  this.resolve();
62
55
  }
56
+ get text() {
57
+ return this.rules.sort((a, b)=>{
58
+ const order = [
59
+ 'layer-statement',
60
+ 'base',
61
+ 'theme',
62
+ 'preset',
63
+ 'components',
64
+ 'general'
65
+ ];
66
+ const indexA = order.indexOf(a.name) === -1 ? Infinity : order.indexOf(a.name);
67
+ const indexB = order.indexOf(b.name) === -1 ? Infinity : order.indexOf(b.name);
68
+ return indexA - indexB;
69
+ }).map(({ text })=>text).join('');
70
+ }
63
71
  resolve() {
64
- this.components = {};
65
- this.selectors = {};
66
- this.variables = {};
67
- this.at = {};
68
- this.animations = {};
72
+ this.components.clear();
73
+ this.selectors.clear();
74
+ this.variables.clear();
75
+ this.at.clear();
76
+ this.animations.clear();
69
77
  this.definedRules.length = 0;
70
78
  const colorVariableNames = {
71
79
  current: undefined,
@@ -85,9 +93,9 @@ class MasterCSS {
85
93
  eachResolvedSelectorText
86
94
  ]){
87
95
  const vendor = eachNewSelectorText.match(/^:(?::)?-(webkit|moz|ms|o)-/m)?.[1] ?? '';
88
- let selectorValues = this.selectors[vendor];
96
+ let selectorValues = this.selectors.get(vendor);
89
97
  if (!selectorValues) {
90
- selectorValues = this.selectors[vendor] = [];
98
+ this.selectors.set(vendor, selectorValues = []);
91
99
  }
92
100
  let currentSelectValue = selectorValues.find(([_valueRegexp])=>_valueRegexp === regexp);
93
101
  if (!currentSelectValue) {
@@ -102,7 +110,7 @@ class MasterCSS {
102
110
  }
103
111
  }
104
112
  if (variables) {
105
- const unexecutedAliasVariable = {};
113
+ const aliasVariableModeResolvers = new Map;
106
114
  const resolveVariable = (variableDefinition, name, mode)=>{
107
115
  if (variableDefinition === undefined || variableDefinition === null) return;
108
116
  const addVariable = (name, variable, replacedMode, alpha)=>{
@@ -126,12 +134,12 @@ class MasterCSS {
126
134
  /**
127
135
  * resolve `variables.screen-*` to `at.*`
128
136
  */ if (variable.name.startsWith('screen-') && variable.type === 'number') {
129
- this.at[variable.name.slice(7)] = variable.value;
137
+ this.at.set(variable.name.slice(7), variable.value);
130
138
  }
131
139
  const currentMode = replacedMode ?? mode;
132
140
  if (currentMode !== undefined) {
133
- if (Object.prototype.hasOwnProperty.call(this.variables, flatName)) {
134
- const foundVariable = this.variables[flatName];
141
+ const foundVariable = this.variables.get(flatName);
142
+ if (foundVariable) {
135
143
  if (currentMode) {
136
144
  if (!foundVariable.modes) {
137
145
  foundVariable.modes = {};
@@ -157,13 +165,13 @@ class MasterCSS {
157
165
  if (variable.type === 'color') {
158
166
  newVariable.space = variable.space;
159
167
  }
160
- this.variables[flatName] = newVariable;
168
+ this.variables.set(flatName, newVariable);
161
169
  } else {
162
- this.variables[flatName] = variable;
170
+ this.variables.set(flatName, variable);
163
171
  }
164
172
  }
165
173
  } else {
166
- this.variables[flatName] = variable;
174
+ this.variables.set(flatName, variable);
167
175
  }
168
176
  };
169
177
  if (typeof variableDefinition === 'object') {
@@ -201,19 +209,21 @@ class MasterCSS {
201
209
  const aliasResult = /^\$\((.*?)\)(?: ?\/ ?(.+?))?$/.exec(variableDefinition);
202
210
  const flatName = name.join('-');
203
211
  if (aliasResult) {
204
- if (!Object.prototype.hasOwnProperty.call(unexecutedAliasVariable, flatName)) {
205
- unexecutedAliasVariable[flatName] = {};
212
+ let aliasVariableModeResolver = aliasVariableModeResolvers.get(flatName);
213
+ if (!aliasVariableModeResolver) {
214
+ aliasVariableModeResolvers.set(flatName, aliasVariableModeResolver = {});
206
215
  }
207
- unexecutedAliasVariable[flatName][mode] = ()=>{
208
- delete unexecutedAliasVariable[flatName][mode];
216
+ aliasVariableModeResolver[mode] = ()=>{
217
+ delete aliasVariableModeResolver[mode];
209
218
  const [alias, aliasMode] = aliasResult[1].split('@');
210
219
  if (alias) {
211
- if (Object.prototype.hasOwnProperty.call(unexecutedAliasVariable, alias)) {
212
- for (const mode of Object.keys(unexecutedAliasVariable[alias])){
213
- unexecutedAliasVariable[alias][mode]?.();
220
+ const eachAliasModeVariableResolver = aliasVariableModeResolvers.get(alias);
221
+ if (eachAliasModeVariableResolver) {
222
+ for (const mode of Object.keys(eachAliasModeVariableResolver)){
223
+ eachAliasModeVariableResolver[mode]?.();
214
224
  }
215
225
  }
216
- const aliasVariable = this.variables[alias];
226
+ const aliasVariable = this.variables.get(alias);
217
227
  if (aliasVariable) {
218
228
  if (aliasMode === undefined && aliasVariable.modes) {
219
229
  addVariable(name, {
@@ -282,18 +292,22 @@ class MasterCSS {
282
292
  ]);
283
293
  }
284
294
  // todo: address to the target variable
285
- for (const name of Object.keys(unexecutedAliasVariable)){
286
- for (const mode of Object.keys(unexecutedAliasVariable[name])){
287
- unexecutedAliasVariable[name][mode]?.();
295
+ aliasVariableModeResolvers.forEach((aliasVariableModeResolver)=>{
296
+ for (const mode of Object.keys(aliasVariableModeResolver)){
297
+ aliasVariableModeResolver[mode]?.();
288
298
  }
289
- }
299
+ });
290
300
  }
291
301
  if (at) {
292
- Object.assign(this.at, flattenObject(at));
302
+ const resolvedAt = flattenObject(at);
303
+ for(const eachAt in resolvedAt){
304
+ this.at.set(eachAt, resolvedAt[eachAt]);
305
+ }
293
306
  }
294
307
  if (animations) {
295
308
  for(const animationName in animations){
296
- const eachAnimation = this.animations[animationName] = {};
309
+ const eachAnimation = {};
310
+ this.animations.set(animationName, eachAnimation);
297
311
  const eachKeyframes = animations[animationName];
298
312
  for(const eachKeyframeValue in eachKeyframes){
299
313
  const newValueByPropertyName = eachAnimation[eachKeyframeValue] = {};
@@ -307,8 +321,9 @@ class MasterCSS {
307
321
  const flattedStyles = components ? flattenObject(components) : {};
308
322
  const utilityNames = Object.keys(flattedStyles);
309
323
  const handleUtilityName = (utilityName)=>{
310
- if (Object.prototype.hasOwnProperty.call(this.components, utilityName)) return;
311
- const currentClass = this.components[utilityName] = [];
324
+ if (this.components.has(utilityName)) return;
325
+ const currentClass = [];
326
+ this.components.set(utilityName, currentClass);
312
327
  const className = flattedStyles[utilityName];
313
328
  if (!className) return;
314
329
  const classNames = className.replace(/(?:\n(?:\s*))+/g, ' ').trim().split(' ');
@@ -320,9 +335,8 @@ class MasterCSS {
320
335
  };
321
336
  if (utilityNames.includes(eachClassName)) {
322
337
  handleUtilityName(eachClassName);
323
- for (const parentClassName of this.components[eachClassName]){
324
- handle(parentClassName);
325
- }
338
+ const componentClasses = this.components.get(eachClassName);
339
+ componentClasses?.forEach(handle);
326
340
  } else {
327
341
  handle(eachClassName);
328
342
  }
@@ -380,12 +394,11 @@ class MasterCSS {
380
394
  }
381
395
  // todo: 不可使用 startsWith 判斷,應改為更精準的從 config.variables 取得目標變數群組,但 config.variables 中的值還沒被 resolve 像是 Array
382
396
  const addResolvedVariables = (groupName)=>{
383
- for(const eachVariableName in this.variables){
384
- const eachVariable = this.variables[eachVariableName];
397
+ this.variables.forEach((eachVariable)=>{
385
398
  if (eachVariable.group === groupName) {
386
399
  syntax.variables[eachVariable.key] = eachVariable;
387
400
  }
388
- }
401
+ });
389
402
  };
390
403
  // 1. custom `config.rules[id].variables`
391
404
  if (eachSyntaxRuleDefinition.variables) {
@@ -441,8 +454,8 @@ class MasterCSS {
441
454
  }
442
455
  });
443
456
  }
444
- for(const utilityName in this.components){
445
- const syntaxRulesByStateToken = this.components[utilityName].map((eachSyntax)=>this.create(eachSyntax)).filter((eachSyntax)=>eachSyntax?.text).reduce((obj, eachSyntaxRule)=>{
457
+ this.components.forEach((componentClasses, componentClass)=>{
458
+ const syntaxRulesByStateToken = componentClasses.map((eachSyntax)=>this.create(eachSyntax)).filter((eachSyntax)=>eachSyntax?.text).reduce((obj, eachSyntaxRule)=>{
446
459
  if (eachSyntaxRule.stateToken in obj) {
447
460
  obj[eachSyntaxRule.stateToken].push(eachSyntaxRule);
448
461
  } else {
@@ -452,11 +465,11 @@ class MasterCSS {
452
465
  }
453
466
  return obj;
454
467
  }, {});
455
- this.components[utilityName] = Object.keys(syntaxRulesByStateToken).map((stateToken)=>{
468
+ this.components.set(componentClass, Object.keys(syntaxRulesByStateToken).map((stateToken)=>{
456
469
  const syntaxRules = syntaxRulesByStateToken[stateToken];
457
470
  return syntaxRules.length === 1 ? syntaxRules[0].name : '{' + syntaxRulesByStateToken[stateToken].map((eachSyntaxRule)=>eachSyntaxRule.name.slice(0, eachSyntaxRule.name.length - eachSyntaxRule.stateToken.length)).join(';') + '}' + stateToken;
458
- });
459
- }
471
+ }));
472
+ });
460
473
  }
461
474
  /**
462
475
  * Match check if Master CSS syntax
@@ -494,27 +507,29 @@ class MasterCSS {
494
507
  * @returns SyntaxRule[]
495
508
  */ generate(className, mode) {
496
509
  let syntaxRules = [];
497
- if (Object.prototype.hasOwnProperty.call(this.components, className)) {
498
- syntaxRules = this.components[className].map((eachSyntax)=>this.create(eachSyntax, className, mode));
510
+ const componentClasses = this.components.get(className);
511
+ if (componentClasses) {
512
+ componentClasses.forEach((eachSyntax)=>{
513
+ const syntaxRule = this.create(eachSyntax, className, mode);
514
+ if (syntaxRule?.text) syntaxRules.push(syntaxRule);
515
+ });
499
516
  } else {
500
517
  const atIndex = className.indexOf('@');
501
518
  if (atIndex !== -1) {
502
519
  const name = className.slice(0, atIndex);
503
- if (Object.prototype.hasOwnProperty.call(this.components, name)) {
520
+ const componentClasses = this.components.get(name);
521
+ if (componentClasses) {
504
522
  const atToken = className.slice(atIndex);
505
- syntaxRules = this.components[name].map((eachSyntax)=>this.create(eachSyntax + atToken, className, mode));
506
- } else {
507
- syntaxRules = [
508
- this.create(className, undefined, mode)
509
- ];
523
+ componentClasses.forEach((eachSyntax)=>{
524
+ const syntaxRule = this.create(eachSyntax + atToken, className, mode);
525
+ if (syntaxRule?.text) syntaxRules.push(syntaxRule);
526
+ });
510
527
  }
511
- } else {
512
- syntaxRules = [
513
- this.create(className, undefined, mode)
514
- ];
515
528
  }
529
+ const syntaxRule = this.create(className, undefined, mode);
530
+ if (syntaxRule?.text) syntaxRules.push(syntaxRule);
516
531
  }
517
- return syntaxRules.filter((eachSyntax)=>eachSyntax?.text);
532
+ return syntaxRules;
518
533
  }
519
534
  generateVendorSelectors(selectorText) {
520
535
  const vendorSelectors = {};
@@ -562,14 +577,15 @@ class MasterCSS {
562
577
  return selectors;
563
578
  };
564
579
  const transformedSelectors = [];
565
- if ('' in this.selectors) {
566
- transformSelector(selectorText, this.selectors[''], transformedSelectors, true);
580
+ const selectorValues = this.selectors.get('');
581
+ if (selectorValues) {
582
+ transformSelector(selectorText, selectorValues, transformedSelectors, true);
567
583
  } else {
568
584
  transformedSelectors.push(selectorText);
569
585
  }
570
586
  const unspacedVendorSelectors = {};
571
- for (const [vendor, selectorValues] of Object.entries(this.selectors)){
572
- if (!vendor) continue;
587
+ this.selectors.forEach((selectorValues, vendor)=>{
588
+ if (!vendor) return;
573
589
  const newUnspacedVendorSelectors = [];
574
590
  for (const eachTransformedSelector of transformedSelectors){
575
591
  transformSelector(eachTransformedSelector, selectorValues, newUnspacedVendorSelectors, false);
@@ -577,7 +593,7 @@ class MasterCSS {
577
593
  if (newUnspacedVendorSelectors.length) {
578
594
  unspacedVendorSelectors[vendor] = newUnspacedVendorSelectors;
579
595
  }
580
- }
596
+ });
581
597
  const insertVendorSelectors = (vendor, selectorTexts)=>{
582
598
  const groupedSelectorTexts = selectorTexts.reduce((arr, eachSuffixSelector)=>{
583
599
  arr.push(...spacedSelectorToken(eachSuffixSelector));
@@ -614,37 +630,26 @@ class MasterCSS {
614
630
  * @param selectorText
615
631
  */ createFromSelectorText(selectorText) {
616
632
  const selectorTextSplits = selectorText.split(' ');
633
+ const stopChars = /[.#\[!\*>+~:,\s]/;
617
634
  for(let i = 0; i < selectorTextSplits.length; i++){
618
635
  const eachField = selectorTextSplits[i];
619
636
  const modeSelector = this.getModeSelector(eachField);
620
637
  if (i === 0 && eachField === modeSelector) continue;
621
- if (eachField[0] === '.') {
638
+ if (eachField.startsWith('.')) {
622
639
  const eachFieldName = eachField.slice(1);
623
640
  let className = '';
624
- for(let l = 0; l < eachFieldName.length; l++){
641
+ let l = 0;
642
+ while(l < eachFieldName.length){
625
643
  const char = eachFieldName[l];
626
644
  const nextChar = eachFieldName[l + 1];
627
- if (char === '\\') {
628
- l++;
629
- if (nextChar !== '\\') {
630
- className += nextChar;
631
- continue;
632
- }
633
- } else if ([
634
- '.',
635
- '#',
636
- '[',
637
- '!',
638
- '*',
639
- '>',
640
- '+',
641
- '~',
642
- ':',
643
- ','
644
- ].includes(char)) {
645
- break;
645
+ if (char === '\\' && nextChar) {
646
+ className += nextChar;
647
+ l += 2;
648
+ continue;
646
649
  }
650
+ if (stopChars.test(char)) break;
647
651
  className += char;
652
+ l++;
648
653
  }
649
654
  const syntaxRules = this.generate(className);
650
655
  if (syntaxRules.length) return syntaxRules;
@@ -663,12 +668,6 @@ class MasterCSS {
663
668
  // @ts-ignore
664
669
  this.config = customConfig?.override ? extendConfig(customConfig) : extendConfig(config, customConfig);
665
670
  this.resolve();
666
- /**
667
- * 拿當前所有的 classNames 按照最新的 colors, config.rules 匹配並生成新的 style
668
- * 所以 refresh 過後 rules 可能會變多也可能會變少
669
- */ this.classCounts.forEach((_, className)=>{
670
- this.add(className);
671
- });
672
671
  return this;
673
672
  }
674
673
  reset() {
@@ -682,7 +681,6 @@ class MasterCSS {
682
681
  }
683
682
  destroy() {
684
683
  this.reset();
685
- this.classCounts.clear();
686
684
  return this;
687
685
  }
688
686
  add(...classNames) {
@@ -696,19 +694,21 @@ class MasterCSS {
696
694
  * class name 從 DOM tree 中被移除,
697
695
  * 匹配並刪除對應的 rule
698
696
  */ for (const className of classNames){
699
- if (Object.prototype.hasOwnProperty.call(this.components, className)) {
700
- for (const eachSyntax of this.components[className]){
701
- this.componentsLayer.delete(className + ' ' + eachSyntax);
702
- }
697
+ const componentClasses = this.components.get(className);
698
+ if (componentClasses) {
699
+ componentClasses.forEach((componentClass)=>{
700
+ this.componentsLayer.delete(className + ' ' + componentClass);
701
+ });
703
702
  } else {
704
703
  const atIndex = className.indexOf('@');
705
704
  if (atIndex !== -1) {
706
705
  const name = className.slice(0, atIndex);
707
- if (Object.prototype.hasOwnProperty.call(this.components, name)) {
706
+ const componentClasses = this.components.get(name);
707
+ if (componentClasses) {
708
708
  const atToken = className.slice(atIndex);
709
- for (const eachSyntax of this.components[name]){
710
- this.componentsLayer.delete(eachSyntax + atToken + ' ' + className);
711
- }
709
+ componentClasses.forEach((componentClass)=>{
710
+ this.componentsLayer.delete(componentClass + atToken + ' ' + className);
711
+ });
712
712
  } else {
713
713
  this.generalLayer.delete(className);
714
714
  }