// base class for all components import { hyphensToCamelCase } from '../utils/hyphens-to-camel-case'; import { Nullable } from '../utils/nullable'; class Component extends HTMLElement { private element: Nullable; private props: Nullable; private state: Nullable; private template: Nullable; private styles: Nullable; protected get root(): Nullable { return this.element; } public get currentProps(): Nullable { return this.props; } public get currentState(): Nullable { return this.state; } constructor(props: Nullable, state: Nullable) { super(); this.attachShadow({ mode: 'open' }); this.element = this.shadowRoot; this.props = props; this.state = state; } private connectedCallback() { this.props = { ...(this.props || {}), ...Object.fromEntries([ ...Array.from(this.attributes) ] .map(prop => [ hyphensToCamelCase(prop.localName), prop.value ])) } as T1; this.afterInit(this.props, this.state); this._render(); } private disconnectedCallback() { this.afterDestroy(); } protected afterInit(props: T1, state: Nullable) { } protected afterRender() { } protected afterStateChange(props: Nullable, state: T2) { } protected afterDestroy() { } public setTemplate(template: string) { this.template = template; } public setStyle(styles: string) { this.styles = styles; } public setState(name: string, val: any) { this.state = { ...(this.state || {}), [ name ]: val } as T2; this.afterStateChange(this.props, this.state); this._render(); } protected replaceState(state: T2): void { this.state = state; this.afterStateChange(this.props, this.state); this._render(); } private async _render() { if (this.template === null || this.template === undefined || this.element === null || this.element === undefined) { return; } if (this.styles) { this.element.innerHTML = `${ this.template }` } else { this.element.innerHTML = this.template; } this.afterRender(); } } export { Component };