From 50c5aeb8d33e2203026ddbf089638ec010306d35 Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Sat, 6 Aug 2016 14:35:41 +0200 Subject: [PATCH] Latest build --- lib/date_picker/DatePicker.js | 20 ++- lib/date_picker/theme.scss | 2 +- lib/input/theme.scss | 4 +- lib/ripple/Ripple.js | 301 +++++++++++++++++++++++++--------- lib/table/Table.js | 30 ++-- lib/time_picker/TimePicker.js | 18 +- lib/time_picker/theme.scss | 2 +- lib/utils/events.js | 4 +- 8 files changed, 266 insertions(+), 115 deletions(-) diff --git a/lib/date_picker/DatePicker.js b/lib/date_picker/DatePicker.js index 1956215c..12dbe386 100644 --- a/lib/date_picker/DatePicker.js +++ b/lib/date_picker/DatePicker.js @@ -80,6 +80,12 @@ var factory = function factory(Input, DatePickerDialog) { active: false }, _this.handleDismiss = function () { _this.setState({ active: false }); + }, _this.handleInputFocus = function (event) { + _events2.default.pauseEvent(event); + _this.setState({ active: true }); + }, _this.handleInputBlur = function (event) { + _events2.default.pauseEvent(event); + _this.setState({ active: false }); }, _this.handleInputMouseDown = function (event) { _events2.default.pauseEvent(event); _this.setState({ active: true }); @@ -106,9 +112,10 @@ var factory = function factory(Input, DatePickerDialog) { var minDate = _props.minDate; var onEscKeyDown = _props.onEscKeyDown; var onOverlayClick = _props.onOverlayClick; + var readonly = _props.readonly; var value = _props.value; - var others = _objectWithoutProperties(_props, ['autoOk', 'inputClassName', 'inputFormat', 'maxDate', 'minDate', 'onEscKeyDown', 'onOverlayClick', 'value']); + var others = _objectWithoutProperties(_props, ['autoOk', 'inputClassName', 'inputFormat', 'maxDate', 'minDate', 'onEscKeyDown', 'onOverlayClick', 'readonly', 'value']); var finalInputFormat = inputFormat || _time2.default.formatDate; var date = Object.prototype.toString.call(value) === '[object Date]' ? value : undefined; @@ -119,14 +126,16 @@ var factory = function factory(Input, DatePickerDialog) { { 'data-react-toolbox': 'date-picker' }, _react2.default.createElement(Input, _extends({}, others, { className: (0, _classnames3.default)(this.props.theme.input, _defineProperty({}, inputClassName, inputClassName)), + disabled: readonly, error: this.props.error, - onMouseDown: this.handleInputMouseDown, - onKeyPress: this.handleInputKeyPress, - name: this.props.name, + icon: this.props.icon, label: this.props.label, + name: this.props.name, + onFocus: this.handleInputFocus, + onKeyPress: this.handleInputKeyPress, + onMouseDown: this.handleInputMouseDown, readOnly: true, type: 'text', - icon: this.props.icon, value: formattedDate })), _react2.default.createElement(DatePickerDialog, { @@ -165,6 +174,7 @@ var factory = function factory(Input, DatePickerDialog) { onEscKeyDown: _react.PropTypes.func, onKeyPress: _react.PropTypes.func, onOverlayClick: _react.PropTypes.func, + readonly: _react.PropTypes.bool, theme: _react.PropTypes.shape({ input: _react.PropTypes.string }), diff --git a/lib/date_picker/theme.scss b/lib/date_picker/theme.scss index 81464ef5..ef3c6b67 100644 --- a/lib/date_picker/theme.scss +++ b/lib/date_picker/theme.scss @@ -3,7 +3,7 @@ @import "../mixins"; @import "./config"; -.input > [role="input"] { +.input:not(.disabled) > .inputElement { cursor: pointer; } diff --git a/lib/input/theme.scss b/lib/input/theme.scss index 739de903..b6b6c813 100644 --- a/lib/input/theme.scss +++ b/lib/input/theme.scss @@ -35,7 +35,7 @@ border: 0; border-bottom: 1px solid $input-text-bottom-border-color; outline: none; - &:focus { + &:focus:not([disabled]):not([readonly]) { ~ .bar:before, ~ .bar:after { width: 50%; } @@ -52,7 +52,7 @@ color: $input-text-highlight-color; } } - &:focus, &.filled, &[type="date"], &[type="time"] { + &:focus:not([disabled]):not([readonly]), &.filled, &[type="date"], &[type="time"] { ~ .label:not(.fixed) { top: $input-focus-label-top; font-size: $input-label-font-size; diff --git a/lib/ripple/Ripple.js b/lib/ripple/Ripple.js index c8fbc356..26e2483d 100644 --- a/lib/ripple/Ripple.js +++ b/lib/ripple/Ripple.js @@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); @@ -20,6 +22,10 @@ var _classnames2 = require('classnames'); var _classnames3 = _interopRequireDefault(_classnames2); +var _reactAddonsUpdate = require('react-addons-update'); + +var _reactAddonsUpdate2 = _interopRequireDefault(_reactAddonsUpdate); + var _reactCssThemr = require('react-css-themr'); var _identifiers = require('../identifiers.js'); @@ -47,6 +53,7 @@ function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in ob var defaults = { centered: false, className: '', + multiple: true, spread: 2, theme: {} }; @@ -58,10 +65,11 @@ var rippleFactory = function rippleFactory() { var defaultCentered = _defaults$options.centered; var defaultClassName = _defaults$options.className; + var defaultMultiple = _defaults$options.multiple; var defaultSpread = _defaults$options.spread; var defaultTheme = _defaults$options.theme; - var props = _objectWithoutProperties(_defaults$options, ['centered', 'className', 'spread', 'theme']); + var props = _objectWithoutProperties(_defaults$options, ['centered', 'className', 'multiple', 'spread', 'theme']); return function (ComposedComponent) { var RippledComponent = function (_Component) { @@ -79,66 +87,130 @@ var rippleFactory = function rippleFactory() { } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(RippledComponent)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.state = { - active: false, - left: null, - restarting: false, - top: null, - width: null - }, _this.handleEnd = function () { - document.removeEventListener(_this.touch ? 'touchend' : 'mouseup', _this.handleEnd); - _this.setState({ active: false }); - }, _this.start = function (_ref) { - var pageX = _ref.pageX; - var pageY = _ref.pageY; - var touch = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; - - if (!_this._isTouchRippleReceivingMouseEvent(touch)) { - _this.touch = touch; - document.addEventListener(_this.touch ? 'touchend' : 'mouseup', _this.handleEnd); - - var _this$_getDescriptor = _this._getDescriptor(pageX, pageY); - - var top = _this$_getDescriptor.top; - var left = _this$_getDescriptor.left; - var width = _this$_getDescriptor.width; - - _this.setState({ active: false, restarting: true, top: top, left: left, width: width }, function () { - _this.refs.ripple.offsetWidth; //eslint-disable-line no-unused-expressions - _this.setState({ active: true, restarting: false }); - }); - } + ripples: {} }, _this.handleMouseDown = function (event) { - if (!_this.props.disabled) _this.start(event); if (_this.props.onMouseDown) _this.props.onMouseDown(event); + if (!_this.props.disabled) { + var _events$getMousePosit = _events2.default.getMousePosition(event); + + var x = _events$getMousePosit.x; + var y = _events$getMousePosit.y; + + _this.animateRipple(x, y, false); + } + }, _this.handleTouchStart = function (event) { + if (_this.props.onTouchStart) _this.props.onTouchStart(event); + if (!_this.props.disabled) { + var _events$getTouchPosit = _events2.default.getTouchPosition(event); + + var x = _events$getTouchPosit.x; + var y = _events$getTouchPosit.y; + + _this.animateRipple(x, y, true); + } }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(RippledComponent, [{ - key: 'componentDidMount', - value: function componentDidMount() { + key: 'componentDidUpdate', + value: function componentDidUpdate(prevProps, prevState) { + // If a new ripple was just added, add a remove event listener to its animation + if (Object.keys(prevState.ripples).length < Object.keys(this.state.ripples).length) { + this.addRippleRemoveEventListener(this.getLastKey()); + } + } + + /** + * Add an event listener to the reference with given key so when the animation transition + * ends we can be sure that it finished and it can be safely removed from the state. + * This function is called whenever a new ripple is added to the component. + * + * @param {String} rippleKey Is the key of the ripple to add the event. + */ + + }, { + key: 'addRippleRemoveEventListener', + value: function addRippleRemoveEventListener(rippleKey) { + var self = this; + _events2.default.addEventListenerOnTransitionEnded(this.refs[rippleKey], function onOpacityEnd(e) { + if (e.propertyName === 'opacity') { + if (self.props.onRippleEnded) self.props.onRippleEnded(e); + _events2.default.removeEventListenerOnTransitionEnded(self.refs[rippleKey], onOpacityEnd); + self.setState({ ripples: (0, _reactAddonsUpdate2.default)(self.state.ripples, _defineProperty({}, rippleKey, { $apply: function $apply(ripplesState) { + delete ripplesState[rippleKey]; + return ripplesState; + } })) }); + } + }); + } + + /** + * Start a ripple animation on an specific point with touch or mouse events. First + * decides if the animation should trigger. If the ripple is multiple or there is no + * ripple present, it creates a new key. If it's a simple ripple and already exists, + * it just restarts the current ripple. The animation happens in two state changes + * to allow triggering via css. + * + * @param {Number} x Coordinate X on the screen where animation should start + * @param {Number} y Coordinate Y on the screen where animation should start + * @param {Boolean} isTouch Use events from touch or mouse. + */ + + }, { + key: 'animateRipple', + value: function animateRipple(x, y, isTouch) { var _this2 = this; - if (this.props.onRippleEnded) { - _events2.default.addEventListenerOnTransitionEnded(this.refs.ripple, function (evt) { - if (evt.propertyName === 'transform') _this2.props.onRippleEnded(evt); - }); + if (this.rippleShouldTrigger(isTouch)) { + (function () { + var _getDescriptor = _this2.getDescriptor(x, y); + + var top = _getDescriptor.top; + var left = _getDescriptor.left; + var width = _getDescriptor.width; + + var noRipplesActive = Object.keys(_this2.state.ripples).length === 0; + var key = _this2.props.rippleMultiple || noRipplesActive ? _this2.getNextKey() : _this2.getLastKey(); + var initialState = { active: false, restarting: true, top: top, left: left, width: width }; + var runningState = { active: true, restarting: false }; + _this2.addRippleDeactivateEventListener(isTouch, key); + _this2.setState((0, _reactAddonsUpdate2.default)(_this2.state, { ripples: _defineProperty({}, key, { $set: initialState }) }), function () { + _this2.refs[key].offsetWidth; //eslint-disable-line no-unused-expressions + _this2.setState((0, _reactAddonsUpdate2.default)(_this2.state, { ripples: _defineProperty({}, key, { $merge: runningState }) })); + }); + })(); } } + + /** + * Determine if a ripple should start depending if its a touch event. For mobile both + * touchStart and mouseDown are launched so in case is touch we should always trigger + * but if its not we should check if a touch was already triggered to decide. + * + * @param {Boolean} isTouch True in case a touch event triggered the ripple false otherwise. + * @return {Boolean} True in case the ripple should trigger or false if it shouldn't. + */ + }, { - key: 'componentWillUnmount', - value: function componentWillUnmount() { - if (this.props.onRippleEnded) { - _events2.default.removeEventListenerOnTransitionEnded(this.refs.ripple); - } + key: 'rippleShouldTrigger', + value: function rippleShouldTrigger(isTouch) { + var shouldStart = isTouch ? true : !this.touchCache; + this.touchCache = isTouch; + return shouldStart; } + + /** + * Find out a descriptor object for the ripple element being created depending on + * the position where the it was triggered and the component's dimensions. + * + * @param {Number} x Coordinate x in the viewport where ripple was triggered + * @param {Number} y Coordinate y in the viewport where ripple was triggered + * @return {Object} Descriptor element including position and size of the element + */ + }, { - key: '_isTouchRippleReceivingMouseEvent', - value: function _isTouchRippleReceivingMouseEvent(touch) { - return this.touch && !touch; - } - }, { - key: '_getDescriptor', - value: function _getDescriptor(pageX, pageY) { + key: 'getDescriptor', + value: function getDescriptor(x, y) { var _ReactDOM$findDOMNode = _reactDom2.default.findDOMNode(this).getBoundingClientRect(); var left = _ReactDOM$findDOMNode.left; @@ -150,51 +222,116 @@ var rippleFactory = function rippleFactory() { var spread = _props.rippleSpread; return { - left: centered ? 0 : pageX - left - width / 2 - window.pageXOffset, - top: centered ? 0 : pageY - top - height / 2 - window.pageYOffset, + left: centered ? 0 : x - left - width / 2, + top: centered ? 0 : y - top - height / 2, width: width * spread }; } + + /** + * Increments and internal counter and returns the next value as a string. It + * is used to assign key references to new ripple elements. + * + * @return {String} Key to be assigned to a ripple. + */ + + }, { + key: 'getNextKey', + value: function getNextKey() { + this.currentCount = this.currentCount ? this.currentCount + 1 : 1; + return this.currentCount.toString(); + } + + /** + * Return the last generated key for a ripple element. When there is only one ripple + * and to get the reference when a ripple was just created. + * + * @return {String} The last generated ripple key. + */ + + }, { + key: 'getLastKey', + value: function getLastKey() { + return this.currentCount.toString(); + } + + /** + * Add an event listener to the document needed deactivate a ripple and make it dissappear. + * Deactivation can happen with a touchend or mouseup depending on the trigger type. + * + * @param {Boolean} isTouch True in case the trigger was a touch event false otherwise. + * @param {String} rippleKey It's a key to identify the ripple that should be deactivated. + */ + + }, { + key: 'addRippleDeactivateEventListener', + value: function addRippleDeactivateEventListener(isTouch, rippleKey) { + var self = this; + var eventType = isTouch ? 'touchend' : 'mouseup'; + document.addEventListener(eventType, function endRipple() { + document.removeEventListener(eventType, endRipple); + self.setState({ ripples: (0, _reactAddonsUpdate2.default)(self.state.ripples, _defineProperty({}, rippleKey, { $merge: { active: false } })) }); + }); + } + }, { + key: 'renderRipple', + value: function renderRipple(key, className, _ref) { + var _classnames; + + var active = _ref.active; + var left = _ref.left; + var restarting = _ref.restarting; + var top = _ref.top; + var width = _ref.width; + + var scale = restarting ? 0 : 1; + var transform = 'translate3d(' + (-width / 2 + left) + 'px, ' + (-width / 2 + top) + 'px, 0) scale(' + scale + ')'; + var _className = (0, _classnames3.default)(this.props.theme.ripple, (_classnames = {}, _defineProperty(_classnames, this.props.theme.rippleActive, active), _defineProperty(_classnames, this.props.theme.rippleRestarting, restarting), _classnames), className); + return _react2.default.createElement( + 'span', + _extends({ key: key, 'data-react-toolbox': 'ripple', className: this.props.theme.rippleWrapper }, props), + _react2.default.createElement('span', { + role: 'ripple', + ref: key, + className: _className, + style: (0, _prefixer2.default)({ transform: transform }, { width: width, height: width }) + }) + ); + } }, { key: 'render', value: function render() { + var _this3 = this; + if (!this.props.ripple) { return _react2.default.createElement(ComposedComponent, this.props); } else { - var _classnames; + var _ret3 = function () { + var ripples = _this3.state.ripples; + var _props2 = _this3.props; + var ripple = _props2.ripple; + var onRippleEnded = _props2.onRippleEnded; + var rippleCentered = _props2.rippleCentered; + var rippleMultiple = _props2.rippleMultiple; + var rippleSpread = _props2.rippleSpread; + var children = _props2.children; + var className = _props2.rippleClassName; - var _props2 = this.props; - var children = _props2.children; - var ripple = _props2.ripple; - var onRippleEnded = _props2.onRippleEnded; - var className = _props2.rippleClassName; - var centered = _props2.rippleCentered; - var spread = _props2.rippleSpread; + var other = _objectWithoutProperties(_props2, ['ripple', 'onRippleEnded', 'rippleCentered', 'rippleMultiple', 'rippleSpread', 'children', 'rippleClassName']); - var other = _objectWithoutProperties(_props2, ['children', 'ripple', 'onRippleEnded', 'rippleClassName', 'rippleCentered', 'rippleSpread']); + return { + v: _react2.default.createElement( + ComposedComponent, + _extends({}, other, { onMouseDown: _this3.handleMouseDown, onTouchStart: _this3.handleTouchStart }), + children ? children : null, + Object.keys(ripples).map(function (key) { + return _this3.renderRipple(key, className, ripples[key]); + }) + ) + }; + }(); - var rippleClassName = (0, _classnames3.default)(this.props.theme.ripple, (_classnames = {}, _defineProperty(_classnames, this.props.theme.rippleActive, this.state.active), _defineProperty(_classnames, this.props.theme.rippleRestarting, this.state.restarting), _classnames), className); - - var _state = this.state; - var left = _state.left; - var top = _state.top; - var width = _state.width; - - var scale = this.state.restarting ? 0 : 1; - var rippleStyle = (0, _prefixer2.default)({ - transform: 'translate3d(' + (-width / 2 + left) + 'px, ' + (-width / 2 + top) + 'px, 0) scale(' + scale + ')' - }, { width: width, height: width }); - - return _react2.default.createElement( - ComposedComponent, - _extends({}, other, { onMouseDown: this.handleMouseDown }), - children ? children : null, - _react2.default.createElement( - 'span', - _extends({ 'data-react-toolbox': 'ripple', className: this.props.theme.rippleWrapper }, props), - _react2.default.createElement('span', { ref: 'ripple', role: 'ripple', className: rippleClassName, style: rippleStyle }) - ) - ); + if ((typeof _ret3 === 'undefined' ? 'undefined' : _typeof(_ret3)) === "object") return _ret3.v; } } }]); @@ -209,6 +346,7 @@ var rippleFactory = function rippleFactory() { ripple: _react.PropTypes.bool, rippleCentered: _react.PropTypes.bool, rippleClassName: _react.PropTypes.string, + rippleMultiple: _react.PropTypes.bool, rippleSpread: _react.PropTypes.number, theme: _react.PropTypes.shape({ ripple: _react.PropTypes.string, @@ -222,6 +360,7 @@ var rippleFactory = function rippleFactory() { ripple: true, rippleCentered: defaultCentered, rippleClassName: defaultClassName, + rippleMultiple: defaultMultiple, rippleSpread: defaultSpread }; diff --git a/lib/table/Table.js b/lib/table/Table.js index a3055289..addc42c9 100644 --- a/lib/table/Table.js +++ b/lib/table/Table.js @@ -33,8 +33,6 @@ var _TableRow2 = _interopRequireDefault(_TableRow); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -69,22 +67,18 @@ var factory = function factory(TableHead, TableRow) { } }, _this.handleRowSelect = function (index) { if (_this.props.onSelect) { - (function () { - var position = _this.props.selected.indexOf(index); - var newSelected = [].concat(_toConsumableArray(_this.props.selected)); - if (position !== -1) { - newSelected = newSelected.filter(function (el, idx) { - return idx != position; - }); - } else { - if (_this.props.multiSelectable) { - newSelected.push(index); - } else { - newSelected = [index]; - } - } - _this.props.onSelect(newSelected); - })(); + var newSelection = []; + if (_this.props.multiSelectable) { + (function () { + var position = _this.props.selected.indexOf(index); + newSelection = _this.props.selected.indexOf(index) !== -1 ? _this.props.selected.filter(function (el, idx) { + return idx !== position; + }) : newSelection.concat([index]); + })(); + } else { + newSelection = [index]; + } + _this.props.onSelect(newSelection); } }, _this.handleRowChange = function (index, key, value) { if (_this.props.onChange) { diff --git a/lib/time_picker/TimePicker.js b/lib/time_picker/TimePicker.js index eaa7bae3..13849a51 100644 --- a/lib/time_picker/TimePicker.js +++ b/lib/time_picker/TimePicker.js @@ -72,6 +72,12 @@ var factory = function factory(TimePickerDialog, Input) { active: false }, _this.handleDismiss = function () { _this.setState({ active: false }); + }, _this.handleInputFocus = function (event) { + _events2.default.pauseEvent(event); + _this.setState({ active: true }); + }, _this.handleInputBlur = function (event) { + _events2.default.pauseEvent(event); + _this.setState({ active: false }); }, _this.handleInputMouseDown = function (event) { _events2.default.pauseEvent(event); _this.setState({ active: true }); @@ -96,21 +102,22 @@ var factory = function factory(TimePickerDialog, Input) { var inputClassName = _props.inputClassName; var onEscKeyDown = _props.onEscKeyDown; var onOverlayClick = _props.onOverlayClick; - var theme = _props.theme; + var readonly = _props.readonly; - var others = _objectWithoutProperties(_props, ['value', 'format', 'inputClassName', 'onEscKeyDown', 'onOverlayClick', 'theme']); + var others = _objectWithoutProperties(_props, ['value', 'format', 'inputClassName', 'onEscKeyDown', 'onOverlayClick', 'readonly']); var formattedTime = value ? _time2.default.formatTime(value, format) : ''; return _react2.default.createElement( 'div', { 'data-react-toolbox': 'time-picker' }, _react2.default.createElement(Input, _extends({}, others, { - className: (0, _classnames3.default)(theme.input, _defineProperty({}, inputClassName, inputClassName)), + className: (0, _classnames3.default)(this.props.theme.input, _defineProperty({}, inputClassName, inputClassName)), + disabled: readonly, error: this.props.error, - name: this.props.name, label: this.props.label, - onMouseDown: this.handleInputMouseDown, + name: this.props.name, onKeyPress: this.handleInputKeyPress, + onMouseDown: this.handleInputMouseDown, readOnly: true, type: 'text', value: formattedTime @@ -145,6 +152,7 @@ var factory = function factory(TimePickerDialog, Input) { onEscKeyDown: _react.PropTypes.func, onKeyPress: _react.PropTypes.func, onOverlayClick: _react.PropTypes.func, + readonly: _react.PropTypes.bool, theme: _react.PropTypes.shape({ input: _react.PropTypes.string }), diff --git a/lib/time_picker/theme.scss b/lib/time_picker/theme.scss index 29798289..328cdc43 100644 --- a/lib/time_picker/theme.scss +++ b/lib/time_picker/theme.scss @@ -3,7 +3,7 @@ @import "../mixins"; @import "./config"; -.input > [role="input"] { +.input:not(.disabled) > .inputElement { cursor: pointer; } diff --git a/lib/utils/events.js b/lib/utils/events.js index 87e42c56..6e5978de 100644 --- a/lib/utils/events.js +++ b/lib/utils/events.js @@ -44,10 +44,10 @@ exports.default = { element.addEventListener(eventName, fn); return true; }, - removeEventListenerOnTransitionEnded: function removeEventListenerOnTransitionEnded(element) { + removeEventListenerOnTransitionEnded: function removeEventListenerOnTransitionEnded(element, fn) { var eventName = transitionEventNamesFor(element); if (!eventName) return false; - element.removeEventListener(eventName); + element.removeEventListener(eventName, fn); return true; } };