@yamato-daiwa/universal-reactive 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,19 @@
1
1
  import type GeneralizedView from "./GeneralizedView";
2
+ import type EventHandlersDataMap from "./Types/EventHandlersDataMap";
3
+ import type { ArbitraryObject } from "@yamato-daiwa/es-extensions";
2
4
  export default abstract class Component {
3
5
  /** @description Initialized by `View` decorator. */
4
- readonly $$mount: (mountingPoint: Element) => void;
6
+ readonly $mount: (mountingPoint: Element) => void;
5
7
  /** @description Initialized by `View` decorator. */
6
- protected readonly $$DOM: ReadonlyArray<Element>;
8
+ protected readonly $DOM: ReadonlyArray<Element>;
7
9
  /** @description Initialized by `View` decorator. */
8
- protected readonly $$view: GeneralizedView;
10
+ protected readonly $view: GeneralizedView;
11
+ /** @description Initialized by `ReactiveState` or `View` decorators. */
12
+ protected readonly $reactiveState: ArbitraryObject;
13
+ /** @description Initialized by `ConstantState` or `View` decorators. */
14
+ protected readonly $constantState: ArbitraryObject;
15
+ /** @description Initialized and frozen by `View` decorator. */
16
+ protected readonly $isReactivityEnabled: false;
17
+ /** @description Initialized by `EventHandler` or `View` decorators. */
18
+ protected readonly $eventsHandlers: EventHandlersDataMap;
9
19
  }
@@ -0,0 +1,5 @@
1
+ declare enum EventPropagationTypes {
2
+ bubbling = "BUBBLING",
3
+ capturing = "CAPTURING"
4
+ }
5
+ export default EventPropagationTypes;
@@ -0,0 +1,2 @@
1
+ declare const ConstantState: PropertyDecorator;
2
+ export default ConstantState;
@@ -0,0 +1,14 @@
1
+ import type EventPropagationTypes from "../Constants/EventPropagationTypes";
2
+ /**
3
+ * @description
4
+ * Been executed BEFORE `View` decorator, thus the methods (and fields) of `Component` class are not defined yet.
5
+ */
6
+ declare const EventHandler: (options?: EventHandler.Options) => MethodDecorator;
7
+ declare namespace EventHandler {
8
+ type Options = Readonly<{
9
+ eventPropagation?: EventPropagationTypes | false;
10
+ mustBeCalledOnce?: boolean;
11
+ mustKeepDefaultBehaviour?: boolean;
12
+ }>;
13
+ }
14
+ export default EventHandler;
@@ -0,0 +1,2 @@
1
+ declare const ReactiveState: PropertyDecorator;
2
+ export default ReactiveState;
@@ -1,3 +1,8 @@
1
1
  import type GeneralizedView from "../GeneralizedView";
2
+ /**
3
+ * @description
4
+ * If class component uses "ReactiveState" decorator, "View" decorator will be called AFTER "ReactiveState" thus to
5
+ * access the reactive state, the patching of the constructor is required.
6
+ */
2
7
  declare const View: (generalizedView: GeneralizedView) => ClassDecorator;
3
8
  export default View;
@@ -1,6 +1,17 @@
1
+ import type EventHandlersDataMap from "./Types/EventHandlersDataMap";
2
+ import type { ArbitraryObject } from "@yamato-daiwa/es-extensions";
1
3
  type GeneralizedView = {
2
4
  onStateFieldsChangedHandlers: Map<string, Set<(currentValue: unknown) => unknown>>;
3
5
  methodsReferences: Map<string, (handler: () => unknown) => unknown>;
4
- generateInitialDOM: () => Array<Element>;
6
+ generateInitialDOM: (parameter: GeneralizedView.InitialDOM_Generating.Parameter) => Array<Element>;
5
7
  };
8
+ declare namespace GeneralizedView {
9
+ namespace InitialDOM_Generating {
10
+ type Parameter = Readonly<{
11
+ $reactiveState: ArbitraryObject;
12
+ $constantState: ArbitraryObject;
13
+ $eventsHandlers: EventHandlersDataMap;
14
+ }>;
15
+ }
16
+ }
6
17
  export default GeneralizedView;
@@ -0,0 +1,10 @@
1
+ import type EventHandler from "../Decorators/EventHandler";
2
+ type EventHandlersDataMap = Map<EventHandlersDataMap.MethodName, EventHandlersDataMap.Payload>;
3
+ declare namespace EventHandlersDataMap {
4
+ type MethodName = string;
5
+ type Payload = {
6
+ handler: (event: Event) => unknown;
7
+ options: EventHandler.Options;
8
+ };
9
+ }
10
+ export default EventHandlersDataMap;
@@ -1,5 +1,8 @@
1
1
  export type { default as GeneralizedView } from "./GeneralizedView";
2
2
  export { default as Component } from "./Component";
3
- export { default as initializeFrontendApplication } from "./Tools/initializeFrontendApplication";
4
- export { default as StateField } from "./Decorators/StateField";
3
+ export type { default as EventPropagationTypes } from "./Constants/EventPropagationTypes";
4
+ export { default as ConstantState } from "./Decorators/ConstantState";
5
+ export { default as EventHandler } from "./Decorators/EventHandler";
6
+ export { default as ReactiveState } from "./Decorators/ReactiveState";
5
7
  export { default as View } from "./Decorators/View";
