From 8d9374a9e5ca8e22e2ef621e7c6488872c8a62b4 Mon Sep 17 00:00:00 2001 From: Tommy Ljungberg Date: Wed, 18 Jul 2018 16:32:56 +0200 Subject: [PATCH] Add support for dynamic html elements (#462) Adds support for cases where the html tag is dynamic: const Heading = `h${props.level}` {props.children} --- .travis.yml | 2 +- src/babel.js | 7 +- test/__snapshots__/attribute.js.snap | 80 ++++++++++-------- test/__snapshots__/external.js.snap | 14 ++++ test/__snapshots__/index.js.snap | 53 ++++++++++++ test/external.js | 5 ++ ...ttribute-generation-classname-rewriting.js | 84 ++++++++++--------- test/fixtures/dynamic-element-class.js | 32 +++++++ test/fixtures/dynamic-element-external.js | 12 +++ test/fixtures/dynamic-element.js | 43 ++++++++++ test/index.js | 10 +++ 11 files changed, 264 insertions(+), 78 deletions(-) create mode 100644 test/fixtures/dynamic-element-class.js create mode 100644 test/fixtures/dynamic-element-external.js create mode 100644 test/fixtures/dynamic-element.js diff --git a/.travis.yml b/.travis.yml index 49ab13c5..c9c1e4b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: node_js node_js: - - "6" - "8" + - "10" \ No newline at end of file diff --git a/src/babel.js b/src/babel.js index 561590a6..24e1ebb3 100644 --- a/src/babel.js +++ b/src/babel.js @@ -40,11 +40,16 @@ export default function({ types: t }) { state.ignoreClosing = 0 } + const tag = path.get('name') + if ( name && name !== 'style' && name !== STYLE_COMPONENT && - name.charAt(0) !== name.charAt(0).toUpperCase() + (name.charAt(0) !== name.charAt(0).toUpperCase() || + Object.values(path.scope.bindings).some(binding => + binding.referencePaths.some(r => r === tag) + )) ) { if (state.className) { addClassName(path, state.className) diff --git a/test/__snapshots__/attribute.js.snap b/test/__snapshots__/attribute.js.snap index eb032a59..a25a1b6e 100644 --- a/test/__snapshots__/attribute.js.snap +++ b/test/__snapshots__/attribute.js.snap @@ -100,41 +100,47 @@ exports[`rewrites className 1`] = ` "var _this = this; import _JSXStyle from \\"styled-jsx/style\\"; -export default (() =>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <_JSXStyle styleId={\\"2886504620\\"} css={\\"div.jsx-2886504620{color:red;}\\"} /> -
);" +export default (() => { + const Element = 'div'; + return
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + <_JSXStyle styleId={\\"2886504620\\"} css={\\"div.jsx-2886504620{color:red;}\\"} /> +
; +});" `; diff --git a/test/__snapshots__/external.js.snap b/test/__snapshots__/external.js.snap index 9614a2a0..01288211 100644 --- a/test/__snapshots__/external.js.snap +++ b/test/__snapshots__/external.js.snap @@ -148,6 +148,20 @@ export default { };" `; +exports[`use external stylesheet and dynamic element 1`] = ` +"import _JSXStyle from \\"styled-jsx/style\\"; +import styles from './styles2'; + +export default (({ level = 1 }) => { + const Element = \`h\${level}\`; + + return +

dynamic element

+ <_JSXStyle styleId={styles.__scopedHash} css={styles.__scoped} /> +
; +});" +`; + exports[`use external stylesheets (global only) 1`] = ` "import _JSXStyle from 'styled-jsx/style'; import styles, { foo as styles3 } from './styles'; diff --git a/test/__snapshots__/index.js.snap b/test/__snapshots__/index.js.snap index 89f49576..61f62683 100644 --- a/test/__snapshots__/index.js.snap +++ b/test/__snapshots__/index.js.snap @@ -103,6 +103,59 @@ class Test extends React.Component { }" `; +exports[`works with dynamic element 1`] = ` +"import _JSXStyle from \\"styled-jsx/style\\"; +export default (({ level = 1 }) => { + const Element = \`h\${level}\`; + + return +

dynamic element

+ <_JSXStyle styleId={\\"1253978709\\"} css={\\".root.jsx-1253978709{background:red;}\\"} /> +
; +}); + +export const TestLowerCase = ({ level = 1 }) => { + const element = \`h\${level}\`; + + return +

dynamic element

+ <_JSXStyle styleId={\\"1253978709\\"} css={\\".root.jsx-1253978709{background:red;}\\"} /> +
; +}; + +const Element2 = 'div'; +export const Test2 = () => { + return +

dynamic element

+ <_JSXStyle styleId={\\"1253978709\\"} css={\\".root.jsx-1253978709{background:red;}\\"} /> +
; +};" +`; + +exports[`works with dynamic element in class 1`] = ` +"import _JSXStyle from 'styled-jsx/style'; +export default class { + render() { + const Element = 'div'; + + return +

dynamic element

+ <_JSXStyle styleId={\\"1800172487\\"} css={\\".root.jsx-1800172487{background:red;}\\"} /> +
; + } +} + +const Element2 = 'div'; +export const Test2 = class { + render() { + return +

dynamic element

+ <_JSXStyle styleId={\\"1800172487\\"} css={\\".root.jsx-1800172487{background:red;}\\"} /> +
; + } +};" +`; + exports[`works with expressions in template literals 1`] = ` "import _JSXStyle from 'styled-jsx/style'; const darken = c => c; diff --git a/test/external.js b/test/external.js index 67325171..13c8d83a 100644 --- a/test/external.js +++ b/test/external.js @@ -88,3 +88,8 @@ test('injects JSXStyle for nested scope', async t => { `) t.snapshot(code) }) + +test('use external stylesheet and dynamic element', async t => { + const { code } = await transform('./fixtures/dynamic-element-external.js') + t.snapshot(code) +}) diff --git a/test/fixtures/attribute-generation-classname-rewriting.js b/test/fixtures/attribute-generation-classname-rewriting.js index b893a35d..34570937 100644 --- a/test/fixtures/attribute-generation-classname-rewriting.js +++ b/test/fixtures/attribute-generation-classname-rewriting.js @@ -1,39 +1,45 @@ -export default () => ( -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-) +export default () => { + const Element = 'div' + return ( +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + +
+ ) +} diff --git a/test/fixtures/dynamic-element-class.js b/test/fixtures/dynamic-element-class.js new file mode 100644 index 00000000..5b8abce8 --- /dev/null +++ b/test/fixtures/dynamic-element-class.js @@ -0,0 +1,32 @@ +export default class { + render() { + const Element = 'div' + + return ( + +

dynamic element

+ +
+ ) + } +} + +const Element2 = 'div' +export const Test2 = class { + render() { + return ( + +

dynamic element

+ +
+ ) + } +} diff --git a/test/fixtures/dynamic-element-external.js b/test/fixtures/dynamic-element-external.js new file mode 100644 index 00000000..12807856 --- /dev/null +++ b/test/fixtures/dynamic-element-external.js @@ -0,0 +1,12 @@ +import styles from './styles2' + +export default ({ level = 1 }) => { + const Element = `h${level}` + + return ( + +

dynamic element

+ +
+ ) +} diff --git a/test/fixtures/dynamic-element.js b/test/fixtures/dynamic-element.js new file mode 100644 index 00000000..64caec35 --- /dev/null +++ b/test/fixtures/dynamic-element.js @@ -0,0 +1,43 @@ +export default ({ level = 1 }) => { + const Element = `h${level}` + + return ( + +

dynamic element

+ +
+ ) +} + +export const TestLowerCase = ({ level = 1 }) => { + const element = `h${level}` + + return ( + +

dynamic element

+ +
+ ) +} + +const Element2 = 'div' +export const Test2 = () => { + return ( + +

dynamic element

+ +
+ ) +} diff --git a/test/index.js b/test/index.js index 87fbd524..d27f3130 100644 --- a/test/index.js +++ b/test/index.js @@ -82,6 +82,16 @@ test('works with css tagged template literals in the same file', async t => { t.snapshot(code) }) +test('works with dynamic element', async t => { + const { code } = await transform('./fixtures/dynamic-element.js') + t.snapshot(code) +}) + +test('works with dynamic element in class', async t => { + const { code } = await transform('./fixtures/dynamic-element-class.js') + t.snapshot(code) +}) + test('does not transpile nested style tags', async t => { const { message } = await t.throws( transform('./fixtures/nested-style-tags.js')