@webstudio-is/css-engine 0.145.0 → 0.163.0
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/lib/index.js +278 -113
- package/lib/types/core/atomic.d.ts +12 -0
- package/lib/types/core/create-style-sheet.d.ts +0 -4
- package/lib/types/core/index.d.ts +2 -2
- package/lib/types/core/rules.d.ts +74 -11
- package/lib/types/core/style-sheet-regular.d.ts +1 -3
- package/lib/types/core/style-sheet.d.ts +10 -2
- package/package.json +7 -8
- package/lib/types/core/style-sheet-atomic.d.ts +0 -10
- /package/lib/types/core/{style-sheet-atomic.test.d.ts → atomic.test.d.ts} +0 -0
package/lib/index.js
CHANGED
|
@@ -96,28 +96,150 @@ var toProperty = (property) => {
|
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
// src/core/rules.ts
|
|
99
|
+
var getDeclarationKey = (declaraionKey) => {
|
|
100
|
+
const { breakpoint, selector, property } = declaraionKey;
|
|
101
|
+
return `${breakpoint}:${selector}:${property}`;
|
|
102
|
+
};
|
|
103
|
+
var MixinRule = class {
|
|
104
|
+
// use map to avoid duplicated properties
|
|
105
|
+
#declarations = /* @__PURE__ */ new Map();
|
|
106
|
+
#dirtyBreakpoints = /* @__PURE__ */ new Set();
|
|
107
|
+
/*
|
|
108
|
+
* check if breakpoint was updated
|
|
109
|
+
*/
|
|
110
|
+
isDirtyBreakpoint(breakpoint) {
|
|
111
|
+
return this.#dirtyBreakpoints.has(breakpoint);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* reset breakpoints invalidation
|
|
115
|
+
*/
|
|
116
|
+
clearBreakpoints() {
|
|
117
|
+
this.#dirtyBreakpoints.clear();
|
|
118
|
+
}
|
|
119
|
+
setDeclaration(declaration) {
|
|
120
|
+
this.#declarations.set(getDeclarationKey(declaration), declaration);
|
|
121
|
+
this.#dirtyBreakpoints.add(declaration.breakpoint);
|
|
122
|
+
}
|
|
123
|
+
deleteDeclaration(declaration) {
|
|
124
|
+
this.#declarations.delete(getDeclarationKey(declaration));
|
|
125
|
+
this.#dirtyBreakpoints.add(declaration.breakpoint);
|
|
126
|
+
}
|
|
127
|
+
getDeclarations() {
|
|
128
|
+
return this.#declarations.values();
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
var NestingRule = class {
|
|
132
|
+
#selector;
|
|
133
|
+
#descendantSuffix;
|
|
134
|
+
#mixinRules = /* @__PURE__ */ new Map();
|
|
135
|
+
#mixins = /* @__PURE__ */ new Set();
|
|
136
|
+
// use map to avoid duplicated properties
|
|
137
|
+
#declarations = /* @__PURE__ */ new Map();
|
|
138
|
+
// cached generated rule by breakpoint
|
|
139
|
+
#cache = /* @__PURE__ */ new Map();
|
|
140
|
+
constructor(mixinRules, selector, descendantSuffix) {
|
|
141
|
+
this.#selector = selector;
|
|
142
|
+
this.#descendantSuffix = descendantSuffix;
|
|
143
|
+
this.#mixinRules = mixinRules;
|
|
144
|
+
}
|
|
145
|
+
getSelector() {
|
|
146
|
+
return this.#selector;
|
|
147
|
+
}
|
|
148
|
+
setSelector(selector) {
|
|
149
|
+
this.#selector = selector;
|
|
150
|
+
this.#cache.clear();
|
|
151
|
+
}
|
|
152
|
+
getDescendantSuffix() {
|
|
153
|
+
return this.#descendantSuffix;
|
|
154
|
+
}
|
|
155
|
+
addMixin(mixin) {
|
|
156
|
+
this.#mixins.add(mixin);
|
|
157
|
+
this.#cache.clear();
|
|
158
|
+
}
|
|
159
|
+
applyMixins(mixins) {
|
|
160
|
+
this.#mixins = new Set(mixins);
|
|
161
|
+
this.#cache.clear();
|
|
162
|
+
}
|
|
163
|
+
setDeclaration(declaration) {
|
|
164
|
+
this.#declarations.set(getDeclarationKey(declaration), declaration);
|
|
165
|
+
this.#cache.delete(declaration.breakpoint);
|
|
166
|
+
}
|
|
167
|
+
deleteDeclaration(declaration) {
|
|
168
|
+
this.#declarations.delete(getDeclarationKey(declaration));
|
|
169
|
+
this.#cache.delete(declaration.breakpoint);
|
|
170
|
+
}
|
|
171
|
+
getDeclarations() {
|
|
172
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
173
|
+
for (const mixin of this.#mixins) {
|
|
174
|
+
const rule = this.#mixinRules.get(mixin);
|
|
175
|
+
if (rule === void 0) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
for (const declaration of rule.getDeclarations()) {
|
|
179
|
+
declarations.set(getDeclarationKey(declaration), declaration);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
for (const declaration of this.#declarations.values()) {
|
|
183
|
+
declarations.set(getDeclarationKey(declaration), declaration);
|
|
184
|
+
}
|
|
185
|
+
return declarations.values();
|
|
186
|
+
}
|
|
187
|
+
toString({
|
|
188
|
+
breakpoint,
|
|
189
|
+
indent = 0,
|
|
190
|
+
transformValue
|
|
191
|
+
}) {
|
|
192
|
+
for (const mixin of this.#mixins) {
|
|
193
|
+
const rule = this.#mixinRules.get(mixin);
|
|
194
|
+
if (rule?.isDirtyBreakpoint(breakpoint)) {
|
|
195
|
+
this.#cache.delete(breakpoint);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const cached = this.#cache.get(breakpoint);
|
|
199
|
+
if (cached && cached.indent === indent && cached.transformValue === transformValue) {
|
|
200
|
+
return cached.generated;
|
|
201
|
+
}
|
|
202
|
+
const spaces = " ".repeat(indent);
|
|
203
|
+
const linesBySelector = /* @__PURE__ */ new Map();
|
|
204
|
+
for (const declaration of this.getDeclarations()) {
|
|
205
|
+
if (declaration.breakpoint !== breakpoint) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const { selector: nestedSelector, property, value } = declaration;
|
|
209
|
+
const selector = this.#selector + this.#descendantSuffix + nestedSelector;
|
|
210
|
+
const lines = linesBySelector.get(selector) ?? "";
|
|
211
|
+
const propertyString = toProperty(property);
|
|
212
|
+
const valueString = toValue(value, transformValue);
|
|
213
|
+
const line = `${spaces} ${propertyString}: ${valueString}`;
|
|
214
|
+
linesBySelector.set(selector, lines === "" ? line : `${lines};
|
|
215
|
+
${line}`);
|
|
216
|
+
}
|
|
217
|
+
const generated = Array.from(linesBySelector).sort(
|
|
218
|
+
([leftSelector], [rightSelector]) => leftSelector.localeCompare(rightSelector)
|
|
219
|
+
).map(
|
|
220
|
+
([selector, lines]) => `${spaces}${selector} {
|
|
221
|
+
${lines}
|
|
222
|
+
${spaces}}
|
|
223
|
+
`
|
|
224
|
+
).join("").trimEnd();
|
|
225
|
+
this.#cache.set(breakpoint, { generated, indent, transformValue });
|
|
226
|
+
return generated;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
99
229
|
var StylePropertyMap = class {
|
|
230
|
+
#cached;
|
|
100
231
|
#styleMap = /* @__PURE__ */ new Map();
|
|
101
|
-
#isDirty = true;
|
|
102
|
-
#string = "";
|
|
103
232
|
#indent = 0;
|
|
104
233
|
#transformValue;
|
|
105
|
-
|
|
106
|
-
constructor(style, transformValue, onChange) {
|
|
107
|
-
this.#transformValue = transformValue;
|
|
108
|
-
this.#onChange = onChange;
|
|
234
|
+
constructor(style) {
|
|
109
235
|
let property;
|
|
110
236
|
for (property in style) {
|
|
111
237
|
this.#styleMap.set(property, style[property]);
|
|
112
238
|
}
|
|
113
239
|
}
|
|
114
|
-
setTransformer(transformValue) {
|
|
115
|
-
this.#transformValue = transformValue;
|
|
116
|
-
}
|
|
117
240
|
set(property, value) {
|
|
118
241
|
this.#styleMap.set(property, value);
|
|
119
|
-
this.#
|
|
120
|
-
this.#onChange?.();
|
|
242
|
+
this.#cached = void 0;
|
|
121
243
|
}
|
|
122
244
|
get(property) {
|
|
123
245
|
return this.#styleMap.get(property);
|
|
@@ -133,19 +255,19 @@ var StylePropertyMap = class {
|
|
|
133
255
|
}
|
|
134
256
|
delete(property) {
|
|
135
257
|
this.#styleMap.delete(property);
|
|
136
|
-
this.#
|
|
137
|
-
this.#onChange?.();
|
|
258
|
+
this.#cached = void 0;
|
|
138
259
|
}
|
|
139
260
|
clear() {
|
|
140
261
|
this.#styleMap.clear();
|
|
141
|
-
this.#
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
262
|
+
this.#cached = void 0;
|
|
263
|
+
}
|
|
264
|
+
toString({
|
|
265
|
+
indent = 0,
|
|
266
|
+
transformValue
|
|
267
|
+
} = {}) {
|
|
268
|
+
if (this.#cached && indent === this.#indent && transformValue === this.#transformValue) {
|
|
269
|
+
return this.#cached;
|
|
147
270
|
}
|
|
148
|
-
this.#indent = indent;
|
|
149
271
|
const block = [];
|
|
150
272
|
const spaces = " ".repeat(indent);
|
|
151
273
|
for (const [property, value] of this.#styleMap) {
|
|
@@ -153,48 +275,53 @@ var StylePropertyMap = class {
|
|
|
153
275
|
continue;
|
|
154
276
|
}
|
|
155
277
|
block.push(
|
|
156
|
-
`${spaces}${toProperty(property)}: ${toValue(
|
|
157
|
-
value,
|
|
158
|
-
this.#transformValue
|
|
159
|
-
)}`
|
|
278
|
+
`${spaces}${toProperty(property)}: ${toValue(value, transformValue)}`
|
|
160
279
|
);
|
|
161
280
|
}
|
|
162
|
-
this.#
|
|
163
|
-
this.#
|
|
164
|
-
|
|
281
|
+
this.#cached = block.join(";\n");
|
|
282
|
+
this.#indent = indent;
|
|
283
|
+
this.#transformValue = transformValue;
|
|
284
|
+
return this.#cached;
|
|
165
285
|
}
|
|
166
286
|
};
|
|
167
287
|
var StyleRule = class {
|
|
168
288
|
styleMap;
|
|
169
289
|
selectorText;
|
|
170
|
-
constructor(selectorText, style
|
|
290
|
+
constructor(selectorText, style) {
|
|
171
291
|
this.selectorText = selectorText;
|
|
172
|
-
this.styleMap = style instanceof StylePropertyMap ? style : new StylePropertyMap(style
|
|
292
|
+
this.styleMap = style instanceof StylePropertyMap ? style : new StylePropertyMap(style);
|
|
173
293
|
}
|
|
174
294
|
get cssText() {
|
|
175
295
|
return this.toString();
|
|
176
296
|
}
|
|
177
|
-
toString(
|
|
178
|
-
|
|
297
|
+
toString({
|
|
298
|
+
indent = 0,
|
|
299
|
+
transformValue
|
|
300
|
+
} = {}) {
|
|
301
|
+
const spaces = " ".repeat(indent);
|
|
302
|
+
const content = this.styleMap.toString({
|
|
303
|
+
indent: indent + 2,
|
|
304
|
+
transformValue
|
|
305
|
+
});
|
|
179
306
|
return `${spaces}${this.selectorText} {
|
|
180
|
-
${
|
|
181
|
-
indent: options.indent + 2
|
|
182
|
-
})}
|
|
307
|
+
${content}
|
|
183
308
|
${spaces}}`;
|
|
184
309
|
}
|
|
185
310
|
};
|
|
186
311
|
var MediaRule = class {
|
|
312
|
+
#name;
|
|
187
313
|
options;
|
|
188
314
|
rules;
|
|
189
315
|
#mediaType;
|
|
190
|
-
constructor(options = {}) {
|
|
316
|
+
constructor(name, options = {}) {
|
|
317
|
+
this.#name = name;
|
|
191
318
|
this.options = options;
|
|
192
319
|
this.rules = /* @__PURE__ */ new Map();
|
|
193
320
|
this.#mediaType = options.mediaType ?? "all";
|
|
194
321
|
}
|
|
195
322
|
insertRule(rule) {
|
|
196
323
|
this.rules.set(
|
|
197
|
-
|
|
324
|
+
rule instanceof StyleRule ? rule.selectorText : rule.cssText,
|
|
198
325
|
rule
|
|
199
326
|
);
|
|
200
327
|
return rule;
|
|
@@ -203,12 +330,31 @@ var MediaRule = class {
|
|
|
203
330
|
return this.toString();
|
|
204
331
|
}
|
|
205
332
|
toString() {
|
|
206
|
-
|
|
333
|
+
return this.generateRule({ nestingRules: [] });
|
|
334
|
+
}
|
|
335
|
+
generateRule({
|
|
336
|
+
nestingRules,
|
|
337
|
+
transformValue
|
|
338
|
+
}) {
|
|
339
|
+
if (this.rules.size === 0 && nestingRules.length === 0) {
|
|
207
340
|
return "";
|
|
208
341
|
}
|
|
209
342
|
const rules = [];
|
|
210
343
|
for (const rule of this.rules.values()) {
|
|
211
|
-
rules.push(rule.toString({ indent: 2 }));
|
|
344
|
+
rules.push(rule.toString({ indent: 2, transformValue }));
|
|
345
|
+
}
|
|
346
|
+
for (const rule of nestingRules) {
|
|
347
|
+
const generatedRule = rule.toString({
|
|
348
|
+
breakpoint: this.#name,
|
|
349
|
+
indent: 2,
|
|
350
|
+
transformValue
|
|
351
|
+
});
|
|
352
|
+
if (generatedRule !== "") {
|
|
353
|
+
rules.push(generatedRule);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (rules.length === 0) {
|
|
357
|
+
return "";
|
|
212
358
|
}
|
|
213
359
|
let conditionText = "";
|
|
214
360
|
const { minWidth, maxWidth } = this.options;
|
|
@@ -227,26 +373,28 @@ ${rules.join(
|
|
|
227
373
|
};
|
|
228
374
|
var PlaintextRule = class {
|
|
229
375
|
cssText;
|
|
230
|
-
styleMap;
|
|
231
376
|
constructor(cssText) {
|
|
232
377
|
this.cssText = cssText;
|
|
233
|
-
this.styleMap = new StylePropertyMap({});
|
|
234
378
|
}
|
|
235
379
|
toString() {
|
|
236
380
|
return this.cssText;
|
|
237
381
|
}
|
|
238
382
|
};
|
|
239
383
|
var FontFaceRule = class {
|
|
240
|
-
|
|
384
|
+
#cached;
|
|
385
|
+
#options;
|
|
241
386
|
constructor(options) {
|
|
242
|
-
this
|
|
387
|
+
this.#options = options;
|
|
243
388
|
}
|
|
244
389
|
get cssText() {
|
|
245
390
|
return this.toString();
|
|
246
391
|
}
|
|
247
392
|
toString() {
|
|
393
|
+
if (this.#cached) {
|
|
394
|
+
return this.#cached;
|
|
395
|
+
}
|
|
248
396
|
const decls = [];
|
|
249
|
-
const { fontFamily, fontStyle, fontWeight, fontDisplay, src } = this
|
|
397
|
+
const { fontFamily, fontStyle, fontWeight, fontDisplay, src } = this.#options;
|
|
250
398
|
const value = toValue(
|
|
251
399
|
{ type: "fontFamily", value: [fontFamily] },
|
|
252
400
|
// Avoids adding a fallback automatically which needs to happen for font family in general but not for font face.
|
|
@@ -257,9 +405,10 @@ var FontFaceRule = class {
|
|
|
257
405
|
decls.push(`font-weight: ${fontWeight}`);
|
|
258
406
|
decls.push(`font-display: ${fontDisplay}`);
|
|
259
407
|
decls.push(`src: ${src}`);
|
|
260
|
-
|
|
408
|
+
this.#cached = `@font-face {
|
|
261
409
|
${decls.join("; ")};
|
|
262
410
|
}`;
|
|
411
|
+
return this.#cached;
|
|
263
412
|
}
|
|
264
413
|
};
|
|
265
414
|
|
|
@@ -325,23 +474,26 @@ var StyleSheet = class {
|
|
|
325
474
|
#cssText = "";
|
|
326
475
|
#mediaRules = /* @__PURE__ */ new Map();
|
|
327
476
|
#plainRules = /* @__PURE__ */ new Map();
|
|
477
|
+
#mixinRules = /* @__PURE__ */ new Map();
|
|
478
|
+
nestingRules = /* @__PURE__ */ new Map();
|
|
328
479
|
#fontFaceRules = [];
|
|
329
|
-
#
|
|
480
|
+
#transformValue;
|
|
330
481
|
#element;
|
|
331
482
|
constructor(element) {
|
|
332
483
|
this.#element = element;
|
|
333
484
|
}
|
|
485
|
+
setTransformer(transformValue) {
|
|
486
|
+
this.#transformValue = transformValue;
|
|
487
|
+
}
|
|
334
488
|
addMediaRule(id, options) {
|
|
335
489
|
let mediaRule = this.#mediaRules.get(id);
|
|
336
490
|
if (mediaRule === void 0) {
|
|
337
|
-
mediaRule = new MediaRule(options);
|
|
491
|
+
mediaRule = new MediaRule(id, options);
|
|
338
492
|
this.#mediaRules.set(id, mediaRule);
|
|
339
|
-
this.#isDirty = true;
|
|
340
493
|
return mediaRule;
|
|
341
494
|
}
|
|
342
495
|
if (options) {
|
|
343
496
|
mediaRule.options = options;
|
|
344
|
-
this.#isDirty = true;
|
|
345
497
|
}
|
|
346
498
|
if (mediaRule === void 0) {
|
|
347
499
|
throw new Error("No media rule found");
|
|
@@ -353,21 +505,32 @@ var StyleSheet = class {
|
|
|
353
505
|
if (rule !== void 0) {
|
|
354
506
|
return rule;
|
|
355
507
|
}
|
|
356
|
-
this.#isDirty = true;
|
|
357
508
|
return this.#plainRules.set(cssText, new PlaintextRule(cssText));
|
|
358
509
|
}
|
|
510
|
+
addMixinRule(name) {
|
|
511
|
+
let rule = this.#mixinRules.get(name);
|
|
512
|
+
if (rule === void 0) {
|
|
513
|
+
rule = new MixinRule();
|
|
514
|
+
this.#mixinRules.set(name, rule);
|
|
515
|
+
}
|
|
516
|
+
return rule;
|
|
517
|
+
}
|
|
518
|
+
addNestingRule(selector, descendantSuffix = "") {
|
|
519
|
+
const key = selector + descendantSuffix;
|
|
520
|
+
let rule = this.nestingRules.get(key);
|
|
521
|
+
if (rule === void 0) {
|
|
522
|
+
rule = new NestingRule(this.#mixinRules, selector, descendantSuffix);
|
|
523
|
+
this.nestingRules.set(key, rule);
|
|
524
|
+
}
|
|
525
|
+
return rule;
|
|
526
|
+
}
|
|
359
527
|
addFontFaceRule(options) {
|
|
360
|
-
this.#isDirty = true;
|
|
361
528
|
return this.#fontFaceRules.push(new FontFaceRule(options));
|
|
362
529
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (this.#isDirty === false) {
|
|
368
|
-
return this.#cssText;
|
|
369
|
-
}
|
|
370
|
-
this.#isDirty = false;
|
|
530
|
+
generateWith({
|
|
531
|
+
nestingRules,
|
|
532
|
+
transformValue
|
|
533
|
+
}) {
|
|
371
534
|
const css = [];
|
|
372
535
|
css.push(...this.#fontFaceRules.map((rule) => rule.cssText));
|
|
373
536
|
for (const plaintextRule of this.#plainRules.values()) {
|
|
@@ -377,19 +540,32 @@ var StyleSheet = class {
|
|
|
377
540
|
(ruleA, ruleB) => compareMedia(ruleA.options, ruleB.options)
|
|
378
541
|
);
|
|
379
542
|
for (const mediaRule of sortedMediaRules) {
|
|
380
|
-
const
|
|
543
|
+
const cssText = mediaRule.generateRule({
|
|
544
|
+
nestingRules,
|
|
545
|
+
transformValue
|
|
546
|
+
});
|
|
381
547
|
if (cssText !== "") {
|
|
382
548
|
css.push(cssText);
|
|
383
549
|
}
|
|
384
550
|
}
|
|
551
|
+
for (const rule of this.#mixinRules.values()) {
|
|
552
|
+
rule.clearBreakpoints();
|
|
553
|
+
}
|
|
385
554
|
this.#cssText = css.join("\n");
|
|
386
555
|
return this.#cssText;
|
|
387
556
|
}
|
|
557
|
+
get cssText() {
|
|
558
|
+
return this.generateWith({
|
|
559
|
+
nestingRules: Array.from(this.nestingRules.values()),
|
|
560
|
+
transformValue: this.#transformValue
|
|
561
|
+
});
|
|
562
|
+
}
|
|
388
563
|
clear() {
|
|
389
564
|
this.#mediaRules.clear();
|
|
565
|
+
this.#mixinRules.clear();
|
|
566
|
+
this.nestingRules.clear();
|
|
390
567
|
this.#plainRules.clear();
|
|
391
568
|
this.#fontFaceRules = [];
|
|
392
|
-
this.#isDirty = true;
|
|
393
569
|
}
|
|
394
570
|
render() {
|
|
395
571
|
this.#element.mount();
|
|
@@ -409,58 +585,12 @@ var StyleSheet = class {
|
|
|
409
585
|
// src/core/style-sheet-regular.ts
|
|
410
586
|
var defaultMediaRuleId = "__default-media-rule__";
|
|
411
587
|
var StyleSheetRegular = class extends StyleSheet {
|
|
412
|
-
addStyleRule(rule, selectorText
|
|
588
|
+
addStyleRule(rule, selectorText) {
|
|
413
589
|
const mediaRule = this.addMediaRule(rule.breakpoint || defaultMediaRuleId);
|
|
414
|
-
|
|
415
|
-
const styleRule = new StyleRule(
|
|
416
|
-
selectorText,
|
|
417
|
-
rule.style,
|
|
418
|
-
transformValue,
|
|
419
|
-
this.#onChangeRule
|
|
420
|
-
);
|
|
590
|
+
const styleRule = new StyleRule(selectorText, rule.style);
|
|
421
591
|
mediaRule.insertRule(styleRule);
|
|
422
592
|
return styleRule;
|
|
423
593
|
}
|
|
424
|
-
#onChangeRule = () => {
|
|
425
|
-
this.markAsDirty();
|
|
426
|
-
};
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
// src/core/style-sheet-atomic.ts
|
|
430
|
-
import hash from "@emotion/hash";
|
|
431
|
-
var defaultMediaRuleId2 = "__default-media-rule__";
|
|
432
|
-
var StyleSheetAtomic = class extends StyleSheet {
|
|
433
|
-
addStyleRule({ style, breakpoint }, selectorSuffix = "", transformValue) {
|
|
434
|
-
const mediaRule = this.addMediaRule(breakpoint || defaultMediaRuleId2);
|
|
435
|
-
const styleRules = [];
|
|
436
|
-
const classes = [];
|
|
437
|
-
let property;
|
|
438
|
-
for (property in style) {
|
|
439
|
-
const stylePropertyMap = new StylePropertyMap(
|
|
440
|
-
{ [property]: style[property] },
|
|
441
|
-
transformValue
|
|
442
|
-
);
|
|
443
|
-
const className = `c${hash(
|
|
444
|
-
stylePropertyMap + selectorSuffix + breakpoint
|
|
445
|
-
)}`;
|
|
446
|
-
classes.push(className);
|
|
447
|
-
const newStyleRule = new StyleRule(
|
|
448
|
-
`.${className}${selectorSuffix}`,
|
|
449
|
-
stylePropertyMap,
|
|
450
|
-
transformValue,
|
|
451
|
-
this.#onChangeRule
|
|
452
|
-
);
|
|
453
|
-
styleRules.push(newStyleRule);
|
|
454
|
-
if (mediaRule.rules.has(newStyleRule.selectorText) === false) {
|
|
455
|
-
mediaRule.insertRule(newStyleRule);
|
|
456
|
-
this.markAsDirty();
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
return { styleRules, classes };
|
|
460
|
-
}
|
|
461
|
-
#onChangeRule = () => {
|
|
462
|
-
this.markAsDirty();
|
|
463
|
-
};
|
|
464
594
|
};
|
|
465
595
|
|
|
466
596
|
// src/core/create-style-sheet.ts
|
|
@@ -468,10 +598,6 @@ var createRegularStyleSheet = (options) => {
|
|
|
468
598
|
const element = new StyleElement(options?.name);
|
|
469
599
|
return new StyleSheetRegular(element);
|
|
470
600
|
};
|
|
471
|
-
var createAtomicStyleSheet = (options) => {
|
|
472
|
-
const element = new StyleElement(options?.name);
|
|
473
|
-
return new StyleSheetAtomic(element);
|
|
474
|
-
};
|
|
475
601
|
|
|
476
602
|
// src/core/match-media.ts
|
|
477
603
|
var matchMedia = (options, width) => {
|
|
@@ -495,6 +621,45 @@ var findApplicableMedia = (media, width) => {
|
|
|
495
621
|
}
|
|
496
622
|
};
|
|
497
623
|
|
|
624
|
+
// src/core/atomic.ts
|
|
625
|
+
import hash from "@emotion/hash";
|
|
626
|
+
var generateAtomic = (sheet, options) => {
|
|
627
|
+
const { getKey, transformValue } = options;
|
|
628
|
+
const atomicRules = /* @__PURE__ */ new Map();
|
|
629
|
+
const classesMap = /* @__PURE__ */ new Map();
|
|
630
|
+
for (const rule of sheet.nestingRules.values()) {
|
|
631
|
+
const descendantSuffix = rule.getDescendantSuffix();
|
|
632
|
+
const groupKey = getKey(rule);
|
|
633
|
+
let classList = classesMap.get(groupKey);
|
|
634
|
+
if (classList === void 0) {
|
|
635
|
+
classList = [];
|
|
636
|
+
classesMap.set(groupKey, classList);
|
|
637
|
+
}
|
|
638
|
+
for (const declaration of rule.getDeclarations()) {
|
|
639
|
+
const atomicHash = hash(
|
|
640
|
+
descendantSuffix + declaration.breakpoint + declaration.selector + declaration.property + toValue(declaration.value, transformValue)
|
|
641
|
+
);
|
|
642
|
+
const className = `c${atomicHash}`;
|
|
643
|
+
let atomicRule = atomicRules.get(atomicHash);
|
|
644
|
+
if (atomicRule === void 0) {
|
|
645
|
+
atomicRule = new NestingRule(
|
|
646
|
+
/* @__PURE__ */ new Map(),
|
|
647
|
+
`.${className}`,
|
|
648
|
+
descendantSuffix
|
|
649
|
+
);
|
|
650
|
+
atomicRule.setDeclaration(declaration);
|
|
651
|
+
atomicRules.set(atomicHash, atomicRule);
|
|
652
|
+
}
|
|
653
|
+
classList.push(className);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
const cssText = sheet.generateWith({
|
|
657
|
+
nestingRules: Array.from(atomicRules.values()),
|
|
658
|
+
transformValue
|
|
659
|
+
});
|
|
660
|
+
return { cssText, classesMap };
|
|
661
|
+
};
|
|
662
|
+
|
|
498
663
|
// src/schema.ts
|
|
499
664
|
import { z } from "zod";
|
|
500
665
|
var Unit = z.string();
|
|
@@ -618,10 +783,10 @@ export {
|
|
|
618
783
|
UnitValue,
|
|
619
784
|
UnparsedValue,
|
|
620
785
|
compareMedia,
|
|
621
|
-
createAtomicStyleSheet,
|
|
622
786
|
createRegularStyleSheet,
|
|
623
787
|
equalMedia,
|
|
624
788
|
findApplicableMedia,
|
|
789
|
+
generateAtomic,
|
|
625
790
|
isValidStaticStyleValue,
|
|
626
791
|
matchMedia,
|
|
627
792
|
toProperty,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StyleSheet } from "./style-sheet";
|
|
2
|
+
import { NestingRule } from "./rules";
|
|
3
|
+
import { type TransformValue } from "./to-value";
|
|
4
|
+
type Options = {
|
|
5
|
+
getKey: (rule: NestingRule) => string;
|
|
6
|
+
transformValue?: TransformValue;
|
|
7
|
+
};
|
|
8
|
+
export declare const generateAtomic: (sheet: StyleSheet, options: Options) => {
|
|
9
|
+
cssText: string;
|
|
10
|
+
classesMap: Map<string, string[]>;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { StyleSheetRegular } from "./style-sheet-regular";
|
|
2
|
-
import { StyleSheetAtomic } from "./style-sheet-atomic";
|
|
3
2
|
export declare const createRegularStyleSheet: (options?: {
|
|
4
3
|
name?: string;
|
|
5
4
|
}) => StyleSheetRegular;
|
|
6
|
-
export declare const createAtomicStyleSheet: (options?: {
|
|
7
|
-
name?: string;
|
|
8
|
-
}) => StyleSheetAtomic;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type { NestingRule, StyleRule, MediaRule, PlaintextRule, FontFaceRule, } from "./rules";
|
|
2
2
|
export type { StyleSheetRegular } from "./style-sheet-regular";
|
|
3
|
-
export type { StyleSheetAtomic } from "./style-sheet-atomic";
|
|
4
3
|
export * from "./create-style-sheet";
|
|
5
4
|
export * from "./to-value";
|
|
6
5
|
export * from "./to-property";
|
|
@@ -8,3 +7,4 @@ export * from "./match-media";
|
|
|
8
7
|
export * from "./equal-media";
|
|
9
8
|
export * from "./compare-media";
|
|
10
9
|
export * from "./find-applicable-media";
|
|
10
|
+
export * from "./atomic";
|
|
@@ -1,9 +1,67 @@
|
|
|
1
1
|
import type { Style, StyleProperty, StyleValue } from "../schema";
|
|
2
2
|
import { type TransformValue } from "./to-value";
|
|
3
|
+
type Declaration = {
|
|
4
|
+
breakpoint: string;
|
|
5
|
+
selector: string;
|
|
6
|
+
property: StyleProperty;
|
|
7
|
+
value: StyleValue;
|
|
8
|
+
};
|
|
9
|
+
type DeclarationKey = Omit<Declaration, "value">;
|
|
10
|
+
/**
|
|
11
|
+
* Reusable style rule in any nesting rule
|
|
12
|
+
*
|
|
13
|
+
* @mixin name {
|
|
14
|
+
* \@media breakpoint {
|
|
15
|
+
* &selector {
|
|
16
|
+
* property: value
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*/
|
|
21
|
+
export declare class MixinRule {
|
|
22
|
+
#private;
|
|
23
|
+
isDirtyBreakpoint(breakpoint: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* reset breakpoints invalidation
|
|
26
|
+
*/
|
|
27
|
+
clearBreakpoints(): void;
|
|
28
|
+
setDeclaration(declaration: Declaration): void;
|
|
29
|
+
deleteDeclaration(declaration: DeclarationKey): void;
|
|
30
|
+
getDeclarations(): IterableIterator<Declaration>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Universal style rule with nested selectors and media queries support
|
|
34
|
+
* Rules are generated by each media query
|
|
35
|
+
* and heavily cached to avoid complex computation
|
|
36
|
+
*
|
|
37
|
+
* selector {
|
|
38
|
+
* \@media breakpoint {
|
|
39
|
+
* &selector {
|
|
40
|
+
* property: value
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
*/
|
|
45
|
+
export declare class NestingRule {
|
|
46
|
+
#private;
|
|
47
|
+
constructor(mixinRules: Map<string, MixinRule>, selector: string, descendantSuffix: string);
|
|
48
|
+
getSelector(): string;
|
|
49
|
+
setSelector(selector: string): void;
|
|
50
|
+
getDescendantSuffix(): string;
|
|
51
|
+
addMixin(mixin: string): void;
|
|
52
|
+
applyMixins(mixins: string[]): void;
|
|
53
|
+
setDeclaration(declaration: Declaration): void;
|
|
54
|
+
deleteDeclaration(declaration: DeclarationKey): void;
|
|
55
|
+
getDeclarations(): IterableIterator<Declaration>;
|
|
56
|
+
toString({ breakpoint, indent, transformValue, }: {
|
|
57
|
+
breakpoint: string;
|
|
58
|
+
indent?: number;
|
|
59
|
+
transformValue?: TransformValue;
|
|
60
|
+
}): string;
|
|
61
|
+
}
|
|
3
62
|
export declare class StylePropertyMap {
|
|
4
63
|
#private;
|
|
5
|
-
constructor(style: Style
|
|
6
|
-
setTransformer(transformValue: TransformValue): void;
|
|
64
|
+
constructor(style: Style);
|
|
7
65
|
set(property: StyleProperty, value?: StyleValue): void;
|
|
8
66
|
get(property: StyleProperty): {
|
|
9
67
|
type: "unit";
|
|
@@ -1024,17 +1082,19 @@ export declare class StylePropertyMap {
|
|
|
1024
1082
|
keys(): IterableIterator<StyleProperty>;
|
|
1025
1083
|
delete(property: StyleProperty): void;
|
|
1026
1084
|
clear(): void;
|
|
1027
|
-
toString({ indent }?: {
|
|
1028
|
-
indent?: number
|
|
1085
|
+
toString({ indent, transformValue, }?: {
|
|
1086
|
+
indent?: number;
|
|
1087
|
+
transformValue?: TransformValue;
|
|
1029
1088
|
}): string;
|
|
1030
1089
|
}
|
|
1031
1090
|
export declare class StyleRule {
|
|
1032
1091
|
styleMap: StylePropertyMap;
|
|
1033
1092
|
selectorText: string;
|
|
1034
|
-
constructor(selectorText: string, style: StylePropertyMap | Style
|
|
1093
|
+
constructor(selectorText: string, style: StylePropertyMap | Style);
|
|
1035
1094
|
get cssText(): string;
|
|
1036
|
-
toString(
|
|
1037
|
-
indent
|
|
1095
|
+
toString({ indent, transformValue, }?: {
|
|
1096
|
+
indent?: number;
|
|
1097
|
+
transformValue?: TransformValue;
|
|
1038
1098
|
}): string;
|
|
1039
1099
|
}
|
|
1040
1100
|
export type MediaRuleOptions = {
|
|
@@ -1046,14 +1106,17 @@ export declare class MediaRule {
|
|
|
1046
1106
|
#private;
|
|
1047
1107
|
options: MediaRuleOptions;
|
|
1048
1108
|
rules: Map<string, StyleRule | PlaintextRule>;
|
|
1049
|
-
constructor(options?: MediaRuleOptions);
|
|
1109
|
+
constructor(name: string, options?: MediaRuleOptions);
|
|
1050
1110
|
insertRule(rule: StyleRule | PlaintextRule): StyleRule | PlaintextRule;
|
|
1051
1111
|
get cssText(): string;
|
|
1052
1112
|
toString(): string;
|
|
1113
|
+
generateRule({ nestingRules, transformValue, }: {
|
|
1114
|
+
nestingRules: NestingRule[];
|
|
1115
|
+
transformValue?: TransformValue;
|
|
1116
|
+
}): string;
|
|
1053
1117
|
}
|
|
1054
1118
|
export declare class PlaintextRule {
|
|
1055
1119
|
cssText: string;
|
|
1056
|
-
styleMap: StylePropertyMap;
|
|
1057
1120
|
constructor(cssText: string);
|
|
1058
1121
|
toString(): string;
|
|
1059
1122
|
}
|
|
@@ -1065,9 +1128,9 @@ export type FontFaceOptions = {
|
|
|
1065
1128
|
src: string;
|
|
1066
1129
|
};
|
|
1067
1130
|
export declare class FontFaceRule {
|
|
1068
|
-
|
|
1131
|
+
#private;
|
|
1069
1132
|
constructor(options: FontFaceOptions);
|
|
1070
1133
|
get cssText(): string;
|
|
1071
1134
|
toString(): string;
|
|
1072
1135
|
}
|
|
1073
|
-
export
|
|
1136
|
+
export {};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { StyleRule } from "./rules";
|
|
2
|
-
import type { TransformValue } from "./to-value";
|
|
3
2
|
import { StyleSheet, type CssRule } from "./style-sheet";
|
|
4
3
|
export declare class StyleSheetRegular extends StyleSheet {
|
|
5
|
-
|
|
6
|
-
addStyleRule(rule: CssRule, selectorText: string, transformValue?: TransformValue): StyleRule;
|
|
4
|
+
addStyleRule(rule: CssRule, selectorText: string): StyleRule;
|
|
7
5
|
}
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import type { Style } from "../schema";
|
|
2
|
-
import { MediaRule, PlaintextRule, type FontFaceOptions, type MediaRuleOptions } from "./rules";
|
|
2
|
+
import { MediaRule, MixinRule, NestingRule, PlaintextRule, type FontFaceOptions, type MediaRuleOptions } from "./rules";
|
|
3
3
|
import { StyleElement } from "./style-element";
|
|
4
|
+
import type { TransformValue } from "./to-value";
|
|
4
5
|
export type CssRule = {
|
|
5
6
|
style: Style;
|
|
6
7
|
breakpoint?: string;
|
|
7
8
|
};
|
|
8
9
|
export declare class StyleSheet {
|
|
9
10
|
#private;
|
|
11
|
+
nestingRules: Map<string, NestingRule>;
|
|
10
12
|
constructor(element: StyleElement);
|
|
13
|
+
setTransformer(transformValue: TransformValue): void;
|
|
11
14
|
addMediaRule(id: string, options?: MediaRuleOptions): MediaRule;
|
|
12
15
|
addPlaintextRule(cssText: string): PlaintextRule | Map<string, PlaintextRule>;
|
|
16
|
+
addMixinRule(name: string): MixinRule;
|
|
17
|
+
addNestingRule(selector: string, descendantSuffix?: string): NestingRule;
|
|
13
18
|
addFontFaceRule(options: FontFaceOptions): number;
|
|
14
|
-
|
|
19
|
+
generateWith({ nestingRules, transformValue, }: {
|
|
20
|
+
nestingRules: NestingRule[];
|
|
21
|
+
transformValue?: TransformValue;
|
|
22
|
+
}): string;
|
|
15
23
|
get cssText(): string;
|
|
16
24
|
clear(): void;
|
|
17
25
|
render(): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webstudio-is/css-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.163.0",
|
|
4
4
|
"description": "CSS Renderer for Webstudio",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
"@emotion/hash": "^0.9.1",
|
|
10
10
|
"hyphenate-style-name": "^1.0.4",
|
|
11
11
|
"zod": "^3.22.4",
|
|
12
|
-
"@webstudio-is/fonts": "0.
|
|
13
|
-
"@webstudio-is/error-utils": "0.
|
|
12
|
+
"@webstudio-is/fonts": "0.163.0",
|
|
13
|
+
"@webstudio-is/error-utils": "0.163.0"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@jest/globals": "^29.7.0",
|
|
17
|
-
"@storybook/addon-essentials": "^
|
|
18
|
-
"@storybook/addon-links": "^
|
|
19
|
-
"@storybook/react": "^
|
|
17
|
+
"@storybook/addon-essentials": "^8.1.2",
|
|
18
|
+
"@storybook/addon-links": "^8.1.2",
|
|
19
|
+
"@storybook/react": "^8.1.2",
|
|
20
20
|
"@types/hyphenate-style-name": "^1.0.0",
|
|
21
21
|
"@types/react": "^18.2.70",
|
|
22
22
|
"@types/react-dom": "^18.2.25",
|
|
@@ -30,8 +30,7 @@
|
|
|
30
30
|
"exports": {
|
|
31
31
|
"webstudio": "./src/index.ts",
|
|
32
32
|
"types": "./lib/types/index.d.ts",
|
|
33
|
-
"import": "./lib/index.js"
|
|
34
|
-
"require": "./lib/index.js"
|
|
33
|
+
"import": "./lib/index.js"
|
|
35
34
|
},
|
|
36
35
|
"files": [
|
|
37
36
|
"lib/*",
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { StyleRule } from "./rules";
|
|
2
|
-
import type { TransformValue } from "./to-value";
|
|
3
|
-
import { StyleSheet, type CssRule } from "./style-sheet";
|
|
4
|
-
export declare class StyleSheetAtomic extends StyleSheet {
|
|
5
|
-
#private;
|
|
6
|
-
addStyleRule({ style, breakpoint }: CssRule, selectorSuffix?: string, transformValue?: TransformValue): {
|
|
7
|
-
styleRules: StyleRule[];
|
|
8
|
-
classes: string[];
|
|
9
|
-
};
|
|
10
|
-
}
|
|
File without changes
|