@webstudio-is/css-engine 0.0.0-017f1bd

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.
Files changed (36) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +6 -0
  3. package/lib/index.js +988 -0
  4. package/lib/runtime.js +114 -0
  5. package/lib/types/__generated__/types.d.ts +3 -0
  6. package/lib/types/core/atomic.d.ts +14 -0
  7. package/lib/types/core/atomic.test.d.ts +1 -0
  8. package/lib/types/core/compare-media.d.ts +6 -0
  9. package/lib/types/core/compare-media.test.d.ts +1 -0
  10. package/lib/types/core/create-style-sheet.d.ts +4 -0
  11. package/lib/types/core/css-engine.stories.d.ts +5 -0
  12. package/lib/types/core/equal-media.d.ts +2 -0
  13. package/lib/types/core/equal-media.test.d.ts +1 -0
  14. package/lib/types/core/find-applicable-media.d.ts +2 -0
  15. package/lib/types/core/find-applicable-media.test.d.ts +1 -0
  16. package/lib/types/core/index.d.ts +13 -0
  17. package/lib/types/core/match-media.d.ts +2 -0
  18. package/lib/types/core/match-media.test.d.ts +1 -0
  19. package/lib/types/core/merger.d.ts +604 -0
  20. package/lib/types/core/merger.test.d.ts +1 -0
  21. package/lib/types/core/prefixer.d.ts +2 -0
  22. package/lib/types/core/prefixer.test.d.ts +1 -0
  23. package/lib/types/core/rules.d.ts +107 -0
  24. package/lib/types/core/style-element.d.ts +10 -0
  25. package/lib/types/core/style-sheet-regular.d.ts +3 -0
  26. package/lib/types/core/style-sheet-regular.test.d.ts +1 -0
  27. package/lib/types/core/style-sheet.d.ts +24 -0
  28. package/lib/types/core/to-property.d.ts +5 -0
  29. package/lib/types/core/to-property.test.d.ts +1 -0
  30. package/lib/types/core/to-value.d.ts +3 -0
  31. package/lib/types/core/to-value.test.d.ts +1 -0
  32. package/lib/types/css.d.ts +1 -0
  33. package/lib/types/index.d.ts +5 -0
  34. package/lib/types/runtime.d.ts +1 -0
  35. package/lib/types/schema.d.ts +9623 -0
  36. package/package.json +46 -0
