UNPKG

derby

Version:

MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers.

206 lines (205 loc) 9.21 kB
import { type ChildModel } from 'racer'; import { Controller } from './Controller'; import { Page } from './Page'; import derbyTemplates = require('./templates'); import { Context } from './templates/contexts'; import { Expression } from './templates/expressions'; import { Attribute, Binding } from './templates/templates'; export interface DataConstructor extends Record<string, unknown> { new (): Record<string, unknown>; } type AnyVoidFunction = (...args: any[]) => void; export interface ComponentConstructor { new (context: Context, data: Record<string, unknown>): Component; DataConstructor?: DataConstructor; singleton?: undefined; view?: ComponentViewDefinition; } export interface SingletonComponentConstructor { new (): object; singleton: true; view?: ComponentViewDefinition; } export interface ComponentViewDefinition { dependencies?: Array<ComponentConstructor | SingletonComponentConstructor>; file?: string; is?: string; source?: string; viewPartialDependencies?: Array<string | { is: string; }>; } export declare abstract class Component<T extends object = object> extends Controller<T> { context: Context; /** * Unique ID assigned to the component */ id: string; /** * Whether the component instance is fully destroyed. Initially set to false. */ isDestroyed: boolean; page: Page; /** * Reference to the containing controller */ parent: Controller; singleton?: true; _scope: string[]; view?: ComponentViewDefinition; static DataConstructor?: DataConstructor; constructor(context: Context, data: Record<string, unknown>); /** * Method called by Derby after instantiating a component and before rendering the template. * * This should initialize any data needed by the component, like with `this.model.start(...)`. * * `init()` could be called from the server and the browser, so do not use any DOM-only methods * here. Put those in `create()` instead. */ init?(_model: ChildModel): void; /** * Method called by Derby once a component is loaded and ready in the DOM. * * Any model listeners (`this.model.on(...)`) and DOM listeners (`this.dom.addListener(...)`) * should be added here. * * This will only be called in the browser. */ create?(): void; destroy(): void; /** * Generate a function, bound function to the component instance's `this`. * The returned function will no longer be invoked once the component is destroyed. * * @param fn - A function to be invoked with the component as its `this` value. * @returns a bound function, similar to JavaScript's Function.bind() * * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind */ bind(fn: (...args: unknown[]) => void): (...args: any[]) => any; /** * Generate a function that, when passing in a numeric delay, calls the function at * most once per that many milliseconds. Additionally, implements an interface * intended to be used with window.requestAnimationFrame, process.nextTick, or window.setImmediate. * * @param fn - A function to be invoked with the component instance as its `this` value. * @param delayArg - Amount of time (in ms) to wait until invoking `fn` again. Default '0'. * * When passing in a numeric delay, calls the function at most once per that * many milliseconds. Like Underscore, the function will be called on the * leading and the trailing edge of the delay as appropriate. Unlike Underscore, * calls are consistently called via setTimeout and are never synchronous. This * should be used for reducing the frequency of ongoing updates, such as scroll * events or other continuous streams of events. * * Additionally, implements an interface intended to be used with * window.requestAnimationFrame or process.nextTick. If one of these is passed, * it will be used to create a single async call following any number of * synchronous calls. This mode is typically used to coalesce many synchronous * events (such as multiple model events) into a single async event. * Like component.bind(), will no longer call back once the component is - * destroyed, which avoids possible bugs and memory leaks. * * @returns a bound function */ throttle(fn: (...args: unknown[]) => void, delayArg?: number | ((fn: () => void) => void)): (...args: any[]) => void; /** * Safe wrapper around `window.requestAnimationFrame` that ensures function not invoked * when component has been destroyed * @param fn - A function to be invoked with the component instance as its `this` value. */ requestAnimationFrame(fn: () => void): void; /** * Safe wrapper around `process.nextTick` that ensures function not invoked * when component has been destroyed * @param fn - A function to be invoked with the component instance as its `this` value. */ nextTick(fn: () => void): void; /** * Suppresses calls until the function is no longer called for that many milliseconds. * This should be used for delaying updates triggered by user input or typing text. * * @param fn - A function to be invoked with the component instance as its `this` value. * @param delay - Amount of time (in ms) to wait until invoking `fn`. Default '0'. * * @returns a bound function */ debounce<F extends AnyVoidFunction>(fn: (...args: Parameters<F>) => void, delay?: number): (...args: Parameters<F>) => void; /** * Like debounce(), suppresses calls until the function is no longer called for * that many milliseconds. In addition, suppresses calls while the callback * function is running. In other words, the callback will not be called again * until the supplied done() argument is called. When the debounced function is * called while the callback is running, the callback will be called again * immediately after done() is called. Thus, the callback will always receive * the last value passed to the debounced function. * * This avoids the potential for multiple callbacks to execute in parallel and * complete out of order. It also acts as an adaptive rate limiter. Use this * method to debounce any field that triggers an async call as the user types. * * Like component.bind(), will no longer call back once the component is * destroyed, which avoids possible bugs and memory leaks. * * Forked from: https://github.com/juliangruber/async-debounce * * @param fn - A function to be invoked with the component instance as its `this` value. * @param delay - Amount of time (in ms) to wait until invoking `fn`. Default '0'. * * @returns a bound function */ debounceAsync<F extends AnyVoidFunction>(fn: (...args: Parameters<F>) => void, delay?: number): (...args: Parameters<F>) => void; get(viewName: string, unescaped: boolean): any; getFragment(viewName: string, _ns?: string): any; getView(viewName: string, _ns?: string): any; /** * Retrieve the appropriate view attribute's value for a given view instance. * If the value is a template, it will be rendered prior to being returned. * * @param attrName the name of the view attribute used with a component instance * @returns any of the possible values that can be expressed with a view attribute * * @see https://derbyjs.github.io/derby/views/template-syntax/view-attributes */ getAttribute<T>(attrName: string): T; setAttribute(key: string, value: Attribute): void; setNullAttribute(key: string, value: Attribute): void; } export declare class ComponentAttribute { expression: Expression; model: ChildModel; key: string; constructor(expression: Expression, model: ChildModel, key: string); update(context: Context, binding: Binding): void; } export declare class ComponentAttributeBinding extends Binding { template: any; context: Context; condition: any; constructor(expression: Expression, model: any, key: any, context: Context); } export declare function createFactory(constructor: ComponentConstructor | SingletonComponentConstructor): SingletonComponentFactory | ComponentFactory; export declare class ComponentModelData { id: string; $controller: Controller; $element: any; $event: any; [key: string]: unknown; } export declare class ComponentFactory { constructorFn: ComponentConstructor; constructor(constructorFn: ComponentConstructor); init(context: Context): derbyTemplates.contexts.Context; create(context: any): void; } declare class SingletonComponentFactory { constructorFn: SingletonComponentConstructor; isSingleton: true; component: Component; constructor(constructorFn: any); init(context: any): any; create(): void; } export declare function extendComponent(constructor: SingletonComponentConstructor | ComponentConstructor): void; export {};