mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-30 00:27:43 +09:00
refactor: parse styles into flat list (#3666)
Ref https://github.com/webstudio-is/webstudio/issues/2647 We need to support more grouping properties in parsed css for example breakpoints would require additional nesting. Here I took slightly different approach and moved all styles into single array with additional `selector` property. Now we can easily support parsing styles without selectors and parsing styles without breakpoints. And optionally we can always use `Map.groupBy(styles, styleDecl => styleDecl.selector)` and the same later by breakpoint.
This commit is contained in:
1 parent
50a17ebb8b
commit
e19fe92f15
4 files changed
+378
-612
No files matched your search
@@ -115,7 +115,7 @@ const toParsedVariants = (variants: UnparsedVariants) => {
|
||||
const { breakpointName, state } = parseVariantName(variant);
|
||||
if (typeof styles === "string") {
|
||||
try {
|
||||
const parsed = parseCss(`.styles${state} {${styles}}`).styles ?? [];
|
||||
const parsed = parseCss(`.styles${state} {${styles}}`) ?? [];
|
||||
const allBreakpointStyles = parsedVariants.get(breakpointName) ?? [];
|
||||
allBreakpointStyles.push(...parsed);
|
||||
parsedVariants.set(breakpointName, allBreakpointStyles);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,10 +1,16 @@
|
||||
import { camelCase } from "change-case";
|
||||
import * as csstree from "css-tree";
|
||||
import { StyleValue, type StyleProperty } from "@webstudio-is/css-engine";
|
||||
import type { EmbedTemplateStyleDecl } from "@webstudio-is/react-sdk";
|
||||
import { parseCssValue as parseCssValueLonghand } from "./parse-css-value";
|
||||
import { expandShorthands } from "./shorthands";
|
||||
|
||||
export type ParsedStyleDecl = {
|
||||
selector: string;
|
||||
state?: string;
|
||||
property: StyleProperty;
|
||||
value: StyleValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Store prefixed properties without change
|
||||
* and convert to camel case only unprefixed properties
|
||||
@@ -50,8 +56,6 @@ const unprefixProperty = (property: string) => {
|
||||
|
||||
type Selector = string;
|
||||
|
||||
export type Styles = Record<Selector, Array<EmbedTemplateStyleDecl>>;
|
||||
|
||||
const parseCssValue = (
|
||||
property: string,
|
||||
value: string
|
||||
@@ -96,10 +100,10 @@ export const parseCss = (css: string) => {
|
||||
const ast = cssTreeTryParse(css);
|
||||
let selectors: Selector[] = [];
|
||||
let states = new Map<Selector, Array<string | undefined>>();
|
||||
const styles: Styles = {};
|
||||
const styles = new Map<string, ParsedStyleDecl>();
|
||||
|
||||
if (ast === undefined) {
|
||||
return styles;
|
||||
return [];
|
||||
}
|
||||
|
||||
csstree.walk(ast, (node, item) => {
|
||||
@@ -142,13 +146,9 @@ export const parseCss = (css: string) => {
|
||||
|
||||
for (const [property, value] of parsedCss) {
|
||||
try {
|
||||
StyleValue.parse(value);
|
||||
selectors.forEach((selector, index) => {
|
||||
let declarations = styles[selector];
|
||||
if (declarations === undefined) {
|
||||
declarations = styles[selector] = [];
|
||||
}
|
||||
const styleDecl: EmbedTemplateStyleDecl = {
|
||||
const styleDecl: ParsedStyleDecl = {
|
||||
selector,
|
||||
property: normalizePropertyName(
|
||||
unprefixProperty(property)
|
||||
) as StyleProperty,
|
||||
@@ -156,21 +156,13 @@ export const parseCss = (css: string) => {
|
||||
};
|
||||
|
||||
const statesArray = states.get(selector) ?? [];
|
||||
if (statesArray[index]) {
|
||||
styleDecl.state = statesArray[index];
|
||||
const state = statesArray[index] ?? "";
|
||||
if (state) {
|
||||
styleDecl.state = state;
|
||||
}
|
||||
|
||||
// Checks if there is already a prorperty that is exactly the same and will be overwritten,
|
||||
// so we may as well remove it from the data.
|
||||
const existingIndex = declarations.findIndex(
|
||||
(decl) =>
|
||||
decl.property === styleDecl.property &&
|
||||
decl.state === styleDecl.state
|
||||
);
|
||||
if (existingIndex !== -1) {
|
||||
declarations.splice(existingIndex, 1);
|
||||
}
|
||||
declarations.push(styleDecl);
|
||||
// deduplicate styles within selector and state by using map
|
||||
styles.set(`${selector}:${state}:${property}`, styleDecl);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Bad CSS declaration", error, parsedCss);
|
||||
@@ -179,5 +171,5 @@ export const parseCss = (css: string) => {
|
||||
}
|
||||
});
|
||||
|
||||
return styles;
|
||||
return Array.from(styles.values());
|
||||
};
|
||||
@@ -70,7 +70,8 @@ export const parseTailwindToWebstudio = async (
|
||||
warn = warnOnce
|
||||
) => {
|
||||
const css = await parseTailwindToCss(classes, warn);
|
||||
let styles = Object.values(parseCss(css)).flat();
|
||||
// remove properties from parsed declaration to align with embed template
|
||||
let styles = parseCss(css).map(({ selector, ...styleDecl }) => styleDecl);
|
||||
// postprocessing
|
||||
styles = postprocessBorder(styles);
|
||||
|
||||
|
||||
Reference in new issue
Block a user