# HG changeset patch # User cin # Date 2020-09-20 21:57:45 # Node ID e8012fdf09ae442094f3831abe70649f8520659e # Parent 3f5cb4deed2a052fd6ea03e9ca9eda0a41e2e4fb Support for Function Components Added JSX.IntrinsicElements diff --git a/src/main/ts/tsx.ts b/src/main/ts/tsx.ts --- a/src/main/ts/tsx.ts +++ b/src/main/ts/tsx.ts @@ -2,8 +2,9 @@ import { Constructor } from "@implab/cor import { HtmlElementContext } from "./tsx/HtmlElementContext"; import { WidgetContext } from "./tsx/WidgetContext"; import { isWidgetConstructor, BuildContext } from "./tsx/traits"; +import { FunctionComponentContext } from "./tsx/FunctionComponentContext"; -export function createElement(elementType: string | T, ...args: any[]): BuildContext { +export function createElement Element)>(elementType: T, ...args: any[]): BuildContext { if (typeof elementType === "string") { const ctx = new HtmlElementContext(elementType); if (args) @@ -16,6 +17,12 @@ export function createElement ctx.visitNext(x)); return ctx; + } else if (typeof elementType === "function") { + const ctx = new FunctionComponentContext(elementType as (props: any) => Element); + if (args) + args.forEach(x => ctx.visitNext(x)); + + return ctx; } else { throw new Error(`The element type '${elementType}' is unsupported`); } diff --git a/src/main/ts/tsx/BuildContextBase.ts b/src/main/ts/tsx/BuildContextBase.ts --- a/src/main/ts/tsx/BuildContextBase.ts +++ b/src/main/ts/tsx/BuildContextBase.ts @@ -4,29 +4,25 @@ import { isPlainObject, isNode, isBuildC import dom = require("dojo/dom-construct"); export abstract class BuildContextBase implements BuildContext { - _attrs = {}; + private _attrs = {}; - _children = new Array(); + private _children = new Array(); - _created: boolean = false; + private _created: boolean = false; visitNext(v: any) { + if (this._created) + throw new Error("The Element is already created"); + if (isNull(v)) return; if (isPlainObject(v)) { - - if (this._created) - this._setAttrs(v); - else - mixin(this._attrs, v); + mixin(this._attrs, v); } else if (v instanceof Array) { - v.forEach(x => this._addChild(x)); + v.forEach(x => this.visitNext(x)); } else { - if (this._created) - this._addChild(v); - else - this._children.push(v); + this._children.push(v); } } @@ -68,9 +64,5 @@ export abstract class BuildContextBase { + private _component: (props: any) => Element; + + private _element: Element | undefined; + + constructor(component: (props: any) => Element) { + super(); + argumentNotNull(component, "component"); + + this._component = component; + } + + _create(attrs: object, children: any[]) { + const _attrs: any = attrs || {}; + _attrs.children = children.map(x => this.getChildDom(x)); + + this._element = this._component.call(null, _attrs); + } + + _getDomNode() { + if (!this._element) + throw new Error("The instance of the widget isn't created"); + return this._element; + } + +} diff --git a/src/main/ts/tsx/HtmlElementContext.ts b/src/main/ts/tsx/HtmlElementContext.ts --- a/src/main/ts/tsx/HtmlElementContext.ts +++ b/src/main/ts/tsx/HtmlElementContext.ts @@ -21,13 +21,6 @@ export class HtmlElementContext extends dom.place(this.getChildDom(child), this._element); } - _setAttrs(attrs: object): void { - if (!this._element) - throw new Error("The HTML element isn't created"); - - attr.set(this._element, attrs); - } - _create(attrs: object, children: any[]) { this._element = dom.create(this.elementType, attrs); diff --git a/src/main/ts/tsx/WidgetContext.ts b/src/main/ts/tsx/WidgetContext.ts --- a/src/main/ts/tsx/WidgetContext.ts +++ b/src/main/ts/tsx/WidgetContext.ts @@ -36,12 +36,8 @@ export class WidgetContext extends Build dom.place(this.getChildDom(child), this._instance.containerNode); } - _setAttrs(attrs: object): void { - this._instance?.set(attrs); - } - _create(attrs: object, children: any[]) { - this._instance = new this.widgetClass(this._attrs); + this._instance = new this.widgetClass(attrs); if (children) children.forEach(x => this._addChild(x)); } diff --git a/src/main/typings/index.d.ts b/src/main/typings/index.d.ts --- a/src/main/typings/index.d.ts +++ b/src/main/typings/index.d.ts @@ -4,8 +4,13 @@ declare module "@implab/djx/css!*" { } declare namespace JSX { - interface IntrinsicElements { - [name: string]: any; + interface DjxIntrinsicAttributes { + class: string; + "data-dojo-attach-point": string; + "data-dojo-attach-event": string; + } + type IntrinsicElements = { + [name in keyof HTMLElementTagNameMap]: Partial & DjxIntrinsicAttributes>; } } diff --git a/src/test/js/index.js b/src/test/js/index.js new file mode 100644 --- /dev/null +++ b/src/test/js/index.js @@ -0,0 +1,13 @@ +var rjs = require('requirejs'); + +rjs.config({ + baseUrl: '.', + nodeRequire: require, + packages: [ + { name: "dojo", location: "../../node_modules/dojo" }, + { name: "@implab", location: "../../node_modules/@implab" } + ] +}); + + +rjs(['./plan']); \ No newline at end of file diff --git a/src/test/ts/DeclareTests.ts b/src/test/ts/DeclareTests.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/DeclareTests.ts @@ -0,0 +1,10 @@ +import { Baz } from "./mock/Baz"; + +console.log("Declare tests"); + +const baz = new Baz(); + +const data: string[] = []; +baz.writeHello(data); + +console.log(data.join("\n")); diff --git a/src/test/ts/index.ts b/src/test/ts/index.ts deleted file mode 100644 diff --git a/src/test/ts/mock/BarMixin.ts b/src/test/ts/mock/BarMixin.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/mock/BarMixin.ts @@ -0,0 +1,17 @@ +import { djclass, djbase } from "../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"); + } +} diff --git a/src/test/ts/mock/Baz.ts b/src/test/ts/mock/Baz.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/mock/Baz.ts @@ -0,0 +1,15 @@ +import { djbase, djclass } from "../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"); + } +} diff --git a/src/test/ts/mock/BoxMixin.ts b/src/test/ts/mock/BoxMixin.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/mock/BoxMixin.ts @@ -0,0 +1,16 @@ +import { djbase, djclass } from "../declare"; + +interface Super { + writeHello(out: string[]): void; +} + +@djclass +export class BoxMixin extends djbase() { + writeHello(out: string[]) { + out.push("-> Box"); + + super.writeHello(out); + + out.push("<- Box"); + } +} diff --git a/src/test/ts/mock/FooMixin.ts b/src/test/ts/mock/FooMixin.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/mock/FooMixin.ts @@ -0,0 +1,16 @@ +import { djclass, djbase } from "../declare"; + +interface Super { + writeHello(out: string[]): void; +} + +@djclass +export class FooMixin extends djbase() { + writeHello(out: string[]) { + out.push("-> Foo"); + + super.writeHello(out); + + out.push("<- Foo"); + } +} \ No newline at end of file diff --git a/src/test/ts/plan.ts b/src/test/ts/plan.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/plan.ts @@ -0,0 +1,1 @@ +import "./DeclareTests"; \ No newline at end of file diff --git a/src/test/ts/view/MyWidget.tsx b/src/test/ts/view/MyWidget.tsx --- a/src/test/ts/view/MyWidget.tsx +++ b/src/test/ts/view/MyWidget.tsx @@ -19,25 +19,28 @@ interface MyWidgetEvents { @djclass export class MyWidget extends djbase(DjxWidgetBase as AbstractConstructor>) { - @bind({node: "titleNode", type:"innerHTML"}) + @bind({ node: "titleNode", type: "innerHTML" }) title = ""; @prototype() counter = 0; render() { + const Frame = (props: any) =>
{props.children}
; return

- this._onIncClick()}>[+] - this._onDecClick()}>[-] + + this._onIncClick(e)}>[+] + this._onDecClick()}>[-] +
; } - _onIncClick() { - this.emit("count-inc", { bubbles: false } ); + _onIncClick(e: MouseEvent) { + this.emit("count-inc", { bubbles: false }); } _onDecClick() { - this.emit("count-dec", { bubbles: false } ); + this.emit("count-dec", { bubbles: false }); } }