@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
JavaScript
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();