@yauheni-shcharbakou/rxspa
Version:
419 lines (403 loc) • 9.34 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Application: () => Application,
Component: () => Component,
Modal: () => Modal,
Page: () => Page,
Router: () => Router,
Store: () => Store,
Stream: () => Stream,
bootstrap: () => bootstrap,
component: () => component,
log: () => log,
render: () => render,
useBackground: () => useBackground,
useHtml: () => useHtml,
useVars: () => useVars
});
module.exports = __toCommonJS(index_exports);
// 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]);
});
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Application,
Component,
Modal,
Page,
Router,
Store,
Stream,
bootstrap,
component,
log,
render,
useBackground,
useHtml,
useVars
});