UNPKG

@yauheni-shcharbakou/rxspa

Version:
379 lines (365 loc) 7.98 kB
// src/decorators/component.decorator.ts var component = (params) => { return function(Constructor) { return class extends Constructor { constructor(...args) { super(...args); this.template = params.template; } }; }; }; // src/decorators/log.decorator.ts var log = (message) => { return (target, propertyKey, descriptor) => { const stock = descriptor.value; descriptor.value = function(...args) { console.log(message || propertyKey); return stock.apply(this, args); }; }; }; // src/entities/router.ts var Router = class { /** * Base router constructor * * @param openPage callback for open page * @param openModal callback for open modal * @param rootContainer {HTMLElement} app root element */ constructor(openPage, openModal, rootContainer) { this.openPage = openPage; this.openModal = openModal; this.rootContainer = rootContainer; this.openPage = openPage; this.openModal = openModal; this.rootContainer = rootContainer; } /** * Method for get app root element from component */ getRootContainer() { return this.rootContainer; } }; // src/utils/index.ts function bootstrap(app) { app.bootstrap(); } function render(component2) { return component2.render(); } // src/constants/index.ts var BASE_DELAY = 100; // src/entities/application.ts var Application = class { /** * Application class constructor * * @param appConfig app configuration object * @param context app context object */ constructor(appConfig, context) { this.context = context; this.rootContainer = appConfig.root; this.pages = appConfig.pages; this.modals = appConfig.modals; this.router = new Router( (id) => this.openPage(id), (id) => this.openModal(id), appConfig.root ); this.currentPage = this.initComponent(appConfig.entry); this.prevPage = null; this.currentModal = null; this.onInit(); } rootContainer; pages; modals; router; currentPage; prevPage; currentModal; /** * Prebuilt method for add logic when app starts * * @protected */ onInit() { } /** * Prebuilt method for build component * * @param Component Component class * @protected */ initComponent(Component2) { return new Component2(this.router, this.context); } /** * Method for show current page */ bootstrap() { this.rootContainer.append(render(this.currentPage)); } /** * Method for open page * * @param id {string} page id from app config * @protected */ openPage(id) { if (Object.keys(this.pages).indexOf(id) !== -1) { window.scrollTo({ top: 0 }); this.prevPage = this.currentPage; this.currentPage = this.initComponent(this.pages[id]); this.bootstrap(); this.prevPage.close(); this.currentPage.open(); } } /** * Method for open modal * * @param id {string} modal id from app config * @protected */ openModal(id) { if (Object.keys(this.modals).indexOf(id) !== -1) { this.currentModal = this.initComponent(this.modals[id]); this.rootContainer.append(render(this.currentModal)); setTimeout(() => this.currentModal?.open(), BASE_DELAY); } } }; // src/hooks/useHtml.ts var useHtml = (template, vars = {}) => { const htmlContainer = document.createElement("template"); htmlContainer.innerHTML = Object.keys(vars).reduce( (acc, v) => acc.replace(new RegExp(`{{( ?| +)${v}( ?| +)}}`, "gi"), vars[v].toString()), template ); return htmlContainer.content.firstChild; }; // src/entities/component.ts var Component = class { template = "<div></div>"; node = document.createElement("div"); vars() { return {}; } /** * Method for compile component from template * * @protected */ compile() { this.node = useHtml(this.template, this.vars()); } /** * Prebuilt method for init component (subscribe subjects, declare children, etc.) * * @protected */ onInit() { } /** * Prebuilt method for binding * * @protected */ bindElements() { } /** * Prebuilt method for add dynamic content to element * * @protected */ inject() { } /** * Prebuilt method for handle component events * * @protected */ handleEvents() { } /** * Prebuilt method for render component */ render() { this.compile(); this.onInit(); this.bindElements(); this.inject(); this.handleEvents(); return this.node; } }; // src/entities/page.ts var Page = class extends Component { /** * Page constructor * * @param router app router * @param context app context * @protected */ constructor(router, context) { super(); this.router = router; this.context = context; } activeClass = "active"; prevClass = "anim-prev"; nextClass = "anim-next"; /** * Prebuilt method for open this page */ open() { const { node, activeClass, prevClass } = this; node.classList.add(activeClass, prevClass); node.addEventListener("animationend", () => { node.classList.remove(prevClass); }); } /** * Prebuilt method for close this page */ close() { const { node, nextClass } = this; node.classList.add(nextClass); node.addEventListener("animationend", () => { this.onDestroy(); node.remove(); }); } /** * Prebuilt method for handle destroy event */ onDestroy() { } }; // src/entities/modal.ts var Modal = class extends Page { /** * Prebuilt method for open this modal */ open() { this.node.classList.add(this.activeClass); } /** * Prebuilt method for close this modal */ close() { this.node.classList.remove(this.activeClass); setTimeout(() => this.node.remove(), BASE_DELAY); } }; // src/entities/store.ts var Store = class { /** * Base store class constructor */ constructor() { this.onInit(); } /** * Prebuilt method for handle init event * * @protected */ onInit() { } }; // src/entities/stream.ts var Stream = class { /** * Base stream constructor * * @param _value stream value * @param storeKey {string | undefined} local storage key (for auto save, optional) */ constructor(_value, storeKey) { this._value = _value; this.storeKey = storeKey; this.storeKey = storeKey; this._value = this.load() || _value; } actions = []; /** * Stream value getter */ get value() { return this._value; } /** * Stream value setter * * @param val new value */ set value(val) { this._value = val; this.actions.forEach((action) => action(this._value)); if (this.storeKey) { localStorage.setItem(this.storeKey, JSON.stringify(this._value)); } } /** * Method for subscribe observer * * @param action action, which will triggered after change value */ subscribe(action) { this.actions.push(action); } /** * Method for unsubscribe subscribed action * * @param action action */ unsubscribe(action) { this.actions = this.actions.filter((act) => act !== action); } /** * Method for load saved in ls stream value * * @protected */ load() { return this.storeKey && localStorage.getItem(this.storeKey) ? JSON.parse(localStorage.getItem(this.storeKey)) : null; } }; // src/hooks/useBackground.ts var useBackground = (el, src) => { const img = new Image(); const element = el; img.src = src; img.onload = () => { element.style.backgroundImage = `url("${src}")`; }; }; // src/hooks/useVars.ts var useVars = (vars = {}) => { Object.keys(vars).forEach((key) => { document.documentElement.style.setProperty(key, vars[key]); }); }; export { Application, Component, Modal, Page, Router, Store, Stream, bootstrap, component, log, render, useBackground, useHtml, useVars };