@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.
- package/Distributable/Component.d.ts +13 -3
- package/Distributable/Constants/EventPropagationTypes.d.ts +5 -0
- package/Distributable/Decorators/ConstantState.d.ts +2 -0
- package/Distributable/Decorators/EventHandler.d.ts +14 -0
- package/Distributable/Decorators/ReactiveState.d.ts +2 -0
- package/Distributable/Decorators/View.d.ts +5 -0
- package/Distributable/GeneralizedView.d.ts +12 -1
- package/Distributable/Types/EventHandlersDataMap.d.ts +10 -0
- package/Distributable/index.d.ts +5 -2
- package/Distributable/index.js +1 -1
- package/README.md +203 -21
- package/package.json +6 -6
- package/Distributable/Decorators/StateField.d.ts +0 -2
|
@@ -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
|
|
6
|
+
readonly $mount: (mountingPoint: Element) => void;
|
|
5
7
|
/** @description Initialized by `View` decorator. */
|
|
6
|
-
protected readonly
|
|
8
|
+
protected readonly $DOM: ReadonlyArray<Element>;
|
|
7
9
|
/** @description Initialized by `View` decorator. */
|
|
8
|
-
protected readonly
|
|
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,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;
|
|
@@ -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;
|
package/Distributable/index.d.ts
CHANGED
|
@@ -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
|
|
4
|
-
export { default as
|
|
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";
|
package/Distributable/index.js
CHANGED
|
@@ -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://
|
|
6
|
-
alt="The
|
|
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;">
|
|
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
|
|
18
|
-
tasks without stealing too much attention and forcing of specific architecture, naming and directories
|
|
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
|
|
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
|
|
25
|
-
+ No new file names
|
|
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
|
-
@
|
|
60
|
+
@onLeftClick=onClickIncrementingButton
|
|
55
61
|
) Increment
|
|
56
62
|
|
|
57
63
|
button(
|
|
58
64
|
type="button"
|
|
59
|
-
@
|
|
65
|
+
@onLeftClick=onClickDecrementingButton
|
|
60
66
|
) Decrement
|
|
61
67
|
```
|
|
62
68
|
|
|
63
|
-
The YDUR components templates
|
|
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.
|
|
78
|
-
|
|
83
|
+
@YDFR.ReactiveState
|
|
84
|
+
protected currentValue: number = 0;
|
|
79
85
|
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
@YDFR.EventHandler()
|
|
87
|
+
protected onClickIncrementingButton(): void {
|
|
88
|
+
this.currentValue++;
|
|
82
89
|
}
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
29
|
-
"@yamato-daiwa/es-extensions-browserjs": "1.8.
|
|
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.
|
|
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.
|
|
35
|
-
"rimraf": "6.
|
|
34
|
+
"@yamato-daiwa/style_guides": "0.11.2",
|
|
35
|
+
"rimraf": "6.1.2",
|
|
36
36
|
"typescript": "5.9.3"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|