Skip to content

Commit b405755

Browse files
authored
nkoech/ENG-9389/fix issue where bindings' responsiveStyles keys (when destructured) aren't well accessed. (#1774)
* fix issue where bindings responsiveStyles key aren't well accessed after destructure and add tests * remove comment-out line * remove repeated test:should handle direct responsiveStyles bindings correctly * move test 10a168d#diff-1ed5e8c9d3ab5936982abcac91050e07a5541d312aba3a3c42b43f179eb72c6eR679-R697 into the new responsive-styles.test.ts file * remove test 'should handle invalid code with escapeInvalidCode option' since its been handled in invalid-jsx-flag.test.ts file * remove unnecessary test 'should handle empty bindings' since it's been handled in https://github.com/BuilderIO/mitosis/blob/65f3324be9772366da000b4ad6f8fdd0a098da93/packages/core/src/__tests__/builder/builder.test.ts#L335-L357 * add different screen sizes and convert to mitosis json to get more coverage * remove commented-out code * add changeset * patch changeset * remove major patch
1 parent 65f3324 commit b405755

File tree

4 files changed

+165
-87
lines changed

4 files changed

+165
-87
lines changed

.changeset/hip-ads-wait.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@builder.io/mitosis': patch
3+
---
4+
5+
fix issue where bindings' responsiveStyles keys (when destructured) aren't well accessed.

packages/core/src/__tests__/builder/builder.test.ts

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -911,91 +911,6 @@ describe('Builder', () => {
911911
);
912912
});
913913

