mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 14:03:33 +09:00
feat: Extend tailwind-to-webstudio conversion to support background properties (#2387)
## Description 1. Add support of simple tuple types to the parseCssValue 2. Add background properties conversion ## Steps for reproduction see tests ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env.example` and the `builder/env-check.js` if mandatory
This commit is contained in:
1 parent
e56995d7af
commit
3c75b4e870
4 files changed
+129
-8
No files matched your search
@@ -105,6 +105,27 @@ describe("Parse CSS value", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Tuples", () => {
|
||||
test("backgroundPosition", () => {
|
||||
expect(parseCssValue("backgroundPosition", "left top"))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"type": "tuple",
|
||||
"value": [
|
||||
{
|
||||
"type": "keyword",
|
||||
"value": "left",
|
||||
},
|
||||
{
|
||||
"type": "keyword",
|
||||
"value": "top",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Colors", () => {
|
||||
test("Color rgba values", () => {
|
||||
expect(parseCssValue("backgroundColor", "rgba(0,0,0,0)")).toEqual({
|
||||
|
||||
@@ -2,7 +2,12 @@ import { colord } from "colord";
|
||||
import * as csstree from "css-tree";
|
||||
import hyphenate from "hyphenate-style-name";
|
||||
import warnOnce from "warn-once";
|
||||
import type { StyleProperty, StyleValue, Unit } from "@webstudio-is/css-engine";
|
||||
import {
|
||||
TupleValue,
|
||||
type StyleProperty,
|
||||
type StyleValue,
|
||||
type Unit,
|
||||
} from "@webstudio-is/css-engine";
|
||||
import { keywordValues } from "./__generated__/keyword-values";
|
||||
import { units } from "./__generated__/units";
|
||||
|
||||
@@ -150,6 +155,27 @@ export const parseCssValue = (
|
||||
}
|
||||
}
|
||||
|
||||
// Probably a tuple like background-position
|
||||
if (ast != null && ast.type === "Value" && ast.children.size === 2) {
|
||||
const tupleFirst = parseCssValue(
|
||||
property,
|
||||
csstree.generate(ast.children.first!)
|
||||
);
|
||||
const tupleLast = parseCssValue(
|
||||
property,
|
||||
csstree.generate(ast.children.last!)
|
||||
);
|
||||
|
||||
const tupleResult = TupleValue.safeParse({
|
||||
type: "tuple",
|
||||
value: [tupleFirst, tupleLast],
|
||||
});
|
||||
|
||||
if (tupleResult.success) {
|
||||
return tupleResult.data;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: "unparsed",
|
||||
value: input,
|
||||
|
||||
@@ -19,8 +19,11 @@ Quick Validation of Generated CSS in WebStudio:
|
||||
{
|
||||
"property": "backgroundImage",
|
||||
"value": {
|
||||
"type": "unparsed",
|
||||
"value": "linear-gradient(to right,rgba(99,102,241,1) 0%,rgba(99,102,241,0) 100%)"
|
||||
"type": "layers",
|
||||
"value": [{
|
||||
type: "unparsed",
|
||||
value: "linear-gradient(to right,rgba(99,102,241,1) 0%,rgba(99,102,241,0) 100%)"
|
||||
}]
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -75,7 +78,7 @@ describe("parseTailwindToWebstudio", () => {
|
||||
});
|
||||
|
||||
test("substitute variables - gradient", async () => {
|
||||
const tailwindClasses = `bg-gradient-to-r from-indigo-500`;
|
||||
const tailwindClasses = `bg-left-top bg-gradient-to-r from-indigo-500 from-10% via-sky-500 via-30% to-emerald-500 to-90%`;
|
||||
|
||||
expect(await parseTailwindToWebstudio(tailwindClasses))
|
||||
.toMatchInlineSnapshot(`
|
||||
@@ -83,8 +86,34 @@ describe("parseTailwindToWebstudio", () => {
|
||||
{
|
||||
"property": "backgroundImage",
|
||||
"value": {
|
||||
"type": "unparsed",
|
||||
"value": "linear-gradient(to right,rgba(99,102,241,1) 0%,rgba(99,102,241,0) 100%)",
|
||||
"type": "layers",
|
||||
"value": [
|
||||
{
|
||||
"type": "unparsed",
|
||||
"value": "linear-gradient(to right,rgba(99,102,241,1) 10%,rgba(14,165,233,1) 30%,rgba(16,185,129,1) 90%)",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"property": "backgroundPosition",
|
||||
"value": {
|
||||
"type": "layers",
|
||||
"value": [
|
||||
{
|
||||
"type": "tuple",
|
||||
"value": [
|
||||
{
|
||||
"type": "keyword",
|
||||
"value": "left",
|
||||
},
|
||||
{
|
||||
"type": "keyword",
|
||||
"value": "top",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -7,7 +7,7 @@ import { expandTailwindShorthand } from "./shorthand";
|
||||
import { substituteVariables } from "./substitute";
|
||||
import warnOnce from "warn-once";
|
||||
import { parseCssValue } from "../parse-css-value";
|
||||
import { type StyleProperty } from "@webstudio-is/css-engine";
|
||||
import { LayersValue, type StyleProperty } from "@webstudio-is/css-engine";
|
||||
|
||||
let unoLazy: UnoGenerator<Theme> | undefined = undefined;
|
||||
|
||||
@@ -55,6 +55,48 @@ const parseCssToWebstudio = (css: string) => {
|
||||
return styles;
|
||||
};
|
||||
|
||||
/**
|
||||
* In WebStudio, background-related properties are managed using a specialized "layer" type.
|
||||
**/
|
||||
const postprocessBackgrounds = (
|
||||
styles: EmbedTemplateStyleDecl[],
|
||||
warn = warnOnce
|
||||
) => {
|
||||
const backgroundProps = [
|
||||
"backgroundAttachment",
|
||||
"backgroundClip",
|
||||
"backgroundBlendMode",
|
||||
"backgroundImage",
|
||||
"backgroundOrigin",
|
||||
"backgroundPosition",
|
||||
"backgroundRepeat",
|
||||
"backgroundSize",
|
||||
];
|
||||
|
||||
return styles.map((style) => {
|
||||
if (backgroundProps.includes(style.property)) {
|
||||
const layersResult = LayersValue.safeParse({
|
||||
type: "layers",
|
||||
value: [style.value],
|
||||
});
|
||||
|
||||
if (layersResult.success) {
|
||||
return {
|
||||
property: style.property,
|
||||
value: layersResult.data,
|
||||
};
|
||||
}
|
||||
warn(
|
||||
true,
|
||||
`Failed to convert background property ${
|
||||
style.property
|
||||
} with value ${JSON.stringify(style.value)} to layers`
|
||||
);
|
||||
}
|
||||
return style;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses Tailwind classes to webstudio template format.
|
||||
*/
|
||||
@@ -63,6 +105,9 @@ export const parseTailwindToWebstudio = async (
|
||||
warn = warnOnce
|
||||
) => {
|
||||
const css = await parseTailwindToCss(classes, warn);
|
||||
const styles = parseCssToWebstudio(css);
|
||||
let styles = parseCssToWebstudio(css);
|
||||
// postprocessing
|
||||
styles = postprocessBackgrounds(styles, warn);
|
||||
|
||||
return styles;
|
||||
};
|
||||
Reference in new issue
Block a user