AnimatedPropertyList.js (3881B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 Component, 9 createFactory, 10 } = require("resource://devtools/client/shared/vendor/react.mjs"); 11 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 12 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 13 14 const AnimatedPropertyItem = createFactory( 15 require("resource://devtools/client/inspector/animation/components/AnimatedPropertyItem.js") 16 ); 17 18 class AnimatedPropertyList extends Component { 19 static get propTypes() { 20 return { 21 animation: PropTypes.object.isRequired, 22 emitEventForTest: PropTypes.func.isRequired, 23 getAnimatedPropertyMap: PropTypes.func.isRequired, 24 getComputedStyle: PropTypes.func.isRequired, 25 simulateAnimation: PropTypes.func.isRequired, 26 }; 27 } 28 29 constructor(props) { 30 super(props); 31 32 this.state = { 33 // Array of object which has the property name, the keyframes, its aniamtion type 34 // and unchanged flag. 35 animatedProperties: null, 36 // To avoid rendering while the state is updating 37 // since we call an async function in updateState. 38 isStateUpdating: false, 39 }; 40 } 41 42 componentDidMount() { 43 // No need to set isStateUpdating state since paint sequence is finish here. 44 this.updateState(this.props.animation); 45 } 46 47 // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507 48 UNSAFE_componentWillReceiveProps(nextProps) { 49 this.setState({ isStateUpdating: true }); 50 this.updateState(nextProps.animation); 51 } 52 53 shouldComponentUpdate(nextProps, nextState) { 54 return !nextState.isStateUpdating; 55 } 56 57 getPropertyState(property) { 58 const { animation } = this.props; 59 60 for (const propState of animation.state.propertyState) { 61 if (propState.property === property) { 62 return propState; 63 } 64 } 65 66 return null; 67 } 68 69 async updateState(animation) { 70 const { getAnimatedPropertyMap, emitEventForTest } = this.props; 71 72 let propertyMap = null; 73 let propertyNames = null; 74 let types = null; 75 76 try { 77 propertyMap = getAnimatedPropertyMap(animation); 78 propertyNames = [...propertyMap.keys()]; 79 types = await animation.getAnimationTypes(propertyNames); 80 } catch (e) { 81 // Expected if we've already been destroyed or other node have been selected 82 // in the meantime. 83 console.error(e); 84 return; 85 } 86 87 const animatedProperties = propertyNames.map(name => { 88 const keyframes = propertyMap.get(name); 89 const type = types[name]; 90 const isUnchanged = keyframes.every( 91 keyframe => keyframe.value === keyframes[0].value 92 ); 93 return { isUnchanged, keyframes, name, type }; 94 }); 95 96 animatedProperties.sort((a, b) => { 97 if (a.isUnchanged === b.isUnchanged) { 98 return a.name > b.name ? 1 : -1; 99 } 100 101 return a.isUnchanged ? 1 : -1; 102 }); 103 104 this.setState({ 105 animatedProperties, 106 isStateUpdating: false, 107 }); 108 109 emitEventForTest("animation-keyframes-rendered"); 110 } 111 112 render() { 113 const { getComputedStyle, simulateAnimation } = this.props; 114 const { animatedProperties } = this.state; 115 116 if (!animatedProperties) { 117 return null; 118 } 119 120 return dom.ul( 121 { 122 className: "animated-property-list", 123 }, 124 animatedProperties.map(({ isUnchanged, keyframes, name, type }) => { 125 const state = this.getPropertyState(name); 126 return AnimatedPropertyItem({ 127 getComputedStyle, 128 isUnchanged, 129 keyframes, 130 name, 131 simulateAnimation, 132 state, 133 type, 134 }); 135 }) 136 ); 137 } 138 } 139 140 module.exports = AnimatedPropertyList;