emotion-js / emotion

πŸ‘©β€πŸŽ€ CSS-in-JS library designed for high performance style composition
https://emotion.sh/
MIT License
17.5k stars 1.11k forks source link

Allow instances of Emotion #430

Closed jstcki closed 6 years ago

jstcki commented 7 years ago

I'm currently evaluating different CSS-in-JS solutions and one thing that seems missing from most is a mode where you create an instance of the sheet/registry and manage styles using this instance instead of relying on a global singleton.

Why do I need this? Aside from "global shared mutable state is bad" etc. I maintain Catalog, a style guide builder that can render components from your codebase (similar to Storybook). Catalog itself is a React app and currently uses Radium which I want to replace for several reasons. Because users can include any code, I need to make sure that the replacement styling library doesn't conflict with anything else, including other versions of the same library.

Something like this could work, probably even without breaking existing API:

import Emotion from 'emotion/class';

const emo = new Emotion({key: 'my-special-key'});

emo.css`
  /* ... css etc */
`

The Emotion instance basically would expose the same methods like the emotion/index module does.

Alternatively, css et al. could take the instance as an additional argument.

The key option has two purposes:

Other aspects:

For reference, styletron and fela already work like this.

tkh44 commented 7 years ago

I like this idea on the surface, but I really need to think about it. I'm also curious what @mitchellhamilton thinks.

hanford commented 7 years ago

+1

This is one of my bigger frustrations with various different css-in-js solutions. I'm using lerna and am building out a large react component library where each component has it's own build step and as a result I need different instances to play nice.

This bit me pretty hard with styled-components 2.x (weirdly it works fine w/ 1.2.X so I've downgraded to that).. I've also ran into this exact issue with https://github.com/zeit/styled-jsx/issues/309

anyways, I'd like to switch to emotion as it seems superior to styled-components, and I'm really digging a lot of the newer additions like facepaint.

tkh44 commented 7 years ago

@hanford Would it work if you created a sheet package in your lerna packages that was required but the other packages?

hanford commented 7 years ago

Potentially, though decoupling styles from the given components is obviously not ideal

tkh44 commented 7 years ago

What I mean is creating a package in your packages that imports emotion. It would then export that instance of emotion tied to a sheet. You could then import this instance of emotion in your individual components.

hanford commented 7 years ago

@tkh44 πŸ€” that's an interesting idea, I'll give it a try in a few days!

loklaan commented 7 years ago

Sorry to appear out of nowhere πŸƒπŸ’¨

I've been looking for this feature in oss css-in-js libs for awhile, and would be happy to help out any way I can!

I anticipate that exposing this would require the babel plugin to accept further configuration. It could, for example, be given a set of alternative css signatures to look for? This becomes more important when multiple output static css files are expected.

My reason for caring is in the collapsable at the bottom of this comment. It could be a broad-enough problem to warrant exposing an Emotion class & adding extra functionality to the babel-plugin.

Thoughts? I'm keen to jump on this if you're willing to accept it in to emotion! :)

Case: Alternative styling systems Here is a strong case for several instances of sheet/emotion in a page (and from the babel plugin, several extracted css files); _alternative styling systems_. They might need extra functionality to work-around CSS ordering issues. I've been using a styling system for React apps that dictates how styles are applied to elements in components. eg. `
` When called, it sources styling primitives from three potential locations: 1. Default styles, which are usually found in the component's module file 2. Local overrides, which are provided at usage-time of the component 3. App-wide* overrides, which can be found being used by a top level theme provider component This system ends up working really well for component re-use across differently branded apps, because one brand may need to drastically change some internal styling of a component; the dev didn't have to anticipate every styling case, and instead accommodates any kind of styling change! *That's the preamble done.* The problems that occur in Browsers, with this alternative styling system, are to do with CSS ordering. For example, you'd expect your "App-wide" overrides to override defaults, right? You should. But depending on how you've structured your app & it's dependency graph, a component's "Default styles" might be given to your css-in-js lib _after_ your App-wide overriding styles... This results in the default styles taking precedence over it's intended overrides, which breaks everything. This class of problem can be solved b asking the css-in-js library, like emotion, to put the styles from each "location" into it's own `