jcore-ui
Version:
jcore-ui - components for building an interface
163 lines (127 loc) • 4.19 kB
text/typescript
import Component, { IComponent, IComponentOn, IComponentOptions, IComponentSelector } from "../core/Component";
import config from '../../config';
import createElement from "../utils/createElement";
import event from "../utils/event";
import { $, JDom } from "../core/JDom";
const selectors = {
element: `.${config.prefix}-modal`,
overlay: `.${config.prefix}-modal-overlay`,
content: `.${config.prefix}-modal-content`,
close: `.${config.prefix}-modal-close`,
btnTarget: `data-modal-target`,
}
interface IModalSelector extends IComponentSelector {
overlay: string;
content: string;
close: string;
btnTarget: string;
}
interface IModalOptions extends IComponentOptions {
adaptive?: boolean;
children?: HTMLElement[];
}
interface IModalOn extends IComponentOn {
// change?: (ctx?: Component) => void;
}
interface IModalElements {
// $close?: HTMLElement
$btnTarget?: JDom;
$container?: JDom;
}
interface IModal extends IComponent {
selectors?: IModalSelector;
options?: IModalOptions;
on?: IModalOn;
elements?: IModalElements;
}
interface Modal {
selectors: IModalSelector;
$overlay: JDom;
$close: JDom;
$btnTarget: JDom;
$container?: JDom;
options: IModalOptions;
on: IModalOn;
props: IModal;
isRender: boolean;
}
class Modal extends Component {
constructor(props: IModal = {}) {
super({
...props,
Component: Modal,
selectors: Object.assign(selectors, props.selectors || {})
});
this.props = props;
if (this.options && this.options.mount) {
this.mount();
}
}
mount() {
if (!this.$element || this._mount || this.$element.attr('data-mount')) {
return;
}
super.mount();
this.options = Object.assign({
adaptive: this.$element.dataset.adaptive || true,
}, this.options);
this.handlers = {
// change: this.change.bind(this)
};
this.isRender = false;
this.$overlay = $(`<div class="${this.selectors.overlay.replace('.', '')}"></div>`);
this.$close = this.$element.find(this.selectors.close);
this.$btnTarget = this.props.elements?.$btnTarget || $(`[${this.selectors.btnTarget}="${this.options.name}"]`);
this.$container = $(this.props.elements?.$container || $(`body`));
this.addEvents();
this.on.mount(this);
this.emitter.emit('mount', this);
}
addEvents() {
if (this.options.adaptive) {
this.$element.attr('data-adaptive', '');
}
if (this.$btnTarget) {
this.$btnTarget.on('click', e => this.render());
}
this.$overlay.on('click', this.destroy.bind(this));
this.$close.on('click', this.destroy.bind(this));
}
unmount() {
super.unmount();
this.on.unmount(this);
this.emitter.emit('unmount', this);
}
render() {
$('body').style.setProperty('overflow', 'hidden');
this.$container.append(this.$overlay.get());
this.$container.append(this.$element.get());
this.isRender = true;
this.on.render(this);
this.emitter.emit('render', this);
setTimeout(() => {
this.$overlay.attr('data-active', '');
this.$element.attr('data-active', '');
}, 10);
}
destroy() {
if (!this.isRender) {
return;
}
this.$overlay.on(event.transitionEnd(), () => {
this.$overlay.attr('data-closing', null);
this.$element.attr('data-closing', null);
this.$overlay.attr('data-active', null);
this.$element.attr('data-active', null);
this.$overlay.remove();
this.$element.remove();
}, { once: true });
this.$overlay.attr('data-closing', '');
this.$element.attr('data-closing', '');
this.isRender = false;
this.on.destroy(this);
this.emitter.emit('destroy', this);
document.querySelector('body').style.removeProperty('overflow');
}
}
export default Modal