Skip to content

Commit

Permalink
fix: Variable bindings on Class don't show on live site (#4253)
Browse files Browse the repository at this point in the history
## Description

closes #3683

## Steps for reproduction

Tests and fixtures


## 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` file
  • Loading branch information
istarkov authored Oct 9, 2024
1 parent b921c1d commit 02bf597
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 19 deletions.
71 changes: 67 additions & 4 deletions fixtures/webstudio-remix-vercel/.webstudio/data.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"build": {
"id": "40962d82-ea2d-4536-b94f-dece81312190",
"id": "6876de3a-942a-466b-9761-ad7cb2fa2c21",
"projectId": "cddc1d44-af37-4cb6-a430-d300cf6f932d",
"version": 315,
"createdAt": "2024-09-30T13:22:48.689+00:00",
"updatedAt": "2024-09-30T13:22:48.689+00:00",
"version": 321,
"createdAt": "2024-10-08T17:47:04.557+00:00",
"updatedAt": "2024-10-08T17:47:04.557+00:00",
"pages": {
"meta": {
"siteName": "KittyGuardedZone",
Expand Down Expand Up @@ -1540,6 +1540,19 @@
"value": 300
}
}
],
[
"g6Z7dAxi6LYB-XtI6SaRR:UoTkWyaFuTYJihS3MFYK5:marginTop:",
{
"breakpointId": "UoTkWyaFuTYJihS3MFYK5",
"styleSourceId": "g6Z7dAxi6LYB-XtI6SaRR",
"property": "marginTop",
"value": {
"type": "unit",
"value": 12,
"unit": "px"
}
}
]
],
"styleSources": [
Expand Down Expand Up @@ -1717,6 +1730,13 @@
"type": "local",
"id": "o9VRyqmvIarF6HrGMccU8"
}
],
[
"g6Z7dAxi6LYB-XtI6SaRR",
{
"type": "local",
"id": "g6Z7dAxi6LYB-XtI6SaRR"
}
]
],
"styleSourceSelections": [
Expand Down Expand Up @@ -1894,6 +1914,13 @@
"instanceId": "drCx7m8q_gnNQLrhPDA-g",
"values": ["o9VRyqmvIarF6HrGMccU8"]
}
],
[
"T-rqx2b12pRrWcafRRoIG",
{
"instanceId": "T-rqx2b12pRrWcafRRoIG",
"values": ["g6Z7dAxi6LYB-XtI6SaRR"]
}
]
],
"props": [
Expand Down Expand Up @@ -2297,6 +2324,16 @@
"type": "string",
"value": "\"broken'with`symbols"
}
],
[
"I4cM2PzBX49KWxsKdGMd1",
{
"id": "I4cM2PzBX49KWxsKdGMd1",
"instanceId": "T-rqx2b12pRrWcafRRoIG",
"name": "className",
"type": "expression",
"value": "`${$ws$dataSource$FG6camSaR89vSBREAV9PT} class_3`"
}
]
],
"dataSources": [
Expand Down Expand Up @@ -2463,6 +2500,19 @@
"scopeInstanceId": "mdyCS8QnKx3fL1MLXifmy",
"name": "system"
}
],
[
"FG6camSaR89vSBREAV9PT",
{
"type": "variable",
"id": "FG6camSaR89vSBREAV9PT",
"scopeInstanceId": "mdyCS8QnKx3fL1MLXifmy",
"name": "classVar",
"value": {
"type": "string",
"value": "varClass"
}
}
]
],
"resources": [
Expand Down Expand Up @@ -3581,6 +3631,10 @@
{
"type": "id",
"value": "drCx7m8q_gnNQLrhPDA-g"
},
{
"type": "id",
"value": "T-rqx2b12pRrWcafRRoIG"
}
]
}
Expand All @@ -3593,6 +3647,15 @@
"component": "Box",
"children": []
}
],
[
"T-rqx2b12pRrWcafRRoIG",
{
"type": "instance",
"id": "T-rqx2b12pRrWcafRRoIG",
"component": "Box",
"children": []
}
]
],
"deployment": {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions fixtures/webstudio-remix-vercel/app/__generated__/index.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion fixtures/webstudio-remix-vercel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"typecheck": "tsc",
"cli": "NODE_OPTIONS='--conditions=webstudio --import=tsx' webstudio",
"fixtures:link": "pnpm cli link --link https://p-cddc1d44-af37-4cb6-a430-d300cf6f932d-dot-${BUILDER_HOST:-main.development.webstudio.is}'?authToken=1cdc6026-dd5b-4624-b89b-9bd45e9bcc3d'",
"fixtures:sync": "pnpm cli sync --buildId 40962d82-ea2d-4536-b94f-dece81312190 && pnpm prettier --write ./.webstudio/",
"fixtures:sync": "pnpm cli sync --buildId 6876de3a-942a-466b-9761-ad7cb2fa2c21 && pnpm prettier --write ./.webstudio/",
"fixtures:build": "pnpm cli build --template vercel --template internal --preview && pnpm prettier --write ./app/ ./package.json ./tsconfig.json"
},
"private": true,
Expand Down
89 changes: 88 additions & 1 deletion packages/react-sdk/src/component-generator.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,30 @@ test("generate component with variables and actions", () => {
);
});

