@webstudio-is/css-engine 0.49.0 → 0.51.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/cjs/core/index.cjs +1 -0
- package/lib/cjs/core/match-media.cjs +28 -0
- package/lib/cjs/core/rules.cjs +7 -6
- package/lib/cjs/core/to-property.cjs +4 -0
- package/lib/core/index.js +1 -0
- package/lib/core/match-media.js +8 -0
- package/lib/core/rules.js +7 -6
- package/package.json +3 -3
- package/src/core/css-engine.test.ts +39 -0
- package/src/core/index.ts +1 -0
- package/src/core/match-media.test.ts +24 -0
- package/src/core/match-media.ts +7 -0
- package/src/core/rules.ts +4 -6
package/lib/cjs/core/index.cjs
CHANGED
|
@@ -25,3 +25,4 @@ module.exports = __toCommonJS(core_exports);
|
|
|
25
25
|
var import_css_engine = require("./css-engine");
|
|
26
26
|
__reExport(core_exports, require("./create-css-engine"), module.exports);
|
|
27
27
|
__reExport(core_exports, require("./to-value"), module.exports);
|
|
28
|
+
__reExport(core_exports, require("./match-media"), module.exports);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var match_media_exports = {};
|
|
20
|
+
__export(match_media_exports, {
|
|
21
|
+
matchMedia: () => matchMedia
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(match_media_exports);
|
|
24
|
+
const matchMedia = (options, width) => {
|
|
25
|
+
const minWidth = options.minWidth ?? Number.MIN_SAFE_INTEGER;
|
|
26
|
+
const maxWidth = options.maxWidth ?? Number.MAX_SAFE_INTEGER;
|
|
27
|
+
return width >= minWidth && width <= maxWidth;
|
|
28
|
+
};
|
package/lib/cjs/core/rules.cjs
CHANGED
|
@@ -116,6 +116,10 @@ class MediaRule {
|
|
|
116
116
|
this.options = options;
|
|
117
117
|
__privateSet(this, _mediaType, options.mediaType ?? "all");
|
|
118
118
|
}
|
|
119
|
+
// Sort media rules by minWidth.
|
|
120
|
+
// Needed to ensure that more specific media rules are inserted after less specific ones.
|
|
121
|
+
// So that they get a higher specificity.
|
|
122
|
+
// @todo remove this once we have ability to control order from the UI
|
|
119
123
|
static sort(mediaRules) {
|
|
120
124
|
return Array.from(mediaRules).sort((ruleA, ruleB) => {
|
|
121
125
|
return (ruleA.options.minWidth ?? -Number.MAX_SAFE_INTEGER) - (ruleB.options.minWidth ?? -Number.MAX_SAFE_INTEGER);
|
|
@@ -136,15 +140,12 @@ class MediaRule {
|
|
|
136
140
|
let conditionText = "";
|
|
137
141
|
const { minWidth, maxWidth } = this.options;
|
|
138
142
|
if (minWidth !== void 0) {
|
|
139
|
-
conditionText = `min-width: ${minWidth}px`;
|
|
143
|
+
conditionText = ` and (min-width: ${minWidth}px)`;
|
|
140
144
|
}
|
|
141
145
|
if (maxWidth !== void 0) {
|
|
142
|
-
conditionText
|
|
146
|
+
conditionText += ` and (max-width: ${maxWidth}px)`;
|
|
143
147
|
}
|
|
144
|
-
|
|
145
|
-
conditionText = `and (${conditionText}) `;
|
|
146
|
-
}
|
|
147
|
-
return `@media ${__privateGet(this, _mediaType)} ${conditionText}{
|
|
148
|
+
return `@media ${__privateGet(this, _mediaType)}${conditionText} {
|
|
148
149
|
${rules.join(
|
|
149
150
|
"\n"
|
|
150
151
|
)}
|
|
@@ -18,6 +18,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
20
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
26
|
mod
|
|
23
27
|
));
|
package/lib/core/index.js
CHANGED
package/lib/core/rules.js
CHANGED
|
@@ -90,6 +90,10 @@ class MediaRule {
|
|
|
90
90
|
this.options = options;
|
|
91
91
|
__privateSet(this, _mediaType, options.mediaType ?? "all");
|
|
92
92
|
}
|
|
93
|
+
// Sort media rules by minWidth.
|
|
94
|
+
// Needed to ensure that more specific media rules are inserted after less specific ones.
|
|
95
|
+
// So that they get a higher specificity.
|
|
96
|
+
// @todo remove this once we have ability to control order from the UI
|
|
93
97
|
static sort(mediaRules) {
|
|
94
98
|
return Array.from(mediaRules).sort((ruleA, ruleB) => {
|
|
95
99
|
return (ruleA.options.minWidth ?? -Number.MAX_SAFE_INTEGER) - (ruleB.options.minWidth ?? -Number.MAX_SAFE_INTEGER);
|
|
@@ -110,15 +114,12 @@ class MediaRule {
|
|
|
110
114
|
let conditionText = "";
|
|
111
115
|
const { minWidth, maxWidth } = this.options;
|
|
112
116
|
if (minWidth !== void 0) {
|
|
113
|
-
conditionText = `min-width: ${minWidth}px`;
|
|
117
|
+
conditionText = ` and (min-width: ${minWidth}px)`;
|
|
114
118
|
}
|
|
115
119
|
if (maxWidth !== void 0) {
|
|
116
|
-
conditionText
|
|
120
|
+
conditionText += ` and (max-width: ${maxWidth}px)`;
|
|
117
121
|
}
|
|
118
|
-
|
|
119
|
-
conditionText = `and (${conditionText}) `;
|
|
120
|
-
}
|
|
121
|
-
return `@media ${__privateGet(this, _mediaType)} ${conditionText}{
|
|
122
|
+
return `@media ${__privateGet(this, _mediaType)}${conditionText} {
|
|
122
123
|
${rules.join(
|
|
123
124
|
"\n"
|
|
124
125
|
)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webstudio-is/css-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"description": "CSS Renderer for Webstudio",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"hyphenate-style-name": "^1.0.4",
|
|
10
10
|
"react": "^17.0.2",
|
|
11
11
|
"react-dom": "^17.0.2",
|
|
12
|
-
"@webstudio-is/fonts": "^0.
|
|
12
|
+
"@webstudio-is/fonts": "^0.51.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@jest/globals": "^29.3.1",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@types/react-dom": "^17.0.9",
|
|
20
20
|
"jest": "^29.3.1",
|
|
21
21
|
"typescript": "4.9.5",
|
|
22
|
-
"@webstudio-is/css-data": "^0.
|
|
22
|
+
"@webstudio-is/css-data": "^0.51.0",
|
|
23
23
|
"@webstudio-is/jest-config": "^1.0.2",
|
|
24
24
|
"@webstudio-is/scripts": "^0.0.0",
|
|
25
25
|
"@webstudio-is/storybook-config": "^0.0.0",
|
|
@@ -29,6 +29,45 @@ describe("CssEngine", () => {
|
|
|
29
29
|
|
|
30
30
|
beforeEach(reset);
|
|
31
31
|
|
|
32
|
+
test("minWidth media rule", () => {
|
|
33
|
+
engine.addMediaRule("0", { minWidth: 0 });
|
|
34
|
+
engine.addStyleRule(".c1", {
|
|
35
|
+
style: { color: { type: "keyword", value: "red" } },
|
|
36
|
+
breakpoint: "0",
|
|
37
|
+
});
|
|
38
|
+
expect(engine.cssText).toMatchInlineSnapshot(`
|
|
39
|
+
"@media all and (min-width: 0px) {
|
|
40
|
+
.c1 { color: red }
|
|
41
|
+
}"
|
|
42
|
+
`);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("maxWidth media rule", () => {
|
|
46
|
+
engine.addMediaRule("0", { maxWidth: 1000 });
|
|
47
|
+
engine.addStyleRule(".c1", {
|
|
48
|
+
style: { color: { type: "keyword", value: "red" } },
|
|
49
|
+
breakpoint: "0",
|
|
50
|
+
});
|
|
51
|
+
expect(engine.cssText).toMatchInlineSnapshot(`
|
|
52
|
+
"@media all and (max-width: 1000px) {
|
|
53
|
+
.c1 { color: red }
|
|
54
|
+
}"
|
|
55
|
+
`);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("maxWidth and maxWith media rule", () => {
|
|
59
|
+
engine.addMediaRule("0", { maxWidth: 1000, minWidth: 360 });
|
|
60
|
+
engine.addStyleRule(".c1", {
|
|
61
|
+
style: { color: { type: "keyword", value: "red" } },
|
|
62
|
+
breakpoint: "0",
|
|
63
|
+
});
|
|
64
|
+
expect(engine.cssText).toMatchInlineSnapshot(`
|
|
65
|
+
"@media all and (min-width: 360px) and (max-width: 1000px) {
|
|
66
|
+
.c1 { color: red }
|
|
67
|
+
}"
|
|
68
|
+
`);
|
|
69
|
+
});
|
|
70
|
+
|
|
32
71
|
test("use default media rule when there is no matching one registered", () => {
|
|
33
72
|
engine.addStyleRule(".c", {
|
|
34
73
|
style: style0,
|
package/src/core/index.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { matchMedia } from "./match-media";
|
|
3
|
+
|
|
4
|
+
describe("matchMedia", () => {
|
|
5
|
+
test("minWidth", () => {
|
|
6
|
+
expect(matchMedia({ minWidth: 100 }, 10)).toBe(false);
|
|
7
|
+
expect(matchMedia({ minWidth: 100 }, 100)).toBe(true);
|
|
8
|
+
expect(matchMedia({ minWidth: 100 }, 101)).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("maxWidth", () => {
|
|
12
|
+
expect(matchMedia({ maxWidth: 100 }, 101)).toBe(false);
|
|
13
|
+
expect(matchMedia({ maxWidth: 100 }, 100)).toBe(true);
|
|
14
|
+
expect(matchMedia({ maxWidth: 100 }, 10)).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("minWidth and maxWidth", () => {
|
|
18
|
+
expect(matchMedia({ maxWidth: 100, minWidth: 10 }, 9)).toBe(false);
|
|
19
|
+
expect(matchMedia({ maxWidth: 100, minWidth: 10 }, 101)).toBe(false);
|
|
20
|
+
expect(matchMedia({ maxWidth: 100, minWidth: 10 }, 100)).toBe(true);
|
|
21
|
+
expect(matchMedia({ maxWidth: 100, minWidth: 10 }, 10)).toBe(true);
|
|
22
|
+
expect(matchMedia({ maxWidth: 100, minWidth: 10 }, 11)).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MediaRuleOptions } from "./rules";
|
|
2
|
+
|
|
3
|
+
export const matchMedia = (options: MediaRuleOptions, width: number) => {
|
|
4
|
+
const minWidth = options.minWidth ?? Number.MIN_SAFE_INTEGER;
|
|
5
|
+
const maxWidth = options.maxWidth ?? Number.MAX_SAFE_INTEGER;
|
|
6
|
+
return width >= minWidth && width <= maxWidth;
|
|
7
|
+
};
|
package/src/core/rules.ts
CHANGED
|
@@ -76,6 +76,7 @@ export class MediaRule {
|
|
|
76
76
|
// Sort media rules by minWidth.
|
|
77
77
|
// Needed to ensure that more specific media rules are inserted after less specific ones.
|
|
78
78
|
// So that they get a higher specificity.
|
|
79
|
+
// @todo remove this once we have ability to control order from the UI
|
|
79
80
|
static sort(mediaRules: Iterable<MediaRule>) {
|
|
80
81
|
return Array.from(mediaRules).sort((ruleA, ruleB) => {
|
|
81
82
|
return (
|
|
@@ -106,15 +107,12 @@ export class MediaRule {
|
|
|
106
107
|
let conditionText = "";
|
|
107
108
|
const { minWidth, maxWidth } = this.options;
|
|
108
109
|
if (minWidth !== undefined) {
|
|
109
|
-
conditionText = `min-width: ${minWidth}px`;
|
|
110
|
+
conditionText = ` and (min-width: ${minWidth}px)`;
|
|
110
111
|
}
|
|
111
112
|
if (maxWidth !== undefined) {
|
|
112
|
-
conditionText
|
|
113
|
+
conditionText += ` and (max-width: ${maxWidth}px)`;
|
|
113
114
|
}
|
|
114
|
-
|
|
115
|
-
conditionText = `and (${conditionText}) `;
|
|
116
|
-
}
|
|
117
|
-
return `@media ${this.#mediaType} ${conditionText}{\n${rules.join(
|
|
115
|
+
return `@media ${this.#mediaType}${conditionText} {\n${rules.join(
|
|
118
116
|
"\n"
|
|
119
117
|
)}\n}`;
|
|
120
118
|
}
|