@webstudio-is/css-engine 0.145.0 → 0.151.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 CHANGED
@@ -96,28 +96,141 @@ 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
+ #mixinRules = /* @__PURE__ */ new Map();
134
+ #mixins = /* @__PURE__ */ new Set();
135
+ // use map to avoid duplicated properties
136
+ #declarations = /* @__PURE__ */ new Map();
137
+ // cached generated rule by breakpoint
138
+ #cache = /* @__PURE__ */ new Map();
139
+ constructor(selector, mixinRules) {
140
+ this.#selector = selector;
141
+ this.#mixinRules = mixinRules;
142
+ }
143
+ getSelector() {
144
+ return this.#selector;
145
+ }
146
+ addMixin(mixin) {
147
+ this.#mixins.add(mixin);
148
+ this.#cache.clear();
149
+ }
150
+ applyMixins(mixins) {
151
+ this.#mixins = new Set(mixins);
152
+ this.#cache.clear();
153
+ }
154
+ setDeclaration(declaration) {
155
+ this.#declarations.set(getDeclarationKey(declaration), declaration);
156
+ this.#cache.delete(declaration.breakpoint);
157
+ }
158
+ deleteDeclaration(declaration) {
159
+ this.#declarations.delete(getDeclarationKey(declaration));
160
+ this.#cache.delete(declaration.breakpoint);
161
+ }
162
+ getDeclarations() {
163
+ const declarations = /* @__PURE__ */ new Map();
164
+ for (const mixin of this.#mixins) {
165
+ const rule = this.#mixinRules.get(mixin);
166
+ if (rule === void 0) {
167
+ continue;
168
+ }
169
+ for (const declaration of rule.getDeclarations()) {
170
+ declarations.set(getDeclarationKey(declaration), declaration);
171
+ }
172
+ }
173
+ for (const declaration of this.#declarations.values()) {
174
+ declarations.set(getDeclarationKey(declaration), declaration);
175
+ }
176
+ return declarations.values();
177
+ }
178
+ toString({
179
+ breakpoint,
180
+ indent = 0,
181
+ transformValue
182
+ }) {
183
+ for (const mixin of this.#mixins) {
184
+ const rule = this.#mixinRules.get(mixin);
185
+ if (rule?.isDirtyBreakpoint(breakpoint)) {
186
+ this.#cache.delete(breakpoint);
187
+ }
188
+ }
189
+ const cached = this.#cache.get(breakpoint);
190
+ if (cached && cached.indent === indent && cached.transformValue === transformValue) {
191
+ return cached.generated;
192
+ }
193
+ const spaces = " ".repeat(indent);
194
+ const linesBySelector = /* @__PURE__ */ new Map();
195
+ for (const declaration of this.getDeclarations()) {
196
+ if (declaration.breakpoint !== breakpoint) {
197
+ continue;
198
+ }
199
+ const { selector: nestedSelector, property, value } = declaration;
200
+ const selector = `${this.#selector}${nestedSelector}`;
201
+ const lines = linesBySelector.get(selector) ?? "";
202
+ const propertyString = toProperty(property);
203
+ const valueString = toValue(value, transformValue);
204
+ const line = `${spaces} ${propertyString}: ${valueString}`;
205
+ linesBySelector.set(selector, lines === "" ? line : `${lines};
206
+ ${line}`);
207
+ }
208
+ const generated = Array.from(linesBySelector).sort(
209
+ ([leftSelector], [rightSelector]) => leftSelector.localeCompare(rightSelector)
210
+ ).map(
211
+ ([selector, lines]) => `${spaces}${selector} {
212
+ ${lines}
213
+ ${spaces}}
214
+ `
215
+ ).join("").trimEnd();
216
+ this.#cache.set(breakpoint, { generated, indent, transformValue });
217
+ return generated;
218
+ }
219
+ };
99
220
  var StylePropertyMap = class {
221
+ #cached;
100
222
  #styleMap = /* @__PURE__ */ new Map();
101
- #isDirty = true;
102
- #string = "";
103
223
  #indent = 0;
104
224
  #transformValue;
105
- #onChange;
106
- constructor(style, transformValue, onChange) {
107
- this.#transformValue = transformValue;
108
- this.#onChange = onChange;
225
+ constructor(style) {
109
226
  let property;
110
227
  for (property in style) {
111
228
  this.#styleMap.set(property, style[property]);
112
229
  }
113
230
  }
114
- setTransformer(transformValue) {
115
- this.#transformValue = transformValue;
116
- }
117
231
  set(property, value) {
118
232
  this.#styleMap.set(property, value);
119
- this.#isDirty = true;
120
- this.#onChange?.();
233
+ this.#cached = void 0;
121
234
  }
122
235
  get(property) {
123
236
  return this.#styleMap.get(property);
@@ -133,19 +246,19 @@ var StylePropertyMap = class {
133
246
  }
134
247
  delete(property) {
135
248
  this.#styleMap.delete(property);
136
- this.#isDirty = true;
137
- this.#onChange?.();
249
+ this.#cached = void 0;
138
250
  }
139
251
  clear() {
140
252
  this.#styleMap.clear();
141
- this.#isDirty = true;
142
- this.#onChange?.();
143
- }
144
- toString({ indent = 0 } = {}) {
145
- if (this.#isDirty === false && indent === this.#indent) {
146
- return this.#string;
253
+ this.#cached = void 0;
254
+ }
255
+ toString({
256
+ indent = 0,
257
+ transformValue
258
+ } = {}) {
259
+ if (this.#cached && indent === this.#indent && transformValue === this.#transformValue) {
260
+ return this.#cached;
147
261
  }
148
- this.#indent = indent;
149
262
  const block = [];
150
263
  const spaces = " ".repeat(indent);
151
264
  for (const [property, value] of this.#styleMap) {
@@ -153,48 +266,53 @@ var StylePropertyMap = class {
153
266
  continue;
154
267
  }
155
268
  block.push(
156
- `${spaces}${toProperty(property)}: ${toValue(
157
- value,
158
- this.#transformValue
159
- )}`
269
+ `${spaces}${toProperty(property)}: ${toValue(value, transformValue)}`
160
270
  );
161
271
  }
162
- this.#string = block.join(";\n");
163
- this.#isDirty = false;
164
- return this.#string;
272
+ this.#cached = block.join(";\n");
273
+ this.#indent = indent;
274
+ this.#transformValue = transformValue;
275
+ return this.#cached;
165
276
  }
166
277
  };
167
278
  var StyleRule = class {
168
279
  styleMap;
169
280
  selectorText;
170
- constructor(selectorText, style, transformValue, onChange) {
281
+ constructor(selectorText, style) {
171
282
  this.selectorText = selectorText;
172
- this.styleMap = style instanceof StylePropertyMap ? style : new StylePropertyMap(style, transformValue, onChange);
283
+ this.styleMap = style instanceof StylePropertyMap ? style : new StylePropertyMap(style);
173
284
  }
174
285
  get cssText() {
175
286
  return this.toString();
176
287
  }
177
- toString(options = { indent: 0 }) {
178
- const spaces = " ".repeat(options.indent);
288
+ toString({
289
+ indent = 0,
290
+ transformValue
291
+ } = {}) {
292
+ const spaces = " ".repeat(indent);
293
+ const content = this.styleMap.toString({
294
+ indent: indent + 2,
295
+ transformValue
296
+ });
179
297
  return `${spaces}${this.selectorText} {
180
- ${this.styleMap.toString({
181
- indent: options.indent + 2
182
- })}
298
+ ${content}
183
299
  ${spaces}}`;
184
300
  }
185
301
  };
186
302
  var MediaRule = class {
303
+ #name;
187
304
  options;
188
305
  rules;
189
306
  #mediaType;
190
- constructor(options = {}) {
307
+ constructor(name, options = {}) {
308
+ this.#name = name;
191
309
  this.options = options;
192
310
  this.rules = /* @__PURE__ */ new Map();
193
311
  this.#mediaType = options.mediaType ?? "all";
194
312
  }
195
313
  insertRule(rule) {
196
314
  this.rules.set(
197
- "selectorText" in rule ? rule.selectorText : rule.cssText,
315
+ rule instanceof StyleRule ? rule.selectorText : rule.cssText,
198
316
  rule
199
317
  );
200
318
  return rule;
@@ -203,12 +321,31 @@ var MediaRule = class {
203
321
  return this.toString();
204
322
  }
205
323
  toString() {
206
- if (this.rules.size === 0) {
324
+ return this.generateRule({ nestingRules: [] });
325
+ }
326
+ generateRule({
327
+ nestingRules,
328
+ transformValue
329
+ }) {
330
+ if (this.rules.size === 0 && nestingRules.length === 0) {
207
331
  return "";
208
332
  }
209
333
  const rules = [];
210
334
  for (const rule of this.rules.values()) {
211
- rules.push(rule.toString({ indent: 2 }));
335
+ rules.push(rule.toString({ indent: 2, transformValue }));
336
+ }
337
+ for (const rule of nestingRules) {
338
+ const generatedRule = rule.toString({
339
+ breakpoint: this.#name,
340
+ indent: 2,
341
+ transformValue
342
+ });
343
+ if (generatedRule !== "") {
344
+ rules.push(generatedRule);
345
+ }
346
+ }
347
+ if (rules.length === 0) {
348
+ return "";
212
349
  }
213
350
  let conditionText = "";
214
351
  const { minWidth, maxWidth } = this.options;
@@ -227,26 +364,28 @@ ${rules.join(
227
364
  };
228
365
  var PlaintextRule = class {
229
366
  cssText;
230
- styleMap;
231
367
  constructor(cssText) {
232
368
  this.cssText = cssText;
233
- this.styleMap = new StylePropertyMap({});
234
369
  }
235
370
  toString() {
236
371
  return this.cssText;
237
372
  }
238
373
  };
239
374
  var FontFaceRule = class {
240
- options;
375
+ #cached;
376
+ #options;
241
377
  constructor(options) {
242
- this.options = options;
378
+ this.#options = options;
243
379
  }
244
380
  get cssText() {
245
381
  return this.toString();
246
382
  }
247
383
  toString() {
384
+ if (this.#cached) {
385
+ return this.#cached;
386
+ }
248
387
  const decls = [];
249
- const { fontFamily, fontStyle, fontWeight, fontDisplay, src } = this.options;
388
+ const { fontFamily, fontStyle, fontWeight, fontDisplay, src } = this.#options;
250
389
  const value = toValue(
251
390
  { type: "fontFamily", value: [fontFamily] },
252
391
  // Avoids adding a fallback automatically which needs to happen for font family in general but not for font face.
@@ -257,9 +396,10 @@ var FontFaceRule = class {
257
396
  decls.push(`font-weight: ${fontWeight}`);
258
397
  decls.push(`font-display: ${fontDisplay}`);
259
398
  decls.push(`src: ${src}`);
260
- return `@font-face {
399
+ this.#cached = `@font-face {
261
400
  ${decls.join("; ")};
262
401
  }`;
402
+ return this.#cached;
263
403
  }
264
404
  };
265
405
 
@@ -325,23 +465,26 @@ var StyleSheet = class {
325
465
  #cssText = "";
326
466
  #mediaRules = /* @__PURE__ */ new Map();
327
467
  #plainRules = /* @__PURE__ */ new Map();
468
+ #mixinRules = /* @__PURE__ */ new Map();
469
+ nestingRules = /* @__PURE__ */ new Map();
328
470
  #fontFaceRules = [];
329
- #isDirty = false;
471
+ #transformValue;
330
472
  #element;
331
473
  constructor(element) {
332
474
  this.#element = element;
333
475
  }
476
+ setTransformer(transformValue) {
477
+ this.#transformValue = transformValue;
478
+ }
334
479
  addMediaRule(id, options) {
335
480
  let mediaRule = this.#mediaRules.get(id);
336
481
  if (mediaRule === void 0) {
337
- mediaRule = new MediaRule(options);
482
+ mediaRule = new MediaRule(id, options);
338
483
  this.#mediaRules.set(id, mediaRule);
339
- this.#isDirty = true;
340
484
  return mediaRule;
341
485
  }
342
486
  if (options) {
343
487
  mediaRule.options = options;
344
- this.#isDirty = true;
345
488
  }
346
489
  if (mediaRule === void 0) {
347
490
  throw new Error("No media rule found");
@@ -353,21 +496,31 @@ var StyleSheet = class {
353
496
  if (rule !== void 0) {
354
497
  return rule;
355
498
  }
356
- this.#isDirty = true;
357
499
  return this.#plainRules.set(cssText, new PlaintextRule(cssText));
358
500
  }
501
+ addMixinRule(name) {
502
+ let rule = this.#mixinRules.get(name);
503
+ if (rule === void 0) {
504
+ rule = new MixinRule();
505
+ this.#mixinRules.set(name, rule);
506
+ }
507
+ return rule;
508
+ }
509
+ addNestingRule(selector) {
510
+ let rule = this.nestingRules.get(selector);
511
+ if (rule === void 0) {
512
+ rule = new NestingRule(selector, this.#mixinRules);
513
+ this.nestingRules.set(selector, rule);
514
+ }
515
+ return rule;
516
+ }
359
517
  addFontFaceRule(options) {
360
- this.#isDirty = true;
361
518
  return this.#fontFaceRules.push(new FontFaceRule(options));
362
519
  }
363
- markAsDirty() {
364
- this.#isDirty = true;
365
- }
366
- get cssText() {
367
- if (this.#isDirty === false) {
368
- return this.#cssText;
369
- }
370
- this.#isDirty = false;
520
+ generateWith({
521
+ nestingRules,
522
+ transformValue
523
+ }) {
371
524
  const css = [];
372
525
  css.push(...this.#fontFaceRules.map((rule) => rule.cssText));
373
526
  for (const plaintextRule of this.#plainRules.values()) {
@@ -377,19 +530,32 @@ var StyleSheet = class {
377
530
  (ruleA, ruleB) => compareMedia(ruleA.options, ruleB.options)
378
531
  );
379
532
  for (const mediaRule of sortedMediaRules) {
380
- const { cssText } = mediaRule;
533
+ const cssText = mediaRule.generateRule({
534
+ nestingRules,
535
+ transformValue
536
+ });
381
537
  if (cssText !== "") {
382
538
  css.push(cssText);
383
539
  }
384
540
  }
541
+ for (const rule of this.#mixinRules.values()) {
542
+ rule.clearBreakpoints();
543
+ }
385
544
  this.#cssText = css.join("\n");
386
545
  return this.#cssText;
387
546
  }
547
+ get cssText() {
548
+ return this.generateWith({
549
+ nestingRules: Array.from(this.nestingRules.values()),
550
+ transformValue: this.#transformValue
551
+ });
552
+ }
388
553
  clear() {
389
554
  this.#mediaRules.clear();
555
+ this.#mixinRules.clear();
556
+ this.nestingRules.clear();
390
557
  this.#plainRules.clear();
391
558
  this.#fontFaceRules = [];
392
- this.#isDirty = true;
393
559
  }
394
560
  render() {
395
561
  this.#element.mount();
@@ -409,58 +575,12 @@ var StyleSheet = class {
409
575
  // src/core/style-sheet-regular.ts
410
576
  var defaultMediaRuleId = "__default-media-rule__";
411
577
  var StyleSheetRegular = class extends StyleSheet {
412
- addStyleRule(rule, selectorText, transformValue) {
578
+ addStyleRule(rule, selectorText) {
413
579
  const mediaRule = this.addMediaRule(rule.breakpoint || defaultMediaRuleId);
414
- this.markAsDirty();
415
- const styleRule = new StyleRule(
416
- selectorText,
417
- rule.style,
418
- transformValue,
419
- this.#onChangeRule
420
- );
580
+ const styleRule = new StyleRule(selectorText, rule.style);
421
581
  mediaRule.insertRule(styleRule);
422
582
  return styleRule;
423
583
  }
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
584
  };
465
585
 
466
586
  // src/core/create-style-sheet.ts
@@ -468,10 +588,6 @@ var createRegularStyleSheet = (options) => {
468
588
  const element = new StyleElement(options?.name);
469
589
  return new StyleSheetRegular(element);
470
590
  };
471
- var createAtomicStyleSheet = (options) => {
472
- const element = new StyleElement(options?.name);
473
- return new StyleSheetAtomic(element);
474
- };
475
591
 
476
592
  // src/core/match-media.ts
477
593
  var matchMedia = (options, width) => {
@@ -495,6 +611,37 @@ var findApplicableMedia = (media, width) => {
495
611
  }
496
612
  };
497
613
 
614
+ // src/core/atomic.ts
615
+ import hash from "@emotion/hash";
616
+ var generateAtomic = (sheet, options) => {
617
+ const { getKey, transformValue } = options;
618
+ const atomicRules = /* @__PURE__ */ new Map();
619
+ const classesMap = /* @__PURE__ */ new Map();
620
+ for (const rule of sheet.nestingRules.values()) {
621
+ const groupKey = getKey(rule);
622
+ const classList = [];
623
+ for (const declaration of rule.getDeclarations()) {
624
+ const atomicHash = hash(
625
+ declaration.breakpoint + declaration.selector + declaration.property + toValue(declaration.value, transformValue)
626
+ );
627
+ const className = `c${atomicHash}`;
628
+ let atomicRule = atomicRules.get(atomicHash);
629
+ if (atomicRule === void 0) {
630
+ atomicRule = new NestingRule(`.${className}`, /* @__PURE__ */ new Map());
631
+ atomicRule.setDeclaration(declaration);
632
+ atomicRules.set(atomicHash, atomicRule);
633
+ }
634
+ classList.push(className);
635
+ }
636
+ classesMap.set(groupKey, classList);
637
+ }
638
+ const cssText = sheet.generateWith({
639
+ nestingRules: Array.from(atomicRules.values()),
640
+ transformValue
641
+ });
642
+ return { cssText, classesMap };
643
+ };
644
+
498
645
  // src/schema.ts
499
646
  import { z } from "zod";
500
647
  var Unit = z.string();
@@ -618,10 +765,10 @@ export {
618
765
  UnitValue,
619
766
  UnparsedValue,
620
767
  compareMedia,
621
- createAtomicStyleSheet,
622
768
  createRegularStyleSheet,
623
769
  equalMedia,
624
770
  findApplicableMedia,
771
+ generateAtomic,
625
772
  isValidStaticStyleValue,
626
773
  matchMedia,
627
774
  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 { AnyRule, StyleRule, MediaRule, PlaintextRule, FontFaceRule, } from "./rules";
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,65 @@
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(selector: string, mixinRules: Map<string, MixinRule>);
48
+ getSelector(): string;
49
+ addMixin(mixin: string): void;
50
+ applyMixins(mixins: string[]): void;
51
+ setDeclaration(declaration: Declaration): void;
52
+ deleteDeclaration(declaration: DeclarationKey): void;
53
+ getDeclarations(): IterableIterator<Declaration>;
54
+ toString({ breakpoint, indent, transformValue, }: {
55
+ breakpoint: string;
56
+ indent?: number;
57
+ transformValue?: TransformValue;
58
+ }): string;
59
+ }
3
60
  export declare class StylePropertyMap {
4
61
  #private;
5
- constructor(style: Style, transformValue?: TransformValue, onChange?: () => void);
6
- setTransformer(transformValue: TransformValue): void;
62
+ constructor(style: Style);
7
63
  set(property: StyleProperty, value?: StyleValue): void;
8
64
  get(property: StyleProperty): {
9
65
  type: "unit";
@@ -1024,17 +1080,19 @@ export declare class StylePropertyMap {
1024
1080
  keys(): IterableIterator<StyleProperty>;
1025
1081
  delete(property: StyleProperty): void;
1026
1082
  clear(): void;
1027
- toString({ indent }?: {
1028
- indent?: number | undefined;
1083
+ toString({ indent, transformValue, }?: {
1084
+ indent?: number;
1085
+ transformValue?: TransformValue;
1029
1086
  }): string;
1030
1087
  }
1031
1088
  export declare class StyleRule {
1032
1089
  styleMap: StylePropertyMap;
1033
1090
  selectorText: string;
1034
- constructor(selectorText: string, style: StylePropertyMap | Style, transformValue?: TransformValue, onChange?: () => void);
1091
+ constructor(selectorText: string, style: StylePropertyMap | Style);
1035
1092
  get cssText(): string;
1036
- toString(options?: {
1037
- indent: number;
1093
+ toString({ indent, transformValue, }?: {
1094
+ indent?: number;
1095
+ transformValue?: TransformValue;
1038
1096
  }): string;
1039
1097
  }
1040
1098
  export type MediaRuleOptions = {
@@ -1046,14 +1104,17 @@ export declare class MediaRule {
1046
1104
  #private;
1047
1105
  options: MediaRuleOptions;
1048
1106
  rules: Map<string, StyleRule | PlaintextRule>;
1049
- constructor(options?: MediaRuleOptions);
1107
+ constructor(name: string, options?: MediaRuleOptions);
1050
1108
  insertRule(rule: StyleRule | PlaintextRule): StyleRule | PlaintextRule;
1051
1109
  get cssText(): string;
1052
1110
  toString(): string;
1111
+ generateRule({ nestingRules, transformValue, }: {
1112
+ nestingRules: NestingRule[];
1113
+ transformValue?: TransformValue;
1114
+ }): string;
1053
1115
  }
1054
1116
  export declare class PlaintextRule {
1055
1117
  cssText: string;
1056
- styleMap: StylePropertyMap;
1057
1118
  constructor(cssText: string);
1058
1119
  toString(): string;
1059
1120
  }
@@ -1065,9 +1126,9 @@ export type FontFaceOptions = {
1065
1126
  src: string;
1066
1127
  };
1067
1128
  export declare class FontFaceRule {
1068
- options: FontFaceOptions;
1129
+ #private;
1069
1130
  constructor(options: FontFaceOptions);
1070
1131
  get cssText(): string;
1071
1132
  toString(): string;
1072
1133
  }
1073
- export type AnyRule = StyleRule | MediaRule | PlaintextRule | FontFaceRule;
1134
+ 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
- #private;
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): NestingRule;
13
18
  addFontFaceRule(options: FontFaceOptions): number;
14
- markAsDirty(): void;
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.145.0",
3
+ "version": "0.151.0",
4
4
  "description": "CSS Renderer for Webstudio",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -9,8 +9,8 @@
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.145.0",
13
- "@webstudio-is/error-utils": "0.145.0"
12
+ "@webstudio-is/fonts": "0.151.0",
13
+ "@webstudio-is/error-utils": "0.151.0"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@jest/globals": "^29.7.0",
@@ -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
- }