From 68fb54b2a6ec7687b09122beb3226ee89b0771c7 Mon Sep 17 00:00:00 2001 From: Daniel Del Core Date: Sun, 21 Feb 2021 21:32:28 +1100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=20Refactors=20the=20macro=20to=20c?= =?UTF-8?q?lean=20things=20up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- packages/macro/src/macro.js | 130 +++++----- packages/macro/src/macro.spec.ts | 224 ++++++++++++------ .../macro/src/runtime/jsx.server.spec.tsx | 64 +++-- packages/macro/src/runtime/jsx.spec.tsx | 70 ++++-- packages/macro/src/runtime/jsx.tsx | 6 - 6 files changed, 332 insertions(+), 164 deletions(-) diff --git a/package.json b/package.json index 95689f6..96f2c17 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "start": "run-p start:*", "start:watch": "preconstruct watch", "start:stories": "start-storybook -p 9000 -s assets", - "clean": "rm -rf node_modules/.cache && rimraf packages/*/{tsconfig.tsbuildinfo,lib,dist}", + "clean": "rm -rf node_modules/.cache && rimraf packages/**/{tsconfig.tsbuildinfo,lib,dist}", "validate": "yarn build && yarn lint && yarn monorepo:check && preconstruct validate", "postinstall": "preconstruct dev && yarn monorepo:check", "monorepo:check": "manypkg check", diff --git a/packages/macro/src/macro.js b/packages/macro/src/macro.js index f66f930..3fd6a12 100644 --- a/packages/macro/src/macro.js +++ b/packages/macro/src/macro.js @@ -3,6 +3,14 @@ const { parse } = require('@babel/parser'); const { process, themify } = require('@trousers/core'); const hash = require('@trousers/hash').default; +const libraryMeta = { + runtimeComponent: 'TrousersNested', + runtimeModulePath: '@trousers/macro/runtime', +}; + +const findJsxAttribute = (path, attributeName) => + path.node.attributes.find(attr => attr.name.name === attributeName); + const parseObject = (objectExpression, onInterpolation = () => {}) => objectExpression.properties.reduce((accum, { key, value }) => { let parsedValue; @@ -41,11 +49,9 @@ function macro({ references, babel }) { if (references.css.length === 0) return; const program = references.css[0].findParent(path => path.isProgram()); + const interpolations = []; - let interpolationsCount = 0; - - references.css.forEach(reference => { - const interpolations = []; + references.css.forEach((reference, index) => { const styleBlocks = []; const importName = reference.node.name; @@ -71,8 +77,12 @@ function macro({ references, babel }) { const rawStyleBlock = parseObject( objectExpression, interpolation => { - const id = `--interpol${interpolationsCount++}`; - interpolations.push({ reference, id, interpolation }); + const id = `--interpol${interpolations.length}`; + interpolations.push({ + referenceIndex: index, + id, + value: interpolation, + }); return `var(${id})`; }, ); @@ -84,8 +94,8 @@ function macro({ references, babel }) { switch (type) { case importName: - elementId = id; - className = `.${id && id + '-'}${hashedStyles}`; + elementId = `${id && id + '-'}${hashedStyles}`; + className = `.${elementId}`; processedStyles = process(className, rawStyleBlock); break; case 'modifier': @@ -116,76 +126,80 @@ function macro({ references, babel }) { ]), ); }); + }); - // Dynamic interpolations - let jsxOpeningElements = []; - const parentJsxElement = reference.find(path => - path.isJSXOpeningElement(), - ); - if (parentJsxElement) jsxOpeningElements.push(parentJsxElement); - - if (!jsxOpeningElements.length) { - const styleVariable = reference.findParent( - path => path.type === 'VariableDeclarator', - ); - const styleVariableId = styleVariable && styleVariable.node.id.name; - - program.traverse({ - JSXOpeningElement: path => { - const cssAttr = path.node.attributes.find( - attr => - attr.name.name === 'css' && - attr.value.expression.name === styleVariableId, - ); - if (!cssAttr) return; - - jsxOpeningElements.push(path); - }, - }); - } - - jsxOpeningElements.forEach(jsxOpeningElement => { - const stylesAttr = jsxOpeningElement.node.attributes.find( - attr => attr.name.name === 'styles', - ); + program.traverse({ + JSXOpeningElement: path => { + const cssAttr = findJsxAttribute(path, 'css'); + if (!cssAttr) return; + const cssPropExpression = cssAttr.value.expression; + const stylesAttr = findJsxAttribute(path, 'styles'); const styleProperties = stylesAttr ? stylesAttr.value.expression.properties : []; - // ERROR: This code runs over opening elements multiple times.... - // need to refactor this whole damn thing - jsxOpeningElement.replaceWith( + const interpolationProperties = interpolations + .filter(({ referenceIndex }) => { + let matchedReferenceIndex = -1; + references.css.forEach((referencePath, i) => { + // collector passed directly into css prop + if ( + cssPropExpression.callee && + cssPropExpression.callee.name === + referencePath.node.name && + cssPropExpression.callee.start === + referencePath.node.start + ) { + matchedReferenceIndex = i; + } + + // collector variable passed into css prop + const variableDeclarator = referencePath.find(p => + p.isVariableDeclarator(), + ); + + if ( + variableDeclarator.node.id.name === + cssPropExpression.name + ) { + matchedReferenceIndex = i; + } + }); + + return referenceIndex === matchedReferenceIndex; + }) + .map(({ id, value }) => + t.objectProperty(t.stringLiteral(id), value), + ); + + path.replaceWith( t.jsxOpeningElement( - t.jsxIdentifier('TrousersNested'), + t.jsxIdentifier(libraryMeta.runtimeComponent), [ - ...jsxOpeningElement.node.attributes.filter( + ...path.node.attributes.filter( attr => attr.name.name !== 'styles', ), t.jsxAttribute( t.jsxIdentifier('elementType'), - t.stringLiteral(jsxOpeningElement.node.name.name), + t.stringLiteral(path.node.name.name), ), t.jsxAttribute( - t.jsxIdentifier('styles'), + t.jsxIdentifier('style'), t.jsxExpressionContainer( t.objectExpression([ ...styleProperties, - ...interpolations.map( - ({ id, interpolation }) => - t.objectProperty( - t.stringLiteral(id), - interpolation, - ), - ), + ...interpolationProperties, ]), ), ), ], - jsxOpeningElement.node.selfClosing, + path.node.selfClosing, ), ); - }); + + path.skip(); + }, }); // Import manipulation @@ -199,11 +213,11 @@ function macro({ references, babel }) { t.identifier(importName), ), t.importSpecifier( - t.identifier('TrousersNested'), - t.identifier('TrousersNested'), + t.identifier(libraryMeta.runtimeComponent), + t.identifier(libraryMeta.runtimeComponent), ), ], - t.stringLiteral('@trousers/macro/runtime'), + t.stringLiteral(libraryMeta.runtimeModulePath), ), ); diff --git a/packages/macro/src/macro.spec.ts b/packages/macro/src/macro.spec.ts index f27f338..f053583 100644 --- a/packages/macro/src/macro.spec.ts +++ b/packages/macro/src/macro.spec.ts @@ -17,6 +17,7 @@ describe('macro', () => { describe('when parsing css collectors', () => { it('should process element collector', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 'blue' }); const App = () => ; @@ -25,6 +26,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-2561700995\\": \\"color: blue;\\" }); @@ -32,7 +34,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -40,6 +42,7 @@ describe('macro', () => { it('should process element collector without an identifier', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css({ color: 'blue' }); const App = () => ; @@ -48,6 +51,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"\\", { \\".2561700995\\": \\"color: blue;\\" }); @@ -55,7 +59,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -63,6 +67,7 @@ describe('macro', () => { it('should process collector with a single modifier', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 'blue' }) .modifier('primary', { color: 'brown' }); @@ -72,6 +77,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-2561700995\\": \\"color: blue;\\" }).modifier(\\"primary\\", { @@ -82,7 +88,7 @@ describe('macro', () => { css: styles, $primary: true, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -90,6 +96,7 @@ describe('macro', () => { it('should process collector with multiple modifiers', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 'blue' }) .modifier('primary', { color: 'brown' }) @@ -104,6 +111,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-2561700995\\": \\"color: blue;\\" }).modifier(\\"primary\\", { @@ -122,7 +130,7 @@ describe('macro', () => { $primary: primary, $secondary: secondary, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" }); };" @@ -131,6 +139,7 @@ describe('macro', () => { it('should process collector with many modifiers', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 'blue' }) .modifier('primary', { color: 'brown' }) @@ -143,6 +152,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-2561700995\\": \\"color: blue;\\" }).modifier(\\"primary\\", { @@ -158,7 +168,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -166,6 +176,7 @@ describe('macro', () => { it('should process collector with a theme', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 'var(--brand-background)' }) .theme({ brand: { background: 'green' }}); @@ -175,6 +186,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-2140373281\\": \\"color: var(--brand-background);\\" }).theme(\\"\\", { @@ -184,7 +196,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -192,6 +204,7 @@ describe('macro', () => { it('should process collector with a deeply nested theme', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 'var(--brand-background)' }) .theme({ @@ -207,6 +220,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-2140373281\\": \\"color: var(--brand-background);\\" }).theme(\\"\\", { @@ -216,7 +230,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -224,6 +238,7 @@ describe('macro', () => { it('should process collector with a global', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', {}) .global({ @@ -237,6 +252,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", {}).global(\\"global-Button-480010618\\", { \\":root\\": \\"background-color: red;\\" }); @@ -244,7 +260,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -268,7 +284,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); @@ -276,12 +292,14 @@ describe('macro', () => { it('should do nothing in the case of an unused import', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const App = () => ; `; expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; + import React from 'react'; const App = () => /*#__PURE__*/_jsx(\\"button\\", { children: \\"Submit\\" @@ -291,8 +309,9 @@ describe('macro', () => { }); describe('when interpolations are detected', () => { - it('should correctly render elements without interpolations', () => { + it('should render elements without interpolations', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 'red' }); const App = () => ; @@ -301,6 +320,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-2313942302\\": \\"color: red;\\" }); @@ -308,14 +328,15 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); }); - it('should correctly interpolate booleans (BooleanLiteral)', () => { + it('should interpolate booleans (BooleanLiteral)', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: true }); const App = () => ; @@ -324,6 +345,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-3336976155\\": \\"color: true;\\" }); @@ -331,14 +353,15 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); }); - it('should correctly interpolate numbers (NumericLiteral)', () => { + it('should interpolate numbers (NumericLiteral)', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 5 }); const App = () => ; @@ -347,6 +370,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-1906181116\\": \\"color: 5;\\" }); @@ -354,14 +378,15 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: {}, + style: {}, children: \\"Submit\\" });" `); }); - it('should correctly interpolate variables (Identifier)', () => { + it('should interpolate variables (Identifier)', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const foo = 'blue'; const styles = css('Button', { color: foo }); @@ -371,6 +396,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const foo = 'blue'; const styles = css(\\"Button\\", { \\".Button-4214914708\\": \\"color: var(--interpol0);\\" @@ -379,7 +405,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: { + style: { \\"--interpol0\\": foo }, children: \\"Submit\\" @@ -387,8 +413,9 @@ describe('macro', () => { `); }); - it('should correctly interpolate functions (CallExpression)', () => { + it('should interpolate functions (CallExpression)', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: foo() }); const App = () => ; @@ -397,6 +424,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-4214914708\\": \\"color: var(--interpol0);\\" }); @@ -404,7 +432,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: { + style: { \\"--interpol0\\": foo() }, children: \\"Submit\\" @@ -412,8 +440,9 @@ describe('macro', () => { `); }); - it('should correctly interpolate evaluations (BinaryExpression)', () => { + it('should interpolate evaluations (BinaryExpression)', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const styles = css('Button', { color: 5+5 }); const App = () => ; @@ -422,6 +451,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const styles = css(\\"Button\\", { \\".Button-4214914708\\": \\"color: var(--interpol0);\\" }); @@ -429,7 +459,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: { + style: { \\"--interpol0\\": 5 + 5 }, children: \\"Submit\\" @@ -439,6 +469,7 @@ describe('macro', () => { it('should not add interpolations to jsx element if styles are not in use', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const foo = 'blue'; const styles = css('Button', { color: foo }); @@ -449,6 +480,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const foo = 'blue'; const styles = css(\\"Button\\", { \\".Button-4214914708\\": \\"color: var(--interpol0);\\" @@ -460,26 +492,28 @@ describe('macro', () => { `); }); - it('should correctly interpolate styles used by nested elements', () => { + it('should interpolate styles used by nested elements', () => { const result = transform` + import React from 'react'; import { css } from './macro'; - const foo = 'blue'; - const bar = 'green'; - const styles = css('Button', { color: foo }); - const innerStyles = css('ButtonInner', { color: bar }); + const foo = 'blue'; + const bar = 'green'; + const styles = css('Button', { color: foo }); + const innerStyles = css('ButtonInner', { color: bar }); - const App = () => ( - - ); + const App = () => ( + + ); `; expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const foo = 'blue'; const bar = 'green'; const styles = css(\\"Button\\", { @@ -492,13 +526,13 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: { + style: { \\"--interpol0\\": foo }, children: /*#__PURE__*/_jsx(TrousersNested, { css: innerStyles, elementType: \\"span\\", - styles: { + style: { \\"--interpol1\\": bar }, children: \\"Hello, World!\\" @@ -507,30 +541,32 @@ describe('macro', () => { `); }); - it('should correctly interpolate styles used by sibling elements', () => { + it('should interpolate styles used by sibling elements', () => { const result = transform` + import React from 'react'; import { css } from './macro'; - const foo = 'blue'; - const bar = 'green'; - const styles = css('Button', { color: foo }); - const siblingStyles = css('ButtonInner', { color: bar }); + const foo = 'blue'; + const bar = 'green'; + const styles = css('Button', { color: foo }); + const siblingStyles = css('ButtonInner', { color: bar }); - const App = () => ( -
- - Hello, World! - - -
- ); + const App = () => ( +
+ + Hello, World! + + +
+ ); `; expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { jsxs as _jsxs } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const foo = 'blue'; const bar = 'green'; const styles = css(\\"Button\\", { @@ -544,14 +580,14 @@ describe('macro', () => { children: [/*#__PURE__*/_jsx(TrousersNested, { css: siblingStyles, elementType: \\"span\\", - styles: { + style: { \\"--interpol1\\": bar }, children: \\"Hello, World!\\" }), /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: { + style: { \\"--interpol0\\": foo }, children: \\"Submit\\" @@ -560,8 +596,9 @@ describe('macro', () => { `); }); - it('should correctly interpolate reused styles', () => { + it('should interpolate reused styles', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const foo = 'blue'; const styles = css('Button', { color: foo }); @@ -578,6 +615,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const foo = 'blue'; const styles = css(\\"Button\\", { \\".Button-4214914708\\": \\"color: var(--interpol0);\\" @@ -586,13 +624,13 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: { + style: { \\"--interpol0\\": foo }, children: /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"span\\", - styles: { + style: { \\"--interpol0\\": foo }, children: \\"Hello, World!\\" @@ -601,8 +639,9 @@ describe('macro', () => { `); }); - it('should correctly add interpolations to an in-use style attribute', () => { + it('should add interpolations to an in-use style attribute', () => { const result = transform` + import React from 'react'; import { css } from './macro'; const foo = 'blue'; const styles = css('Button', { color: foo }); @@ -617,6 +656,7 @@ describe('macro', () => { expect(result).toMatchInlineSnapshot(` "import { jsx as _jsx } from \\"react/jsx-runtime\\"; import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React from 'react'; const foo = 'blue'; const styles = css(\\"Button\\", { \\".Button-4214914708\\": \\"color: var(--interpol0);\\" @@ -625,7 +665,7 @@ describe('macro', () => { const App = () => /*#__PURE__*/_jsx(TrousersNested, { css: styles, elementType: \\"button\\", - styles: { + style: { color: 'red', \\"--interpol0\\": foo }, @@ -634,20 +674,60 @@ describe('macro', () => { `); }); - it('should correctly interpolate styles passed directly into the css prop', () => { + it('should interpolate styles passed directly into the css prop', () => { const result = transform` import React, { useState } from 'react'; - import { css } from './macro'; + import { css } from './macro'; + + const App = () => { + const [foo, setFoo] = useState('blue'); + + return ( + + ); + } + `; + + expect(result).toMatchInlineSnapshot(` + "import { jsx as _jsx } from \\"react/jsx-runtime\\"; + import { css, TrousersNested } from \\"@trousers/macro/runtime\\"; + import React, { useState } from 'react'; const App = () => { const [foo, setFoo] = useState('blue'); + return /*#__PURE__*/_jsx(TrousersNested, { + css: css(\\"Button\\", { + \\".Button-4214914708\\": \\"color: var(--interpol0);\\" + }), + elementType: \\"button\\", + style: { + \\"--interpol0\\": foo + }, + children: \\"Hello, World!\\" + }); + };" + `); + }); - return ( - - ); - } + it('should interpolate styles passed directly into multiple css props', () => { + const result = transform` + import React, { useState } from 'react'; + import { css } from './macro'; + + const App = () => { + const [foo, setFoo] = useState('blue'); + const [bar, setBar] = useState('red'); + + return ( + + ); + } `; expect(result).toMatchInlineSnapshot(` @@ -657,15 +737,25 @@ describe('macro', () => { const App = () => { const [foo, setFoo] = useState('blue'); + const [bar, setBar] = useState('red'); return /*#__PURE__*/_jsx(TrousersNested, { css: css(\\"Button\\", { \\".Button-4214914708\\": \\"color: var(--interpol0);\\" }), elementType: \\"button\\", - styles: { + style: { \\"--interpol0\\": foo }, - children: \\"Hello, World!\\" + children: /*#__PURE__*/_jsx(TrousersNested, { + css: css(\\"Span\\", { + \\".Span-4214944499\\": \\"color: var(--interpol1);\\" + }), + elementType: \\"span\\", + style: { + \\"--interpol1\\": bar + }, + children: \\"Hello, World!\\" + }) }); };" `); diff --git a/packages/macro/src/runtime/jsx.server.spec.tsx b/packages/macro/src/runtime/jsx.server.spec.tsx index 9f4ab68..ba30641 100644 --- a/packages/macro/src/runtime/jsx.server.spec.tsx +++ b/packages/macro/src/runtime/jsx.server.spec.tsx @@ -1,6 +1,6 @@ -/** @jsx jsx */ +import React from 'react'; import css from './css'; -import jsx from './jsx'; +import TrousersNested from './jsx'; import { render } from '@testing-library/react'; jest.mock('@trousers/core', () => ({ @@ -13,8 +13,12 @@ describe('jsx (ssr mode)', () => { it('renders element styles', () => { const styles = css('element', { '.element-2313942302': 'color: red;' }); const { container, getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -25,8 +29,12 @@ describe('jsx (ssr mode)', () => { it('renders element styles without id', () => { const styles = css('', { '.2313942302': 'color: red;' }); const { container, getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"2313942302"`, @@ -40,8 +48,12 @@ describe('jsx (ssr mode)', () => { }).modifier('primary', { '.primary-2561700995': 'color: blue;' }); const { container, getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -57,8 +69,13 @@ describe('jsx (ssr mode)', () => { }); const { container, getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -74,8 +91,13 @@ describe('jsx (ssr mode)', () => { }); const { container, getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -91,8 +113,13 @@ describe('jsx (ssr mode)', () => { }); const { container, getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302 primary-2561700995"`, @@ -107,8 +134,13 @@ describe('jsx (ssr mode)', () => { '.primary-2561700995': 'color: blue;', }); const { container, getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"2313942302 primary-2561700995"`, diff --git a/packages/macro/src/runtime/jsx.spec.tsx b/packages/macro/src/runtime/jsx.spec.tsx index 67fb7b2..2af1ad9 100644 --- a/packages/macro/src/runtime/jsx.spec.tsx +++ b/packages/macro/src/runtime/jsx.spec.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-empty-interface */ -/** @jsx jsx */ +import React from 'react'; import css from './css'; -import jsx from './jsx'; +import TrousersNested from './jsx'; import { render } from '@testing-library/react'; let mountMock = jest.fn(); @@ -20,8 +20,14 @@ describe('jsx', () => { it('mounts element styles', () => { const styles = css('element', { '.element-2313942302': 'color: red;' }); - // @ts-ignore runtime css prop has no types when consumed - const { getByTestId } = render(
); + const { getByTestId } = render( + , + ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -35,8 +41,14 @@ describe('jsx', () => { it('mounts element styles without id', () => { const styles = css('', { '.2313942302': 'color: red;' }); - // @ts-ignore runtime css prop has no types when consumed - const { getByTestId } = render(
); + const { getByTestId } = render( + , + ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"2313942302"`, @@ -55,8 +67,14 @@ describe('jsx', () => { '.primary-2561700995': 'color: blue;', }); - // @ts-ignore runtime css prop has no types when consumed - const { getByTestId } = render(
); + const { getByTestId } = render( + , + ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -78,8 +96,13 @@ describe('jsx', () => { }); const { getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -100,8 +123,13 @@ describe('jsx', () => { }); const { getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( `"element-2313942302"`, @@ -122,8 +150,13 @@ describe('jsx', () => { }); const { getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( @@ -150,8 +183,13 @@ describe('jsx', () => { }); const { getByTestId } = render( - // @ts-ignore runtime css prop has no types when consumed -
, + , ); expect(getByTestId('test').className).toMatchInlineSnapshot( diff --git a/packages/macro/src/runtime/jsx.tsx b/packages/macro/src/runtime/jsx.tsx index 9be21b2..ceedd4a 100644 --- a/packages/macro/src/runtime/jsx.tsx +++ b/packages/macro/src/runtime/jsx.tsx @@ -43,12 +43,6 @@ const TrousersNested: FC = props => { return obj; }, {}); - // console.log(props); - // console.log(props.elementType); - // console.log(props.elementType); - // console.log(props.elementType); - // console.log(props.elementType); - const Element = createElement( props.elementType, {