Files
webstudio/packages/sdk/scripts/normalize.css.ts
Oleg Isonen 8de2fd47f6 fix: CSS shorthand properties not saved when value contains var() (#5688)
Shorthand properties like background: var(--color) were silently dropped
when pasting into the CSS editor because the shorthand expander can't
handle unresolved var() references.

Fix: CSS vars from the current element's computed styles are now
resolved before expanding shorthands. Inline and nested fallbacks
(var(--a, var(--b))) are supported. If a var still can't be resolved, a
toast error is shown instead of silently dropping the property.
2026-04-12 17:14:01 +02:00

69 lines
1.8 KiB
TypeScript

import { mkdir, readFile, writeFile } from "node:fs/promises";
import htmlTags from "html-tags";
import { parseCss } from "@webstudio-is/css-data";
const mapGroupBy = <Item, Key>(
array: Item[] | Iterable<Item>,
getKey: (item: Item) => Key
) => {
const groups = new Map<Key, Item[]>();
for (const item of array) {
const key = getKey(item);
let group = groups.get(key);
if (group === undefined) {
group = [];
groups.set(key, group);
}
group.push(item);
}
return groups;
};
const css = await readFile("./src/normalize.css", "utf8");
const { styles: parsed } = parseCss(css, new Map());
const groups = mapGroupBy(parsed, (styleDecl) => styleDecl.selector);
const validTags = [
...htmlTags,
// exceptions to access preset styles in Checkbox and Radio components
"checkbox",
"radio",
];
const cache = new Map<string, string>();
let code = "";
code += `import type { CssProperty, StyleValue } from "@webstudio-is/css-engine";\n`;
code += `
type StyleDecl = {
state?: string;
property: CssProperty;
value: StyleValue;
}
`;
for (const [tag, styles] of groups) {
if (validTags.includes(tag) === false) {
throw Error(`Unexpected tag "${tag}"`);
}
const newStyles = styles.map(({ state, property, value }) => ({
state,
property,
value,
}));
let serializedStyles = JSON.stringify(newStyles);
const cachedTag = cache.get(serializedStyles);
// to prevent duplicating same styles
// assign already rendered tag to the tag with same styles
if (cachedTag) {
serializedStyles = cachedTag;
code += `export const ${tag} = ${cachedTag};\n\n`;
} else {
cache.set(serializedStyles, tag);
code += `export const ${tag}: StyleDecl[] = ${serializedStyles};\n\n`;
}
}
await mkdir("./src/__generated__", { recursive: true });
await writeFile("./src/__generated__/normalize.css.ts", code);