8
+ export { default as initializeFrontendApplication } from "./Tools/initializeFrontendApplication";
@@ -1 +1 @@
1
- class e{}function t(e){return void 0===e}function n(e){return"string"==typeof e}function r(e){return"string"==typeof e&&e.length>0}function o(e,{mustConsiderNaN_AsNumber:t}){return"number"==typeof e&&(!isNaN(e)||t)}function i(e){return"bigint"==typeof e}function a(e){return"boolean"==typeof e}function c(e){return void 0!==e}function s(e){return null===e}function l(e){return null!==e}class u{static DOUBLE_SPACE=" ";#e=0;get currentIndentationMultiplier(){return this.#e}incrementIndent(){this.#e++}decrementIndent(){this.#e--}insertIndent(){return u.DOUBLE_SPACE.repeat(this.#e)}incrementIndentAndInsert(){return this.incrementIndent(),this.insertIndent()}decrementIndentAndInsert(){return this.decrementIndent(),this.insertIndent()}insertIncrementedIndentWithoutUpdatingOfIndentationMultiplier(){return u.DOUBLE_SPACE.repeat(this.#e+1)}addCurrentIndentationToEachLineOf(e){return function(e){return e.split("\n")}(e).map(e=>`${this.insertIndent()}${e}`).join("\n")}}function m(e){const t=Array.from(e);return t.pop(),t.join("")}class d{static stringifyAndFormat(e,t){switch(typeof e){case"string":return`"${e}"`;case"symbol":case"number":return e.toString();case"bigint":return`${e.toString()}n`;case"boolean":return`${e}`;case"undefined":return"undefined";case"function":return["String","Number","BigInt","Boolean","Array"].includes(e.name)?`[${e.name}]`:e.toString();case"object":return e instanceof Error||e instanceof RegExp?e.toString():null===e?"null":e instanceof Array?d.stringifyAsArray(e,t):e instanceof Set?d.stringifyAndFormatSet(e,t):e instanceof Map?d.stringifyAndFormatMap(e,t):e instanceof Date?e.toISOString():d.stringifyAsPlainObject(e,t)}}static stringifyAsArray(e,t=new u){let n="[";t.incrementIndent();for(const r of e)n=n+`\n${t.insertIndent()}`+`${d.stringifyAndFormat(r,t)},`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAndFormatSet(e,t=new u){let n=`Set(${e.size}) [`;t.incrementIndent();for(const r of e)n=n+`\n${t.insertIndent()}`+`${d.stringifyAndFormat(r,t)},`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAndFormatMap(e,t=new u){let n=`Map(${e.size}) [`;t.incrementIndent();for(const[r,o]of e.entries())n=n+`\n${t.insertIndent()}[\n`+t.incrementIndentAndInsert()+`${d.stringifyAndFormat(r,t)},\n`+t.insertIndent()+`${d.stringifyAndFormat(o,t)}\n`+`${t.decrementIndentAndInsert()}],`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAsPlainObject(e,t=new u){let n="{";t.incrementIndent();for(const[r,o]of Object.entries(e))n=n+`\n${t.insertIndent()}`+`${r}: ${d.stringifyAndFormat(o,t)},`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}}`}}function g(e){return d.stringifyAndFormat(e)}const p={badgesDefaultTitles:{error:"Error",warning:"Warning",success:"Success",info:"Info",debug:"Debug",generic:"Common"},errorType:"Error type",occurrenceLocation:"Occurrence location",caughtError:"Caught error",innerError:"Inner error",appendedData:"Appended data"};class f{static implementation=null;static localization=p;static setImplementation(e){return f.implementation=e,f}static setLocalization(e){return f.localization=e,f}static throwErrorWithFormattedMessage(e,t={}){if(c(f.implementation?.throwErrorWithFormattedMessage))return f.implementation.throwErrorWithFormattedMessage(e,t);let n;c(e.innerError)&&(n=g(e.innerError),e.innerError instanceof Error&&r(e.innerError.stack)&&(n=e.innerError.stack.includes(n)?e.innerError.stack:`${n}\n${e.innerError.stack}`));const o=f.generateFormattedErrorFromThrownErrorLog(e,n);if("errorInstance"in e)throw e.errorInstance.message=o,e.errorInstance;const i=new Error(o);throw i.name=e.errorType,!0===t.mustLogErrorBeforeThrowing&&f.logErrorLikeMessage({title:i.name,description:i.message}),i}static logError(e){l(f.implementation)?f.implementation.logError(e):n(e)?console.error(e):!1!==e.mustOutputIf&&console.error(f.formatErrorLog(e))}static logErrorLikeMessage(e){l(f.implementation)?f.implementation.logErrorLikeMessage(e):n(e)?console.error(e):!1!==e.mustOutputIf&&console.error(f.formatGenericLog(e,f.localization.badgesDefaultTitles.error))}static logWarning(e){l(f.implementation)?f.implementation.logWarning(e):n(e)?console.warn(e):!1!==e.mustOutputIf&&console.warn(f.formatGenericLog(e,f.localization.badgesDefaultTitles.warning))}static logInfo(e){l(f.implementation)?f.implementation.logInfo(e):n(e)?console.info(e):!1!==e.mustOutputIf&&console.info(f.formatGenericLog(e,f.localization.badgesDefaultTitles.info))}static logSuccess(e){l(f.implementation)?f.implementation.logSuccess(e):n(e)?console.info(e):!1!==e.mustOutputIf&&console.info(f.formatGenericLog(e,f.localization.badgesDefaultTitles.success))}static logDebug(e){l(f.implementation)?f.implementation.logDebug(e):n(e)||o(e,{mustConsiderNaN_AsNumber:!0})||i(e)||a(e)||s(e)||t(e)?console.debug(e):!1!==e.mustOutputIf&&console.debug(f.formatGenericLog(e,f.localization.badgesDefaultTitles.debug))}static logGeneric(e){l(f.implementation)?f.implementation.logGeneric(e):n(e)||o(e,{mustConsiderNaN_AsNumber:!0})||i(e)||a(e)||s(e)||t(e)?console.log(e):!1!==e.mustOutputIf&&console.log(f.formatGenericLog(e,f.localization.badgesDefaultTitles.generic))}static logPromiseError(e){l(f.implementation)&&c(f.implementation.logPromiseError)?f.implementation.logPromiseError(e):console.error(e)}static highlightText(e){return l(f.implementation)?f.implementation.highlightText(e):e}static generateFormattedErrorFromThrownErrorLog(e,t){return[e.title,...!0===e.compactLayout?[" "]:["\n"],..."errorInstance"in e?[e.errorInstance.message]:[e.description],`\n\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`,...c(t)?[`\n\n${f.localization.innerError}:\n${t}`]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[],"\n"].join("")}static formatErrorLog(e){return[...f.generateBadgeIfMust(e.badge,f.localization.badgesDefaultTitles.error),e.title,...!0===e.compactLayout?[" "]:["\n"],e.description,`\n\n${f.localization.errorType}: ${e.errorType}`,`\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`,...c(e.caughtError)?[`\n\n${f.localization.caughtError}:\n${g(e.caughtError)}`+(e.caughtError instanceof Error&&r(e.caughtError.stack)?`\n${e.caughtError.toString()}\n${e.caughtError.stack}`:"")]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[]].join("")}static formatGenericLog(e,t){return[...f.generateBadgeIfMust(e.badge,t),e.title,...!0===e.compactLayout?[" "]:["\n"],e.description,..."occurrenceLocation"in e?[`\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[]].join("")}static generateBadgeIfMust(e,t){return!1===e?[]:[`[ ${e?.customText??t} ] `]}}const E=f,h={defaultTitle:"DOM Element not Found",generateDescription:({selector:e})=>`The DOM element with selector: ${e} not found.`};class I extends Error{static NAME="DOM_ElementRetrievingFailedError";static localization=h;constructor(e){super(),this.name=I.NAME,this.message="customMessage"in e?e.customMessage:I.localization.generateDescription(e)}}const $=I,y={defaultTitle:"Unexpected Event Occurred"};class b extends Error{static NAME="UnexpectedEventError";static localization=y;constructor(e){super(),this.name=b.NAME,this.message=e}}const M=b;function D({mountingPointSelector:e,rootComponent:n}){(new n).$$mount(function(e){let n;if(t(e.contextElement))n=document;else if("selector"in e.contextElement){const t=document.querySelectorAll(e.contextElement.selector);0===t.length?E.throwErrorWithFormattedMessage({errorInstance:new $({customMessage:`The context element has not been found by the selector "${e.contextElement.selector}".`}),title:$.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}):t.length>1&&E.logError({errorType:M.NAME,title:M.localization.defaultTitle,description:`Multiple elements are corresponding to context element selector "${e.contextElement.selector}" while the context element must be single.`,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),n=t[0]}else n=e.contextElement;const r=e.selector,o=n.querySelectorAll(r);0===o.length&&E.throwErrorWithFormattedMessage({errorInstance:new $({selector:r}),title:$.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),o.length>1&&E.logError({errorType:M.NAME,title:M.localization.defaultTitle,description:`Contrary to expectations, ${o.length} elements has been found for the selector "${r}". First one will be picked.`,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"});const i=o[0];return t(e.expectedDOM_ElementSubtype)||i instanceof e.expectedDOM_ElementSubtype||E.throwErrorWithFormattedMessage({errorInstance:new M(`Contrary to expectations, the picked element in not instance of "${e.expectedDOM_ElementSubtype.name}".`),title:M.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),i}({selector:e,contextElement:document}))}const A=(e,n)=>{let r=e[n];Object.defineProperty(e,n,{get:()=>r,set(e){if(e!==r||"object"==typeof e||"function"==typeof e||"object"==typeof r||"function"==typeof r){r=e;for(const e of function(e,n){const r=e.get(n);return t(r)&&E.throwErrorWithFormattedMessage({errorInstance:new M(`Contrary to expectations, there is no pair with key "${String(n)}" in target map.`),title:M.localization.defaultTitle,occurrenceLocation:"getExpectedToBeExistingMapValue(targetMap, targetKey)"}),r}(this.$$view.onStateFieldsChangedHandlers,n))e(r)}},enumerable:!0,configurable:!0})},w=e=>t=>{const n=t;Object.defineProperty(n.prototype,"$$view",{value:e,writable:!1,configurable:!1,enumerable:!1});const r=e.generateInitialDOM();Object.defineProperty(n.prototype,"$$DOM",{value:r,writable:!1,configurable:!1,enumerable:!1}),Object.defineProperty(n.prototype,"$$mount",{value(e){e.replaceWith(...r)},writable:!1,configurable:!1,enumerable:!1});for(const[t,r]of e.methodsReferences.entries())r(n.prototype[t].bind(n.prototype));return t};export{e as Component,A as StateField,w as View,D as initializeFrontendApplication};
1
+ class e{}function t(e){return"string"==typeof e}function n(e){return"string"==typeof e&&e.length>0}function r(e,{mustConsiderNaN_AsNumber:t}){return"number"==typeof e&&(!isNaN(e)||t)}function o(e){return"bigint"==typeof e}function i(e){return"boolean"==typeof e}function a(e){return void 0===e}function c(e){return void 0!==e}function s(e){return null===e}function l(e){return null!==e}class u{static DOUBLE_SPACE=" ";#e=0;get currentIndentationMultiplier(){return this.#e}incrementIndent(){this.#e++}decrementIndent(){this.#e--}insertIndent(){return u.DOUBLE_SPACE.repeat(this.#e)}incrementIndentAndInsert(){return this.incrementIndent(),this.insertIndent()}decrementIndentAndInsert(){return this.decrementIndent(),this.insertIndent()}insertIncrementedIndentWithoutUpdatingOfIndentationMultiplier(){return u.DOUBLE_SPACE.repeat(this.#e+1)}addCurrentIndentationToEachLineOf(e){return function(e){return e.split("\n")}(e).map(e=>`${this.insertIndent()}${e}`).join("\n")}}function d(e){const t=Array.from(e);return t.pop(),t.join("")}class m{static stringifyAndFormat(e,t){switch(typeof e){case"string":return`"${e}"`;case"symbol":case"number":return e.toString();case"bigint":return`${e.toString()}n`;case"boolean":return`${e}`;case"undefined":return"undefined";case"function":return["String","Number","BigInt","Boolean","Array"].includes(e.name)?`[${e.name}]`:e.toString();case"object":return e instanceof Error||e instanceof RegExp?e.toString():null===e?"null":e instanceof Array?m.stringifyAsArray(e,t):e instanceof Set?m.stringifyAndFormatSet(e,t):e instanceof Map?m.stringifyAndFormatMap(e,t):e instanceof Date?e.toISOString():m.stringifyAsPlainObject(e,t)}}static stringifyAsArray(e,t=new u){if(0===e.length)return"[]";let n="[";t.incrementIndent();for(const r of e)n=n+`\n${t.insertIndent()}`+`${m.stringifyAndFormat(r,t)},`;return n=d(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAndFormatSet(e,t=new u){if(0===e.size)return"Set(0) []";let n=`Set(${e.size}) [`;t.incrementIndent();for(const r of e)n=n+`\n${t.insertIndent()}`+`${m.stringifyAndFormat(r,t)},`;return n=d(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAndFormatMap(e,t=new u){if(0===e.size)return"Map(0) []";let n=`Map(${e.size}) [`;t.incrementIndent();for(const[r,o]of e.entries())n=n+`\n${t.insertIndent()}[\n`+t.incrementIndentAndInsert()+`${m.stringifyAndFormat(r,t)},\n`+t.insertIndent()+`${m.stringifyAndFormat(o,t)}\n`+`${t.decrementIndentAndInsert()}],`;return n=d(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAsPlainObject(e,t=new u){const n=Object.entries(e);if(0===n.length)return"{}";let r="{";t.incrementIndent();for(const[e,o]of n)r=r+`\n${t.insertIndent()}`+`${e}: ${m.stringifyAndFormat(o,t)},`;return r=d(r),t.decrementIndent(),`${r}\n${t.insertIndent()}}`}}function g(e){return m.stringifyAndFormat(e)}const p={badgesDefaultTitles:{error:"Error",warning:"Warning",success:"Success",info:"Info",debug:"Debug",generic:"Common"},errorType:"Error type",occurrenceLocation:"Occurrence location",caughtError:"Caught error",innerError:"Inner error",appendedData:"Appended data"};class f{static implementation=null;static localization=p;static setImplementation(e){return f.implementation=e,f}static setLocalization(e){return f.localization=e,f}static throwErrorWithFormattedMessage(e,t={}){if(c(f.implementation?.throwErrorWithFormattedMessage))return f.implementation.throwErrorWithFormattedMessage(e,t);let r;c(e.innerError)&&(r=g(e.innerError),e.innerError instanceof Error&&n(e.innerError.stack)&&(r=e.innerError.stack.includes(r)?e.innerError.stack:`${r}\n${e.innerError.stack}`));const o=f.generateFormattedErrorFromThrownErrorLog(e,r);if("errorInstance"in e)throw e.errorInstance.message=o,e.errorInstance;const i=new Error(o);throw i.name=e.errorType,!0===t.mustLogErrorBeforeThrowing&&f.logErrorLikeMessage({title:i.name,description:i.message}),i}static logError(e){l(f.implementation)?f.implementation.logError(e):t(e)?console.error(e):!1!==e.mustOutputIf&&console.error(f.formatErrorLog(e))}static logErrorLikeMessage(e){l(f.implementation)?f.implementation.logErrorLikeMessage(e):t(e)?console.error(e):!1!==e.mustOutputIf&&console.error(f.formatGenericLog(e,f.localization.badgesDefaultTitles.error))}static logWarning(e){l(f.implementation)?f.implementation.logWarning(e):t(e)?console.warn(e):!1!==e.mustOutputIf&&console.warn(f.formatGenericLog(e,f.localization.badgesDefaultTitles.warning))}static logInfo(e){l(f.implementation)?f.implementation.logInfo(e):t(e)?console.info(e):!1!==e.mustOutputIf&&console.info(f.formatGenericLog(e,f.localization.badgesDefaultTitles.info))}static logSuccess(e){l(f.implementation)?f.implementation.logSuccess(e):t(e)?console.info(e):!1!==e.mustOutputIf&&console.info(f.formatGenericLog(e,f.localization.badgesDefaultTitles.success))}static logDebug(e){l(f.implementation)?f.implementation.logDebug(e):t(e)||r(e,{mustConsiderNaN_AsNumber:!0})||o(e)||i(e)||s(e)||a(e)?console.debug(e):!1!==e.mustOutputIf&&console.debug(f.formatGenericLog(e,f.localization.badgesDefaultTitles.debug))}static logGeneric(e){l(f.implementation)?f.implementation.logGeneric(e):t(e)||r(e,{mustConsiderNaN_AsNumber:!0})||o(e)||i(e)||s(e)||a(e)?console.log(e):!1!==e.mustOutputIf&&console.log(f.formatGenericLog(e,f.localization.badgesDefaultTitles.generic))}static logPromiseError(e){l(f.implementation)&&c(f.implementation.logPromiseError)?f.implementation.logPromiseError(e):console.error(e)}static highlightText(e){return l(f.implementation)?f.implementation.highlightText(e):e}static generateFormattedErrorFromThrownErrorLog(e,t){return[e.title,...!0===e.compactLayout?[" "]:["\n"],..."errorInstance"in e?[e.errorInstance.message]:[e.description],`\n\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`,...c(t)?[`\n\n${f.localization.innerError}:\n${t}`]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[],"\n"].join("")}static formatErrorLog(e){return[...f.generateBadgeIfMust(e.badge,f.localization.badgesDefaultTitles.error),e.title,...!0===e.compactLayout?[" "]:["\n"],e.description,`\n\n${f.localization.errorType}: ${e.errorType}`,`\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`,...c(e.caughtError)?[`\n\n${f.localization.caughtError}:\n${g(e.caughtError)}`+(e.caughtError instanceof Error&&n(e.caughtError.stack)?`\n${e.caughtError.toString()}\n${e.caughtError.stack}`:"")]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[]].join("")}static formatGenericLog(e,t){return[...f.generateBadgeIfMust(e.badge,t),e.title,...!0===e.compactLayout?[" "]:["\n"],e.description,..."occurrenceLocation"in e?[`\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[]].join("")}static generateBadgeIfMust(e,t){return!1===e?[]:[`[ ${e?.customText??t} ] `]}}const h=f,E={defaultTitle:"Improper Usage"};class b extends Error{static NAME="ImproperUsageError";static localization=E;constructor(e){super(),this.name=b.NAME,this.message=e}}const $=b,y=(t,n)=>{t instanceof e||h.throwErrorWithFormattedMessage({errorInstance:new $("The `StateField` decorator can be used only for YDUR component classes."),title:$.localization.defaultTitle,occurrenceLocation:"StateField(componentClassPrototype, propertyKey)"}),a(Reflect.get(t,"$constantState"))&&Object.defineProperty(t,"$constantState",{value:{},enumerable:!1,configurable:!1,writable:!1}),Object.defineProperty(t,n,{get(){return this.$constantState[n]},set(e){Object.defineProperty(this.$constantState,n,{configurable:!1,writable:!1,value:e})},enumerable:!1,configurable:!1})},I=(t={})=>(n,r,o)=>{n instanceof e||h.throwErrorWithFormattedMessage({errorInstance:new $("The `EventHandler` decorator can be used only for YDUR component classes."),title:$.localization.defaultTitle,occurrenceLocation:"EventHandler.MethodDecorator(componentClassPrototype, methodKey, descriptor)"});const i=Reflect.get(n,"$eventsHandlers");let a;i instanceof Map?a=i:(a=new Map,Object.defineProperty(n,"$eventsHandlers",{value:a,enumerable:!1,configurable:!1,writable:!1})),a.set(String(r),{handler:o.value.bind(n),options:t})},M={defaultTitle:"Unexpected Event Occurred"};class S extends Error{static NAME="UnexpectedEventError";static localization=M;constructor(e){super(),this.name=S.NAME,this.message=e}}const w=S,D=(t,n)=>{t instanceof e||h.throwErrorWithFormattedMessage({errorInstance:new $("The `StateField` decorator can be used only for YDUR component classes."),title:$.localization.defaultTitle,occurrenceLocation:"StateField(componentClassPrototype, propertyKey)"}),a(Reflect.get(t,"$reactiveState"))&&Object.defineProperty(t,"$reactiveState",{value:{},enumerable:!1,configurable:!1,writable:!1}),Object.defineProperty(t,n,{get(){return this.$reactiveState[n]},set(e){const t=this.$reactiveState[n];if((e!==t||"object"==typeof e||"function"==typeof e||"object"==typeof t||"function"==typeof t)&&(this.$reactiveState[n]=e,this.$isReactivityEnabled))for(const e of function(e,t){const n=e.get(t);return a(n)&&h.throwErrorWithFormattedMessage({errorInstance:new w(`Contrary to expectations, there is no pair with key "${String(t)}" in target map.`),title:w.localization.defaultTitle,occurrenceLocation:"getExpectedToBeExistingMapValue(targetMap, targetKey)"}),n}(this.$view.onStateFieldsChangedHandlers,n))e(this.$reactiveState[n])},enumerable:!0,configurable:!0})},O=e=>t=>{const n=t;Object.defineProperty(n.prototype,"$view",{value:e,writable:!1,configurable:!1,enumerable:!1});const r=n;return class extends r{constructor(){super(),a(this.$reactiveState)&&Object.defineProperty(this,"$reactiveState",{value:{},enumerable:!1,configurable:!1,writable:!1}),a(this.$constantState)&&Object.defineProperty(this,"$constantState",{value:{},enumerable:!1,configurable:!1,writable:!1}),a(this.$eventsHandlers)&&Object.defineProperty(this,"$eventsHandlers",{value:new Map,enumerable:!1,configurable:!1,writable:!1}),Object.defineProperty(n.prototype,"$DOM",{value:e.generateInitialDOM({$reactiveState:this.$reactiveState,$constantState:this.$constantState,$eventsHandlers:this.$eventsHandlers}),writable:!1,configurable:!1,enumerable:!1}),Object.defineProperty(n.prototype,"$mount",{value:e=>{e.replaceWith(...this.$DOM)},writable:!1,configurable:!1,enumerable:!1}),Object.defineProperty(n.prototype,"$isReactivityEnabled",{value:!0,configurable:!1,enumerable:!1,writable:!1})}}},T={defaultTitle:"DOM Element not Found",generateDescription:({selector:e})=>`The DOM element with selector: ${e} not found.`};class v extends Error{static NAME="DOM_ElementRetrievingFailedError";static localization=T;constructor(e){super(),this.name=v.NAME,this.message="customMessage"in e?e.customMessage:v.localization.generateDescription(e)}}const A=v;function L({mountingPointSelector:e,rootComponent:t}){(new t).$mount(function(e){let t;if(a(e.contextElement))t=document;else if("selector"in e.contextElement){const n=document.querySelectorAll(e.contextElement.selector);0===n.length?h.throwErrorWithFormattedMessage({errorInstance:new A({customMessage:`The context element has not been found by the selector "${e.contextElement.selector}".`}),title:A.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}):n.length>1&&h.logError({errorType:w.NAME,title:w.localization.defaultTitle,description:`Multiple elements are corresponding to context element selector "${e.contextElement.selector}" while the context element must be single.`,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),t=n[0]}else t=e.contextElement;const n=e.selector,r=t.querySelectorAll(n);0===r.length&&h.throwErrorWithFormattedMessage({errorInstance:new A({selector:n}),title:A.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),r.length>1&&h.logError({errorType:w.NAME,title:w.localization.defaultTitle,description:`Contrary to expectations, ${r.length} elements has been found for the selector "${n}". First one will be picked.`,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"});const o=r[0];return a(e.expectedDOM_ElementSubtype)||o instanceof e.expectedDOM_ElementSubtype||h.throwErrorWithFormattedMessage({errorInstance:new w(`Contrary to expectations, the picked element in not instance of "${e.expectedDOM_ElementSubtype.name}".`),title:w.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),o}({selector:e,contextElement:document}))}export{e as Component,y as ConstantState,I as EventHandler,D as ReactiveState,O as View,L as initializeFrontendApplication};
package/README.md CHANGED
@@ -2,10 +2,13 @@
2
2
 
3
3
  <figure align="center">
4
4
  <img
5
- src="https://github.com/user-attachments/assets/c129e15c-4969-4178-8213-c0acfd2b7b47"
6
- alt="The decrative image shows that the library is in development."
5
+ src="https://imgur.com/a/NMyzesK"
6
+ alt="The decorative image shows that the library is in development."
7
7
  >
8
- <figcaption style="text-align: center;">The library is in development. See the "Roadmap" section for progress.</figcaption>
8
+ <figcaption style="text-align: center;">
9
+ The library is in development.
10
+ See the <a href="#planned">Features/Planned</a> section to get information about progress.
11
+ </figcaption>
9
12
  </figure>
10
13
 
11
14
 
@@ -14,15 +17,18 @@
14
17
  The object-oriented programming-based library for the frontend Web+ development alternative to React, Vue, Svelte and
15
18
  the like.
16
19
 
17
- No plans to position is as a framework because it is intended to be the tool taking care of typical frontend development
18
- tasks without stealing too much attention and forcing of specific architecture, naming and directories structure.
20
+ No plans to position it as a framework because it is intended to be the just the _tool_ taking care of typical frontend
21
+ development tasks without stealing too much attention and forcing of specific architecture, naming and directories
22
+ structure.
19
23
 
20
24
 
21
- ## Features (May be Pros of Cons Depending on Your Preferences)
25
+ ## Features
26
+
27
+ The following feature may be pros of cons depending on your preferences.
22
28
 
23
29
  + Class-based components. No functional API planned.
24
- + [Pug](https://pugjs.org/api/getting-started.html) is the only language for templates. No plaing HTML support planned.
25
- + No new file names extension like `.vue` or `.jsx`.
30
+ + [Pug](https://pugjs.org/api/getting-started.html) is the only language for templates. No plain HTML support planned.
31
+ + No new file names extensions like `.vue` or `.jsx`.
26
32
  + No new syntaxes like Vue single file components or JSX. Just plain Pug and TypeScript.
27
33
  + Project building tool like Webpack is required.
28
34
 
@@ -45,22 +51,22 @@ The sequence may be changed during the development.
45
51
  ##### "Counter.ydfr.pug" — The Component Template
46
52
 
47
53
  ```pug
48
- samp= $currentValue
54
+ samp= $reactiveState.currentValue
49
55
 
50
56
  .Counter-ActionBar
51
57
 
52
58
  button(
53
59
  type="button"
54
- @click=onClickIncrementingButton
60
+ @onLeftClick=onClickIncrementingButton
55
61
  ) Increment
56
62
 
57
63
  button(
58
64
  type="button"
59
- @click=onClickDecrementingButton
65
+ @onLeftClick=onClickDecrementingButton
60
66
  ) Decrement
61
67
  ```
62
68
 
63
- The YDUR components templates is been defined by [Pug](https://github.com/pugjs/pug), the template language.
69
+ The YDUR components templates are been defined by [Pug](https://github.com/pugjs/pug), the template language.
64
70
  No plans to support HTML.
65
71
 
66
72
 
@@ -74,15 +80,17 @@ import componentTemplate from "./Counter.ydur.pug";
74
80
  @YDFR.View(componentTemplate)
75
81
  export default class Counter extends YDFR.Component {
76
82
 
77
- @YDFR.StateField
78
- public $currentValue: number = 0;
83
+ @YDFR.ReactiveState
84
+ protected currentValue: number = 0;
79
85
 
80
- public onClickIncrementingButton(): void {
81
- this.$currentValue++;
86
+ @YDFR.EventHandler()
87
+ protected onClickIncrementingButton(): void {
88
+ this.currentValue++;
82
89
  }
83
90
 
84
- public onClickDecrementingButton(): void {
85
- this.$currentValue--;
91
+ @YDFR.EventHandler()
92
+ protected onClickDecrementingButton(): void {
93
+ this.currentValue--;
86
94
  }
87
95
 
88
96
  }
@@ -91,12 +99,21 @@ export default class Counter extends YDFR.Component {
91
99
  + The component logic is the plain TypeScript class with decorators.
92
100
  Besides its main role, you can use it as the plain TypeScript classes, for example, define
93
101
  the public static members and call them from outside (when it makes sense).
94
- * To import `componentTemplate` from Pug file correctly, you need the appropriate plugin for you project building
102
+ + To import `componentTemplate` from Pug file correctly, you need the appropriate plugin for you project building
95
103
  system.
96
104
  Currently, the [Webpack loader](https://www.npmjs.com/package/@yamato-daiwa/universal-reactive-webpack-loader) is available.
97
- The value of `componentTemplate` is not the string with HTML code — the YDUR templates compiler builds the JavaScript
105
+ The value of `componentTemplate` is _not_ the string with HTML code — the YDUR templates compiler builds the JavaScript
98
106
  object called "View" based on Pug code.
99
107
  Such an approach is Svelte-like, one advantage of it is better performance than DOM diffing as in React.
108
+ + The `currentValue` field has been declared with `@YDFR.ReactiveState` decorator.
109
+ It means the changing of this field will update the DOM depends on it.
110
+ `currentValue` is accessible from template as `$reativeState.currentValue`.
111
+ Contrary to `$reativeState` state, there is the `$constantState` one.
112
+ + The methods are accessible from the template by names as event handlers, but must be decorated by
113
+ `@YDFR.EventHandler()` decoratory. Unlike `@YDFR.ReactiveState`, it requires `()` becaue optionally the event hanling
114
+ options may be passed.
115
+ + You can make all instance members private in this example, but the **TypeScript** and/all linting tool may complain
116
+ about these fields have not been explicitly used.
100
117
 
101
118
 
102
119
  ##### index.ts — The Entry Point
@@ -113,4 +130,169 @@ YDFR.initializeFrontendApplication({
113
130
  ```
114
131
 
115
132
  You need at least one component to create the application instance.
116
- Once it defined, the application may created by one function.
133
+ Once it defined, the application may be created by one function.
134
+ Of course, the HTML element with ID `APPLICATION_ROOT` must exist to initialize the application succesfully.
135
+
136
+
137
+
138
+ ### Reactive and Constant State
139
+
140
+ Some state fields are not intended to be updated during the component lifecycle.
141
+ It means no need to make them to a reactive state for performance purposes.
142
+ As default, the class fields are not accessible from template, but to declare the constant state field you can use the
143
+ `@YDFR.ConstantState` field:
144
+
145
+ ```ts
146
+ import * as YDFR from "@yamato-daiwa/universal-reactive";
147
+ import componentTemplate from "./Counter.ydur.pug";
148
+
149
+
150
+ @YDFR.View(componentTemplate)
151
+ export default class Counter extends YDFR.Component {
152
+
153
+ // Basically, should be set to `readonly` but we will try to change it for experiment.
154
+ @YDFR.ConstantState
155
+ protected heading: string = "Counter";
156
+
157
+ @YDFR.ReactiveState
158
+ public currentValue: number = 0;
159
+
160
+ @YDFR.EventHandler()
161
+ public onClickIncrementingButton(): void {
162
+
163
+ this.currentValue++;
164
+
165
+ // You will get TypeError if try to chage it. Of course, DOM dependes in this firld will not be updated.
166
+ this.heading = "NEW HEADING"
167
+
168
+ }
169
+
170
+ @YDFR.EventHandler()
171
+ public onClickDecrementingButton(): void {
172
+ this.currentValue--;
173
+ }
174
+
175
+ }
176
+ ```
177
+
178
+ You can access to `heading` in template via `$constantState` object:
179
+
180
+ ```pug
181
+ h1= $constantState.heading
182
+
183
+ samp= $reativeState.currentValue
184
+
185
+ .Counter-ActionBar
186
+
187
+ button(
188
+ type="button"
189
+ @onLeftClick=onClickIncrementingButton
190
+ ) Increment
191
+
192
+ button(
193
+ type="button"
194
+ @onLeftClick=onClickDecrementingButton
195
+ ) Decrement
196
+ ```
197
+
198
+
199
+ ### Events Handling
200
+
201
+ You can access to instance methods by name from template if they has been decorated by `@YDFR.EventHandler()`:
202
+
203
+ ```ts
204
+ @YDFR.View(componentTemplate)
205
+ export default class Counter extends YDFR.Component {
206
+
207
+ // ...
208
+
209
+ @YDFR.EventHandler()
210
+ public onClickIncrementingButton(): void {
211
+ // ...
212
+ }
213
+
214
+ @YDFR.EventHandler()
215
+ public onClickDecrementingButton(): void {
216
+ // ...
217
+ }
218
+
219
+ }
220
+ ```
221
+
222
+ Unlike `@YDFR.ReactiveState` or `@YDFR.ConstantState`, `@YDFR.EventHandler` decorator must be invoked because the optons
223
+ may be passed:
224
+
225
+ ```ts
226
+ type Options = Readonly<{
227
+
228
+ /* @default EventPropagationTypes.bubbling */
229
+ eventPropagation?: EventPropagationTypes | false;
230
+
231
+ /* @default false */
232
+ mustBeCalledOnce?: boolean;
233
+
234
+ /* @default false */
235
+ mustKeepDefaultBehaviour?: boolean;
236
+
237
+ }>;
238
+
239
+ enum EventPropagationTypes {
240
+ bubbling = "BUBBLING",
241
+ capturing = "CAPTURING"
242
+ }
243
+ ```
244
+
245
+ The names of the options has been designed such as does not need any explanations.
246
+
247
+ If you don't know about **bubbling** and **capturing**, it is a *common* terminology, not terminology of YDR.
248
+ Check [this](https://javascript.info/bubbling-and-capturing) tutorial for details.
249
+
250
+ Once decorated, the method can be referred from the template by the following attributes.
251
+
252
+ ```pug
253
+ .Counter-ActionBar
254
+
255
+ button(
256
+ type="button"
257
+ @onLeftClick=onClickIncrementingButton
258
+ ) Increment
259
+
260
+ button(
261
+ type="button"
262
+ @onLeftClick=onClickDecrementingButton
263
+ ) Decrement
264
+ ```
265
+
266
+ Currently available events name listed below.
267
+
268
+ #### Mouse Events
269
+
270
+ | YDUR Event Name | Native event name |
271
+ |--------------------|-------------------|
272
+ | @onLeftClick | click |
273
+ | @onDoubleLeftClick | dblclick |
274
+ | @onRightClick | auxclick |
275
+ | @onMouseDown | mousedown |
276
+ | @onMouseUp | mouseup |
277
+ | @onMouseMoved | mousemove |
278
+ | @onMouseOver | mouseover |
279
+ | @onMouseOut | mouseout |
280
+ | @onMouseEntered | mouseenter |
281
+ | @onMouseLeft | mouseleave |
282
+
283
+
284
+ #### Keyboard Events
285
+
286
+ | YDUR Event Name | Native event name |
287
+ |-----------------|-------------------|
288
+ | @onKeyPressed | keyup |
289
+ | @onKeyUp | keyup |
290
+ | @onKeyDown | keydown |
291
+ | @onInput | input |
292
+
293
+
294
+ #### Common Events
295
+
296
+ | YDUR Event Name | Native event name |
297
+ |-----------------|-------------------|
298
+ | @onChange | change |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yamato-daiwa/universal-reactive",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "description": "OOP-based library for frontend development.",
5
5
  "keywords": [
6
6
  "frontend"
@@ -25,14 +25,14 @@
25
25
  "module": "./Distributable/index.js",
26
26
  "types": "./Distributable/index.d.ts",
27
27
  "dependencies": {
28
- "@yamato-daiwa/es-extensions": "1.8.2",
29
- "@yamato-daiwa/es-extensions-browserjs": "1.8.2"
28
+ "@yamato-daiwa/es-extensions": "1.8.4",
29
+ "@yamato-daiwa/es-extensions-browserjs": "1.8.4"
30
30
  },
31
31
  "devDependencies": {
32
- "@yamato-daiwa/automation": "0.8.0",
32
+ "@yamato-daiwa/automation": "0.9.0-alpha.3",
33
33
  "@yamato-daiwa/frontend": "2.0.0-beta.11",
34
- "@yamato-daiwa/style_guides": "0.10.1",
35
- "rimraf": "6.0.1",
34
+ "@yamato-daiwa/style_guides": "0.11.2",
35
+ "rimraf": "6.1.2",
36
36
  "typescript": "5.9.3"
37
37
  },
38
38
  "scripts": {
@@ -1,2 +0,0 @@
1
- declare const StateField: PropertyDecorator;
2
- export default StateField;