UNPKG

react-customized-notifications

Version:

A React Notification System forked from https://github.com/igorprado/react-notification-system

352 lines (292 loc) 8.66 kB
var React = require('react'); var createReactClass = require('create-react-class'); var PropTypes = require('prop-types'); var ReactDOM = require('react-dom'); var Constants = require('./constants'); var Helpers = require('./helpers'); var merge = require('object-assign'); /* From Modernizr */ var whichTransitionEvent = function() { var el = document.createElement('fakeelement'); var transition; var transitions = { transition: 'transitionend', OTransition: 'oTransitionEnd', MozTransition: 'transitionend', WebkitTransition: 'webkitTransitionEnd' }; Object.keys(transitions).forEach(function(transitionKey) { if (el.style[transitionKey] !== undefined) { transition = transitions[transitionKey]; } }); return transition; }; var NotificationItem = createReactClass({ propTypes: { notification: PropTypes.object, getStyles: PropTypes.object, onRemove: PropTypes.func, allowHTML: PropTypes.bool, noAnimation: PropTypes.bool, children: PropTypes.oneOfType([ PropTypes.string, PropTypes.element ]), itemClassName: PropTypes.string, itemOnClick: PropTypes.func }, getDefaultProps: function() { return { noAnimation: false, onRemove: function() {}, allowHTML: false }; }, getInitialState: function() { return { visible: undefined, removed: false }; }, componentWillMount: function() { var getStyles = this.props.getStyles; var level = this.props.notification.level; this._noAnimation = this.props.noAnimation; this._styles = { notification: getStyles.byElement('notification')(level), title: getStyles.byElement('title')(level), dismiss: getStyles.byElement('dismiss')(level), messageWrapper: getStyles.byElement('messageWrapper')(level), actionWrapper: getStyles.byElement('actionWrapper')(level), action: getStyles.byElement('action')(level) }; if (!this.props.notification.dismissible) { this._styles.notification.cursor = 'default'; } }, _styles: {}, _notificationTimer: null, _height: 0, _noAnimation: null, _isMounted: false, _removeCount: 0, _getCssPropertyByPosition: function() { var position = this.props.notification.position; var css = {}; switch (position) { case Constants.positions.tl: case Constants.positions.bl: css = { property: 'left', value: -200 }; break; case Constants.positions.tr: case Constants.positions.br: // TODO introduce way of overwriting this css = { property: 'right', value: -200 }; break; case Constants.positions.tc: css = { property: 'top', value: -100 }; break; case Constants.positions.bc: css = { property: 'bottom', value: -100 }; break; default: } return css; }, _defaultAction: function(event) { var notification = this.props.notification; event.preventDefault(); this._hideNotification(); if (typeof notification.action.callback === 'function') { notification.action.callback(); } }, _hideNotification: function() { if (this._notificationTimer) { this._notificationTimer.clear(); } if (this._isMounted) { this.setState({ visible: false, removed: true }); } if (this._noAnimation) { this._removeNotification(); } }, _removeNotification: function() { this.props.onRemove(this.props.notification.uid); }, _dismiss: function() { if (!this.props.notification.dismissible) { return; } this._hideNotification(); }, _showNotification: function() { var self = this; setTimeout(function() { if (self._isMounted) { self.setState({ visible: true }); } }, 50); }, _onTransitionEnd: function() { if (this._removeCount > 0) return; if (this.state.removed) { this._removeCount += 1; this._removeNotification(); } }, componentDidMount: function() { var self = this; var transitionEvent = whichTransitionEvent(); var notification = this.props.notification; var element = ReactDOM.findDOMNode(this); this._height = element.offsetHeight; this._isMounted = true; // Watch for transition end if (!this._noAnimation) { if (transitionEvent) { element.addEventListener(transitionEvent, this._onTransitionEnd); } else { this._noAnimation = true; } } if (notification.autoDismiss) { this._notificationTimer = new Helpers.Timer(function() { self._hideNotification(); }, notification.autoDismiss * 1000); } this._showNotification(); }, _handleMouseEnter: function() { var notification = this.props.notification; if (notification.autoDismiss) { this._notificationTimer.pause(); } }, _handleMouseLeave: function() { var notification = this.props.notification; if (notification.autoDismiss) { this._notificationTimer.resume(); } }, componentWillUnmount: function() { var element = ReactDOM.findDOMNode(this); var transitionEvent = whichTransitionEvent(); element.removeEventListener(transitionEvent, this._onTransitionEnd); this._isMounted = false; }, _allowHTML: function(string) { return { __html: string }; }, render: function() { var notification = this.props.notification; var className = 'notification notification-' + notification.level + ' ' + this.props.itemClassName; var notificationStyle = merge({}, this._styles.notification); var cssByPos = this._getCssPropertyByPosition(); var dismiss = null; var actionButton = null; var children = null; var title = null; var message = null; var itemOnClick = this.props.itemOnClick; if (this.state.visible) { className += ' notification-visible'; } else if (this.state.visible === false) { className += ' notification-hidden'; } if (!notification.dismissible) { className += ' notification-not-dismissible'; } if (this.props.getStyles.overrideStyle) { if (!this.state.visible && !this.state.removed) { notificationStyle[cssByPos.property] = cssByPos.value; } if (this.state.visible && !this.state.removed) { notificationStyle.height = this._height; notificationStyle[cssByPos.property] = 0; } if (this.state.removed) { notificationStyle.overlay = 'hidden'; notificationStyle.height = 0; notificationStyle.marginTop = 0; notificationStyle.paddingTop = 0; notificationStyle.paddingBottom = 0; } notificationStyle.opacity = this.state.visible ? this._styles.notification.isVisible.opacity : this._styles.notification.isHidden.opacity; } if (notification.title) { title = <h4 className="notification-title" style={ this._styles.title }>{ notification.title }</h4>; } if (notification.message) { if (this.props.allowHTML) { message = ( <div className="notification-message" style={ this._styles.messageWrapper } dangerouslySetInnerHTML={ this._allowHTML(notification.message) } /> ); } else { message = ( <div className="notification-message" style={ this._styles.messageWrapper }>{ notification.message }</div> ); } } if (notification.dismissible) { dismiss = ( <span className="notification-dismiss" style={ this._styles.dismiss } onClick={ this._dismiss } > &times; </span> ); } if (notification.action) { actionButton = ( <div className="notification-action-wrapper" style={ this._styles.actionWrapper }> <button className="notification-action-button" onClick={ this._defaultAction } style={ this._styles.action }> { notification.action.label } </button> </div> ); } if (notification.children) { children = notification.children; } return ( <div className={ className } onClick={ itemOnClick || this._dismiss } onMouseEnter={ this._handleMouseEnter } onMouseLeave={ this._handleMouseLeave } style={ notificationStyle } > { title } { message } { children } { dismiss } { actionButton } </div> ); } }); module.exports = NotificationItem;