UNPKG

x-view-model

Version:

A lightweight, type-safe MVVM state management solution for React applications. Features reactive updates, computed properties, and deep path selection with minimal bundle size.

192 lines (176 loc) 7.36 kB
type ChangeType = "insert" | "update" | "delete" | "reverse" | "shuffle"; /** * `Observable` allows to observe any (deep) changes on its underlying object graph * * - created by `from` static method, via cloning the target * - important: the type `T` is not preserved, beside its shape */ declare abstract class Observable { /** * create Observable from the target * - target is cloned, remaining unchanged in itself * - important: the type `T` is NOT preserved, beside its shape * * @param target source, to create `Observable` from * @param options observable options */ static from<T>(target: T, options?: ObservableOptions): Observable & T; /** * check input for being `Observable` * * @param input any object to be checked as `Observable` */ static isObservable(input: unknown): boolean; /** * add observer to handle the observable's changes * * @param observable observable to set observer on * @param observer observer function / logic * @param options observation options */ static observe( observable: Observable, observer: Observer, options?: ObserverOptions ): void; /** * remove observer/s from observable * * @param observable observable to remove observer/s from * @param observers 0 to many observers to remove; if none supplied, ALL observers will be removed */ static unobserve(observable: Observable, ...observers: Observer[]): void; } interface ObservableOptions { async: boolean; } interface Observer { (changes: Change[]): void; } interface ObserverOptions { path?: string; pathsOf?: string; pathsFrom?: string; } interface Change { type: ChangeType; path: string[]; value?: any; oldValue?: any; object: object; } type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`; type GetDotKeys<T> = T extends Date | Array<any> ? "" : (T extends object ? { [K in Exclude<keyof T, symbol>]: `${K}` | `${K}${DotPrefix<GetDotKeys<T[K]>>}`; }[Exclude<keyof T, symbol>] : "") extends infer D ? Extract<D, string> : never; type GetFunctionKeys<T> = { [K in Exclude<keyof T, symbol>]: T[K] extends Function ? `${K}` : ""; }[Exclude<keyof T, symbol>] extends infer D ? Extract<D, string> : never; type GetFunctionParams<T> = { [K in keyof T]: T[K] extends (args: any) => void ? Parameters<T[K]>[0] : any; }; type GetFunctionReturn<T> = { [K in keyof T]: T[K] extends (args: any) => any ? ReturnType<T[K]> : void; }; type ComponentState = { enabled: boolean; paths: string[]; }; interface DevToolsState { components: Map<PropertyHandler<any>, Record<string, ComponentState>>; } declare class DevToolsHandler { private state; constructor(); components(): Map<PropertyHandler<any>, Record<string, ComponentState>>; registerComponent(context: PropertyHandler<any>, componentName: string, componentPaths?: string[]): void; } declare class EventHandler<K> { private handlers; constructor(); on: (event: K, func: (...args: any) => void) => this; off: (event: K, func: (...args: any) => void) => this; callEmitFromMT: (this: { func: Function; args: any[]; }) => void; emit: (event: K, args?: any) => this; clear: () => void; } declare class ServiceHandler<R> extends EventHandler<string> { constructor(parent: PropertyHandler<R>); } type SendHistory = { name: string; componentName: string; payload: any; timestamp: number; result?: any; error?: Error; }; type Middleware<T> = (changes: Change[], next: () => void, state: T) => void | Promise<void>; type HistoryHandler<T> = (history: SendHistory, state: T) => void | Promise<void>; type HistoryOptions<T> = { handler?: HistoryHandler<T>; maxSize?: number; }; type PropertyHandlerOptions<T> = { name: string; deep: boolean; middlewares?: Middleware<T>[]; history?: HistoryOptions<T>; }; declare class PropertyHandler<R> extends EventHandler<GetDotKeys<R>> { private _property; private _observable; private _reference; private _started; private _options?; private middlewares; private _sendHistory; private _historyHandler; private _historyMaxSize; private _componentName; services: ServiceHandler<R>; private devTools?; constructor(init_property: R, options?: PropertyHandlerOptions<R>, devTools?: DevToolsHandler); use(middleware: Middleware<R>): this; private executeMiddlewares; get state(): Observable & R; get property(): R; get reference(): number; get name(): string; private set reference(value); private watch; increaseReference(): void; decreaseReference(): void; private start; private stop; private pause; restart(): this; snapshot(): string; rebase(json: string | Partial<R>): this; restore(json: string | Partial<R>): this; private addHistory; send<K extends GetFunctionKeys<R>>(name: K, payload: GetFunctionParams<R>[K], async?: boolean): Promise<GetFunctionReturn<R>[K] extends Promise<infer U> ? U : GetFunctionReturn<R>[K]>; getSendHistory(): SendHistory[]; clearSendHistory(): void; } type DataModel<T> = T extends (...args: never[]) => Promise<infer Response> ? Response : never; type ViewModel<T, R> = { context: PropertyHandler<T>; ref: R; }; declare const devTools: DevToolsHandler; declare const registViewModel: <T, R = undefined>(data: T, options?: PropertyHandlerOptions<T> | undefined, ref?: R | undefined) => ViewModel<T, R>; declare const useViewModel: <T, R>(vm: ViewModel<T, R>, keys?: GetDotKeys<T>[] | undefined, componentInfo?: { name: string; paths: string[]; }) => [T, <K extends GetFunctionKeys<T>>(name: K, payload: GetFunctionParams<T>[K], async?: boolean) => Promise<GetFunctionReturn<T>[K] extends Promise<infer U> ? U : GetFunctionReturn<T>[K]>, R]; type GetDotKeysImpl<T> = T extends object ? { [K in keyof T & (string | number)]: T[K] extends object ? K | `${K}.${GetDotKeysImpl<T[K]>}` : K; }[keyof T & (string | number)] : never; type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; declare const useComputedViewModel: <T, R, S>(vm: ViewModel<T, R>, selector: (state: T) => S, keys?: GetDotKeys<T>[] | undefined) => [S, <K extends GetFunctionKeys<T>>(name: K, payload: GetFunctionParams<T>[K], async?: boolean) => Promise<GetFunctionReturn<T>[K] extends Promise<infer U> ? U : GetFunctionReturn<T>[K]>, R]; declare const useMemoizedViewModel: <T, R, K extends GetDotKeysImpl<T>>(vm: ViewModel<T, R>, keys?: K[] | undefined) => [UnionToIntersection<{ [P in K & string]: P extends keyof T ? { [Key in P]: T[Key]; } : P extends `${infer A}.${infer B}` ? A extends keyof T ? B extends keyof T[A] ? { [Key_1 in A]: { [SubKey in B]: T[A][SubKey]; }; } : never : never : never; }[K & string]>, <K_1 extends GetFunctionKeys<T>>(name: K_1, payload: GetFunctionParams<T>[K_1], async?: boolean) => Promise<GetFunctionReturn<T>[K_1] extends Promise<infer U> ? U : GetFunctionReturn<T>[K_1]>, R]; export { ComponentState, DataModel, DevToolsHandler, DevToolsState, ViewModel, devTools, registViewModel, useComputedViewModel, useMemoizedViewModel, useViewModel };