UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

291 lines 9.57 kB
import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import ToastListFoundation from '@douyinfe/semi-foundation/lib/es/toast/toastListFoundation'; import { cssClasses, strings } from '@douyinfe/semi-foundation/lib/es/toast/constants'; import BaseComponent from '../_base/baseComponent'; import Toast from './toast'; import '@douyinfe/semi-foundation/lib/es/toast/toast.css'; import getUuid from '@douyinfe/semi-foundation/lib/es/utils/uuid'; import useToast from './useToast'; import CSSAnimation from '../_cssAnimation'; import cls from 'classnames'; const createBaseToast = () => { var _a; return _a = class ToastList extends BaseComponent { constructor(props) { super(props); this.stack = false; this.innerWrapperRef = /*#__PURE__*/React.createRef(); this.handleMouseEnter = e => { if (this.stack) { this.foundation.handleMouseInSideChange(true); } }; this.handleMouseLeave = e => { var _a; if (this.stack) { const height = (_a = this.foundation.getInputWrapperRect()) === null || _a === void 0 ? void 0 : _a.height; if (height) { this.foundation.handleMouseInSideChange(false); } } }; this.state = { list: [], removedItems: [], updatedItems: [], mouseInSide: false }; this.foundation = new ToastListFoundation(this.adapter); } get adapter() { return Object.assign(Object.assign({}, super.adapter), { updateToast: (list, removedItems, updatedItems) => { this.setState({ list, removedItems, updatedItems }); }, handleMouseInSideChange: mouseInSide => { this.setState({ mouseInSide }); }, getInputWrapperRect: () => { var _a; return (_a = this.innerWrapperRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect(); } }); } static create(opts) { var _a; const id = (_a = opts.id) !== null && _a !== void 0 ? _a : getUuid('toast'); // this.id = id; if (!ToastList.ref) { const div = document.createElement('div'); if (!this.wrapperId) { this.wrapperId = getUuid('toast-wrapper').slice(0, 26); } div.className = cssClasses.WRAPPER; div.id = this.wrapperId; div.style.zIndex = String(typeof opts.zIndex === 'number' ? opts.zIndex : ToastList.defaultOpts.zIndex); ['top', 'left', 'bottom', 'right'].map(pos => { if (pos in ToastList.defaultOpts || pos in opts) { const val = opts[pos] ? opts[pos] : ToastList.defaultOpts[pos]; div.style[pos] = typeof val === 'number' ? `${val}px` : val; } }); // document.body.appendChild(div); if (ToastList.defaultOpts.getPopupContainer) { const container = ToastList.defaultOpts.getPopupContainer(); container.appendChild(div); } else { document.body.appendChild(div); } ReactDOM.render(/*#__PURE__*/React.createElement(ToastList, { ref: instance => ToastList.ref = instance }), div, () => { ToastList.ref.add(Object.assign(Object.assign({}, opts), { id })); ToastList.ref.stack = Boolean(opts.stack); }); } else { const node = document.querySelector(`#${this.wrapperId}`); ['top', 'left', 'bottom', 'right'].map(pos => { if (pos in opts) { node.style[pos] = typeof opts[pos] === 'number' ? `${opts[pos]}px` : opts[pos]; } }); if (Boolean(opts.stack) !== ToastList.ref.stack) { ToastList.ref.stack = Boolean(opts.stack); } if (ToastList.ref.has(id)) { ToastList.ref.update(id, Object.assign(Object.assign({}, opts), { id })); } else { ToastList.ref.add(Object.assign(Object.assign({}, opts), { id })); } } return id; } static close(id) { if (ToastList.ref) { ToastList.ref.remove(id); } } static destroyAll() { if (ToastList.ref) { ToastList.ref.destroyAll(); const wrapper = document.querySelector(`#${this.wrapperId}`); ReactDOM.unmountComponentAtNode(wrapper); wrapper && wrapper.parentNode.removeChild(wrapper); ToastList.ref = null; this.wrapperId = null; } } static getWrapperId() { return this.wrapperId; } static info(opts) { if (typeof opts === 'string') { opts = { content: opts }; } return this.create(Object.assign(Object.assign(Object.assign({}, ToastList.defaultOpts), opts), { type: 'info' })); } static warning(opts) { if (typeof opts === 'string') { opts = { content: opts }; } return this.create(Object.assign(Object.assign(Object.assign({}, ToastList.defaultOpts), opts), { type: 'warning' })); } static error(opts) { if (typeof opts === 'string') { opts = { content: opts }; } return this.create(Object.assign(Object.assign(Object.assign({}, ToastList.defaultOpts), opts), { type: 'error' })); } static success(opts) { if (typeof opts === 'string') { opts = { content: opts }; } return this.create(Object.assign(Object.assign(Object.assign({}, ToastList.defaultOpts), opts), { type: 'success' })); } static config(opts) { ['top', 'left', 'bottom', 'right'].forEach(pos => { if (pos in opts) { ToastList.defaultOpts[pos] = opts[pos]; } }); if (typeof opts.theme === 'string' && strings.themes.includes(opts.theme)) { ToastList.defaultOpts.theme = opts.theme; } if (typeof opts.zIndex === 'number') { ToastList.defaultOpts.zIndex = opts.zIndex; } if (typeof opts.duration === 'number') { ToastList.defaultOpts.duration = opts.duration; } if (typeof opts.getPopupContainer === 'function') { ToastList.defaultOpts.getPopupContainer = opts.getPopupContainer; } } has(id) { return this.foundation.hasToast(id); } add(opts) { return this.foundation.addToast(opts); } update(id, opts) { return this.foundation.updateToast(id, opts); } remove(id) { return this.foundation.removeToast(id); } destroyAll() { return this.foundation.destroyAll(); } render() { let { list } = this.state; const { removedItems, updatedItems } = this.state; list = Array.from(new Set([...list, ...removedItems])); const updatedIds = updatedItems.map(_ref => { let { id } = _ref; return id; }); const refFn = toast => { var _a; if (((_a = toast === null || toast === void 0 ? void 0 : toast.foundation) === null || _a === void 0 ? void 0 : _a._id) && updatedIds.includes(toast.foundation._id)) { toast.foundation.restartCloseTimer(); } }; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { className: cls({ [`${cssClasses.PREFIX}-innerWrapper`]: true, [`${cssClasses.PREFIX}-innerWrapper-hover`]: this.state.mouseInSide }), ref: this.innerWrapperRef, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave }, list.map((item, index) => { const isRemoved = removedItems.find(removedItem => removedItem.id === item.id) !== undefined; return /*#__PURE__*/React.createElement(CSSAnimation, { key: item.id, motion: item.motion, animationState: isRemoved ? "leave" : "enter", startClassName: isRemoved ? `${cssClasses.PREFIX}-animation-hide` : `${cssClasses.PREFIX}-animation-show` }, _ref2 => { let { animationClassName, animationEventsNeedBind, isAnimating } = _ref2; return isRemoved && !isAnimating ? null : /*#__PURE__*/React.createElement(Toast, Object.assign({}, item, { stack: this.stack, stackExpanded: this.state.mouseInSide, positionInList: { length: list.length, index }, className: cls({ [item.className]: Boolean(item.className), [animationClassName]: true }) }, animationEventsNeedBind, { style: Object.assign({}, item.style), close: id => this.remove(id), ref: refFn })); }); }))); } }, _a.defaultOpts = { motion: true, zIndex: 1010, content: '' }, _a.propTypes = { content: PropTypes.node, duration: PropTypes.number, onClose: PropTypes.func, icon: PropTypes.node, direction: PropTypes.oneOf(strings.directions), stack: PropTypes.bool }, _a.defaultProps = {}, _a; }; export class ToastFactory { static create(config) { const newToast = createBaseToast(); newToast.useToast = useToast; config && newToast.config(config); return newToast; } } export default ToastFactory.create();