@webstudio-is/css-engine 0.51.0 → 0.53.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/compare-media.js +32 -0
- package/lib/cjs/core/{css-engine.cjs → css-engine.js} +5 -1
- package/lib/cjs/core/equal-media.js +26 -0
- package/lib/cjs/core/{index.cjs → index.js} +2 -0
- package/lib/cjs/core/{rules.cjs → rules.js} +0 -9
- package/lib/cjs/package.json +1 -0
- package/lib/core/compare-media.js +12 -0
- package/lib/core/css-engine.js +5 -1
- package/lib/core/equal-media.js +6 -0
- package/lib/core/index.js +2 -0
- package/lib/core/rules.js +0 -9
- package/lib/types/core/compare-media.d.ts +6 -0
- package/lib/types/core/compare-media.test.d.ts +1 -0
- package/lib/types/core/create-css-engine.d.ts +2 -0
- package/lib/types/core/css-engine.d.ts +19 -0
- package/lib/types/core/css-engine.stories.d.ts +6 -0
- package/lib/types/core/css-engine.test.d.ts +1 -0
- package/lib/types/core/equal-media.d.ts +2 -0
- package/lib/types/core/equal-media.test.d.ts +1 -0
- package/lib/types/core/index.d.ts +7 -0
- package/lib/types/core/match-media.d.ts +2 -0
- package/lib/types/core/match-media.test.d.ts +1 -0
- package/lib/types/core/rules.d.ts +51 -0
- package/lib/types/core/style-element.d.ts +10 -0
- package/lib/types/core/style-sheet.d.ts +6 -0
- package/lib/types/core/to-property.d.ts +2 -0
- package/lib/types/core/to-property.test.d.ts +1 -0
- package/lib/types/core/to-value.d.ts +6 -0
- package/lib/types/core/to-value.test.d.ts +1 -0
- package/lib/types/index.d.ts +1 -0
- package/package.json +6 -5
- package/src/core/compare-media.test.ts +40 -0
- package/src/core/compare-media.ts +18 -0
- package/src/core/css-engine.ts +6 -1
- package/src/core/equal-media.test.ts +31 -0
- package/src/core/equal-media.ts +5 -0
- package/src/core/index.ts +2 -0
- package/src/core/rules.ts +0 -12
- /package/lib/cjs/core/{create-css-engine.cjs → create-css-engine.js} +0 -0
- /package/lib/cjs/core/{match-media.cjs → match-media.js} +0 -0
- /package/lib/cjs/core/{style-element.cjs → style-element.js} +0 -0
- /package/lib/cjs/core/{style-sheet.cjs → style-sheet.js} +0 -0
- /package/lib/cjs/core/{to-property.cjs → to-property.js} +0 -0
- /package/lib/cjs/core/{to-value.cjs → to-value.js} +0 -0
- /package/lib/cjs/{index.cjs → index.js} +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
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 compare_media_exports = {};
|
|
20
|
+
__export(compare_media_exports, {
|
|
21
|
+
compareMedia: () => compareMedia
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(compare_media_exports);
|
|
24
|
+
const compareMedia = (optionA, optionB) => {
|
|
25
|
+
if (optionA?.minWidth !== void 0 && optionB?.minWidth !== void 0) {
|
|
26
|
+
return optionA.minWidth - optionB.minWidth;
|
|
27
|
+
}
|
|
28
|
+
if (optionA?.maxWidth !== void 0 && optionB?.maxWidth !== void 0) {
|
|
29
|
+
return optionB.maxWidth - optionA.maxWidth;
|
|
30
|
+
}
|
|
31
|
+
return "minWidth" in optionA ? 1 : -1;
|
|
32
|
+
};
|
|
@@ -40,6 +40,7 @@ __export(css_engine_exports, {
|
|
|
40
40
|
});
|
|
41
41
|
module.exports = __toCommonJS(css_engine_exports);
|
|
42
42
|
var import_rules = require("./rules");
|
|
43
|
+
var import_compare_media = require("./compare-media");
|
|
43
44
|
var import_style_element = require("./style-element");
|
|
44
45
|
var import_style_sheet = require("./style-sheet");
|
|
45
46
|
var _element, _mediaRules, _plainRules, _fontFaceRules, _sheet, _isDirty, _cssText, _onChangeRule;
|
|
@@ -120,7 +121,10 @@ class CssEngine {
|
|
|
120
121
|
for (const plaintextRule of __privateGet(this, _plainRules).values()) {
|
|
121
122
|
css.push(plaintextRule.cssText);
|
|
122
123
|
}
|
|
123
|
-
|
|
124
|
+
const sortedMediaRules = Array.from(__privateGet(this, _mediaRules).values()).sort(
|
|
125
|
+
(ruleA, ruleB) => (0, import_compare_media.compareMedia)(ruleA.options, ruleB.options)
|
|
126
|
+
);
|
|
127
|
+
for (const mediaRule of sortedMediaRules) {
|
|
124
128
|
const { cssText } = mediaRule;
|
|
125
129
|
if (cssText !== "") {
|
|
126
130
|
css.push(cssText);
|
|
@@ -0,0 +1,26 @@
|
|
|
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 equal_media_exports = {};
|
|
20
|
+
__export(equal_media_exports, {
|
|
21
|
+
equalMedia: () => equalMedia
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(equal_media_exports);
|
|
24
|
+
const equalMedia = (left, right) => {
|
|
25
|
+
return left.minWidth === right.minWidth && left.maxWidth === right.maxWidth;
|
|
26
|
+
};
|
|
@@ -26,3 +26,5 @@ 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
28
|
__reExport(core_exports, require("./match-media"), module.exports);
|
|
29
|
+
__reExport(core_exports, require("./equal-media"), module.exports);
|
|
30
|
+
__reExport(core_exports, require("./compare-media"), module.exports);
|
|
@@ -116,15 +116,6 @@ 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
|
|
123
|
-
static sort(mediaRules) {
|
|
124
|
-
return Array.from(mediaRules).sort((ruleA, ruleB) => {
|
|
125
|
-
return (ruleA.options.minWidth ?? -Number.MAX_SAFE_INTEGER) - (ruleB.options.minWidth ?? -Number.MAX_SAFE_INTEGER);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
119
|
insertRule(rule) {
|
|
129
120
|
this.rules.push(rule);
|
|
130
121
|
return rule;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const compareMedia = (optionA, optionB) => {
|
|
2
|
+
if (optionA?.minWidth !== void 0 && optionB?.minWidth !== void 0) {
|
|
3
|
+
return optionA.minWidth - optionB.minWidth;
|
|
4
|
+
}
|
|
5
|
+
if (optionA?.maxWidth !== void 0 && optionB?.maxWidth !== void 0) {
|
|
6
|
+
return optionB.maxWidth - optionA.maxWidth;
|
|
7
|
+
}
|
|
8
|
+
return "minWidth" in optionA ? 1 : -1;
|
|
9
|
+
};
|
|
10
|
+
export {
|
|
11
|
+
compareMedia
|
|
12
|
+
};
|
package/lib/core/css-engine.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
PlaintextRule,
|
|
24
24
|
StyleRule
|
|
25
25
|
} from "./rules";
|
|
26
|
+
import { compareMedia } from "./compare-media";
|
|
26
27
|
import { StyleElement } from "./style-element";
|
|
27
28
|
import { StyleSheet } from "./style-sheet";
|
|
28
29
|
const defaultMediaRuleId = "__default-media-rule__";
|
|
@@ -102,7 +103,10 @@ class CssEngine {
|
|
|
102
103
|
for (const plaintextRule of __privateGet(this, _plainRules).values()) {
|
|
103
104
|
css.push(plaintextRule.cssText);
|
|
104
105
|
}
|
|
105
|
-
|
|
106
|
+
const sortedMediaRules = Array.from(__privateGet(this, _mediaRules).values()).sort(
|
|
107
|
+
(ruleA, ruleB) => compareMedia(ruleA.options, ruleB.options)
|
|
108
|
+
);
|
|
109
|
+
for (const mediaRule of sortedMediaRules) {
|
|
106
110
|
const { cssText } = mediaRule;
|
|
107
111
|
if (cssText !== "") {
|
|
108
112
|
css.push(cssText);
|
package/lib/core/index.js
CHANGED
package/lib/core/rules.js
CHANGED
|
@@ -90,15 +90,6 @@ 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
|
|
97
|
-
static sort(mediaRules) {
|
|
98
|
-
return Array.from(mediaRules).sort((ruleA, ruleB) => {
|
|
99
|
-
return (ruleA.options.minWidth ?? -Number.MAX_SAFE_INTEGER) - (ruleB.options.minWidth ?? -Number.MAX_SAFE_INTEGER);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
93
|
insertRule(rule) {
|
|
103
94
|
this.rules.push(rule);
|
|
104
95
|
return rule;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MediaRuleOptions } from "./rules";
|
|
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.
|
|
5
|
+
*/
|
|
6
|
+
export declare const compareMedia: (optionA: MediaRuleOptions, optionB: MediaRuleOptions) => number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CssRule } from "@webstudio-is/css-data";
|
|
2
|
+
import { MediaRule, PlaintextRule, StyleRule, type FontFaceOptions, type MediaRuleOptions } from "./rules";
|
|
3
|
+
export type CssEngineOptions = {
|
|
4
|
+
name?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class CssEngine {
|
|
7
|
+
#private;
|
|
8
|
+
constructor({ name }: CssEngineOptions);
|
|
9
|
+
addMediaRule(id: string, options?: MediaRuleOptions): MediaRule;
|
|
10
|
+
addStyleRule(selectorText: string, rule: CssRule): StyleRule;
|
|
11
|
+
addPlaintextRule(cssText: string): PlaintextRule | Map<string, PlaintextRule>;
|
|
12
|
+
addFontFaceRule(options: FontFaceOptions): number;
|
|
13
|
+
clear(): void;
|
|
14
|
+
render(): void;
|
|
15
|
+
unmount(): void;
|
|
16
|
+
setAttribute(name: string, value: string): void;
|
|
17
|
+
getAttribute(name: string): string | null | undefined;
|
|
18
|
+
get cssText(): string;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CssEngine } from "./css-engine";
|
|
2
|
+
export type { AnyRule, StyleRule, MediaRule, PlaintextRule, FontFaceRule, } from "./rules";
|
|
3
|
+
export * from "./create-css-engine";
|
|
4
|
+
export * from "./to-value";
|
|
5
|
+
export * from "./match-media";
|
|
6
|
+
export * from "./equal-media";
|
|
7
|
+
export * from "./compare-media";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Style, StyleProperty, StyleValue } from "@webstudio-is/css-data";
|
|
2
|
+
declare class StylePropertyMap {
|
|
3
|
+
#private;
|
|
4
|
+
onChange?: () => void;
|
|
5
|
+
set(property: StyleProperty, value?: StyleValue): void;
|
|
6
|
+
has(property: StyleProperty): boolean;
|
|
7
|
+
keys(): IterableIterator<"color" | "left" | "right" | "top" | "bottom" | "contain" | "clip" | "content" | "filter" | "float" | "fontFamily" | "width" | "height" | `--${string}` | "accentColor" | "alignContent" | "alignItems" | "alignSelf" | "alignTracks" | "animationComposition" | "animationDelay" | "animationDirection" | "animationDuration" | "animationFillMode" | "animationIterationCount" | "animationName" | "animationPlayState" | "animationTimingFunction" | "animationTimeline" | "appearance" | "aspectRatio" | "backdropFilter" | "backfaceVisibility" | "backgroundAttachment" | "backgroundBlendMode" | "backgroundClip" | "backgroundColor" | "backgroundImage" | "backgroundOrigin" | "backgroundPosition" | "backgroundPositionX" | "backgroundPositionY" | "backgroundRepeat" | "backgroundSize" | "blockOverflow" | "blockSize" | "borderBlockColor" | "borderBlockStyle" | "borderBlockWidth" | "borderBlockEndColor" | "borderBlockEndStyle" | "borderBlockEndWidth" | "borderBlockStartColor" | "borderBlockStartStyle" | "borderBlockStartWidth" | "borderBottomColor" | "borderBottomLeftRadius" | "borderBottomRightRadius" | "borderBottomStyle" | "borderBottomWidth" | "borderCollapse" | "borderEndEndRadius" | "borderEndStartRadius" | "borderImageOutset" | "borderImageRepeat" | "borderImageSlice" | "borderImageSource" | "borderImageWidth" | "borderInlineColor" | "borderInlineStyle" | "borderInlineWidth" | "borderInlineEndColor" | "borderInlineEndStyle" | "borderInlineEndWidth" | "borderInlineStartColor" | "borderInlineStartStyle" | "borderInlineStartWidth" | "borderLeftColor" | "borderLeftStyle" | "borderLeftWidth" | "borderRightColor" | "borderRightStyle" | "borderRightWidth" | "borderSpacing" | "borderStartEndRadius" | "borderStartStartRadius" | "borderTopColor" | "borderTopLeftRadius" | "borderTopRightRadius" | "borderTopStyle" | "borderTopWidth" | "boxDecorationBreak" | "boxShadow" | "boxSizing" | "breakAfter" | "breakBefore" | "breakInside" | "captionSide" | "caretColor" | "caretShape" | "clear" | "clipPath" | "printColorAdjust" | "colorScheme" | "columnCount" | "columnFill" | "columnGap" | "columnRuleColor" | "columnRuleStyle" | "columnRuleWidth" | "columnSpan" | "columnWidth" | "containIntrinsicBlockSize" | "containIntrinsicHeight" | "containIntrinsicInlineSize" | "containIntrinsicWidth" | "contentVisibility" | "counterIncrement" | "counterReset" | "counterSet" | "cursor" | "direction" | "display" | "emptyCells" | "flexBasis" | "flexDirection" | "flexGrow" | "flexShrink" | "flexWrap" | "fontFeatureSettings" | "fontKerning" | "fontLanguageOverride" | "fontOpticalSizing" | "fontVariationSettings" | "fontSize" | "fontSizeAdjust" | "fontStretch" | "fontStyle" | "fontSynthesis" | "fontVariant" | "fontVariantAlternates" | "fontVariantCaps" | "fontVariantEastAsian" | "fontVariantLigatures" | "fontVariantNumeric" | "fontVariantPosition" | "fontWeight" | "forcedColorAdjust" | "gridAutoColumns" | "gridAutoFlow" | "gridAutoRows" | "gridColumnEnd" | "gridColumnStart" | "gridRowEnd" | "gridRowStart" | "gridTemplateAreas" | "gridTemplateColumns" | "gridTemplateRows" | "hangingPunctuation" | "hyphenateCharacter" | "hyphens" | "imageOrientation" | "imageRendering" | "imageResolution" | "initialLetter" | "initialLetterAlign" | "inlineSize" | "inputSecurity" | "insetBlockEnd" | "insetBlockStart" | "insetInlineEnd" | "insetInlineStart" | "isolation" | "justifyContent" | "justifyItems" | "justifySelf" | "justifyTracks" | "letterSpacing" | "lineBreak" | "lineClamp" | "lineHeight" | "lineHeightStep" | "listStyleImage" | "listStylePosition" | "listStyleType" | "marginBlockEnd" | "marginBlockStart" | "marginBottom" | "marginInlineEnd" | "marginInlineStart" | "marginLeft" | "marginRight" | "marginTop" | "marginTrim" | "maskBorderMode" | "maskBorderOutset" | "maskBorderRepeat" | "maskBorderSlice" | "maskBorderSource" | "maskBorderWidth" | "maskClip" | "maskComposite" | "maskImage" | "maskMode" | "maskOrigin" | "maskPosition" | "maskRepeat" | "maskSize" | "maskType" | "masonryAutoFlow" | "mathDepth" | "mathShift" | "mathStyle" | "maxBlockSize" | "maxHeight" | "maxInlineSize" | "maxLines" | "maxWidth" | "minBlockSize" | "minHeight" | "minInlineSize" | "minWidth" | "mixBlendMode" | "objectFit" | "objectPosition" | "offsetAnchor" | "offsetDistance" | "offsetPath" | "offsetPosition" | "offsetRotate" | "opacity" | "order" | "orphans" | "outlineColor" | "outlineOffset" | "outlineStyle" | "outlineWidth" | "overflow" | "overflowAnchor" | "overflowBlock" | "overflowClipMargin" | "overflowInline" | "overflowWrap" | "overflowX" | "overflowY" | "overscrollBehavior" | "overscrollBehaviorBlock" | "overscrollBehaviorInline" | "overscrollBehaviorX" | "overscrollBehaviorY" | "paddingBlockEnd" | "paddingBlockStart" | "paddingBottom" | "paddingInlineEnd" | "paddingInlineStart" | "paddingLeft" | "paddingRight" | "paddingTop" | "pageBreakAfter" | "pageBreakBefore" | "pageBreakInside" | "paintOrder" | "perspective" | "perspectiveOrigin" | "pointerEvents" | "position" | "quotes" | "resize" | "rotate" | "rowGap" | "rubyAlign" | "rubyMerge" | "rubyPosition" | "scale" | "scrollbarColor" | "scrollbarGutter" | "scrollbarWidth" | "scrollBehavior" | "scrollMarginBlockStart" | "scrollMarginBlockEnd" | "scrollMarginBottom" | "scrollMarginInlineStart" | "scrollMarginInlineEnd" | "scrollMarginLeft" | "scrollMarginRight" | "scrollMarginTop" | "scrollPaddingBlockStart" | "scrollPaddingBlockEnd" | "scrollPaddingBottom" | "scrollPaddingInlineStart" | "scrollPaddingInlineEnd" | "scrollPaddingLeft" | "scrollPaddingRight" | "scrollPaddingTop" | "scrollSnapAlign" | "scrollSnapStop" | "scrollSnapType" | "scrollTimelineAxis" | "scrollTimelineName" | "shapeImageThreshold" | "shapeMargin" | "shapeOutside" | "tabSize" | "tableLayout" | "textAlign" | "textAlignLast" | "textCombineUpright" | "textDecorationColor" | "textDecorationLine" | "textDecorationSkip" | "textDecorationSkipInk" | "textDecorationStyle" | "textDecorationThickness" | "textEmphasisColor" | "textEmphasisPosition" | "textEmphasisStyle" | "textIndent" | "textJustify" | "textOrientation" | "textOverflow" | "textRendering" | "textShadow" | "textSizeAdjust" | "textTransform" | "textUnderlineOffset" | "textUnderlinePosition" | "touchAction" | "transform" | "transformBox" | "transformOrigin" | "transformStyle" | "transitionDelay" | "transitionDuration" | "transitionProperty" | "transitionTimingFunction" | "translate" | "unicodeBidi" | "userSelect" | "verticalAlign" | "visibility" | "whiteSpace" | "widows" | "willChange" | "wordBreak" | "wordSpacing" | "wordWrap" | "writingMode" | "zIndex">;
|
|
8
|
+
delete(property: StyleProperty): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
toString(): string;
|
|
11
|
+
}
|
|
12
|
+
export declare class StyleRule {
|
|
13
|
+
#private;
|
|
14
|
+
styleMap: StylePropertyMap;
|
|
15
|
+
selectorText: string;
|
|
16
|
+
onChange?: () => void;
|
|
17
|
+
constructor(selectorText: string, style: Style);
|
|
18
|
+
get cssText(): string;
|
|
19
|
+
}
|
|
20
|
+
export type MediaRuleOptions = {
|
|
21
|
+
minWidth?: number;
|
|
22
|
+
maxWidth?: number;
|
|
23
|
+
mediaType?: "all" | "screen" | "print";
|
|
24
|
+
};
|
|
25
|
+
export declare class MediaRule {
|
|
26
|
+
#private;
|
|
27
|
+
options: MediaRuleOptions;
|
|
28
|
+
rules: Array<StyleRule | PlaintextRule>;
|
|
29
|
+
constructor(options?: MediaRuleOptions);
|
|
30
|
+
insertRule(rule: StyleRule | PlaintextRule): StyleRule | PlaintextRule;
|
|
31
|
+
get cssText(): string;
|
|
32
|
+
}
|
|
33
|
+
export declare class PlaintextRule {
|
|
34
|
+
cssText: string;
|
|
35
|
+
styleMap: StylePropertyMap;
|
|
36
|
+
constructor(cssText: string);
|
|
37
|
+
}
|
|
38
|
+
export type FontFaceOptions = {
|
|
39
|
+
fontFamily: string;
|
|
40
|
+
fontStyle?: "normal" | "italic" | "oblique";
|
|
41
|
+
fontWeight?: number | string;
|
|
42
|
+
fontDisplay: "swap" | "auto" | "block" | "fallback" | "optional";
|
|
43
|
+
src: string;
|
|
44
|
+
};
|
|
45
|
+
export declare class FontFaceRule {
|
|
46
|
+
options: FontFaceOptions;
|
|
47
|
+
constructor(options: FontFaceOptions);
|
|
48
|
+
get cssText(): string;
|
|
49
|
+
}
|
|
50
|
+
export type AnyRule = StyleRule | MediaRule | PlaintextRule | FontFaceRule;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class StyleElement {
|
|
2
|
+
#private;
|
|
3
|
+
constructor(name?: string);
|
|
4
|
+
get isMounted(): boolean;
|
|
5
|
+
mount(): void;
|
|
6
|
+
unmount(): void;
|
|
7
|
+
render(cssText: string): void;
|
|
8
|
+
setAttribute(name: string, value: string): void;
|
|
9
|
+
getAttribute(name: string): string | null | undefined;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./core";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webstudio-is/css-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.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.53.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@jest/globals": "^29.3.1",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"@types/react": "^17.0.24",
|
|
19
19
|
"@types/react-dom": "^17.0.9",
|
|
20
20
|
"jest": "^29.3.1",
|
|
21
|
-
"typescript": "
|
|
22
|
-
"@webstudio-is/css-data": "^0.
|
|
21
|
+
"typescript": "5.0.3",
|
|
22
|
+
"@webstudio-is/css-data": "^0.53.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,7 +29,7 @@
|
|
|
29
29
|
"source": "./src/index.ts",
|
|
30
30
|
"import": "./lib/index.js"
|
|
31
31
|
},
|
|
32
|
-
"types": "
|
|
32
|
+
"types": "lib/types/index.d.ts",
|
|
33
33
|
"files": [
|
|
34
34
|
"lib/*",
|
|
35
35
|
"src/*",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"checks": "pnpm typecheck && pnpm lint && pnpm test",
|
|
44
44
|
"dev": "build-package --watch",
|
|
45
45
|
"build": "build-package",
|
|
46
|
+
"dts": "tsc --emitDeclarationOnly --declaration --declarationDir lib/types",
|
|
46
47
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
47
48
|
"lint": "eslint ./src --ext .ts,.tsx --max-warnings 0",
|
|
48
49
|
"storybook:run": "start-storybook -p 6006",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, test, expect } from "@jest/globals";
|
|
2
|
+
import { compareMedia } from "./compare-media";
|
|
3
|
+
|
|
4
|
+
describe("Compare media", () => {
|
|
5
|
+
test("mobile first", () => {
|
|
6
|
+
const initial = [
|
|
7
|
+
{ minWidth: 0 },
|
|
8
|
+
{ minWidth: 768 },
|
|
9
|
+
{ minWidth: 1024 },
|
|
10
|
+
{ minWidth: 1280 },
|
|
11
|
+
];
|
|
12
|
+
expect(initial.sort(compareMedia)).toStrictEqual(initial);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("random minWidth", () => {
|
|
16
|
+
const initial = [{ minWidth: 0 }, { minWidth: 3 }, { minWidth: 2 }];
|
|
17
|
+
const sorted = [{ minWidth: 0 }, { minWidth: 2 }, { minWidth: 3 }];
|
|
18
|
+
expect(initial.sort(compareMedia)).toStrictEqual(sorted);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("webflow", () => {
|
|
22
|
+
const initial = [
|
|
23
|
+
{ maxWidth: 991 },
|
|
24
|
+
{ maxWidth: 767 },
|
|
25
|
+
{ maxWidth: 479 },
|
|
26
|
+
{ minWidth: 1280 },
|
|
27
|
+
{ minWidth: 1440 },
|
|
28
|
+
{ minWidth: 1920 },
|
|
29
|
+
];
|
|
30
|
+
const sorted = [
|
|
31
|
+
{ maxWidth: 991 },
|
|
32
|
+
{ maxWidth: 767 },
|
|
33
|
+
{ maxWidth: 479 },
|
|
34
|
+
{ minWidth: 1280 },
|
|
35
|
+
{ minWidth: 1440 },
|
|
36
|
+
{ minWidth: 1920 },
|
|
37
|
+
];
|
|
38
|
+
expect(initial.sort(compareMedia)).toStrictEqual(sorted);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MediaRuleOptions } from "./rules";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sort by minWidth descending or maxWidth ascending
|
|
5
|
+
* We want media querries with bigger minWidth to override the smaller once, but the smaller maxWidth to override the bigger once.
|
|
6
|
+
*/
|
|
7
|
+
export const compareMedia = (
|
|
8
|
+
optionA: MediaRuleOptions,
|
|
9
|
+
optionB: MediaRuleOptions
|
|
10
|
+
) => {
|
|
11
|
+
if (optionA?.minWidth !== undefined && optionB?.minWidth !== undefined) {
|
|
12
|
+
return optionA.minWidth - optionB.minWidth;
|
|
13
|
+
}
|
|
14
|
+
if (optionA?.maxWidth !== undefined && optionB?.maxWidth !== undefined) {
|
|
15
|
+
return optionB.maxWidth - optionA.maxWidth;
|
|
16
|
+
}
|
|
17
|
+
return "minWidth" in optionA ? 1 : -1;
|
|
18
|
+
};
|
package/src/core/css-engine.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type FontFaceOptions,
|
|
8
8
|
type MediaRuleOptions,
|
|
9
9
|
} from "./rules";
|
|
10
|
+
import { compareMedia } from "./compare-media";
|
|
10
11
|
import { StyleElement } from "./style-element";
|
|
11
12
|
import { StyleSheet } from "./style-sheet";
|
|
12
13
|
|
|
@@ -90,7 +91,11 @@ export class CssEngine {
|
|
|
90
91
|
for (const plaintextRule of this.#plainRules.values()) {
|
|
91
92
|
css.push(plaintextRule.cssText);
|
|
92
93
|
}
|
|
93
|
-
|
|
94
|
+
|
|
95
|
+
const sortedMediaRules = Array.from(this.#mediaRules.values()).sort(
|
|
96
|
+
(ruleA, ruleB) => compareMedia(ruleA.options, ruleB.options)
|
|
97
|
+
);
|
|
98
|
+
for (const mediaRule of sortedMediaRules) {
|
|
94
99
|
const { cssText } = mediaRule;
|
|
95
100
|
if (cssText !== "") {
|
|
96
101
|
css.push(cssText);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { equalMedia } from "./equal-media";
|
|
3
|
+
|
|
4
|
+
describe("equalMedia", () => {
|
|
5
|
+
test("minWidth", () => {
|
|
6
|
+
expect(equalMedia({ minWidth: 100 }, { minWidth: 10 })).toBe(false);
|
|
7
|
+
expect(equalMedia({ minWidth: 100 }, { minWidth: 100 })).toBe(true);
|
|
8
|
+
expect(equalMedia({ minWidth: 100 }, { minWidth: 101 })).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("maxWidth", () => {
|
|
12
|
+
expect(equalMedia({ maxWidth: 100 }, { maxWidth: 101 })).toBe(false);
|
|
13
|
+
expect(equalMedia({ maxWidth: 100 }, { maxWidth: 100 })).toBe(true);
|
|
14
|
+
expect(equalMedia({ maxWidth: 100 }, { maxWidth: 10 })).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("minWidth and maxWidth", () => {
|
|
18
|
+
expect(equalMedia({ maxWidth: 100, minWidth: 10 }, { maxWidth: 100 })).toBe(
|
|
19
|
+
false
|
|
20
|
+
);
|
|
21
|
+
expect(equalMedia({ maxWidth: 100, minWidth: 10 }, { minWidth: 10 })).toBe(
|
|
22
|
+
false
|
|
23
|
+
);
|
|
24
|
+
expect(
|
|
25
|
+
equalMedia(
|
|
26
|
+
{ maxWidth: 100, minWidth: 10 },
|
|
27
|
+
{ maxWidth: 100, minWidth: 10 }
|
|
28
|
+
)
|
|
29
|
+
).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
});
|
package/src/core/index.ts
CHANGED
package/src/core/rules.ts
CHANGED
|
@@ -73,18 +73,6 @@ export type MediaRuleOptions = {
|
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
export class MediaRule {
|
|
76
|
-
// Sort media rules by minWidth.
|
|
77
|
-
// Needed to ensure that more specific media rules are inserted after less specific ones.
|
|
78
|
-
// So that they get a higher specificity.
|
|
79
|
-
// @todo remove this once we have ability to control order from the UI
|
|
80
|
-
static sort(mediaRules: Iterable<MediaRule>) {
|
|
81
|
-
return Array.from(mediaRules).sort((ruleA, ruleB) => {
|
|
82
|
-
return (
|
|
83
|
-
(ruleA.options.minWidth ?? -Number.MAX_SAFE_INTEGER) -
|
|
84
|
-
(ruleB.options.minWidth ?? -Number.MAX_SAFE_INTEGER)
|
|
85
|
-
);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
76
|
options: MediaRuleOptions;
|
|
89
77
|
rules: Array<StyleRule | PlaintextRule> = [];
|
|
90
78
|
#mediaType;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|