Skip to content

Commit a24c157

Browse files
authored
Skip shorthand property expansion if CSS variable given as value (#1467)
* Skip shorthand property expansion if CSS variable given as value * Update tests * Remove useless line from test case * Add changeset
1 parent 0013694 commit a24c157

File tree

4 files changed

+124
-9
lines changed

4 files changed

+124
-9
lines changed

.changeset/big-walls-boil.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@compiled/css': minor
3+
'@compiled/babel-plugin': patch
4+
---
5+
6+
Skip expansion of shorthand properties (e.g. padding, margin) if they have dynamic values (e.g. CSS variables, ternary expressions, arrow functions)

packages/babel-plugin/src/css-prop/__tests__/object-literal.test.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -606,10 +606,7 @@ describe('css prop object literal', () => {
606606
}}>hello world</div>
607607
`);
608608

609-
expect(actual).toInclude('{padding-top:0}');
610-
expect(actual).toInclude('{padding-right:var(--_1xlms2h)}');
611-
expect(actual).toInclude('{padding-bottom:0}');
612-
expect(actual).toInclude('{padding-left:var(--_1xlms2h)}');
609+
expect(actual).toInclude('{padding:0 var(--_1xlms2h)}');
613610
});
614611

615612
it('should parse an inline string interpolation delimited by multiple spaces', () => {
@@ -625,10 +622,7 @@ describe('css prop object literal', () => {
625622
}}>hello world</div>
626623
`);
627624

628-
expect(actual).toInclude('{padding-top:0}');
629-
expect(actual).toInclude('{padding-right:var(--_1xlms2h)}');
630-
expect(actual).toInclude('{padding-bottom:0}');
631-
expect(actual).toInclude('{padding-left:0}');
625+
expect(actual).toInclude('{padding:0 var(--_1xlms2h) 0 0}');
632626
});
633627

634628
it('should parse an inline string interpolation delimited by multiple spaces and suffix', () => {
@@ -784,4 +778,27 @@ describe('css prop object literal', () => {
784778

785779
expect(actual).toInclude('{display:grid}');
786780
});
781+
782+
it('should correctly expand shorthand property with ternary expression', () => {
783+
const actual = transform(`
784+
import { css } from '@compiled/react';
785+
786+
const morePadding = true;
787+
788+
<div css={{
789+
padding: morePadding ? "10px 20px 30px 40px" : "4px 8px",
790+
}}>
791+
Hello world
792+
</div>
793+
`);
794+
795+
expect(actual).toMatchInlineSnapshot(`
796+
"import*as React from'react';import{ax,ix,CC,CS}from"@compiled/react/runtime";const _4="._19bv1ylp{padding-left:40px}";const _3="._n3td1ul9{padding-bottom:30px}";const _2="._u5f3gktf{padding-right:20px}";const _="._ca0q19bv{padding-top:10px}";const morePadding=true;<CC>
797+
<CS>{[_,_2,_3,_4]}</CS>
798+
{<div className={ax(["_ca0q19bv _u5f3gktf _n3td1ul9 _19bv1ylp"])}>
799+
Hello world
800+
</div>}
801+
</CC>;"
802+
`);
803+
});
787804
});