package/lib/index.js ADDED
@@ -0,0 +1,988 @@
1
+ // src/core/prefixer.ts
2
+ var prefixStyles = (styleMap) => {
3
+ const newStyleMap = /* @__PURE__ */ new Map();
4
+ for (const [property, value] of styleMap) {
5
+ if (property === "background-clip") {
6
+ newStyleMap.set("-webkit-background-clip", value);
7
+ }
8
+ if (property === "user-select") {
9
+ newStyleMap.set("-webkit-user-select", value);
10
+ }
11
+ if (property === "text-size-adjust") {
12
+ newStyleMap.set("-webkit-text-size-adjust", value);
13
+ }
14
+ if (property === "backdrop-filter") {
15
+ newStyleMap.set("-webkit-backdrop-filter", value);
16
+ }
17
+ if (property === "view-timeline-name" || property === "scroll-timeline-name" || property === "view-timeline-inset") {
18
+ newStyleMap.set(`--${property}`, value);
19
+ }
20
+ newStyleMap.set(property, value);
21
+ }
22
+ return newStyleMap;
23
+ };
24
+
25
+ // src/schema.ts
26
+ import { z } from "zod";
27
+
28
+ // src/core/to-value.ts
29
+ import { DEFAULT_FONT_FALLBACK, SYSTEM_FONTS } from "@webstudio-is/fonts";
30
+ var fallbackTransform = (styleValue) => {
31
+ if (styleValue.type !== "fontFamily") {
32
+ return;
33
+ }
34
+ let { value } = styleValue;
35
+ if (value.length === 0) {
36
+ value = [DEFAULT_FONT_FALLBACK];
37
+ }
38
+ if (value.length === 1) {
39
+ const stack = SYSTEM_FONTS.get(value[0])?.stack;
40
+ value = stack ?? [value[0], DEFAULT_FONT_FALLBACK];
41
+ }
42
+ return {
43
+ type: "fontFamily",
44
+ value: Array.from(new Set(value))
45
+ };
46
+ };
47
+ var sanitizeCssUrl = (str) => JSON.stringify(str);
48
+ var toValue = (styleValue, transformValue) => {
49
+ if (styleValue === void 0) {
50
+ return "";
51
+ }
52
+ const transformedValue = transformValue?.(styleValue) ?? fallbackTransform(styleValue);
53
+ const value = transformedValue ?? styleValue;
54
+ if (value.type === "unit") {
55
+ return value.value + (value.unit === "number" ? "" : value.unit);
56
+ }
57
+ if (value.type === "fontFamily") {
58
+ const families = [];
59
+ for (const family of value.value) {
60
+ families.push(family.includes(" ") ? `"${family}"` : family);
61
+ }
62
+ return families.join(", ");
63
+ }
64
+ if (value.type === "var") {
65
+ if (value.hidden) {
66
+ return "";
67
+ }
68
+ let fallbacksString = "";
69
+ if (value.fallback) {
70
+ fallbacksString = `, ${toValue(value.fallback, transformValue)}`;
71
+ }
72
+ return `var(--${value.value}${fallbacksString})`;
73
+ }
74
+ if (value.type === "keyword") {
75
+ if (value.hidden === true) {
76
+ return "";
77
+ }
78
+ return value.value;
79
+ }
80
+ if (value.type === "invalid") {
81
+ return value.value;
82
+ }
83
+ if (value.type === "unset") {
84
+ return value.value;
85
+ }
86
+ if (value.type === "rgb") {
87
+ return `rgba(${value.r}, ${value.g}, ${value.b}, ${value.alpha})`;
88
+ }
89
+ if (value.type === "image") {
90
+ if (value.hidden || value.value.type !== "url") {
91
+ return "none";
92
+ }
93
+ return `url(${sanitizeCssUrl(value.value.url)})`;
94
+ }
95
+ if (value.type === "unparsed") {
96
+ if (value.hidden === true) {
97
+ return "none";
98
+ }
99
+ return value.value;
100
+ }
101
+ if (value.type === "layers") {
102
+ const valueString = value.value.filter((layer) => layer.hidden !== true).map((layer) => toValue(layer, transformValue)).join(", ");
103
+ return valueString === "" ? "none" : valueString;
104
+ }
105
+ if (value.type === "tuple") {
106
+ if (value.hidden === true) {
107
+ return "none";
108
+ }
109
+ return value.value.filter((value2) => value2.hidden !== true).map((value2) => toValue(value2, transformValue)).join(" ");
110
+ }
111
+ if (value.type === "shadow") {
112
+ let shadow = `${toValue(value.offsetX)} ${toValue(value.offsetY)}`;
113
+ if (value.blur) {
114
+ shadow += ` ${toValue(value.blur)}`;
115
+ }
116
+ if (value.spread) {
117
+ shadow += ` ${toValue(value.spread)}`;
118
+ }
119
+ if (value.color) {
120
+ shadow += ` ${toValue(value.color)}`;
121
+ }
122
+ if (value.position === "inset") {
123
+ shadow += ` inset`;
124
+ }
125
+ return shadow;
126
+ }
127
+ if (value.type === "function") {
128
+ if (value.hidden === true) {
129
+ return "";
130
+ }
131
+ return `${value.name}(${toValue(value.args, transformValue)})`;
132
+ }
133
+ if (value.type === "guaranteedInvalid") {
134
+ return "";
135
+ }
136
+ value;
137
+ return "";
138
+ };
139
+
140
+ // src/schema.ts
141
+ var Unit = z.string();
142
+ var UnitValue = z.object({
143
+ type: z.literal("unit"),
144
+ unit: Unit,
145
+ value: z.number(),
146
+ hidden: z.boolean().optional()
147
+ });
148
+ var KeywordValue = z.object({
149
+ type: z.literal("keyword"),
150
+ // @todo use exact type
151
+ value: z.string(),
152
+ hidden: z.boolean().optional()
153
+ });
154
+ var UnparsedValue = z.object({
155
+ type: z.literal("unparsed"),
156
+ value: z.string(),
157
+ // For the builder we want to be able to hide background-image
158
+ hidden: z.boolean().optional()
159
+ });
160
+ var FontFamilyValue = z.object({
161
+ type: z.literal("fontFamily"),
162
+ value: z.array(z.string()),
163
+ hidden: z.boolean().optional()
164
+ });
165
+ var RgbValue = z.object({
166
+ type: z.literal("rgb"),
167
+ r: z.number(),
168
+ g: z.number(),
169
+ b: z.number(),
170
+ alpha: z.number(),
171
+ hidden: z.boolean().optional()
172
+ });
173
+ var FunctionValue = z.object({
174
+ type: z.literal("function"),
175
+ name: z.string(),
176
+ args: z.lazy(() => StyleValue),
177
+ hidden: z.boolean().optional()
178
+ });
179
+ var ImageValue = z.object({
180
+ type: z.literal("image"),
181
+ value: z.union([
182
+ z.object({ type: z.literal("asset"), value: z.string() }),
183
+ // url is not stored in db and only used by css-engine transformValue
184
+ // to prepare image value for rendering
185
+ z.object({ type: z.literal("url"), url: z.string() })
186
+ ]),
187
+ // For the builder we want to be able to hide images
188
+ hidden: z.boolean().optional()
189
+ });
190
+ var GuaranteedInvalidValue = z.object({
191
+ type: z.literal("guaranteedInvalid"),
192
+ hidden: z.boolean().optional()
193
+ });
194
+ var InvalidValue = z.object({
195
+ type: z.literal("invalid"),
196
+ value: z.string(),
197
+ hidden: z.boolean().optional()
198
+ });
199
+ var UnsetValue = z.object({
200
+ type: z.literal("unset"),
201
+ value: z.literal(""),
202
+ hidden: z.boolean().optional()
203
+ });
204
+ var VarFallback = z.union([
205
+ UnparsedValue,
206
+ KeywordValue,
207
+ UnitValue,
208
+ RgbValue
209
+ ]);
210
+ var toVarFallback = (styleValue, transformValue) => {
211
+ if (styleValue.type === "unparsed" || styleValue.type === "keyword" || styleValue.type === "unit" || styleValue.type === "rgb") {
212
+ return styleValue;
213
+ }
214
+ styleValue;
215
+ return { type: "unparsed", value: toValue(styleValue, transformValue) };
216
+ };
217
+ var VarValue = z.object({
218
+ type: z.literal("var"),
219
+ value: z.string(),
220
+ fallback: VarFallback.optional(),
221
+ hidden: z.boolean().optional()
222
+ });
223
+ var TupleValueItem = z.union([
224
+ UnitValue,
225
+ KeywordValue,
226
+ UnparsedValue,
227
+ ImageValue,
228
+ RgbValue,
229
+ FunctionValue,
230
+ VarValue
231
+ ]);
232
+ var TupleValue = z.object({
233
+ type: z.literal("tuple"),
234
+ value: z.array(TupleValueItem),
235
+ hidden: z.boolean().optional()
236
+ });
237
+ var ShadowValue = z.object({
238
+ type: z.literal("shadow"),
239
+ hidden: z.boolean().optional(),
240
+ position: z.union([z.literal("inset"), z.literal("outset")]),
241
+ offsetX: z.union([UnitValue, VarValue]),
242
+ offsetY: z.union([UnitValue, VarValue]),
243
+ blur: z.union([UnitValue, VarValue]).optional(),
244
+ spread: z.union([UnitValue, VarValue]).optional(),
245
+ color: z.union([RgbValue, KeywordValue, VarValue]).optional()
246
+ });
247
+ var LayerValueItem = z.union([
248
+ UnitValue,
249
+ KeywordValue,
250
+ UnparsedValue,
251
+ ImageValue,
252
+ TupleValue,
253
+ ShadowValue,
254
+ RgbValue,
255
+ InvalidValue,
256
+ FunctionValue,
257
+ VarValue
258
+ ]);
259
+ var LayersValue = z.object({
260
+ type: z.literal("layers"),
261
+ value: z.array(LayerValueItem),
262
+ hidden: z.boolean().optional()
263
+ });
264
+ var StyleValue = z.union([
265
+ ImageValue,
266
+ LayersValue,
267
+ UnitValue,
268
+ KeywordValue,
269
+ FontFamilyValue,
270
+ RgbValue,
271
+ UnparsedValue,
272
+ TupleValue,
273
+ FunctionValue,
274
+ GuaranteedInvalidValue,
275
+ InvalidValue,
276
+ UnsetValue,
277
+ VarValue,
278
+ ShadowValue
279
+ ]);
280
+
281
+ // src/css.ts
282
+ var cssWideKeywords = /* @__PURE__ */ new Set([
283
+ "initial",
284
+ "inherit",
285
+ "unset",
286
+ "revert",
287
+ "revert-layer"
288
+ ]);
289
+
290
+ // src/core/merger.ts
291
+ var isLonghandValue = (value) => {
292
+ if (value === void 0) {
293
+ return false;
294
+ }
295
+ if (value.type === "keyword" && cssWideKeywords.has(value.value)) {
296
+ return false;
297
+ }
298
+ if (value.type === "var") {
299
+ const fallback = value.fallback;
300
+ if (fallback?.type === "keyword" && cssWideKeywords.has(fallback.value)) {
301
+ return false;
302
+ }
303
+ }
304
+ return true;
305
+ };
306
+ var mergeBorder = (styleMap, base) => {
307
+ const width = styleMap.get(`${base}-width`);
308
+ const style = styleMap.get(`${base}-style`);
309
+ const color = styleMap.get(`${base}-color`);
310
+ if (isLonghandValue(width) && isLonghandValue(style) && isLonghandValue(color)) {
311
+ styleMap.delete(`${base}-width`);
312
+ styleMap.delete(`${base}-style`);
313
+ styleMap.delete(`${base}-color`);
314
+ styleMap.set(base, { type: "tuple", value: [width, style, color] });
315
+ }
316
+ };
317
+ var mergeBox = (styleMap, base) => {
318
+ const topValue = styleMap.get(`${base}-top`);
319
+ const top = toValue(topValue);
320
+ const right = toValue(styleMap.get(`${base}-right`));
321
+ const bottom = toValue(styleMap.get(`${base}-bottom`));
322
+ const left = toValue(styleMap.get(`${base}-left`));
323
+ if (isLonghandValue(topValue) && top === right && top === bottom && top === left) {
324
+ styleMap.delete(`${base}-top`);
325
+ styleMap.delete(`${base}-right`);
326
+ styleMap.delete(`${base}-bottom`);
327
+ styleMap.delete(`${base}-left`);
328
+ styleMap.set(base, topValue);
329
+ }
330
+ };
331
+ var mergeWhiteSpaceAndTextWrap = (styleMap) => {
332
+ const collapseValue = styleMap.get("white-space-collapse");
333
+ const collapse = toValue(collapseValue);
334
+ const modeValue = styleMap.get("text-wrap-mode");
335
+ const mode = toValue(modeValue);
336
+ const styleValue = styleMap.get("text-wrap-style");
337
+ const style = toValue(styleValue);
338
+ styleMap.delete("text-wrap-mode");
339
+ styleMap.delete("text-wrap-style");
340
+ if (collapse === "collapse" || collapse === "initial" || mode === "wrap" || mode === "initial") {
341
+ styleMap.set("white-space", { type: "keyword", value: "normal" });
342
+ }
343
+ if (mode === "nowrap") {
344
+ styleMap.set("white-space", { type: "keyword", value: "nowrap" });
345
+ }
346
+ if (collapse === "preserve") {
347
+ if (mode === "nowrap") {
348
+ styleMap.set("white-space", { type: "keyword", value: "pre" });
349
+ } else {
350
+ styleMap.set("white-space", { type: "keyword", value: "pre-wrap" });
351
+ }
352
+ }
353
+ if (collapse === "preserve-breaks") {
354
+ styleMap.set("white-space", { type: "keyword", value: "pre-line" });
355
+ }
356
+ if (collapse === "break-spaces") {
357
+ styleMap.set("white-space", { type: "keyword", value: "break-spaces" });
358
+ }
359
+ if (style === "auto") {
360
+ styleMap.set("text-wrap", modeValue ?? { type: "keyword", value: "wrap" });
361
+ }
362
+ if (style === "balance" || style === "stable" || style === "pretty") {
363
+ styleMap.set("text-wrap", { type: "keyword", value: style });
364
+ }
365
+ const textWrap = (styleValue?.type !== "keyword" ? styleValue : void 0) ?? (modeValue?.type !== "keyword" ? modeValue : void 0);
366
+ if (textWrap) {
367
+ styleMap.set("text-wrap", textWrap);
368
+ }
369
+ if (collapseValue) {
370
+ styleMap.delete("white-space-collapse");
371
+ styleMap.set("white-space-collapse", collapseValue);
372
+ }
373
+ };
374
+ var mergeBackgroundPosition = (styleMap) => {
375
+ const x = styleMap.get("background-position-x");
376
+ const y = styleMap.get("background-position-y");
377
+ if (x?.type === "layers" && y?.type === "layers" && x.value.length === y.value.length) {
378
+ const position = x.value.map((xValue, index) => {
379
+ const yValue = y.value[index];
380
+ return {
381
+ type: "tuple",
382
+ value: [xValue, yValue]
383
+ };
384
+ });
385
+ styleMap.delete("background-position-x");
386
+ styleMap.delete("background-position-y");
387
+ styleMap.set("background-position", {
388
+ type: "layers",
389
+ value: position
390
+ });
391
+ }
392
+ };
393
+ var mergeStyles = (styleMap) => {
394
+ const newStyle = new Map(styleMap);
395
+ mergeBorder(newStyle, "border-top");
396
+ mergeBorder(newStyle, "border-right");
397
+ mergeBorder(newStyle, "border-bottom");
398
+ mergeBorder(newStyle, "border-left");
399
+ mergeBorder(newStyle, "border");
400
+ mergeBorder(newStyle, "outline");
401
+ mergeBox(newStyle, "border");
402
+ mergeBox(newStyle, "margin");
403
+ mergeBox(newStyle, "padding");
404
+ mergeWhiteSpaceAndTextWrap(newStyle);
405
+ mergeBackgroundPosition(newStyle);
406
+ return newStyle;
407
+ };
408
+
409
+ // src/core/to-property.ts
410
+ var hyphenateProperty = (property) => property.replace(
411
+ /[A-Z]/g,
412
+ (match) => "-" + match.toLowerCase()
413
+ );
414
+
415
+ // src/core/rules.ts
416
+ var mapGroupBy = (array, getKey) => {
417
+ const groups = /* @__PURE__ */ new Map();
418
+ for (const item of array) {
419
+ const key = getKey(item);
420
+ let group = groups.get(key);
421
+ if (group === void 0) {
422
+ group = [];
423
+ groups.set(key, group);
424
+ }
425
+ group.push(item);
426
+ }
427
+ return groups;
428
+ };
429
+ var mergeDeclarations = (declarations) => {
430
+ const newDeclarations = [];
431
+ const groups = mapGroupBy(
432
+ declarations,
433
+ (declaration) => declaration.breakpoint + declaration.selector
434
+ );
435
+ for (const groupDeclarations of groups.values()) {
436
+ const { breakpoint, selector } = groupDeclarations[0];
437
+ const merged = mergeStyles(
438
+ new Map(
439
+ groupDeclarations.map((item) => [item.property, item.value])
440
+ )
441
+ );
442
+ for (const [property, value] of merged) {
443
+ newDeclarations.push({
444
+ breakpoint,
445
+ selector,
446
+ property,
447
+ value
448
+ });
449
+ }
450
+ }
451
+ return newDeclarations;
452
+ };
453
+ var generateStyleMap = (style, {
454
+ indent = 0,
455
+ transformValue
456
+ } = {}) => {
457
+ const spaces = " ".repeat(indent);
458
+ let lines = "";
459
+ for (const [property, value] of style) {
460
+ const propertyString = hyphenateProperty(property);
461
+ const valueString = toValue(value, transformValue);
462
+ const line = `${spaces}${propertyString}: ${valueString}`;
463
+ lines += lines === "" ? line : `;
464
+ ${line}`;
465
+ }
466
+ return lines;
467
+ };
468
+ var normalizeDeclaration = (declaration) => ({
469
+ ...declaration,
470
+ property: hyphenateProperty(declaration.property)
471
+ });
472
+ var getDeclarationKey = (declaraionKey) => {
473
+ const { breakpoint, selector, property } = declaraionKey;
474
+ return `${breakpoint}:${selector}:${property}`;
475
+ };
476
+ var MixinRule = class {
477
+ // use map to avoid duplicated properties
478
+ #declarations = /* @__PURE__ */ new Map();
479
+ #dirtyBreakpoints = /* @__PURE__ */ new Set();
480
+ /*
481
+ * check if breakpoint was updated
482
+ */
483
+ isDirtyBreakpoint(breakpoint) {
484
+ return this.#dirtyBreakpoints.has(breakpoint);
485
+ }
486
+ /**
487
+ * reset breakpoints invalidation
488
+ */
489
+ clearBreakpoints() {
490
+ this.#dirtyBreakpoints.clear();
491
+ }
492
+ setDeclaration(declaration) {
493
+ declaration = normalizeDeclaration(declaration);
494
+ this.#declarations.set(getDeclarationKey(declaration), declaration);
495
+ this.#dirtyBreakpoints.add(declaration.breakpoint);
496
+ }
497
+ deleteDeclaration(declaration) {
498
+ declaration = normalizeDeclaration(declaration);
499
+ this.#declarations.delete(getDeclarationKey(declaration));
500
+ this.#dirtyBreakpoints.add(declaration.breakpoint);
501
+ }
502
+ getDeclarations() {
503
+ return this.#declarations.values();
504
+ }
505
+ };
506
+ var NestingRule = class {
507
+ #selector;
508
+ #descendantSuffix;
509
+ #mixinRules = /* @__PURE__ */ new Map();
510
+ #mixins = /* @__PURE__ */ new Set();
511
+ // use map to avoid duplicated properties
512
+ #declarations = /* @__PURE__ */ new Map();
513
+ // cached generated rule by breakpoint
514
+ #cache = /* @__PURE__ */ new Map();
515
+ constructor(mixinRules, selector, descendantSuffix) {
516
+ this.#selector = selector;
517
+ this.#descendantSuffix = descendantSuffix;
518
+ this.#mixinRules = mixinRules;
519
+ }
520
+ getSelector() {
521
+ return this.#selector;
522
+ }
523
+ setSelector(selector) {
524
+ this.#selector = selector;
525
+ this.#cache.clear();
526
+ }
527
+ getDescendantSuffix() {
528
+ return this.#descendantSuffix;
529
+ }
530
+ addMixin(mixin) {
531
+ this.#mixins.add(mixin);
532
+ this.#cache.clear();
533
+ }
534
+ applyMixins(mixins) {
535
+ this.#mixins = new Set(mixins);
536
+ this.#cache.clear();
537
+ }
538
+ setDeclaration(declaration) {
539
+ declaration = normalizeDeclaration(declaration);
540
+ this.#declarations.set(getDeclarationKey(declaration), declaration);
541
+ this.#cache.delete(declaration.breakpoint);
542
+ }
543
+ deleteDeclaration(declaration) {
544
+ declaration = normalizeDeclaration(declaration);
545
+ this.#declarations.delete(getDeclarationKey(declaration));
546
+ this.#cache.delete(declaration.breakpoint);
547
+ }
548
+ #getDeclarations() {
549
+ const declarations = /* @__PURE__ */ new Map();
550
+ for (const mixin of this.#mixins) {
551
+ const rule = this.#mixinRules.get(mixin);
552
+ if (rule === void 0) {
553
+ continue;
554
+ }
555
+ for (const declaration of rule.getDeclarations()) {
556
+ declarations.set(getDeclarationKey(declaration), declaration);
557
+ }
558
+ }
559
+ for (const declaration of this.#declarations.values()) {
560
+ declarations.set(getDeclarationKey(declaration), declaration);
561
+ }
562
+ return declarations.values();
563
+ }
564
+ getMergedDeclarations() {
565
+ return mergeDeclarations(this.#getDeclarations());
566
+ }
567
+ toString({
568
+ breakpoint,
569
+ indent = 0,
570
+ transformValue
571
+ }) {
572
+ for (const mixin of this.#mixins) {
573
+ const rule = this.#mixinRules.get(mixin);
574
+ if (rule?.isDirtyBreakpoint(breakpoint)) {
575
+ this.#cache.delete(breakpoint);
576
+ }
577
+ }
578
+ const cached = this.#cache.get(breakpoint);
579
+ if (cached && cached.indent === indent && cached.transformValue === transformValue) {
580
+ return cached.generated;
581
+ }
582
+ const styleBySelector = /* @__PURE__ */ new Map();
583
+ for (const declaration of this.getMergedDeclarations()) {
584
+ if (declaration.breakpoint !== breakpoint) {
585
+ continue;
586
+ }
587
+ let nestedSelector = declaration.selector;
588
+ if (nestedSelector === ":local-link") {
589
+ nestedSelector = "[aria-current=page]";
590
+ }
591
+ const selector = this.#selector + this.#descendantSuffix + nestedSelector;
592
+ let style = styleBySelector.get(selector);
593
+ if (style === void 0) {
594
+ style = /* @__PURE__ */ new Map();
595
+ styleBySelector.set(selector, style);
596
+ }
597
+ style.set(declaration.property, declaration.value);
598
+ }
599
+ const spaces = " ".repeat(indent);
600
+ const generated = Array.from(styleBySelector).sort(
601
+ ([leftSelector], [rightSelector]) => leftSelector.localeCompare(rightSelector)
602
+ ).map(([selector, style]) => {
603
+ const content = generateStyleMap(prefixStyles(style), {
604
+ indent: indent + 2,
605
+ transformValue
606
+ });
607
+ return `${spaces}${selector} {
608
+ ${content}
609
+ ${spaces}}
610
+ `;
611
+ }).join("").trimEnd();
612
+ this.#cache.set(breakpoint, { generated, indent, transformValue });
613
+ return generated;
614
+ }
615
+ };
616
+ var MediaRule = class {
617
+ #name;
618
+ options;
619
+ rules;
620
+ #mediaType;
621
+ constructor(name, options = {}) {
622
+ this.#name = name;
623
+ this.options = options;
624
+ this.rules = /* @__PURE__ */ new Map();
625
+ this.#mediaType = options.mediaType ?? "all";
626
+ }
627
+ insertRule(rule) {
628
+ this.rules.set(rule.cssText, rule);
629
+ return rule;
630
+ }
631
+ get cssText() {
632
+ return this.toString();
633
+ }
634
+ toString() {
635
+ return this.generateRule({ nestingRules: [] });
636
+ }
637
+ generateRule({
638
+ nestingRules,
639
+ transformValue
640
+ }) {
641
+ if (this.rules.size === 0 && nestingRules.length === 0) {
642
+ return "";
643
+ }
644
+ const rules = [];
645
+ for (const rule of this.rules.values()) {
646
+ rules.push(rule.toString());
647
+ }
648
+ for (const rule of nestingRules) {
649
+ const generatedRule = rule.toString({
650
+ breakpoint: this.#name,
651
+ indent: 2,
652
+ transformValue
653
+ });
654
+ if (generatedRule !== "") {
655
+ rules.push(generatedRule);
656
+ }
657
+ }
658
+ if (rules.length === 0) {
659
+ return "";
660
+ }
661
+ let conditionText = "";
662
+ const { minWidth, maxWidth } = this.options;
663
+ if (minWidth !== void 0) {
664
+ conditionText = ` and (min-width: ${minWidth}px)`;
665
+ }
666
+ if (maxWidth !== void 0) {
667
+ conditionText += ` and (max-width: ${maxWidth}px)`;
668
+ }
669
+ return `@media ${this.#mediaType}${conditionText} {
670
+ ${rules.join(
671
+ "\n"
672
+ )}
673
+ }`;
674
+ }
675
+ };
676
+ var PlaintextRule = class {
677
+ cssText;
678
+ constructor(cssText) {
679
+ this.cssText = cssText;
680
+ }
681
+ toString() {
682
+ return this.cssText;
683
+ }
684
+ };
685
+ var FontFaceRule = class {
686
+ #cached;
687
+ #options;
688
+ constructor(options) {
689
+ this.#options = options;
690
+ }
691
+ get cssText() {
692
+ return this.toString();
693
+ }
694
+ toString() {
695
+ if (this.#cached) {
696
+ return this.#cached;
697
+ }
698
+ const decls = [];
699
+ const { fontFamily, fontStyle, fontWeight, fontDisplay, src } = this.#options;
700
+ const value = toValue(
701
+ { type: "fontFamily", value: [fontFamily] },
702
+ // Avoids adding a fallback automatically which needs to happen for font family in general but not for font face.
703
+ (value2) => value2
704
+ );
705
+ decls.push(`font-family: ${value}`);
706
+ decls.push(`font-style: ${fontStyle}`);
707
+ decls.push(`font-weight: ${fontWeight}`);
708
+ decls.push(`font-display: ${fontDisplay}`);
709
+ decls.push(`src: ${src}`);
710
+ this.#cached = `@font-face {
711
+ ${decls.join("; ")};
712
+ }`;
713
+ return this.#cached;
714
+ }
715
+ };
716
+
717
+ // src/core/compare-media.ts
718
+ var compareMedia = (optionA, optionB) => {
719
+ if (optionA.minWidth === void 0 && optionA.maxWidth === void 0) {
720
+ return -1;
721
+ }
722
+ if (optionB.minWidth === void 0 && optionB.maxWidth === void 0) {
723
+ return 1;
724
+ }
725
+ if (optionA.minWidth !== void 0 && optionB.minWidth !== void 0) {
726
+ return optionA.minWidth - optionB.minWidth;
727
+ }
728
+ if (optionA.maxWidth !== void 0 && optionB.maxWidth !== void 0) {
729
+ return optionB.maxWidth - optionA.maxWidth;
730
+ }
731
+ return "minWidth" in optionA ? 1 : -1;
732
+ };
733
+
734
+ // src/core/style-element.ts
735
+ var StyleElement = class {
736
+ #element;
737
+ #name;
738
+ constructor(name = "") {
739
+ this.#name = name;
740
+ }
741
+ get isMounted() {
742
+ return this.#element?.parentElement != null;
743
+ }
744
+ mount() {
745
+ if (this.isMounted === false) {
746
+ this.#element = document.createElement("style");
747
+ this.#element.setAttribute("data-webstudio", this.#name);
748
+ document.head.appendChild(this.#element);
749
+ }
750
+ }
751
+ unmount() {
752
+ if (this.isMounted) {
753
+ this.#element?.parentElement?.removeChild(this.#element);
754
+ this.#element = void 0;
755
+ }
756
+ }
757
+ render(cssText) {
758
+ if (this.#element) {
759
+ this.#element.textContent = cssText;
760
+ }
761
+ }
762
+ setAttribute(name, value) {
763
+ if (this.#element) {
764
+ this.#element.setAttribute(name, value);
765
+ }
766
+ }
767
+ getAttribute(name) {
768
+ if (this.#element) {
769
+ return this.#element.getAttribute(name);
770
+ }
771
+ }
772
+ };
773
+
774
+ // src/core/style-sheet.ts
775
+ var StyleSheet = class {
776
+ #cssText = "";
777
+ #mediaRules = /* @__PURE__ */ new Map();
778
+ #plainRules = /* @__PURE__ */ new Map();
779
+ #mixinRules = /* @__PURE__ */ new Map();
780
+ nestingRules = /* @__PURE__ */ new Map();
781
+ #fontFaceRules = [];
782
+ #transformValue;
783
+ #element;
784
+ constructor(element) {
785
+ this.#element = element;
786
+ }
787
+ setTransformer(transformValue) {
788
+ this.#transformValue = transformValue;
789
+ }
790
+ addMediaRule(id, options) {
791
+ let mediaRule = this.#mediaRules.get(id);
792
+ if (mediaRule === void 0) {
793
+ mediaRule = new MediaRule(id, options);
794
+ this.#mediaRules.set(id, mediaRule);
795
+ return mediaRule;
796
+ }
797
+ if (options) {
798
+ mediaRule.options = options;
799
+ }
800
+ if (mediaRule === void 0) {
801
+ throw new Error("No media rule found");
802
+ }
803
+ return mediaRule;
804
+ }
805
+ addPlaintextRule(cssText) {
806
+ const rule = this.#plainRules.get(cssText);
807
+ if (rule !== void 0) {
808
+ return rule;
809
+ }
810
+ return this.#plainRules.set(cssText, new PlaintextRule(cssText));
811
+ }
812
+ addMixinRule(name) {
813
+ let rule = this.#mixinRules.get(name);
814
+ if (rule === void 0) {
815
+ rule = new MixinRule();
816
+ this.#mixinRules.set(name, rule);
817
+ }
818
+ return rule;
819
+ }
820
+ addNestingRule(selector, descendantSuffix = "") {
821
+ const key = selector + descendantSuffix;
822
+ let rule = this.nestingRules.get(key);
823
+ if (rule === void 0) {
824
+ rule = new NestingRule(this.#mixinRules, selector, descendantSuffix);
825
+ this.nestingRules.set(key, rule);
826
+ }
827
+ return rule;
828
+ }
829
+ addFontFaceRule(options) {
830
+ return this.#fontFaceRules.push(new FontFaceRule(options));
831
+ }
832
+ generateWith({
833
+ nestingRules,
834
+ transformValue
835
+ }) {
836
+ const css = [];
837
+ css.push(...this.#fontFaceRules.map((rule) => rule.cssText));
838
+ for (const plaintextRule of this.#plainRules.values()) {
839
+ css.push(plaintextRule.cssText);
840
+ }
841
+ const sortedMediaRules = Array.from(this.#mediaRules.values()).sort(
842
+ (ruleA, ruleB) => compareMedia(ruleA.options, ruleB.options)
843
+ );
844
+ for (const mediaRule of sortedMediaRules) {
845
+ const cssText = mediaRule.generateRule({
846
+ nestingRules,
847
+ transformValue
848
+ });
849
+ if (cssText !== "") {
850
+ css.push(cssText);
851
+ }
852
+ }
853
+ for (const rule of this.#mixinRules.values()) {
854
+ rule.clearBreakpoints();
855
+ }
856
+ this.#cssText = css.join("\n");
857
+ return this.#cssText;
858
+ }
859
+ get cssText() {
860
+ return this.generateWith({
861
+ nestingRules: Array.from(this.nestingRules.values()),
862
+ transformValue: this.#transformValue
863
+ });
864
+ }
865
+ clear() {
866
+ this.#mediaRules.clear();
867
+ this.#mixinRules.clear();
868
+ this.nestingRules.clear();
869
+ this.#plainRules.clear();
870
+ this.#fontFaceRules = [];
871
+ }
872
+ render() {
873
+ this.#element.mount();
874
+ this.#element.render(this.cssText);
875
+ }
876
+ unmount() {
877
+ this.#element.unmount();
878
+ }
879
+ setAttribute(name, value) {
880
+ this.#element.setAttribute(name, value);
881
+ }
882
+ getAttribute(name) {
883
+ return this.#element.getAttribute(name);
884
+ }
885
+ };
886
+
887
+ // src/core/style-sheet-regular.ts
888
+ var StyleSheetRegular = class extends StyleSheet {
889
+ };
890
+
891
+ // src/core/create-style-sheet.ts
892
+ var createRegularStyleSheet = (options) => {
893
+ const element = new StyleElement(options?.name);
894
+ return new StyleSheetRegular(element);
895
+ };
896
+
897
+ // src/core/match-media.ts
898
+ var matchMedia = (options, width) => {
899
+ const minWidth = options.minWidth ?? Number.MIN_SAFE_INTEGER;
900
+ const maxWidth = options.maxWidth ?? Number.MAX_SAFE_INTEGER;
901
+ return width >= minWidth && width <= maxWidth;
902
+ };
903
+
904
+ // src/core/equal-media.ts
905
+ var equalMedia = (left, right) => {
906
+ return left.minWidth === right.minWidth && left.maxWidth === right.maxWidth;
907
+ };
908
+
909
+ // src/core/find-applicable-media.ts
910
+ var findApplicableMedia = (media, width) => {
911
+ const sortedMedia = [...media].sort(compareMedia).reverse();
912
+ for (const options of sortedMedia) {
913
+ if (matchMedia(options, width)) {
914
+ return options;
915
+ }
916
+ }
917
+ };
918
+
919
+ // src/core/atomic.ts
920
+ import hash from "@emotion/hash";
921
+ var generateAtomic = (sheet, options) => {
922
+ const { getKey, transformValue } = options;
923
+ const atomicRules = /* @__PURE__ */ new Map();
924
+ const classes = options.classes ?? /* @__PURE__ */ new Map();
925
+ for (const rule of sheet.nestingRules.values()) {
926
+ const descendantSuffix = rule.getDescendantSuffix();
927
+ const groupKey = getKey(rule);
928
+ if (groupKey === void 0) {
929
+ atomicRules.set(rule.getSelector(), rule);
930
+ continue;
931
+ }
932
+ let classList = classes.get(groupKey);
933
+ if (classList === void 0) {
934
+ classList = [];
935
+ classes.set(groupKey, classList);
936
+ }
937
+ for (const declaration of rule.getMergedDeclarations()) {
938
+ const atomicHash = hash(
939
+ descendantSuffix + declaration.breakpoint + declaration.selector + declaration.property + toValue(declaration.value, transformValue)
940
+ );
941
+ const className = `c${atomicHash}`;
942
+ let atomicRule = atomicRules.get(atomicHash);
943
+ if (atomicRule === void 0) {
944
+ atomicRule = new NestingRule(
945
+ /* @__PURE__ */ new Map(),
946
+ `.${className}`,
947
+ descendantSuffix
948
+ );
949
+ atomicRule.setDeclaration(declaration);
950
+ atomicRules.set(atomicHash, atomicRule);
951
+ }
952
+ classList.push(className);
953
+ }
954
+ }
955
+ const cssText = sheet.generateWith({
956
+ nestingRules: Array.from(atomicRules.values()),
957
+ transformValue
958
+ });
959
+ return { cssText, classes };
960
+ };
961
+ export {
962
+ FunctionValue,
963
+ GuaranteedInvalidValue,
964
+ ImageValue,
965
+ InvalidValue,
966
+ KeywordValue,
967
+ LayersValue,
968
+ ShadowValue,
969
+ StyleValue,
970
+ TupleValue,
971
+ TupleValueItem,
972
+ UnitValue,
973
+ UnparsedValue,
974
+ VarFallback,
975
+ compareMedia,
976
+ createRegularStyleSheet,
977
+ cssWideKeywords,
978
+ equalMedia,
979
+ findApplicableMedia,
980
+ generateAtomic,
981
+ generateStyleMap,
982
+ hyphenateProperty,
983
+ matchMedia,
984
+ mergeStyles,
985
+ prefixStyles,
986
+ toValue,
987
+ toVarFallback
988
+ };