diff --git a/.changeset/cyan-waves-rest.md b/.changeset/cyan-waves-rest.md new file mode 100644 index 000000000..bd9188dd9 --- /dev/null +++ b/.changeset/cyan-waves-rest.md @@ -0,0 +1,5 @@ +--- +'@compiled/babel-plugin': minor +--- + +Fix supporting ternaries referencing cssMap style objects when extracting styles. diff --git a/packages/babel-plugin/src/css-map/__tests__/index.test.ts b/packages/babel-plugin/src/css-map/__tests__/index.test.ts index 95c8d9185..7036eecc4 100644 --- a/packages/babel-plugin/src/css-map/__tests__/index.test.ts +++ b/packages/babel-plugin/src/css-map/__tests__/index.test.ts @@ -22,11 +22,18 @@ describe('css map basic functionality', () => { import { cssMap } from '@compiled/react'; const styles = cssMap(${styles}); + + const Component = () =>
+ + +
`); - expect(actual).toInclude( - 'const styles={danger:"_syaz5scu _bfhk5scu",success:"_syazbf54 _bfhkbf54"};' - ); + expect(actual).toIncludeMultiple([ + 'const styles={danger:"_syaz5scu _bfhk5scu",success:"_syazbf54 _bfhkbf54"};', + '', + '', + ]); }); it('should transform css map even with an empty object', () => { @@ -45,6 +52,42 @@ describe('css map basic functionality', () => { expect(actual).toInclude('const styles={danger:"",success:"_syazbf54 _bfhkbf54"};'); }); + it('should transform ternary-based conditional referencing cssMap declarations', () => { + const actual = transform(` + import { cssMap } from '@compiled/react'; + + const styles = cssMap({ + root: { display: 'block' }, + positive: { background: 'white', color: 'black' }, + negative: { background: 'green', color: 'red' }, + bold: { fontWeight: 'bold' }, + normal: { fontWeight: 'normal' }, + }); + + const Component = ({ isPrimary, weight }) => ( +
+ ); + `); + + expect(actual).toIncludeMultiple([ + '._1e0c1ule{display:block}', + '._bfhk1x77{background-color:white}', + '._syaz11x8{color:black}', + '._bfhkbf54{background-color:green}', + '._syaz5scu{color:red}', + '._k48p8n31{font-weight:bold}', + '._k48p4jg8{font-weight:normal}', + 'const styles={root:"_1e0c1ule",positive:"_bfhk1x77 _syaz11x8",negative:"_bfhkbf54 _syaz5scu",bold:"_k48p8n31",normal:"_k48p4jg8"}', + '
', + ]); + }); + it('should error out if variants are not defined at the top-most scope of the module.', () => { expect(() => { transform(` diff --git a/packages/babel-plugin/src/utils/css-builders.ts b/packages/babel-plugin/src/utils/css-builders.ts index d35a9b293..f0d6d6f0b 100644 --- a/packages/babel-plugin/src/utils/css-builders.ts +++ b/packages/babel-plugin/src/utils/css-builders.ts @@ -381,6 +381,8 @@ const extractConditionalExpression = (node: t.ConditionalExpression, meta: Metad } } else if (t.isConditionalExpression(pathNode)) { cssOutput = extractConditionalExpression(pathNode, meta); + } else if (t.isMemberExpression(pathNode)) { + cssOutput = extractMemberExpression(pathNode, meta, false); } if (cssOutput) { @@ -663,6 +665,44 @@ const extractObjectExpression = (node: t.ObjectExpression, meta: Metadata): CSSO return { css: mergeSubsequentUnconditionalCssItems(css), variables }; }; +/** + * Extracts CSS data from a member expression node (eg. `styles.primary`) + * + * @param node Node we're interested in extracting CSS from. + * @param meta {Metadata} Useful metadata that can be used during the transformation + * @param fallbackToEvaluate {Boolean} Whether to fallback to re-evaluating the expression if it's not a cssMap identifier + */ +function extractMemberExpression( + node: t.MemberExpression, + meta: Metadata, + fallbackToEvaluate?: true +): CSSOutput; +function extractMemberExpression( + node: t.MemberExpression, + meta: Metadata, + fallbackToEvaluate: false +): CSSOutput | undefined; +function extractMemberExpression( + node: t.MemberExpression, + meta: Metadata, + fallbackToEvaluate = true +): CSSOutput | undefined { + const bindingIdentifier = findBindingIdentifier(node); + if (bindingIdentifier && meta.state.cssMap[bindingIdentifier.name]) { + return { + css: [{ type: 'map', expression: node, name: bindingIdentifier.name, css: '' }], + variables: [], + }; + } + + if (fallbackToEvaluate) { + const { value, meta: updatedMeta } = evaluateExpression(node, meta); + return buildCss(value, updatedMeta); + } + + return undefined; +} + /** * Extracts CSS data from a template literal node. * @@ -880,15 +920,7 @@ export const buildCss = (node: t.Expression | t.Expression[], meta: Metadata): C } if (t.isMemberExpression(node)) { - const bindingIdentifier = findBindingIdentifier(node); - if (bindingIdentifier && meta.state.cssMap[bindingIdentifier.name]) { - return { - css: [{ type: 'map', expression: node, name: bindingIdentifier.name, css: '' }], - variables: [], - }; - } - const { value, meta: updatedMeta } = evaluateExpression(node, meta); - return buildCss(value, updatedMeta); + return extractMemberExpression(node, meta); } if (t.isArrowFunctionExpression(node)) { @@ -903,6 +935,10 @@ export const buildCss = (node: t.Expression | t.Expression[], meta: Metadata): C if (t.isConditionalExpression(node.body)) { return extractConditionalExpression(node.body, meta); } + + if (t.isMemberExpression(node.body)) { + return extractMemberExpression(node.body, meta); + } } if (t.isIdentifier(node)) {