packages/babel-plugin/src/styled/__tests__/call-expression.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,4 +641,82 @@ describe('styled object call expression', () => {
641641
"
642642
`);
643643
});
644+
645+
it('should refuse to expand shorthand property when value is unknown at build time (arrow function)', () => {
646+
const actual = transform(`
647+
import { styled } from '@compiled/react';
648+
649+
const Container = styled.div({
650+
padding: ({ customPadding }) => customPadding,
651+
});
652+
`);
653+
654+
expect(actual).toMatchInlineSnapshot(`
655+
"const _ = "._1yt414tu{padding:var(--_1hhnq9y)}";
656+
const Container = forwardRef(
657+
({ as: C = "div", style: __cmpls, ...__cmplp }, __cmplr) => {
658+
const { customPadding, ...__cmpldp } = __cmplp;
659+
return (
660+
<CC>
661+
<CS>{[_]}</CS>
662+
<C
663+
{...__cmpldp}
664+
style={{
665+
...__cmpls,
666+
"--_1hhnq9y": ix(__cmplp.customPadding),
667+
}}
668+
ref={__cmplr}
669+
className={ax(["_1yt414tu", __cmplp.className])}
670+
/>
671+
</CC>
672+
);
673+
}
674+
);
675+
"
676+
`);
677+
});
678+
679+
it('should refuse to expand shorthand property when value is unknown at build time (ternary expression)', () => {
680+
const actual = transform(`
681+
import { styled } from '@compiled/react';
682+
683+
const Container = styled.div({
684+
padding: ({ morePadding }) => morePadding ? morePadding : '4px 8px',
685+
});
686+
`);
687+
688+
expect(actual).toMatchInlineSnapshot(`
689+
"const _5 = "._19bvftgi{padding-left:8px}";
690+
const _4 = "._n3td1y44{padding-bottom:4px}";
691+
const _3 = "._u5f3ftgi{padding-right:8px}";
692+
const _2 = "._ca0q1y44{padding-top:4px}";
693+
const _ = "._1yt41v0o{padding:var(--_1dm0vu2)}";
694+
const Container = forwardRef(
695+
({ as: C = "div", style: __cmpls, ...__cmplp }, __cmplr) => {
696+
const { morePadding, ...__cmpldp } = __cmplp;
697+
return (
698+
<CC>
699+
<CS>{[_, _2, _3, _4, _5]}</CS>
700+
<C
701+
{...__cmpldp}
702+
style={{
703+
...__cmpls,
704+
"--_1dm0vu2": ix(__cmplp.morePadding),
705+
}}
706+
ref={__cmplr}
707+
className={ax([
708+
"",
709+
__cmplp.morePadding
710+
? "_1yt41v0o"
711+
: "_ca0q1y44 _u5f3ftgi _n3td1y44 _19bvftgi",
712+
__cmplp.className,
713+
])}
714+
/>
715+
</CC>
716+
);
717+
}
718+
);
719+
"
720+
`);
721+
});
644722
});

packages/css/src/plugins/expand-shorthands/index.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Plugin } from 'postcss';
2-
import { parse } from 'postcss-values-parser';
2+
import { parse, type ChildNode } from 'postcss-values-parser';
33

44
import { background } from './background';
55
import { flex } from './flex';
@@ -56,6 +56,15 @@ const shorthands: Record<string, ConversionFunction> = {
5656
*/
5757
};
5858

59+
const valueIsNotSafeToExpand = (node: ChildNode): boolean => {
60+
// This is the case where a CSS variable is given as the value, e.g.
61+
// `padding: var(--_fl6vf6)`. Value of _fl6vf6 is unknown, so this
62+
// cannot be expanded safely.
63+
//
64+
// https://github.com/atlassian-labs/compiled/issues/1331
65+
return node.type === 'func' && node.isVar;
66+
};
67+
5968
/**
6069
* PostCSS plugin that expands shortform properties to their longform equivalents.
6170
*/
@@ -68,12 +77,17 @@ export const expandShorthands = (): Plugin => {
6877
if (!expand) {
6978
return;
7079
}
80+
7181
const valueNode = parse(decl.value);
82+
if (valueNode.nodes.some(valueIsNotSafeToExpand)) {
83+
return;
84+
}
7285

7386
const longforms = expand(valueNode);
7487
if (!longforms) {
7588
throw new Error('Longform properties were not returned!');
7689
}
90+
7791
/** Return early if not replacing a node */
7892
if (longforms.length === 1 && longforms[0].prop === undefined) {
7993
return;

0 commit comments

Comments
 (0)