import { Constructor } from "@implab/core-amd/interfaces"; import { HtmlRendition } from "./tsx/HtmlRendition"; import { WidgetRendition } from "./tsx/WidgetRendition"; import { isWidgetConstructor, Rendition } from "./tsx/traits"; import { FunctionRendition } from "./tsx/FunctionRendition"; import Stateful = require("dojo/Stateful"); import _WidgetBase = require("dijit/_WidgetBase"); import { DjxWidgetBase } from "./tsx/DjxWidgetBase"; import { WatchRendition } from "./tsx/WatchRendition"; import { observe } from "./observable"; export function createElement Element)>(elementType: T, ...args: any[]): Rendition { if (typeof elementType === "string") { const ctx = new HtmlRendition(elementType); if (args) args.forEach(x => ctx.visitNext(x)); return ctx; } else if (isWidgetConstructor(elementType)) { const ctx = new WidgetRendition(elementType); if (args) args.forEach(x => ctx.visitNext(x)); return ctx; } else if (typeof elementType === "function") { const ctx = new FunctionRendition(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`); } } export interface EventDetails { detail: T; } export interface EventSelector { selectorTarget: HTMLElement; target: HTMLElement; } export type DojoMouseEvent = MouseEvent & EventSelector & EventDetails; type StatefulProps = T extends Stateful ? A : never; /** * Observers the property and calls render callback each change. * * @param target The target object which property will be observed. * @param prop The name of the property. * @param render The callback which will be called every time the value is changed * @returns Rendition which is created instantly */ export function watch( target: W, prop: K, render: (model: W[K]) => any ): Rendition; /** * Observers the property and calls render callback each change. * * @param target The target object which property will be observed. * @param prop The name of the property. * @param render The callback which will be called every time the value is changed * @returns Rendition which is created instantly */ export function watch>( target: T, prop: K, render: (model: StatefulProps[K]) => any ): Rendition; export function watch & string>( target: T, prop: K, render: (model: StatefulProps[K]) => any ) { return new WatchRendition( render, observe(({next}) => { const h = target.watch( prop, (_prop, oldValue, newValue) => oldValue !== newValue && next(newValue) ); return () => h.remove(); }) ) } /** Decorates the method which will be registered as the handle for the specified event. * This decorator can be applied to DjxWidgetBase subclass methods. * * ``` * @on("click") * _onClick(eventObj: MouseEvent) { * // ... * } * ``` */ export const on = (...eventNames: E[]) => , EV extends Event >( target: T, key: K, _descriptor: TypedPropertyDescriptor<(eventObj: EV) => void> | TypedPropertyDescriptor<() => void> ): any => { const handlers = eventNames.map(eventName => ({ eventName, handlerMethod: key })); target._eventHandlers = target._eventHandlers ? target._eventHandlers.concat(handlers) : handlers; };