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
TypeScript
/**
*
* 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;