You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-03 00:33:22 +03:00 
			
		
		
		
	Move velocity stuff / contextual menu from Vector to React.
This commit is contained in:
		@@ -29,7 +29,8 @@
 | 
				
			|||||||
    "optimist": "^0.6.1",
 | 
					    "optimist": "^0.6.1",
 | 
				
			||||||
    "q": "^1.4.1",
 | 
					    "q": "^1.4.1",
 | 
				
			||||||
    "react": "^0.14.2",
 | 
					    "react": "^0.14.2",
 | 
				
			||||||
    "react-dom": "^0.14.2"
 | 
					    "react-dom": "^0.14.2",
 | 
				
			||||||
 | 
					    "velocity-animate": "^1.2.3"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "//deps": "The loader packages are here because webpack in a project that depends on us needs them in this package's node_modules folder",
 | 
					  "//deps": "The loader packages are here because webpack in a project that depends on us needs them in this package's node_modules folder",
 | 
				
			||||||
  "//depsbuglink": "https://github.com/webpack/webpack/issues/1472",
 | 
					  "//depsbuglink": "https://github.com/webpack/webpack/issues/1472",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										82
									
								
								src/ContextualMenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/ContextualMenu.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 OpenMarket Ltd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var React = require('react');
 | 
				
			||||||
 | 
					var ReactDOM = require('react-dom');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Shamelessly ripped off Modal.js.  There's probably a better way
 | 
				
			||||||
 | 
					// of doing reusable widgets like dialog boxes & menus where we go and
 | 
				
			||||||
 | 
					// pass in a custom control as the actual body.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    ContextualMenuContainerId: "mx_ContextualMenu_Container",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getOrCreateContainer: function() {
 | 
				
			||||||
 | 
					        var container = document.getElementById(this.ContextualMenuContainerId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!container) {
 | 
				
			||||||
 | 
					            container = document.createElement("div");
 | 
				
			||||||
 | 
					            container.id = this.ContextualMenuContainerId;
 | 
				
			||||||
 | 
					            document.body.appendChild(container);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return container;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    createMenu: function (Element, props) {
 | 
				
			||||||
 | 
					        var self = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var closeMenu = function() {
 | 
				
			||||||
 | 
					            ReactDOM.unmountComponentAtNode(self.getOrCreateContainer());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (props && props.onFinished) props.onFinished.apply(null, arguments);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var position = {
 | 
				
			||||||
 | 
					            top: props.top - 20,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var chevron = null;
 | 
				
			||||||
 | 
					        if (props.left) {
 | 
				
			||||||
 | 
					            chevron = <img className="mx_ContextualMenu_chevron_left" src="img/chevron-left.png" width="9" height="16" />
 | 
				
			||||||
 | 
					            position.left = props.left + 8;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            chevron = <img className="mx_ContextualMenu_chevron_right" src="img/chevron-right.png" width="9" height="16" />
 | 
				
			||||||
 | 
					            position.right = props.right + 8;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var className = 'mx_ContextualMenu_wrapper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // FIXME: If a menu uses getDefaultProps it clobbers the onFinished
 | 
				
			||||||
 | 
					        // property set here so you can't close the menu from a button click!
 | 
				
			||||||
 | 
					        var menu = (
 | 
				
			||||||
 | 
					            <div className={className}>
 | 
				
			||||||
 | 
					                <div className="mx_ContextualMenu" style={position}>
 | 
				
			||||||
 | 
					                    {chevron}
 | 
				
			||||||
 | 
					                    <Element {...props} onFinished={closeMenu}/>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div className="mx_ContextualMenu_background" onClick={closeMenu}></div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ReactDOM.render(menu, this.getOrCreateContainer());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {close: closeMenu};
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										113
									
								
								src/Velociraptor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/Velociraptor.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					var React = require('react');
 | 
				
			||||||
 | 
					var ReactDom = require('react-dom');
 | 
				
			||||||
 | 
					var Velocity = require('velocity-animate');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The Velociraptor contains components and animates transitions with velocity.
 | 
				
			||||||
 | 
					 * It will only pick up direct changes to properties ('left', currently), and so
 | 
				
			||||||
 | 
					 * will not work for animating positional changes where the position is implicit
 | 
				
			||||||
 | 
					 * from DOM order. This makes it a lot simpler and lighter: if you need fully
 | 
				
			||||||
 | 
					 * automatic positional animation, look at react-shuffle or similar libraries.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					module.exports = React.createClass({
 | 
				
			||||||
 | 
					    displayName: 'Velociraptor',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    propTypes: {
 | 
				
			||||||
 | 
					        children: React.PropTypes.array,
 | 
				
			||||||
 | 
					        transition: React.PropTypes.object,
 | 
				
			||||||
 | 
					        container: React.PropTypes.string
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    componentWillMount: function() {
 | 
				
			||||||
 | 
					        this.children = {};
 | 
				
			||||||
 | 
					        this.nodes = {};
 | 
				
			||||||
 | 
					        var self = this;
 | 
				
			||||||
 | 
					        React.Children.map(this.props.children, function(c) {
 | 
				
			||||||
 | 
					            self.children[c.key] = c;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    componentWillReceiveProps: function(nextProps) {
 | 
				
			||||||
 | 
					        var self = this;
 | 
				
			||||||
 | 
					        var oldChildren = this.children;
 | 
				
			||||||
 | 
					        this.children = {};
 | 
				
			||||||
 | 
					        React.Children.map(nextProps.children, function(c) {
 | 
				
			||||||
 | 
					            if (oldChildren[c.key]) {
 | 
				
			||||||
 | 
					                var old = oldChildren[c.key];
 | 
				
			||||||
 | 
					                var oldNode = ReactDom.findDOMNode(self.nodes[old.key]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (oldNode.style.left != c.props.style.left) {
 | 
				
			||||||
 | 
					                    Velocity(oldNode, { left: c.props.style.left }, self.props.transition).then(function() {
 | 
				
			||||||
 | 
					                        // special case visibility because it's nonsensical to animate an invisible element
 | 
				
			||||||
 | 
					                        // so we always hidden->visible pre-transition and visible->hidden after
 | 
				
			||||||
 | 
					                        if (oldNode.style.visibility == 'visible' && c.props.style.visibility == 'hidden') {
 | 
				
			||||||
 | 
					                            oldNode.style.visibility = c.props.style.visibility;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    if (oldNode.style.visibility == 'hidden' && c.props.style.visibility == 'visible') {
 | 
				
			||||||
 | 
					                        oldNode.style.visibility = c.props.style.visibility;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    //console.log("translation: "+oldNode.style.left+" -> "+c.props.style.left);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                self.children[c.key] = old;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // new element. If it has a startStyle, use that as the style and go through
 | 
				
			||||||
 | 
					                // the enter animations
 | 
				
			||||||
 | 
					                var newProps = {
 | 
				
			||||||
 | 
					                    ref: self.collectNode.bind(self, c.key)
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                if (c.props.startStyle && Object.keys(c.props.startStyle).length) {
 | 
				
			||||||
 | 
					                    var startStyle = c.props.startStyle;
 | 
				
			||||||
 | 
					                    if (Array.isArray(startStyle)) {
 | 
				
			||||||
 | 
					                        startStyle = startStyle[0];
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    newProps._restingStyle = c.props.style;
 | 
				
			||||||
 | 
					                    newProps.style = startStyle;
 | 
				
			||||||
 | 
					                    //console.log("mounted@startstyle0: "+JSON.stringify(startStyle));
 | 
				
			||||||
 | 
					                    // apply the enter animations once it's mounted
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                self.children[c.key] = React.cloneElement(c, newProps);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    collectNode: function(k, node) {
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            this.nodes[k] === undefined &&
 | 
				
			||||||
 | 
					            node.props.startStyle &&
 | 
				
			||||||
 | 
					            Object.keys(node.props.startStyle).length
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            var domNode = ReactDom.findDOMNode(node);
 | 
				
			||||||
 | 
					            var startStyles = node.props.startStyle;
 | 
				
			||||||
 | 
					            var transitionOpts = node.props.enterTransitionOpts;
 | 
				
			||||||
 | 
					            if (!Array.isArray(startStyles)) {
 | 
				
			||||||
 | 
					                startStyles = [ startStyles ];
 | 
				
			||||||
 | 
					                transitionOpts = [ transitionOpts ];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // start from startStyle 1: 0 is the one we gave it
 | 
				
			||||||
 | 
					            // to start with, so now we animate 1 etc.
 | 
				
			||||||
 | 
					            for (var i = 1; i < startStyles.length; ++i) {
 | 
				
			||||||
 | 
					                Velocity(domNode, startStyles[i], transitionOpts[i-1]);
 | 
				
			||||||
 | 
					                //console.log("start: "+JSON.stringify(startStyles[i]));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // and then we animate to the resting state
 | 
				
			||||||
 | 
					            Velocity(domNode, node.props._restingStyle, transitionOpts[i-1]);
 | 
				
			||||||
 | 
					            //console.log("enter: "+JSON.stringify(node.props._restingStyle));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.nodes[k] = node;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    render: function() {
 | 
				
			||||||
 | 
					        var self = this;
 | 
				
			||||||
 | 
					        var childList = Object.keys(this.children).map(function(k) {
 | 
				
			||||||
 | 
					            return React.cloneElement(self.children[k], {
 | 
				
			||||||
 | 
					                ref: self.collectNode.bind(self, self.children[k].key)
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <span>
 | 
				
			||||||
 | 
					                {childList}
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/VelocityBounce.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/VelocityBounce.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					var Velocity = require('velocity-animate');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// courtesy of https://github.com/julianshapiro/velocity/issues/283
 | 
				
			||||||
 | 
					// We only use easeOutBounce (easeInBounce is just sort of nonsensical)
 | 
				
			||||||
 | 
					function bounce( p ) {
 | 
				
			||||||
 | 
					    var pow2,
 | 
				
			||||||
 | 
					        bounce = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
 | 
				
			||||||
 | 
					    return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Velocity.Easings.easeOutBounce = function(p) {
 | 
				
			||||||
 | 
					    return 1 - bounce(1 - p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,10 +24,9 @@ var sdk = require('../../../index');
 | 
				
			|||||||
var MatrixClientPeg = require('../../../MatrixClientPeg')
 | 
					var MatrixClientPeg = require('../../../MatrixClientPeg')
 | 
				
			||||||
var TextForEvent = require('../../../TextForEvent');
 | 
					var TextForEvent = require('../../../TextForEvent');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FIXME BROKEN IMPORTS
 | 
					var ContextualMenu = require('../../../ContextualMenu');
 | 
				
			||||||
var ContextualMenu = require('../../../../ContextualMenu');
 | 
					var Velociraptor = require('../../../Velociraptor');
 | 
				
			||||||
var Velociraptor = require('../../../../Velociraptor');
 | 
					require('../../../VelocityBounce');
 | 
				
			||||||
require('../../../../VelocityBounce');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
var bounce = false;
 | 
					var bounce = false;
 | 
				
			||||||
try {
 | 
					try {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user