-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
Animations: extract keyframes from styles #9623
Conversation
class CSSKeyframesRuleDef { | ||
constructor() { | ||
/** @type {string} */ | ||
this.name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to set these values, declaring them like this doesn't help the JS engine's internal structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just the definition for closure, in place of extern. Per closure it's fine. The class itself is not used - only its type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you mark as an interface, then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried, but unfortunately can't. The underlying CSSRule
is declared as a class, not interface. See this. This is kind of what our Def
suffix means at this point. I'm going to contribute the same declarations to them, but we are slightly behind their externs version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, to remove this inconsistency, I just moved this declaration to our closure externs. So this should be now cleaner.
keyframeRule.keyText == 'from' ? 0 : | ||
keyframeRule.keyText == 'to' ? 1 : | ||
parseFloat(keyframeRule.keyText) / 100; | ||
for (let j = 0; j < keyframeRule.style.length; j++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: store style
in a variable. Some engines do weird things (like re-initialize) when accessing native objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
return null; | ||
} | ||
// Exlcude AMP's own styles. | ||
if (styleNode.hasAttribute('amp-boilerplate') || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could this be if (!styleNode.hasAttribute('amp-custom'))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (rule.name == name && isEnabled(win, rule)) { | ||
return buildKeyframes(keyframesRule); | ||
} | ||
} else if (rule.type == /* CSSMediaRule */ 4) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
checking media match before the recursion should be a decent optimization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I didn't do this is because there are potentially a lot more @media
definitions than @keyframes
. And checking in each case is somewhat expensive. So instead I first find a likely candidate @keyframes name
and then check if its parents are enabled recursively.
for (let j = 0; j < keyframeRule.style.length; j++) { | ||
const styleName = keyframeRule.style[j]; | ||
let propName = styleName; | ||
if (styleName == 'animation-timing-function') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
end with to account for vendor prefixes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(TIL you could specify animation-timing-function
in keyframe def, totally did not know this is possible)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. Done.
const array = []; | ||
for (let i = 0; i < keyframesRule.cssRules.length; i++) { | ||
const keyframeRule = keyframesRule.cssRules[i]; | ||
const keyframe = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cssRules
are of type CSSRuleList
, so it's not an array :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map
returns an object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @aghassemi meant map on all, e.g. const array = keyframesRule.cssRules.map(rule => {})
. Unfortunately cssRules
is not an array and I thought we decided to avoid simple toArray
conversions just for better for-loops?
Partial for #9129.