Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component as Selectors for Object Syntax #501

Closed
stoutmusclenugget opened this issue Dec 21, 2017 · 4 comments
Closed

Component as Selectors for Object Syntax #501

stoutmusclenugget opened this issue Dec 21, 2017 · 4 comments

Comments

@stoutmusclenugget
Copy link
Contributor

  • emotion version: 8.0.12
  • react version: 16.2.0

What you did:

We use object syntax to create our emotion components. There are times when we would like to use Components as selectors, just like for template literals (https://github.com/emotion-js/emotion/blob/master/docs/styled.md#targeting-another-emotion-component). I attempted this code:

const One = styled('div')({
  display: 'block'
});

const Two = styled('div')({
  [One]: {
    display: 'none'
  }
});

However, the markup did not reflect the style hierarchy. The elements have classes, but no associated styles:

screenshot 2017-12-21 14 32 58

screenshot 2017-12-21 14 32 41

screenshot 2017-12-21 14 32 32

If I swap the code out for template strings, like so:

const One = styled.div`
  display: block;
`;

const Two = styled.div`
  ${One} {
    display: none;
  }
`;

It works as expected. Is there a reason there is not enabled for object styles syntax?

Suggested solution:
I would prefer that there were a consistent api across object style syntax.

@emmatown
Copy link
Member

emmatown commented Dec 21, 2017

I think we definitely need to support this! There are a few changes that we need to make but it would be great if you could submit a PR for this!

To add the properties to styled object calls, we need to add the target property to the options object in the styled call, it would happen in a way something like this.

diff --git a/packages/babel-plugin-emotion/src/index.js b/packages/babel-plugin-emotion/src/index.js
index 5d4699d..1b7003a 100644
--- a/packages/babel-plugin-emotion/src/index.js
+++ b/packages/babel-plugin-emotion/src/index.js
@@ -193,6 +193,8 @@ export function buildStyledCallExpression(identifier, tag, path, state, t) {
 }
 
 export function buildStyledObjectCallExpression(path, state, identifier, t) {
+  const targetProperty = buildTargetObjectProperty(path, state, t)
+
   const identifierName = getIdentifierName(path, t)
   const tag = t.isCallExpression(path.node.callee)
     ? path.node.callee.arguments[0]
@@ -203,23 +205,20 @@ export function buildStyledObjectCallExpression(path, state, identifier, t) {
     args.push(t.stringLiteral(addSourceMaps(path.node.loc.start, state)))
   }
 
+  const objectProperties = [targetProperty]
+  if (state.opts.autoLabel && identifierName) {
+    objectProperties.push(
+      t.objectProperty(
+        t.identifier('label'),
+        t.stringLiteral(identifierName.trim())
+      )
+    )
+  }
+
   path.addComment('leading', '#__PURE__')
 
   return t.callExpression(
-    t.callExpression(
-      identifier,
-      state.opts.autoLabel && identifierName
-        ? [
-            tag,
-            t.objectExpression([
-              t.objectProperty(
-                t.identifier('label'),
-                t.stringLiteral(identifierName.trim())
-              )
-            ])
-          ]
-        : [tag]
-    ),
+    t.callExpression(identifier, [tag, t.objectExpression(objectProperties)]),
     args
   )
 }

For this, you shouldn't need to write any new tests, just update the snapshots that already exist.

We also need to add a toString property to Styled like this here

Object.defineProperty(Styled, 'toString', {
  enumerable: false,
  value() {
    if (
      process.env.NODE_ENV !== 'production' &&
      stableClassName === undefined
    ) {
      throw new Error(
        'Component selectors can only be used in conjunction with babel-plugin-emotion.'
      )
    }
    return `.${stableClassName}`
  }
})

For this, if you could add a test here that would be great.

emmatown pushed a commit that referenced this issue Dec 23, 2017
…Selectors Using the Object Syntax #501 (#503)

* [react-emotion][babel-plugin-emotion] Adds Support for Components as Selectors Using the Object Syntax #501

* Add the error message

* Adds Documentation

* Increase Threshold

* Adds test no-babel test coverage
@joelmats
Copy link

joelmats commented Jun 4, 2020

Is there a way to get this syntax to work with typescript?

@Andarist
Copy link
Member

Andarist commented Jun 4, 2020

I believe something like this should work:

const A = styled.div({
  color: 'hotpink',
  [`${OtherStyledComponent}`]: {
    backgroundColor: 'red'
  }
})

Note that this only works when using Babel to transpile your files or this: https://github.com/LeetCode-OpenSource/emotion-ts-plugin

@stoutmusclenugget
Copy link
Contributor Author

@joelmats @Andarist Yeah, I think that should work. We also do this in places which also works:

const A = styled.div({
  color: 'hotpink',
  [OtherStyledComponent.toString()]: {
    backgroundColor: 'red'
  }
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants