@yamato-daiwa/universal-reactive
v0.1.0
Published
OOP-based library for frontend development.
Readme
Yamato Daiwa Universal Reactive
What is Being Developed
The object-oriented programming-based library for the frontend Web+ development alternative to React, Vue, Svelte and the like.
No plans to position it as a framework because it is intended to be the just the tool taking care of typical frontend development tasks without stealing too much attention and forcing of specific architecture, naming and directories structure.
Features
The following feature may be pros of cons depending on your preferences.
- Class-based components. No functional API planned.
- Pug is the only language for templates. No plain HTML support planned.
- No new file names extensions like
.vueor.jsx. - No new syntaxes like Vue single file components or JSX. Just plain Pug and TypeScript.
- Project building tool like Webpack is required.
Planned
The sequence may be changed during the development.
- [ ] Conditional rendering
- [ ] Iterative rendering
- [ ] Nested components
- [ ] Routing
- [ ] Shared state
- [ ] SSR
Quick Tutorials for React/Vue/Svelte Experiencers
Basic ~~"Hello, world"~~ Counter Application
Code
"Counter.ydfr.pug" — The Component Template
samp= $reactiveState.currentValue
.Counter-ActionBar
button(
type="button"
@onLeftClick=onClickIncrementingButton
) Increment
button(
type="button"
@onLeftClick=onClickDecrementingButton
) DecrementThe YDUR components templates are been defined by Pug, the template language. No plans to support HTML.
Counter.ts — The Component Logic
import * as YDFR from "@yamato-daiwa/universal-reactive";
import componentTemplate from "./Counter.ydur.pug";
@YDFR.View(componentTemplate)
export default class Counter extends YDFR.Component {
@YDFR.ReactiveState
protected currentValue: number = 0;
@YDFR.EventHandler()
protected onClickIncrementingButton(): void {
this.currentValue++;
}
@YDFR.EventHandler()
protected onClickDecrementingButton(): void {
this.currentValue--;
}
}- The component logic is the plain TypeScript class with decorators. Besides its main role, you can use it as the plain TypeScript classes, for example, define the public static members and call them from outside (when it makes sense).
- To import
componentTemplatefrom Pug file correctly, you need the appropriate plugin for you project building system. Currently, the Webpack loader is available. The value ofcomponentTemplateis not the string with HTML code — the YDUR templates compiler builds the JavaScript object called "View" based on Pug code. Such an approach is Svelte-like, one advantage of it is better performance than DOM diffing as in React. - The
currentValuefield has been declared with@YDFR.ReactiveStatedecorator. It means the changing of this field will update the DOM depends on it.currentValueis accessible from template as$reativeState.currentValue. Contrary to$reativeStatestate, there is the$constantStateone. - The methods are accessible from the template by names as event handlers, but must be decorated by
@YDFR.EventHandler()decoratory. Unlike@YDFR.ReactiveState, it requires()becaue optionally the event hanling options may be passed. - You can make all instance members private in this example, but the TypeScript and/all linting tool may complain about these fields have not been explicitly used.
index.ts — The Entry Point
import * as YDFR from "@yamato-daiwa/universal-reactive";
import Counter from "./GUI_Components/Counter";
YDFR.initializeFrontendApplication({
mountingPointSelector: "#APPLICATION_ROOT",
rootComponent: Counter
});You need at least one component to create the application instance.
Once it defined, the application may be created by one function.
Of course, the HTML element with ID APPLICATION_ROOT must exist to initialize the application succesfully.
Reactive and Constant State
Some state fields are not intended to be updated during the component lifecycle.
It means no need to make them to a reactive state for performance purposes.
As default, the class fields are not accessible from template, but to declare the constant state field you can use the
@YDFR.ConstantState field:
import * as YDFR from "@yamato-daiwa/universal-reactive";
import componentTemplate from "./Counter.ydur.pug";
@YDFR.View(componentTemplate)
export default class Counter extends YDFR.Component {
// Basically, should be set to `readonly` but we will try to change it for experiment.
@YDFR.ConstantState
protected heading: string = "Counter";
@YDFR.ReactiveState
public currentValue: number = 0;
@YDFR.EventHandler()
public onClickIncrementingButton(): void {
this.currentValue++;
// You will get TypeError if try to chage it. Of course, DOM dependes in this firld will not be updated.
this.heading = "NEW HEADING"
}
@YDFR.EventHandler()
public onClickDecrementingButton(): void {
this.currentValue--;
}
}You can access to heading in template via $constantState object:
h1= $constantState.heading
samp= $reativeState.currentValue
.Counter-ActionBar
button(
type="button"
@onLeftClick=onClickIncrementingButton
) Increment
button(
type="button"
@onLeftClick=onClickDecrementingButton
) DecrementEvents Handling
You can access to instance methods by name from template if they has been decorated by @YDFR.EventHandler():
@YDFR.View(componentTemplate)
export default class Counter extends YDFR.Component {
// ...
@YDFR.EventHandler()
public onClickIncrementingButton(): void {
// ...
}
@YDFR.EventHandler()
public onClickDecrementingButton(): void {
// ...
}
}Unlike @YDFR.ReactiveState or @YDFR.ConstantState, @YDFR.EventHandler decorator must be invoked because the optons
may be passed:
type Options = Readonly<{
/* @default EventPropagationTypes.bubbling */
eventPropagation?: EventPropagationTypes | false;
/* @default false */
mustBeCalledOnce?: boolean;
/* @default false */
mustKeepDefaultBehaviour?: boolean;
}>;
enum EventPropagationTypes {
bubbling = "BUBBLING",
capturing = "CAPTURING"
}The names of the options has been designed such as does not need any explanations.
If you don't know about bubbling and capturing, it is a common terminology, not terminology of YDR. Check this tutorial for details.
Once decorated, the method can be referred from the template by the following attributes.
.Counter-ActionBar
button(
type="button"
@onLeftClick=onClickIncrementingButton
) Increment
button(
type="button"
@onLeftClick=onClickDecrementingButton
) DecrementCurrently available events name listed below.
Mouse Events
| YDUR Event Name | Native event name | |--------------------|-------------------| | @onLeftClick | click | | @onDoubleLeftClick | dblclick | | @onRightClick | auxclick | | @onMouseDown | mousedown | | @onMouseUp | mouseup | | @onMouseMoved | mousemove | | @onMouseOver | mouseover | | @onMouseOut | mouseout | | @onMouseEntered | mouseenter | | @onMouseLeft | mouseleave |
Keyboard Events
| YDUR Event Name | Native event name | |-----------------|-------------------| | @onKeyPressed | keyup | | @onKeyUp | keyup | | @onKeyDown | keydown | | @onInput | input |
Common Events
| YDUR Event Name | Native event name | |-----------------|-------------------| | @onChange | change |