test("merge classes if no className", () => {
expect(
generateWebstudioComponent({
classesMap: new Map([["body", ["cls1"]]]),
scope: createScope(),
name: "Page",
rootInstanceId: "body",
parameters: [],
dataSources: new Map(),
indexesWithinAncestors: new Map(),
...renderJsx(<$.Body ws:id="body"></$.Body>),
})
).toEqual(
validateJSX(
clear(`
const Page = () => {
return <Body
className={"cls1"} />
}
`)
)
);
});

test("add classes and merge classes", () => {
expect(
generateWebstudioComponent({
Expand All @@ -584,7 +608,70 @@ test("add classes and merge classes", () => {
clear(`
const Page = () => {
return <Body
className={"cls1 cls2 \\"cls3\\""} />
className={"cls1" + " " + "cls2 \\"cls3\\""} />
}
`)
)
);
});

test("add classes", () => {
expect(
generateWebstudioComponent({
classesMap: new Map(),
scope: createScope(),
name: "Page",
rootInstanceId: "body",
parameters: [],
dataSources: new Map(),
indexesWithinAncestors: new Map(),
...renderJsx(<$.Body ws:id="body" className='cls2 "cls3"'></$.Body>),
})
).toEqual(
validateJSX(
clear(`
const Page = () => {
return <Body
className={"cls2 \\"cls3\\""} />
}
`)
)
);
});

test("add bind classes and merge classes", () => {
expect(
generateWebstudioComponent({
classesMap: new Map([["body", ["cls1"]]]),
scope: createScope(),
name: "Page",
rootInstanceId: "body",
parameters: [],
dataSources: toMap([
{
type: "variable",
id: "variableId",
name: "variableName",
value: { type: "string", value: "cls3" },
},
]),
indexesWithinAncestors: new Map(),
...renderJsx(
<$.Body
ws:id="body"
className={
new ExpressionValue(`'cls2' + ' ' + $ws$dataSource$variableId`)
}
></$.Body>
),
})
).toEqual(
validateJSX(
clear(`
const Page = () => {
let [variableName, set$variableName] = useVariableState<any>("cls3")
return <Body
className={"cls1" + " " + 'cls2' + ' ' + variableName} />
}
`)
)
Expand Down
17 changes: 11 additions & 6 deletions packages/react-sdk/src/component-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,17 @@ export const generateJsxElement = ({
let collectionDataValue: undefined | string;
let collectionItemValue: undefined | string;

const classes = Array.from(classesMap?.get(instance.id) ?? []);
const classMapArray = classesMap?.get(instance.id);
const classes =
classMapArray !== undefined
? [JSON.stringify(classMapArray.join(" "))]
: [];

for (const prop of props.values()) {
if (prop.instanceId !== instance.id) {
continue;
}

const propValue = generatePropValue({
scope,
prop,
Expand Down Expand Up @@ -210,10 +216,9 @@ export const generateJsxElement = ({
continue;
}
// We need to merge atomic classes with user-defined className prop.
if (prop.name === "className") {
if (prop.type === "string") {
classes.push(prop.value);
}
if (prop.name === "className" && propValue !== undefined) {
classes.push(propValue);

continue;
}
if (propValue !== undefined) {
Expand All @@ -222,7 +227,7 @@ export const generateJsxElement = ({
}

if (classes.length !== 0) {
generatedProps += `\nclassName={${JSON.stringify(classes.join(" "))}}`;
generatedProps += `\nclassName={${classes.join(` + " " + `)}}`;
}

let generatedElement = "";
Expand Down

0 comments on commit 02bf597

Please sign in to comment.