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
[RFC] Move keyframes inside the component-tree #1496
Comments
I lean towards variant const KeyFrame = createKeyframe``;
const Globals = createGlobalStyle``;
const StyledDiv = styled.div`
animation-name: ${props => props.animationName};
`;
const Comp = () => (
<StyledDiv animationName={KeyFrame.name}>
<KeyFrame/>
<Globals/>
</StyledDiv>
); One way to think about #1493 and #1491 is establishing a way to render const KeyFrame = createKeyframe``;
const Globals = createGlobalStyle``;
const StyledDiv = styled.div`
animation-name: ${props => props.animationName};
`;
const Comp = () => (
<StyledDiv animationName={KeyFrame.name}>
{ReactDOM.createPortal(<KeyFrame/>, document.head)}
{ReactDOM.createPortal(<Globals/>, document.head)}
</StyledDiv>
); |
My main problem with version 2 is that people might expect this kind of thing to work: // This is a perfectly fine name for what createKeyframes returns
const FadeIn = createKeyframes`
0% { opacity: 0; }
100% { opacity: 1; }
`
// This is not a fine usage for what createKeyframes returns, this wouldn't work at all
// even though the name and it being a component suggest this would work
<FadeIn>
<MyComponent />
</FadeIn> Which it won't since the returned component is really only responsible for injecting the |
I really like Edit: Another thing is that it's never necessary to remove / unmount them. If we'd introduce special cases around that we'd have yet another special snowflake component. Also, we can solve |
Gotta play devil's advocate for version 1 here for a second, what if we made the recommended usage of const FadeIn = styled.div`
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
animation: fadeIn 1s;
` The keyframes name would be scoped to the component by us here and thusly not sit in a global namespace ( |
Ok, I think I do not understand |
@mxstbr sounds pretty good as well, especially when paired with css mixins: const fadeIn = css`
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
`
const FadeIn = styled.div`
${fadeIn}
animation: fadeIn 1s;
` |
@marionebl We wouldn't inject the We'd do so when we execute the interpolations by checking if an interpolation is Pseudo-code: interpolations.map((interpolation) => {
if (isFunction(interpolation)) return interpolation(props);
if (isKeyframes(interpolation)) {
interpolation.inject(this.context.sheetTarget) // or wherever we get the target from
return interpolation.name;
}
/* ... */
}) |
@kitten the only thing I dislike there is the const FadeIn = styled.div`
${fadeIn}
// v this being a static string sucks, how am I supposed to know what the @keyframes declaration is called?! Am I supposed to look that up like a caveman?!?!
animation: fadeIn 1s;
` |
@kitten @mxstbr Re :
|
@marionebl those names would be obfuscated similar to the classNames, the injected CSS would look something like this: @keyframes FadeIn-asdf123-fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes FadeIn-asdf123-bounce {
0% { transform: none; }
100% { transform: translateY(100%); }
}
.FadeIn-asfd123 {
animation: FadeIn-asdf123-fadeIn 1s;
} In your case, the other components' injected CSS would look something like this: .SomethingElse-dfhg123 {
animation-name: SomethingElse-asdf123-fadeIn;
} Look ma, no name clashes! |
Re: |
You have a point with your example though, which is also what I pointed out above, the keyframes names being static strings sucks. What gets injected in this case: // No keyframes`` with that name interpolated
const SomethingElse = styled.div`
animation-name: fadeIn;
` /* Do we inject this... */
.SomethingElse {
animation-name: fadeIn;
}
/* ...or this? */
.SomethingElse {
animation-name: SomethingElse-asdf123-fadeIn;
} Very confusing, because you could have a global So even with the above said, I don't think 1. is very nice due to the concern around the static string name. |
By the way, this is a total side note but this is a cool API, like, in general: const FadeIn = createAnimatedComponent`
0% { opacity: 0; }
100% { opacity: 1; }
`
<FadeIn>
<MyComponent />
</FadeIn> We can't replace |
Agreed. Understanding |
@mxstbr maybe custom |
I personally find this RFC weird. But then again I'm against the componentization of things that don't make sense as components. |
@evan-scott-zocdoc yep I agree, that's why I much prefer variant 3 to variant 1 😊 @Fer0x that's not a bad idea actually! Are there any edge cases where |
Similar to
injectGlobal
(ref #1333) we need to move thekeyframes``
helper inside the component-tree for two reasons: You should be able to use the theme in your animations and it makes appending by target possible. (ref #1324)There's three main options I can think of here:
keyframes
entirely: Thekeyframes
helper isn't really necessary to style an app with styled-components, you could also just make global@keyframes
declaration in your global styles.keyframes
: Similar to the change from Component-based API for global styling #1333 you'd have aconst FadeIn = createKeyframesComponent``
or something API that returns a component which you can render<FadeIn />
. (note that this wouldn't apply that animation to it's children or anything, like the<GlobalStyle />
component it would only inject the@keyframes
declaration)keyframes
"lazy": Rather than returning the name of the keyframes from thekeyframes``
call, we return a custom Keyframes object. Then, when folks interpolate said object, we check for instanceof and only then inject the@keyframes
declaration into the DOM. We should also be able to walk the ruleset to resolve any interpolated functions etc.Personally, 1. feels weird to me: The whole reason we introduced the
keyframes
helper initially was because it was weird to never have to worry about a global namespace, just to then use a global namespace again for animations. 2. also doesn't fit very well imo, I feel like that takes the component-based thing too far.To me, 3. is the best of all worlds: No big API change (we'd probably still need to cut a major version if people rely on the name being returned), docs all stay the same and you can use e.g. the theme in your keyframes. (and makes #1324 possible)
Any concerns, other ideas or comments? First WIP PRs demonstrating what an implementation could look like would be appreciated!
The text was updated successfully, but these errors were encountered: