-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Allow instances of Emotion #430
Comments
I like this idea on the surface, but I really need to think about it. I'm also curious what @mitchellhamilton thinks. |
+1 This is one of my bigger frustrations with various different css-in-js solutions. I'm using 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 vercel/styled-jsx#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. |
@hanford Would it work if you created a |
Potentially, though decoupling styles from the given components is obviously not ideal |
What I mean is creating a package in your |
@tkh44 🤔 that's an interesting idea, I'll give it a try in a few days! |
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 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 systemsHere 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:
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 |
This is not true with emotion. If you browse around the tests and look at the snapshots you'll see that we compose styles from their raw style strings and not with class names. (this applies to emotion generated class names only) |
Ah sorry, I wasn't too clear on explaining this ordering problem. (btw emotion's composition features are great!) This particular styling system is platform agnostic, since we need it to work with React Native components & apps. It needs to "own" the final composition of styling primitives sourced from defaults or overrides, which would be classname strings and style objects. For the web, each of these sources for our styling system could be classnames generated by emotion. For example, say we have a Button component, and it's using this alternative styling system. It's given default styles generated with emotion via some import { css } from 'emotion'
@styled({ container: css`color: blue;` })
class Button extends Component {
render () {
return <div {...this.props.styles('container')} ></div>
}
} We've generated a classname for the default styles of Button. Elsewhere in the App, we could override them like this. // App overrides
<StylesProvider components={{ 'Button': { container: css`color: green;` } }} />
// Local overrides
<Button styles={{ container: css`color: red;` }} /> Local overrides are intended to take precedence in this system. Our Button should get a color of red. But it actually just depends on where the class sits in CSS on the page.. Because CSS. Problem goes away when we're not using CSS or inline styles, but since we want to take advantage of everything CSS has to give, we're left fighting CSS injection ordering issues. We currently get around those issues by being very careful with our app's call order of our components vs app style overrides. We also avoid memoization/insertions optimisation in emotion (and glamor) because the same string of CSS could be used later in the application's call order, but with the intention of using a newly inserted high (bottom) ordered class name. Our bundle size is a bit bigger. This might all seem really specific right now, but it definitely relates to this github issue! Really keen to help out, given how much I have to gain from it. |
I know it's been a while since this has been discussed but I'm getting close to finishing #464 and I want to see what people think. @loklaan Could you explain how emotion's composition doesn't solve your issue? If you use const newClassName = cx(defaultClassName, appClassName, localClassName) @hanford Am I correct in assuming from slack that your issue is solved? @herrstucki Could you look at #464 and see if it solves your issue?(you might want to look at the |
@mitchellhamilton wow, nice! I don't have much time to dig in right now but from reading the README, I have a couple of questions:
Wouldn't this also work: let myContext = {}; // not sure how this is different to window.__MY_CONTEXT__
export const {...} = createEmotion(myContext);
<!-- head -->
<style data-emotion></style> <!-- singleton emotion -->
<style data-emotion="my-key"></style> <!-- my instance -->
<!-- body -->
<div class="my-key-12345"> <!-- my instance -->
<div class="css-23456">...</div> <!-- singleton emotion -->
</div> |
I definitely need to change the explanation but anyway the context isn't shared between multiple explicit
Yep. It works totally fine, regular emotion is just an instance created with
It's not documented at all but
I have mixed feeling about this. I can see how it would be useful to identify the classes but you can get the tags associated with the instance from |
Thanks for the explanation (and the hard work you put into this!). I haven't tested it yet for my use case but I'd be glad to do so if that helps. My – admittedly quite esoteric – purpose for keying style tags is to clone all style tags execpt my own app's into a dynamically created iframe (to emulate responsive views of third-party components). But having access to The only other (also esoteric?) reason for instance-specific class names that comes to mind are clashes where the name's the same but the actual style's different. Admittedly, the chance is small but may become an issue when combining different versions or libraries which also use the |
I can't tell with certainty if this was addressed above (although it kind of sounds like it...), but I have a use case where I am generating an |
@stephenjwatkins The context is purely used as a way to store caches. It does not control where styles are inserted. I think we'll need an option like @herrstucki I thought about clashes and initially dismissed it for various reasons but thinking about it more it could definitely be an issue because the |
@mitchellhamilton thanks for the clarification. An option for the DOM node would be wonderful for my use case. |
emotion
version: 8react
version: n/aI'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:
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:<style data-emotion="my-key">
instead of<style data-emotion>
)css-
(although this could be a distinct option)Other aspects:
destroy
method which would clean up styles managed by it.npm link
ing #349)For reference, styletron and fela already work like this.
The text was updated successfully, but these errors were encountered: