rabbit-simple-ui
Version:
A simple UI component library based on JavaScript
159 lines (154 loc) • 6.34 kB
text/typescript
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import PREFIX from '../prefix';
import { $el, bind, createElem, setCss, setHtml } from '../../dom-utils';
import { destroyElem, type, useHTMLString } from '../../utils';
import { CssTransition } from '../../mixins';
export type MessageType = 'info' | 'success' | 'warning' | 'error' | 'loading';
export type KeyType = string | number;
export interface MessageConfig {
key?: string | number;
content?: string;
duration?: number;
onClose?: () => void;
closable?: boolean;
background?: boolean;
dangerouslyUseHTMLString?: boolean;
}
export const PREFIX_KEY = 'rab-message-instance';
export const EnterClass = `${PREFIX.message}-move-enter`;
export const LeaveClass = `${PREFIX.message}-move-leave`;
type ConfigType = string | MessageConfig;
const ICONTYPES = {
info: 'ios-information-circle',
success: 'ios-checkmark-circle',
warning: 'ios-alert',
error: 'ios-close-circle',
loading: 'loading-solid'
};
let zIndex = 1010;
let name = 0;
export class CreateInstance {
protected INSTANCES: HTMLElement[];
constructor() {
this.INSTANCES = [];
}
public _init(top: number): void {
const Wrapper = createElem('div');
setCss(Wrapper, 'zIndex', `${zIndex}`);
Wrapper.setAttribute('class', `${PREFIX.message}`);
document.body.appendChild(Wrapper);
setTimeout(() => setCss(Wrapper, 'top', `${top}px`), 0);
}
protected _create(type: MessageType, config: ConfigType, duration: number): void {
const Message = this._setMainTemplate(type);
const MessageContent = Message.querySelector(`.${PREFIX.messageChild}-content`)!;
this._autoAddZIndex();
this._setIcon(type, Message);
this._setContent(Message, config);
if (typeof config === 'object') {
const { key, closable, onClose, background } = config;
this._setKey(Message, key);
this._setClosable(Message, MessageContent, closable, onClose);
this._setBackground(Message, MessageContent, background);
}
this.INSTANCES.push(Message);
$el(`.${PREFIX.message}`).appendChild(Message);
this._autoClose(Message, config, duration);
}
private _setMainTemplate(type: MessageType): HTMLElement {
const MessageNotice = createElem('div');
const template = `
<div class="${PREFIX.messageChild}-content ${PREFIX.messageChild}-content-${type}">
<div class="${PREFIX.messageChild}-content-text">
<div class="${PREFIX.message}-${type}">
<i class="${PREFIX.icon}"></i>
<span id="${PREFIX.messageChild}-text"></span>
</div>
</div>
</div>
`;
MessageNotice.dataset['thisName'] = `${name++}`;
MessageNotice.className = `${PREFIX.message}-notice`;
setHtml(MessageNotice, template);
CssTransition(MessageNotice, {
inOrOut: 'in',
enterCls: EnterClass,
rmCls: true,
timeout: 250
});
return MessageNotice;
}
private _setIcon(type: MessageType, elem: HTMLElement): void {
const MessageIcon = elem.querySelector(`.${PREFIX.icon}`)!;
if (type === 'loading') {
MessageIcon.classList.add('rab-load-loop');
}
MessageIcon.classList.add(`${PREFIX.icon}-${ICONTYPES[type]}`);
}
private _setContent(elem: HTMLElement, content: ConfigType): void {
const MessageText = elem.querySelector(`#${PREFIX.messageChild}-text`)!;
if (typeof content === 'string') {
useHTMLString(MessageText, content, false);
} else if (typeof content === 'object' && content.content) {
useHTMLString(MessageText, content.content, content.dangerouslyUseHTMLString);
}
}
private _setKey(elem: HTMLElement, key?: KeyType): void {
if (!key || (key && !type.isStr(key) && !type.isNum(key))) return;
elem.setAttribute(`${PREFIX_KEY}-key`, `${key}`);
}
private _setClosable(
elem: HTMLElement,
child: Element,
closable?: boolean,
onClose?: () => void
): void {
if (!closable || (closable && !type.isBol(closable))) return;
const template = `
<a class="${PREFIX.messageChild}-close">
<i class="${PREFIX.icon} ${PREFIX.icon}-ios-close"></i>
</a>
`;
elem.classList.add(`${PREFIX.messageChild}-closable`);
child.insertAdjacentHTML('beforeend', template);
this._handleClose(elem, onClose);
}
private _handleClose(elem: HTMLElement, onClose?: () => void): void {
const MessageCloseBtn = elem.querySelector(`.${PREFIX.messageChild}-close`)!;
bind(MessageCloseBtn, 'click', () => {
this._destroy(elem);
onClose && type.isFn(onClose);
});
}
private _setBackground(elem: HTMLElement, child: Element, background?: boolean): void {
if (!background || (background && !type.isBol(background))) return;
elem.classList.add(`${PREFIX.messageChild}-with-background`);
child.classList.add(`${PREFIX.messageChild}-content-background`);
}
private _autoAddZIndex(): void {
zIndex++;
setCss($el(`.${PREFIX.message}`), 'zIndex', `${zIndex}`);
}
private _autoClose(elem: HTMLElement, config: ConfigType, duration: number): void {
if (duration || duration === 0 || !config) {
if (duration === 0) return;
setTimeout(() => {
this._destroy(elem);
}, duration * 1000);
} else {
if (typeof config === 'object' && config.duration) {
setTimeout(() => {
this._destroy(elem);
}, config.duration * 1000);
}
}
}
private _destroy(elem: HTMLElement): void {
destroyElem(elem, {
duration: 0.1,
clsEnter: EnterClass,
clsLeave: LeaveClass
});
this.INSTANCES.splice(Number(elem.dataset['thisName']), 1);
}
}