# @implab/djx ## SYNOPSIS ```tsx import { djbase, djclass, bind, prototype, AbstractConstructor } from "@implab/djx/declare"; import { DjxWidgetBase } from "@implab/djx/tsx/DjxWidgetBase"; import { createElement } from "@implab/djx/tsx"; interface MyWidgetAttrs { title: string; counter: number; } interface MyWidgetEvents { "count-inc": Event; "count-dec": Event; } @djclass export class MyWidget extends djbase( DjxWidgetBase as AbstractConstructor> ) { @bind({ node: "titleNode", type: "innerHTML" }) title = ""; @prototype() counter = 0; render() { const Frame = (props: any) =>
{props.children}
; return

this._onIncClick(e)}>[+] this._onDecClick()}>[-]
; } _onIncClick(e: MouseEvent) { this.emit("count-inc", { bubbles: false }); } _onDecClick() { this.emit("count-dec", { bubbles: false }); } } ``` ## DESCRIPTION This package provides you with the tools to glue your good-fellow dojo with modern techniques of building the webapp. The core concept is to built around widgets and using .tsx to write it. Here are some features: * `djbase()`, `@djaclass` - traits to declare your classes with `dojo/_base/declare` * `@implab/djx/tsx` - traits to build the rendering of your widgets with tsx * `DjxWidgetBase` - abstract class which supports tsx markup and `data-dojo-attach-*` attributes. * `@bind(...)` - annotations provide an easy way of using standard dojo widget attribute bindings. ### djbase, @djclass These two traits provide convenient way of using `dojo/_base/declare` in Typescript for declaring your classes. `djbase(...constructors)` - this method accepts a list of constructors in its parameters and returns the **fake** base type which then can be used to derive your own class. This allows you to provide the Typescript with the correct information about the base type and even use `super`!. The only caveat of this approach is that you **MUST** decorate your class with `@djclass` annotation. Consider the following example: ```ts import { djbase, djclass } from "@implab/djx/declare"; import { FooMixin } from "./FooMixin"; import { BarMixin } from "./BarMixin"; import { BoxMixin } from "./BoxMixin"; @djclass export class Baz extends djbase(FooMixin, BarMixin, BoxMixin) { writeHello(out: string[]) { out.push("-> Baz"); super.writeHello(out); out.push("<- Baz"); } } ``` All mixins are declared like the one below: ```ts import { djclass, djbase } from "@implab/djx/declare"; interface Super { writeHello(out: string[]): void; } @djclass export class BarMixin extends djbase() { writeHello(out: string[]) { out.push("-> Bar"); super.writeHello(out); out.push("<- Bar"); } } ``` finally create an instance and call the `writeHello` method ```ts const baz = new Baz(); const data: string[] = []; baz.writeHello(data); console.log(data.join("\n")); ``` you will get the following output: ```text -> Baz -> Box -> Bar -> Foo <- Foo <- Bar <- Box <- Baz ``` Let's take a closer look at the `Baz` declaration it uses `djbase` to derive from three mixins and the class is decorated with `@djclass` to accomplish the declaration and make a real constructor. To allow access to the next sibling method (in terms of multiple inheritance) Dojo provides `this.inherited(arguments)` method but this approach leads to the problem with 'strict' mode of ES5 and eliminates the type information about a calling method. This library solves the problem calling inherited/next method by utilizing `super` keyword. Under the hood there are proxy methods generated in the prototype of the declared class which make calls to `this.inherited(...)` method. This technique is compatible with 'strict' mode. Mixins are declared similar, they also may have the base types although the most common case is declaring the mixin without any base classes. To allow the mixin to access the next method declare the interface with desired methods and use the special form of `djbase()` without arguments. ### DjxWidgetBase TODO ### Markup (.tsx) Add to your `tsconfig.json` the following options ```json { "compilerOptions": { "types": ["@implab/djx"], "experimentalDecorators": true, "jsxFactory": "createElement", "jsx": "react", } } ``` Import `createElement` into your `.tsx` file ```ts import { createElement } from "@implab/djx/tsx"; ``` You are ready to go! TODO