Skip to content

Commit cc08a8d

Browse files
authored
handle margin/padding shorthands in style props codemod (#7740)
1 parent ff300df commit cc08a8d

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/styleProps.test.ts.snap

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,56 @@ import { style } from "@react-spectrum/s2/style" with { type: "macro" };
171171
})}>Test</Button>"
172172
`;
173173

174+
exports[`Handles multi-value margin/padding shorthands 1`] = `
175+
"import { style } from "@react-spectrum/s2/style" with { type: "macro" };
176+
177+
<>
178+
<div className={style({
179+
margin: "[10px]"
180+
})}>Single Value Margin</div>
181+
182+
<div className={style({
183+
marginY: "[10px]",
184+
marginX: 16
185+
})}>Two Value Margin</div>
186+
187+
<div className={style({
188+
marginTop: "[10px]",
189+
marginX: 16,
190+
marginBottom: 20
191+
})}>Three Value Margin</div>
192+
193+
<div className={style({
194+
marginTop: "[10px]",
195+
marginRight: 16,
196+
marginBottom: 20,
197+
marginLeft: 24
198+
})}>Four Value Margin</div>
199+
200+
<div className={style({
201+
padding: "[10px]"
202+
})}>Single Value Padding</div>
203+
204+
<div className={style({
205+
paddingY: "[10px]",
206+
paddingX: 16
207+
})}>Two Value Padding</div>
208+
209+
<div className={style({
210+
paddingTop: "[10px]",
211+
paddingX: 16,
212+
paddingBottom: 20
213+
})}>Three Value Padding</div>
214+
215+
<div className={style({
216+
paddingTop: "[10px]",
217+
paddingRight: 16,
218+
paddingBottom: 20,
219+
paddingLeft: 24
220+
})}>Four Value Padding</div>
221+
</>"
222+
`;
223+
174224
exports[`Handles responsive style props 1`] = `
175225
"import { TextField } from "@react-spectrum/s2";
176226
import { style } from "@react-spectrum/s2/style" with { type: "macro" };

packages/dev/codemods/src/s1-to-s2/__tests__/styleProps.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,25 @@ import { style } from "@react-spectrum/s2/style" with { type: "macro" };
206206
207207
<TextField label="Name" styles={style({width: 160})} />
208208
`);
209+
210+
test('Handles multi-value margin/padding shorthands', `
211+
import {View} from '@adobe/react-spectrum';
212+
213+
<>
214+
<View margin="10px">Single Value Margin</View>
215+
216+
<View margin="10px 16px">Two Value Margin</View>
217+
218+
<View margin="10px 16px 20px">Three Value Margin</View>
219+
220+
<View margin="10px 16px 20px 24px">Four Value Margin</View>
221+
222+
<View padding="10px">Single Value Padding</View>
223+
224+
<View padding="10px 16px">Two Value Padding</View>
225+
226+
<View padding="10px 16px 20px">Three Value Padding</View>
227+
228+
<View padding="10px 16px 20px 24px">Four Value Padding</View>
229+
</>
230+
`);

packages/dev/codemods/src/s1-to-s2/src/codemods/styleProps.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@ function getStylePropValue(prop: string, value: t.ObjectProperty['value'], eleme
9191
case 'end':
9292
case 'flexBasis': {
9393
if (value.type === 'StringLiteral' || value.type === 'NumericLiteral') {
94+
if (prop === 'margin' && value.type === 'StringLiteral' && /\s/.test(value.value)) {
95+
// Check if it has multiple whitespace-separated values
96+
let expansions = expandSpaceShorthand(prop, value.value, convertDimension);
97+
if (!expansions) {
98+
return null;
99+
}
100+
return {
101+
macroValues: expansions
102+
};
103+
}
104+
94105
let val = convertDimension(value.value, 'space');
95106
if (val != null) {
96107
return {
@@ -316,6 +327,17 @@ function getStylePropValue(prop: string, value: t.ObjectProperty['value'], eleme
316327
case 'paddingBottom':
317328
if (element === 'View') {
318329
if (value.type === 'StringLiteral' || value.type === 'NumericLiteral') {
330+
if (prop === 'padding' && value.type === 'StringLiteral' && /\s/.test(value.value)) {
331+
// Check if it has multiple whitespace-separated values
332+
let expansions = expandSpaceShorthand(prop, value.value, convertDimension);
333+
if (!expansions) {
334+
return null;
335+
}
336+
return {
337+
macroValues: expansions
338+
};
339+
}
340+
319341
let val = convertDimension(value.value, 'space');
320342
if (val != null) {
321343
return {
@@ -519,6 +541,56 @@ function handleProp(
519541
}
520542
}
521543

544+
function expandSpaceShorthand(
545+
prop: string,
546+
rawValue: string,
547+
convertFn: (val: string | number, type: 'space' | 'size' | 'px') => any
548+
) {
549+
// Split on whitespace (e.g. "10px 16px" -> ["10px", "16px"])
550+
let parts = rawValue.trim().split(/\s+/);
551+
552+
// One value => all sides
553+
// Two values => vertical horizontal
554+
// Three values => top, horizontal, bottom
555+
// Four values => top, right, bottom, left
556+
// Return keys and values in an array we can map to macroValues.
557+
switch (parts.length) {
558+
case 1: {
559+
let val = convertFn(parts[0], 'space');
560+
return [{key: prop, value: val}];
561+
}
562+
case 2: {
563+
let [y, x] = parts;
564+
return [
565+
{key: `${prop}Y`, value: convertFn(y, 'space')},
566+
{key: `${prop}X`, value: convertFn(x, 'space')}
567+
];
568+
}
569+
case 3: {
570+
// top horizontal bottom
571+
let [top, x, bottom] = parts;
572+
return [
573+
{key: `${prop}Top`, value: convertFn(top, 'space')},
574+
{key: `${prop}X`, value: convertFn(x, 'space')},
575+
{key: `${prop}Bottom`, value: convertFn(bottom, 'space')}
576+
];
577+
}
578+
case 4: {
579+
// top right bottom left
580+
let [top, right, bottom, left] = parts;
581+
return [
582+
{key: `${prop}Top`, value: convertFn(top, 'space')},
583+
{key: `${prop}Right`, value: convertFn(right, 'space')},
584+
{key: `${prop}Bottom`, value: convertFn(bottom, 'space')},
585+
{key: `${prop}Left`, value: convertFn(left, 'space')}
586+
];
587+
}
588+
default: {
589+
return null;
590+
}
591+
}
592+
}
593+
522594
export function transformStyleProps(path: NodePath<t.JSXElement>, element: string) {
523595
let macroValues = new Map<string, object | string | number | boolean>;
524596
let dynamicValues = new Map<string, t.ObjectProperty['value']>;

0 commit comments

Comments
 (0)