914-
test('preserve bound media query styles when converting to mitosis', () => {
915-
const content = {
916-
data: {
917-
blocks: [
918-
{
919-
'@type': '@builder.io/sdk:Element' as const,
920-
bindings: {
921-
'responsiveStyles.small.left': 'state.left',
922-
'responsiveStyles.small.top': 'state.top',
923-
'responsiveStyles.large.color': 'state.color',
924-
'style.fontSize': 'state.fontSize',
925-
'style.background': '"red"',
926-
'responsiveStyles.large.background': '"green"',
927-
},
928-
},
929-
],
930-
},
931-
};
932-
933-
const mitosis = builderContentToMitosisComponent(content);
934-
expect(mitosis.children[0].bindings).toMatchInlineSnapshot(`
935-
{
936-
"style": {
937-
"bindingType": "expression",
938-
"code": "{ fontSize: state.fontSize, background: \\"red\\", \\"@media (max-width: 640px)\\": { left: state.left, top: state.top }, \\"@media (max-width: 1200px)\\": { color: state.color, background: \\"green\\" }, }",
939-
"type": "single",
940-
},
941-
}
942-
`);
943-
944-
const jsx = componentToMitosis()({ component: mitosis });
945-
expect(jsx).toMatchInlineSnapshot(`
946-
"export default function MyComponent(props) {
947-
return (
948-
<div
949-
style={{
950-
fontSize: state.fontSize,
951-
background: \\"red\\",
952-
\\"@media (max-width: 640px)\\": {
953-
left: state.left,
954-
top: state.top,
955-
},
956-
\\"@media (max-width: 1200px)\\": {
957-
color: state.color,
958-
background: \\"green\\",
959-
},
960-
}}
961-
/>
962-
);
963-
}
964-
"
965-
`);
966-
967-
const json = componentToBuilder()({ component: mitosis });
968-
expect(json).toMatchInlineSnapshot(`
969-
{
970-
"data": {
971-
"blocks": [
972-
{
973-
"@type": "@builder.io/sdk:Element",
974-
"actions": {},
975-
"bindings": {
976-
"responsiveStyles.large.background": "\\"green\\"",
977-
"responsiveStyles.large.color": "state.color",
978-
"responsiveStyles.small.left": "state.left",
979-
"responsiveStyles.small.top": "state.top",
980-
"style.background": "\\"red\\"",
981-
"style.fontSize": "state.fontSize",
982-
},
983-
"children": [],
984-
"code": {
985-
"actions": {},
986-
"bindings": {},
987-
},
988-
"properties": {},
989-
"tagName": "div",
990-
},
991-
],
992-
"jsCode": "",
993-
"tsCode": "",
994-
},
995-
}
996-
`);
997-
});
998-
999914
test('preserve bound call expressions for styles', () => {
1000915
const code = dedent`
1001916
import { useStore } from "@builder.io/mitosis";
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { componentToBuilder } from '@/generators/builder';
2+
import { componentToMitosis } from '@/generators/mitosis';
3+
import { describe, expect, test } from 'vitest';
4+
import {
5+
builderContentToMitosisComponent,
6+
getStyleStringFromBlock,
7+
} from '../../parsers/builder/builder';
8+
9+
const options = {
10+
escapeInvalidCode: true,
11+
includeMeta: true,
12+
includeSpecialBindings: true,
13+
};
14+
15+
describe('Responsive Styles', () => {
16+
test('preserve bound media query styles when converting to mitosis', () => {
17+
const content = {
18+
data: {
19+
blocks: [
20+
{
21+
'@type': '@builder.io/sdk:Element' as const,
22+
bindings: {
23+
'responsiveStyles.small.left': 'state.left',
24+
'responsiveStyles.small.top': 'state.top',
25+
'responsiveStyles.large.color': 'state.color',
26+
'style.fontSize': 'state.fontSize',
27+
'style.background': '"red"',
28+
'responsiveStyles.large.background': '"green"',
29+
'component.options.responsiveStyles.medium.flexDirection':
30+
'state.reverseColumnsWhenStacked && (state.stackColumnsAt === "tablet" || state.stackColumnsAt === "mobile") ? "column-reverse" : undefined',
31+
'component.options.responsiveStyles.small.color': '"red"',
32+
'component.options.responsiveStyles.medium.color': '"green"',
33+
'component.options.responsiveStyles.large.color': '"blue"',
34+
},
35+
},
36+
],
37+
},
38+
};
39+
40+
const result = getStyleStringFromBlock(content.data.blocks[0], options);
41+
42+
// Should contain both media queries
43+
expect(result).toContain('@media (max-width: 1200px)');
44+
expect(result).toContain('@media (max-width: 640px)');
45+
expect(result).toContain('@media (max-width: 991px)');
46+
47+
// Should contain the correct flexDirection bindings
48+
expect(result).toContain(
49+
'flexDirection: state.reverseColumnsWhenStacked && (state.stackColumnsAt === "tablet" || state.stackColumnsAt === "mobile") ? "column-reverse" : undefined',
50+
);
51+
52+
const mitosis = builderContentToMitosisComponent(content);
53+
54+
expect(mitosis.children[0].bindings).toMatchInlineSnapshot(`
55+
{
56+
"responsiveStyles.large.color": {
57+
"bindingType": "expression",
58+
"code": "\\"blue\\"",
59+
"type": "single",
60+
},
61+
"responsiveStyles.medium.color": {
62+
"bindingType": "expression",
63+
"code": "\\"green\\"",
64+
"type": "single",
65+
},
66+
"responsiveStyles.medium.flexDirection": {
67+
"bindingType": "expression",
68+
"code": "state.reverseColumnsWhenStacked && (state.stackColumnsAt === \\"tablet\\" || state.stackColumnsAt === \\"mobile\\") ? \\"column-reverse\\" : undefined",
69+
"type": "single",
70+
},
71+
"responsiveStyles.small.color": {
72+
"bindingType": "expression",
73+
"code": "\\"red\\"",
74+
"type": "single",
75+
},
76+
"style": {
77+
"bindingType": "expression",
78+
"code": "{ fontSize: state.fontSize, background: \\"red\\", \\"@media (max-width: 640px)\\": { left: state.left, top: state.top, color: \\"red\\" }, \\"@media (max-width: 1200px)\\": { color: \\"blue\\", background: \\"green\\" }, \\"@media (max-width: 991px)\\": { flexDirection: state.reverseColumnsWhenStacked && (state.stackColumnsAt === \\"tablet\\" || state.stackColumnsAt === \\"mobile\\") ? \\"column-reverse\\" : undefined, color: \\"green\\" }, }",
79+
"type": "single",
80+
},
81+
}
82+
`);
83+
84+
const jsx = componentToMitosis()({ component: mitosis });
85+
86+
expect(jsx).toMatchInlineSnapshot(`
87+
"export default function MyComponent(props) {
88+
return (
89+
<div
90+
style={{
91+
fontSize: state.fontSize,
92+
background: \\"red\\",
93+
\\"@media (max-width: 640px)\\": {
94+
left: state.left,
95+
top: state.top,
96+
color: \\"red\\",
97+
},
98+
\\"@media (max-width: 1200px)\\": {
99+
color: \\"blue\\",
100+
background: \\"green\\",
101+
},
102+
\\"@media (max-width: 991px)\\": {
103+
flexDirection:
104+
state.reverseColumnsWhenStacked &&
105+
(state.stackColumnsAt === \\"tablet\\" ||
106+
state.stackColumnsAt === \\"mobile\\")
107+
? \\"column-reverse\\"
108+
: undefined,
109+
color: \\"green\\",
110+
},
111+
}}
112+
/>
113+
);
114+
}
115+
"
116+
`);
117+
118+
const json = componentToBuilder()({ component: mitosis });
119+
expect(json).toMatchInlineSnapshot(`
120+
{
121+
"data": {
122+
"blocks": [
123+
{
124+
"@type": "@builder.io/sdk:Element",
125+
"actions": {},
126+
"bindings": {
127+
"responsiveStyles.large.background": "\\"green\\"",
128+
"responsiveStyles.large.color": "\\"blue\\"",
129+
"responsiveStyles.medium.color": "\\"green\\"",
130+
"responsiveStyles.medium.flexDirection": "state.reverseColumnsWhenStacked && (state.stackColumnsAt === \\"tablet\\" || state.stackColumnsAt === \\"mobile\\") ? \\"column-reverse\\" : undefined",
131+
"responsiveStyles.small.color": "\\"red\\"",
132+
"responsiveStyles.small.left": "state.left",
133+
"responsiveStyles.small.top": "state.top",
134+
"style.background": "\\"red\\"",
135+
"style.fontSize": "state.fontSize",
136+
},
137+
"children": [],
138+
"code": {
139+
"actions": {},
140+
"bindings": {},
141+
},
142+
"properties": {},
143+
"tagName": "div",
144+
},
145+
],
146+
"jsCode": "",
147+
"tsCode": "",
148+
},
149+
}
150+
`);
151+
});
152+
});

packages/core/src/parsers/builder/builder.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ const getActionBindingsFromBlock = (
106106
return bindings;
107107
};
108108

109-
const getStyleStringFromBlock = (block: BuilderElement, options: BuilderToMitosisOptions) => {
109+
export const getStyleStringFromBlock = (
110+
block: BuilderElement,
111+
options: BuilderToMitosisOptions,
112+
) => {
110113
const styleBindings: any = {};
111114
const responsiveStyles: Record<string, Record<string, string>> = {};
112115
let styleString = '';
@@ -143,7 +146,10 @@ const getStyleStringFromBlock = (block: BuilderElement, options: BuilderToMitosi
143146
* }
144147
*/
145148
} else if (key.includes('responsiveStyles')) {
146-
const [_, size, prop] = key.split('.');
149+
const parts = key.split('.');
150+
const size = parts[parts.length - 2];
151+
const prop = parts[parts.length - 1];
152+
147153
const mediaKey = `@media (max-width: ${sizes[size as Size].max}px)`;
148154

149155
/**

0 commit comments

Comments
 (0)