@webstudio-is/css-engine 0.237.0 → 0.252.1

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
@@ -720,12 +720,16 @@ var MediaRule = class {
720
720
  return "";
721
721
  }
722
722
  let conditionText = "";
723
- const { minWidth, maxWidth } = this.options;
724
- if (minWidth !== void 0) {
725
- conditionText = ` and (min-width: ${minWidth}px)`;
726
- }
727
- if (maxWidth !== void 0) {
728
- conditionText += ` and (max-width: ${maxWidth}px)`;
723
+ const { minWidth, maxWidth, condition } = this.options;
724
+ if (condition !== void 0) {
725
+ conditionText = ` and (${condition})`;
726
+ } else {
727
+ if (minWidth !== void 0) {
728
+ conditionText = ` and (min-width: ${minWidth}px)`;
729
+ }
730
+ if (maxWidth !== void 0) {
731
+ conditionText += ` and (max-width: ${maxWidth}px)`;
732
+ }
729
733
  }
730
734
  return `@media ${this.#mediaType}${conditionText} {
731
735
  ${rules.join(
@@ -777,6 +781,21 @@ var FontFaceRule = class {
777
781
 
778
782
  // src/core/compare-media.ts
779
783
  var compareMedia = (optionA, optionB) => {
784
+ if (optionA.condition !== void 0 && optionB.condition !== void 0) {
785
+ return optionA.condition.localeCompare(optionB.condition);
786
+ }
787
+ if (optionA.condition !== void 0) {
788
+ if (optionB.minWidth === void 0 && optionB.maxWidth === void 0) {
789
+ return 1;
790
+ }
791
+ return -1;
792
+ }
793
+ if (optionB.condition !== void 0) {
794
+ if (optionA.minWidth === void 0 && optionA.maxWidth === void 0) {
795
+ return -1;
796
+ }
797
+ return 1;
798
+ }
780
799
  if (optionA.minWidth === void 0 && optionA.maxWidth === void 0) {
781
800
  return -1;
782
801
  }
@@ -831,6 +850,22 @@ var StyleElement = class {
831
850
  }
832
851
  }
833
852
  };
853
+ var FakeStyleElement = class {
854
+ get isMounted() {
855
+ return false;
856
+ }
857
+ mount() {
858
+ }
859
+ unmount() {
860
+ }
861
+ render(_cssText) {
862
+ }
863
+ setAttribute(_name, _value) {
864
+ }
865
+ getAttribute(_name) {
866
+ return;
867
+ }
868
+ };
834
869
 
835
870
  // src/core/style-sheet.ts
836
871
  var StyleSheet = class {
@@ -951,7 +986,7 @@ var StyleSheetRegular = class extends StyleSheet {
951
986
 
952
987
  // src/core/create-style-sheet.ts
953
988
  var createRegularStyleSheet = (options) => {
954
- const element = new StyleElement(options?.name);
989
+ const element = options?.element ?? new StyleElement(options?.name);
955
990
  return new StyleSheetRegular(element);
956
991
  };
957
992
 
@@ -964,7 +999,7 @@ var matchMedia = (options, width) => {
964
999
 
965
1000
  // src/core/equal-media.ts
966
1001
  var equalMedia = (left, right) => {
967
- return left.minWidth === right.minWidth && left.maxWidth === right.maxWidth;
1002
+ return left.minWidth === right.minWidth && left.maxWidth === right.maxWidth && left.condition === right.condition;
968
1003
  };
969
1004
 
970
1005
  // src/core/find-applicable-media.ts
@@ -1021,6 +1056,7 @@ var generateAtomic = (sheet, options) => {
1021
1056
  };
1022
1057
  export {
1023
1058
  ColorValue,
1059
+ FakeStyleElement,
1024
1060
  FunctionValue,
1025
1061
  GuaranteedInvalidValue,
1026
1062
  ImageValue,
@@ -1,6 +1,9 @@
1
1
  import type { MediaRuleOptions } from "./rules";
2
2
  /**
3
- * Sort by minWidth descending or maxWidth ascending
4
- * We want media querries with bigger minWidth to override the smaller once, but the smaller maxWidth to override the bigger once.
3
+ * Sort media queries for CSS cascade order.
4
+ * Width-based: minWidth descending, then maxWidth ascending
5
+ * Custom conditions: sorted alphabetically, placed between base and width-based
6
+ *
7
+ * Note: minWidth/maxWidth and condition are mutually exclusive in MediaRuleOptions.
5
8
  */
6
9
  export declare const compareMedia: (optionA: MediaRuleOptions, optionB: MediaRuleOptions) => number;
@@ -1,4 +1,6 @@
1
1
  import { StyleSheetRegular } from "./style-sheet-regular";
2
+ import { StyleElement, FakeStyleElement } from "./style-element";
2
3
  export declare const createRegularStyleSheet: (options?: {
3
4
  name?: string;
5
+ element?: StyleElement | FakeStyleElement;
4
6
  }) => StyleSheetRegular;
@@ -1,2 +1,6 @@
1
1
  import type { MediaRuleOptions } from "./rules";
2
+ /**
3
+ * Compare two media query options for equality.
4
+ * Note: minWidth/maxWidth and condition are mutually exclusive.
5
+ */
2
6
  export declare const equalMedia: (left: MediaRuleOptions, right: MediaRuleOptions) => boolean;
@@ -1,2 +1,7 @@
1
1
  import type { MediaRuleOptions } from "./rules";
2
+ /**
3
+ * Find the applicable media rule that matches the given width.
4
+ * Only matches width-based breakpoints (minWidth/maxWidth).
5
+ * Custom condition breakpoints are not matched by this function.
6
+ */
2
7
  export declare const findApplicableMedia: <Media extends MediaRuleOptions>(media: Array<Media>, width: number) => Media | undefined;
@@ -4,6 +4,7 @@ export { mergeStyles } from "./merger";
4
4
  export { generateStyleMap } from "./rules";
5
5
  export type { StyleSheetRegular } from "./style-sheet-regular";
6
6
  export * from "./create-style-sheet";
7
+ export { FakeStyleElement } from "./style-element";
7
8
  export * from "./to-value";
8
9
  export { hyphenateProperty } from "./to-property";
9
10
  export * from "./match-media";
@@ -1,2 +1,7 @@
1
1
  import type { MediaRuleOptions } from "./rules";
2
+ /**
3
+ * Check if a media query matches a given width.
4
+ * Only applies to width-based breakpoints (minWidth/maxWidth).
5
+ * Custom condition breakpoints are not matched by this function.
6
+ */
2
7
  export declare const matchMedia: (options: MediaRuleOptions, width: number) => boolean;
@@ -68,9 +68,16 @@ export declare class NestingRule {
68
68
  transformValue?: TransformValue;
69
69
  }): string;
70
70
  }
71
+ /**
72
+ * Options for media queries.
73
+ * Note: minWidth/maxWidth and condition are mutually exclusive.
74
+ * If condition is set, minWidth and maxWidth must be undefined.
75
+ * If minWidth or maxWidth is set, condition must be undefined.
76
+ */
71
77
  export type MediaRuleOptions = {
72
78
  minWidth?: number;
73
79
  maxWidth?: number;
80
+ condition?: string;
74
81
  mediaType?: "all" | "screen" | "print";
75
82
  };
76
83
  export declare class MediaRule {
@@ -0,0 +1 @@
1
+ export {};
@@ -8,3 +8,15 @@ export declare class StyleElement {
8
8
  setAttribute(name: string, value: string): void;
9
9
  getAttribute(name: string): string | null | undefined;
10
10
  }
11
+ /**
12
+ * A fake style element that does nothing.
13
+ * Useful for testing stylesheets without DOM.
14
+ */
15
+ export declare class FakeStyleElement {
16
+ get isMounted(): boolean;
17
+ mount(): void;
18
+ unmount(): void;
19
+ render(_cssText: string): void;
20
+ setAttribute(_name: string, _value: string): void;
21
+ getAttribute(_name: string): void;
22
+ }
@@ -1,10 +1,10 @@
1
1
  import { MediaRule, MixinRule, NestingRule, PlaintextRule, type FontFaceOptions, type MediaRuleOptions } from "./rules";
2
- import { StyleElement } from "./style-element";
2
+ import { StyleElement, FakeStyleElement } from "./style-element";
3
3
  import type { TransformValue } from "./to-value";
4
4
  export declare class StyleSheet {
5
5
  #private;
6
6
  nestingRules: Map<string, NestingRule>;
7
- constructor(element: StyleElement);
7
+ constructor(element: StyleElement | FakeStyleElement);
8
8
  setTransformer(transformValue: TransformValue): void;
9
9
  addMediaRule(id: string, options?: MediaRuleOptions): MediaRule;
10
10
  addPlaintextRule(cssText: string): PlaintextRule | Map<string, PlaintextRule>;
@@ -20,5 +20,5 @@ export declare class StyleSheet {
20
20
  render(): void;
21
21
  unmount(): void;
22
22
  setAttribute(name: string, value: string): void;
23
- getAttribute(name: string): string | null | undefined;
23
+ getAttribute(name: string): string | void | null;
24
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstudio-is/css-engine",
3
- "version": "0.237.0",
3
+ "version": "0.252.1",
4
4
  "description": "CSS Renderer for Webstudio",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -8,7 +8,7 @@
8
8
  "dependencies": {
9
9
  "@emotion/hash": "^0.9.2",
10
10
  "zod": "^3.24.2",
11
- "@webstudio-is/fonts": "0.237.0"
11
+ "@webstudio-is/fonts": "0.252.1"
12
12
  },
13
13
  "devDependencies": {
14
14
  "@types/react": "^18.2.70",
@@ -38,7 +38,7 @@
38
38
  "private": false,
39
39
  "sideEffects": false,
40
40
  "scripts": {
41
- "typecheck": "tsc",
41
+ "typecheck": "tsgo --noEmit",
42
42
  "build": "rm -rf lib && esbuild src/index.ts --outdir=lib --bundle --format=esm --packages=external && esbuild src/runtime.ts --outdir=lib --bundle --format=esm --packages=external",
43
43
  "dts": "tsc --project tsconfig.dts.json",
44
44
  "test": "vitest run"