'use strict'; 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 && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 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; }; }(); 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 _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _glamor = require('glamor'); var _TransitionGroup = require('react-transition-group/TransitionGroup'); var _TransitionGroup2 = _interopRequireDefault(_TransitionGroup); var _Toast = require('./Toast'); var _Toast2 = _interopRequireDefault(_Toast); var _DefaultCloseButton = require('./DefaultCloseButton'); var _DefaultCloseButton2 = _interopRequireDefault(_DefaultCloseButton); var _DefaultTransition = require('./DefaultTransition'); var _DefaultTransition2 = _interopRequireDefault(_DefaultTransition); var _constant = require('./constant'); var _style = require('./style'); var _style2 = _interopRequireDefault(_style); var _EventManager = require('./util/EventManager'); var _EventManager2 = _interopRequireDefault(_EventManager); var _propValidator = require('./util/propValidator'); 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; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var toastPosition = function toastPosition(pos) { var positionKey = pos.toUpperCase().replace('-', '_'); var positionRule = typeof _constant.POSITION[positionKey] !== 'undefined' ? _style2.default[positionKey] : _style2.default.TOP_RIGHT; /** define margin for center toast based on toast witdh */ if (positionKey.indexOf('CENTER') !== -1 && typeof positionRule.marginLeft === 'undefined') { positionRule.marginLeft = '-' + parseInt(_style2.default.width, 10) / 2 + 'px'; } return (0, _glamor.css)(positionRule, (0, _glamor.css)(_defineProperty({}, '@media ' + _style2.default.mobile, _extends({ left: 0, margin: 0, position: 'fixed' }, pos.substring(0, 3) === 'top' ? { top: 0 } : { bottom: 0 })))); }; var container = function container(disablePointer, position) { return (0, _glamor.css)(_extends({ zIndex: _style2.default.zIndex, position: 'fixed', padding: '4px', width: _style2.default.width, boxSizing: 'border-box', color: '#fff' }, disablePointer ? { pointerEvents: 'none' } : {}, _defineProperty({}, '@media ' + _style2.default.mobile, { width: '100vw', padding: 0 })), toastPosition(position)); }; var ToastContainer = function (_Component) { _inherits(ToastContainer, _Component); function ToastContainer() { var _ref; var _temp, _this, _ret; _classCallCheck(this, ToastContainer); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = ToastContainer.__proto__ || Object.getPrototypeOf(ToastContainer)).call.apply(_ref, [this].concat(args))), _this), _this.state = { toast: [], isDocumentHidden: false }, _this.collection = {}, _this.isDocumentHidden = function () { return _this.setState({ isDocumentHidden: document.hidden }); }, _this.isToastActive = function (id) { return _this.state.toast.indexOf(parseInt(id, 10)) !== -1; }, _temp), _possibleConstructorReturn(_this, _ret); } /** * Hold toast ids */ /** * Hold toast's informations: * - what to render * - position * - raw content * - options */ _createClass(ToastContainer, [{ key: 'componentDidMount', value: function componentDidMount() { var _this2 = this; var SHOW = _constant.ACTION.SHOW, CLEAR = _constant.ACTION.CLEAR, MOUNTED = _constant.ACTION.MOUNTED; _EventManager2.default.on(SHOW, function (content, options) { return _this2.show(content, options); }).on(CLEAR, function (id) { return id !== null ? _this2.removeToast(id) : _this2.clear(); }).emit(MOUNTED, this); document.addEventListener('visibilitychange', this.isDocumentHidden); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { _EventManager2.default.off(_constant.ACTION.SHOW); _EventManager2.default.off(_constant.ACTION.CLEAR); document.removeEventListener('visibilitychange', this.isDocumentHidden); } }, { key: 'removeToast', value: function removeToast(id) { this.setState({ toast: this.state.toast.filter(function (v) { return v !== parseInt(id, 10); }) }); } }, { key: 'makeCloseButton', value: function makeCloseButton(toastClose, toastId, type) { var _this3 = this; var closeButton = this.props.closeButton; if ((0, _react.isValidElement)(toastClose) || toastClose === false) { closeButton = toastClose; } return closeButton === false ? false : (0, _react.cloneElement)(closeButton, { closeToast: function closeToast() { return _this3.removeToast(toastId); }, type: type }); } }, { key: 'getAutoCloseDelay', value: function getAutoCloseDelay(toastAutoClose) { return toastAutoClose === false || (0, _propValidator.isValidDelay)(toastAutoClose) ? toastAutoClose : this.props.autoClose; } }, { key: 'isFunction', value: function isFunction(object) { return !!(object && object.constructor && object.call && object.apply); } }, { key: 'canBeRendered', value: function canBeRendered(content) { return (0, _react.isValidElement)(content) || typeof content === 'string' || typeof content === 'number' || this.isFunction(content); } }, { key: 'show', value: function show(content, options) { var _this4 = this; if (!this.canBeRendered(content)) { throw new Error('The element you provided cannot be rendered. You provided an element of type ' + (typeof content === 'undefined' ? 'undefined' : _typeof(content))); } var toastId = options.toastId; var closeToast = function closeToast() { return _this4.removeToast(toastId); }; var toastOptions = { id: toastId, type: options.type, closeToast: closeToast, updateId: options.updateId, position: options.position || this.props.position, transition: options.transition || this.props.transition, className: options.className || this.props.toastClassName, bodyClassName: options.bodyClassName || this.props.bodyClassName, closeButton: this.makeCloseButton(options.closeButton, toastId, options.type), pauseOnHover: options.pauseOnHover !== null ? options.pauseOnHover : this.props.pauseOnHover, closeOnClick: options.closeOnClick !== null ? options.closeOnClick : this.props.closeOnClick, progressClassName: options.progressClassName || this.props.progressClassName, autoClose: this.getAutoCloseDelay(options.autoClose !== false ? parseInt(options.autoClose, 10) : options.autoClose), hideProgressBar: typeof options.hideProgressBar === 'boolean' ? options.hideProgressBar : this.props.hideProgressBar }; this.isFunction(options.onOpen) && (toastOptions.onOpen = options.onOpen); this.isFunction(options.onClose) && (toastOptions.onClose = options.onClose); /** * add closeToast function to react component only */ if ((0, _react.isValidElement)(content) && typeof content.type !== 'string' && typeof content.type !== 'number') { content = (0, _react.cloneElement)(content, { closeToast: closeToast }); } else if (this.isFunction(content)) { content = content({ closeToast: closeToast }); } this.collection = _extends({}, this.collection, _defineProperty({}, toastId, { position: toastOptions.position, options: toastOptions, content: content })); this.setState({ toast: toastOptions.updateId !== null ? [].concat(_toConsumableArray(this.state.toast)) : [].concat(_toConsumableArray(this.state.toast), [toastId]) }); } }, { key: 'makeToast', value: function makeToast(content, options) { return _react2.default.createElement( _Toast2.default, _extends({}, options, { isDocumentHidden: this.state.isDocumentHidden, key: 'toast-' + options.id }), content ); } }, { key: 'clear', value: function clear() { this.setState({ toast: [] }); } }, { key: 'renderToast', value: function renderToast() { var _this5 = this; var toastToRender = {}; var _props = this.props, className = _props.className, style = _props.style, newestOnTop = _props.newestOnTop; var collection = newestOnTop ? Object.keys(this.collection).reverse() : Object.keys(this.collection); collection.forEach(function (toastId) { var item = _this5.collection[toastId]; toastToRender[item.position] || (toastToRender[item.position] = []); if (_this5.state.toast.indexOf(parseInt(toastId, 10)) !== -1) { toastToRender[item.position].push(_this5.makeToast(item.content, item.options)); } else { toastToRender[item.position].push(null); delete _this5.collection[toastId]; } }); return Object.keys(toastToRender).map(function (position) { var disablePointer = toastToRender[position].length === 1 && toastToRender[position][0] === null; return _react2.default.createElement( _TransitionGroup2.default, _extends({}, typeof className !== 'string' ? (0, _glamor.css)(container(disablePointer, position), className) : container(disablePointer, position), typeof className === 'string' && { className: className }, style !== null && { style: style }, { key: 'container-' + position }), toastToRender[position] ); }); } }, { key: 'render', value: function render() { return _react2.default.createElement( 'div', null, this.renderToast() ); } }]); return ToastContainer; }(_react.Component); ToastContainer.propTypes = { /** * Set toast position */ position: _propTypes2.default.oneOf((0, _propValidator.objectValues)(_constant.POSITION)), /** * Disable or set autoClose delay */ autoClose: _propValidator.falseOrDelay, /** * Disable or set a custom react element for the close button */ closeButton: _propValidator.falseOrElement, /** * Hide or not progress bar when autoClose is enabled */ hideProgressBar: _propTypes2.default.bool, /** * Pause toast duration on hover */ pauseOnHover: _propTypes2.default.bool, /** * Dismiss toast on click */ closeOnClick: _propTypes2.default.bool, /** * Newest on top */ newestOnTop: _propTypes2.default.bool, /** * An optional className */ className: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.object]), /** * An optional style */ style: _propTypes2.default.object, /** * An optional className for the toast */ toastClassName: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.object]), /** * An optional className for the toast body */ bodyClassName: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.object]), /** * An optional className for the toast progress bar */ progressClassName: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.object]), /** * Define enter and exit transition using react-transition-group */ transition: _propTypes2.default.func }; ToastContainer.defaultProps = { position: _constant.POSITION.TOP_RIGHT, transition: _DefaultTransition2.default, autoClose: 5000, hideProgressBar: false, closeButton: _react2.default.createElement(_DefaultCloseButton2.default, null), pauseOnHover: true, closeOnClick: true, newestOnTop: false, className: null, style: null, toastClassName: '', bodyClassName: '', progressClassName: '' }; exports.default = ToastContainer;