jcore-ui
Version:
jcore-ui - components for building an interface
121 lines (99 loc) • 3.6 kB
text/typescript
import { IObject } from "../interfaces";
import EventEmitter, { TEventEmitter } from "../utils/EventEmitter";
import { $, JDom } from "./JDom";
export interface IComponentSelector {
element: string;
}
export interface IComponentOptions {
mount?: boolean;
name?: string;
}
export interface IComponentOn {
mount?: (ctx?: Component) => void;
render?: (ctx?: Component) => void;
destroy?: (ctx?: Component) => void;
unmount?: (ctx?: Component) => void;
}
export interface IComponent extends IObject {
selectors?: IComponentSelector;
$element?: HTMLElement | NodeListOf<HTMLElement> | string;
options?: IComponentOptions;
on?: IComponentOn;
}
export interface IComponentClass extends IComponent {
Component: any;
}
interface Component {
handlers?: IObject;
$element: JDom;
emitter: TEventEmitter;
components: any[];
selectors: IComponentSelector;
_mount: boolean;
options: IComponentOptions;
on: IComponentOn;
}
class Component {
constructor(props: IComponentClass) {
/**
* Если пришел массив HTMLElement,
* то для каждого вызываем экземпляр компонента
* и записываем их в массив components
*/
if (Array.isArray(props.$element) || props.$element instanceof NodeList) {
let array = Array.from(props.$element);
if (array.length) {
this.components = array.map(el => {
if (this._mount || $(el).hasAttr('data-mount')) {
return;
};
return new props.Component(Object.assign(props, {
$element: el
}));
}).filter(cpm => cpm);
}
return this;
};
/**
* Если не передали HTMLElement,
* то делаем поиск по селектору элемента и вызываем для него экземпляр компонента
*/
if (!props.$element) {
return new props.Component({
...props,
$element: $(props.selectors.element).element
});
};
this.$element = $(props.$element);
if (!this.$element) {
// throw Error(`Не найден HTMLElement ${this.constructor.name}`)
console.log(Error(`Не найден HTMLElement ${this.constructor.name}`));
};
this.options = {
mount: true,
name: this.$element.dataset.name || props.options && props.options.name || ''
};
this.on = {
mount: () => {},
render: () => {},
destroy: () => {},
unmount: () => {},
};
this.selectors = props.selectors;
this.emitter = props.emitter || new EventEmitter();
this.options = Object.assign(this.options, props.options || {});
this.on = Object.assign(this.on, props.on || {});
}
mount() {
this.$element.attr('data-mount', 'true');
this._mount = true;
}
getByName(components: Component[], name: string): Component {
return components.filter(component => component.options.name === name)[0];
}
unmount() {
this._mount = false;
this.$element.attr('data-mount', null);
}
}
export default Component