UNPKG

deleight

Version:

A library with 9 modules for writing more expressive web applications with traditional HTML, CSS and JavaScript.

161 lines (160 loc) 6.29 kB
/** * * Functions (and classes) for creating elements with javascript. * * Can be used on the server or client. Provides a better DX * than manually creating and setting up elements by using * call chaining. * * Benefits: * 1. Easily reuse `templates` which are just JS variables here. * 2. More natural within js code. Variables can be interpolated naturally. * 3. Better intellisense during development. * 4. Leads to more confidence about code correctness. * 5. Elements can be built more dynamically. * 6. Elements can be composed from different places * 7. Use the same code to create elements on the client and server. * 8. Safe by default. You need to pass functions instead of text to * specify HTML text. All text supplied as children are escaped. All * attributes are also escaped. (Note this only applies to `render` methods * which output HTML text). * * Notes: * * 1. This module supersedes 'dom/element/element' but that one has * been retained (for now) to avoid new breaking changes with this * release. Use this one for new code, and if possible, port old code * using the other module to this one. * * 2. Although this module may seem more verbose, it is actually easier to write * because you get autocomplete from the editor/IDE. The explicitness also * makes the code easier to remember, understand and maintain. * */ import { IComponent } from "../dom"; export type IConstructor<T> = { new (): T; prototype: T; }; export type IBuilder = Builder<string, typeof Element>; export type IElementChild = IBuilder | (() => string) | string | number | Element; /** * This will escape all input strings so it is safe by * default. Pass a function that returns a string to explicitly * indicate that you want the string treated as innerHTML. */ export declare class Builder<T extends string, U extends typeof Element> { tag: T; attrs: object; nsAttrs: object; props: object; children: IElementChild[]; components: IComponent[]; parents?: Set<IBuilder>; constructor(tag: T, ...children: IElementChild[]); set(attrs: { [key: string]: any; }): this; setNs(namespace: string, attrs: { [key: string]: any; }): this; assign(props: object): this; prepend(...children: IElementChild[]): this; append(...children: IElementChild[]): this; replaceChildren(...children: IElementChild[]): this; apply(...components: IComponent[]): this; replaceComponents(...components: IComponent[]): this; render(indent?: number): string; build(): InstanceType<U>; create(): InstanceType<U>; setup(element: InstanceType<U>): InstanceType<U>; appendTo(...targets: (Element | IBuilder)[]): this; prependTo(...targets: (Element | IBuilder)[]): this; insertBefore(...targets: (Element | IBuilder)[]): this; insertAfter(...targets: (Element | IBuilder)[]): this; replace(...targets: (Element | IBuilder)[]): this; } export type IBuilderMethods = IMethods<IBuilder>; export type IBuilders = { builders: Iterable<IBuilder>; self?: IBuilders; } & { [key in keyof IBuilderMethods]: (...args: Parameters<IBuilderMethods[key]>) => ReturnType<IBuilderMethods[key]> extends IBuilder ? IBuilders : ReturnType<IBuilderMethods[key]>[]; }; export type ICallable = (...args: any[]) => any; export type IMethods<T> = { [key in keyof T]: T[key] extends ICallable ? T[key] : never; }; export declare function builders(...builders: Builder<string, typeof Element>[]): IBuilders; export declare const b: typeof builders; export declare class HTMLElementBuilder<T extends string & keyof HTMLElementTagNameMap> extends Builder<T, IConstructor<HTMLElementTagNameMap[T]>> { create(): HTMLElementTagNameMap[T]; } /** * * Returns an HTML builder which can be used to create HTMLElement instances * (with `build` method) or their text representations (with `render` method). * * @example * import { html, h } from 'deleight/dom/builder' * // const verboseBuilder = html('main').set({ class: 'right bg' }).append(9); * const builder = h.main.set({ class: 'right bg' }).append(9); * * const markup = builder.render(); * console.log(markup === ` * <main class="right bg"> * 9 * </main> * `); // true * * const element = builder.build(); * console.log(element.tagName); // MAIN * * @param tag * @returns */ export declare function html<T extends string & keyof HTMLElementTagNameMap>(tag: T, ...children: IElementChild[]): HTMLElementBuilder<T>; export type IHtml = typeof html & { [key in keyof HTMLElementTagNameMap]: HTMLElementBuilder<key>; }; export declare const h: IHtml; export type IHtml2 = typeof html & { [key in keyof HTMLElementTagNameMap]: (...children: IElementChild[]) => HTMLElementBuilder<key>; }; export declare const hh: IHtml2; export declare class SVGElementBuilder<T extends string & keyof SVGElementTagNameMap> extends Builder<T, IConstructor<SVGElementTagNameMap[T]>> { create(): SVGElementTagNameMap[T]; } /** * Similar to {@link html} but for SVG elements. * * @param tag * @returns */ export declare function svg<T extends string & keyof SVGElementTagNameMap>(tag: T, ...children: IElementChild[]): SVGElementBuilder<T>; export type ISvg = typeof svg & { [key in keyof SVGElementTagNameMap]: SVGElementBuilder<key>; }; export declare const s: ISvg; export type ISvg2 = typeof svg & { [key in keyof SVGElementTagNameMap]: (...children: IElementChild[]) => SVGElementBuilder<key>; }; export declare const ss: ISvg2; export declare class MathMLElementBuilder<T extends string & keyof MathMLElementTagNameMap> extends Builder<T, IConstructor<MathMLElementTagNameMap[T]>> { create(): MathMLElementTagNameMap[T]; } /** * Similar to {@link html} but for MathML elements. * * @param tag * @returns */ export declare function math<T extends string & keyof MathMLElementTagNameMap>(tag: T, ...children: IElementChild[]): MathMLElementBuilder<T>; export type IMath = typeof math & { [key in keyof MathMLElementTagNameMap]: MathMLElementBuilder<key>; }; export declare const m: IMath; export type IMath2 = typeof math & { [key in keyof MathMLElementTagNameMap]: (...children: IElementChild[]) => MathMLElementBuilder<key>; }; export declare const mm: IMath2;