UNPKG

@v4fire/client

Version:

V4Fire client core library

696 lines (562 loc) • 14.4 kB
/* eslint-disable @typescript-eslint/no-unused-vars-experimental, @typescript-eslint/no-empty-function, @typescript-eslint/unified-signatures */ /*! * V4Fire Client Core * https://github.com/V4Fire/Client * * Released under the MIT license * https://github.com/V4Fire/Client/blob/master/LICENSE */ import type { LogMessageOptions } from 'core/log'; import type Async from 'core/async'; import type { BoundFn, ProxyCb } from 'core/async'; import type { ComponentEngine, ComponentOptions, FunctionalComponentOptions, VNode, ScopedSlot, CreateElement } from 'core/component/engines'; import type { Hook, ComponentMeta, SyncLinkCache, WatchPath, WatchOptions, RawWatchHandler, RenderEngine } from 'core/component/interface'; /** * Component render function */ export type RenderFunction = ComponentOptions<ComponentEngine>['render'] | FunctionalComponentOptions['render']; /** * Base context of a functional component */ export interface FunctionalCtx { componentName: string; meta: ComponentMeta; instance: Dictionary; $options: Dictionary; } export interface ComponentConstructor<T = unknown> { new(): T; } /** * DOM Element that is tied with a component */ export type ComponentElement<T = unknown> = Element & { component?: T; }; export interface RenderReason { value: unknown; oldValue: CanUndef<unknown>; path: unknown[]; } /** * A helper structure to pack the unsafe interface: * it fixes some ambiguous TS warnings */ export type UnsafeGetter<U extends UnsafeComponentInterface = UnsafeComponentInterface> = Dictionary & U['CTX'] & U & {unsafe: any}; /** * Abstract class that represents Vue compatible component API */ export abstract class ComponentInterface { /** * Type: base component */ readonly Component!: ComponentInterface; /** * Type: root component */ readonly Root!: ComponentInterface; /** * Unique component string identifier */ readonly componentId!: string; /** * Name of the component without special postfixes */ readonly componentName!: string; /** * Link to a component instance */ readonly instance!: this; /** * Name of the active component hook */ get hook(): Hook { return 'beforeRuntime'; } /** * Switches the component to a new hook * * @param value * @emits `componentHook:{$value}(value: Hook, oldValue: Hook)` * @emits `componentHookChange(value: Hook, oldValue: Hook) */ protected set hook(value: Hook) { // Loopback } /** * Name of the active rendering group * (it's used with async rendering) */ readonly renderGroup?: string; /** * API for unsafe invoking of internal properties of the component. * It can be useful to create component' friendly classes. */ get unsafe(): UnsafeGetter<UnsafeComponentInterface<this>> { return Object.cast(this); } /** * Link to a DOM element that is tied with the component */ // @ts-ignore (ts error) readonly $el?: ComponentElement<this['Component']>; /** * Raw component options */ readonly $options!: ComponentOptions<ComponentEngine>; /** * Dictionary with initialized input properties of the component */ readonly $props!: Dictionary; /** * List of child components */ // @ts-ignore (ts error) readonly $children?: Array<this['Component']>; /** * Link to the parent component */ // @ts-ignore (ts error) readonly $parent?: this['Component']; /** * Link to the closest non-functional parent component */ readonly $normalParent?: this['Component']; /** * Link to the root component */ readonly $root!: this['Root']; /** * Description object of the used rendering engine */ readonly $renderEngine!: RenderEngine<any>; /** * True if the component can be attached to a parent render function */ readonly isFlyweight?: boolean; /** * Temporary unique component' string identifier * (only for functional components) */ protected readonly $componentId?: string; /** * Link to a component meta object */ protected readonly meta!: ComponentMeta; /** * Value that increments on every re-rendering of the component */ protected renderCounter!: number; /** * The last reason why the component was re-rendered. * The `null` value is means that the component was re-rendered by using $forceUpdate. */ protected lastSelfReasonToRender?: Nullable<RenderReason>; /** * Timestamp of the last component rendering */ protected lastTimeOfRender?: DOMHighResTimeStamp; /** * Cache table for virtual nodes */ protected readonly renderTmp!: Dictionary<VNode>; /** * The special symbol that is tied with async rendering */ protected readonly $asyncLabel!: symbol; /** * Link to the parent component * (using with async rendering) */ // @ts-ignore (ts error) protected readonly $remoteParent?: this['Component']; /** * Internal API for async operations */ protected readonly $async!: Async<ComponentInterface>; /** * Map of component attributes that aren't recognized as input properties */ protected readonly $attrs!: Dictionary<string>; /** * Map of external listeners of component events */ protected readonly $listeners!: Dictionary<CanArray<Function>>; /** * Map of references to elements that have a "ref" attribute */ protected readonly $refs!: Dictionary; /** * Map of handlers that wait appearing of references to elements that have a "ref" attribute */ protected readonly $refHandlers!: Dictionary<Function[]>; /** * Map of available render slots */ protected readonly $slots!: Dictionary<VNode>; /** * Map of available scoped render slots */ protected readonly $scopedSlots!: Dictionary<ScopedSlot>; /** * Map of component fields that can force re-rendering */ protected readonly $data!: Dictionary; /** * The raw map of component fields that can force re-rendering */ protected readonly $fields!: Dictionary; /** * @deprecated * @see [[ComponentInterface.$fields]] */ protected readonly $$data!: Dictionary; /** * The raw map of component fields that can't force re-rendering */ protected readonly $systemFields!: Dictionary; /** * Map of fields and system fields that were modified and need to synchronize * (only for functional components) */ protected readonly $modifiedFields!: Dictionary; /** * Name of the active field to initialize */ protected readonly $activeField?: string; /** * Cache for component links */ protected readonly $syncLinkCache!: SyncLinkCache; /** * Link to a function that creates virtual nodes */ protected $createElement!: CreateElement; /** * Promise of the component initializing */ protected $initializer?: Promise<unknown>; /** * Logs an event with the specified context * * @param ctxOrOpts - logging context or logging options (logLevel, context) * @param [details] - event details */ log?(ctxOrOpts: string | LogMessageOptions, ...details: unknown[]): void; /** * Activates the component. * The deactivated component won't load data from providers on initializing. * * Basically, you don't need to think about a component activation, * because it's automatically synchronized with `keep-alive` or the special input property. * * @param [force] - if true, then the component will be forced to activate, even if it is already activated */ activate(force?: boolean): void {} /** * Deactivates the component. * The deactivated component won't load data from providers on initializing. * * Basically, you don't need to think about a component activation, * because it's automatically synchronized with `keep-alive` or the special input property. */ deactivate(): void {} /** * Forces the component to re-render */ $forceUpdate(): void {} /** * Executes the specified function on the next render tick * @param cb */ $nextTick(cb: Function | BoundFn<this>): void; /** * Returns a promise that will be resolved on the next render tick */ $nextTick(): Promise<void>; $nextTick(): CanPromise<void> {} /** * Mounts the component to a DOM element * @param elementOrSelector - link to an element or selector to an element */ protected $mount(elementOrSelector?: Element | string): this { return this; } /** * Destroys the component */ protected $destroy(): void {} /** * Sets a new reactive value to the specified property of an object * * @param object * @param key * @param value */ protected $set<T = unknown>(object: object, key: unknown, value: T): T { return value; } /** * Deletes the specified reactive property from an object * * @param object * @param key */ protected $delete(object: object, key: unknown): void {} /** * Sets a watcher to a component/object property by the specified path * * @param path * @param handler * @param opts */ protected $watch<T = unknown>( path: WatchPath, opts: WatchOptions, handler: RawWatchHandler<this, T> ): Nullable<Function>; /** * Sets a watcher to a component/object property by the specified path * * @param path * @param handler */ protected $watch<T = unknown>( path: WatchPath, handler: RawWatchHandler<this, T> ): Nullable<Function>; /** * Sets a watcher to the specified watchable object * * @param obj * @param handler */ protected $watch<T = unknown>( obj: object, handler: RawWatchHandler<this, T> ): Nullable<Function>; /** * Sets a watcher to the specified watchable object * * @param obj * @param handler * @param opts */ protected $watch<T = unknown>( obj: object, opts: WatchOptions, handler: RawWatchHandler<this, T> ): Nullable<Function>; protected $watch(): Nullable<Function> { return null; } /** * Attaches an event listener to the specified component event * * @param event * @param handler */ protected $on<E = unknown, R = unknown>(event: CanArray<string>, handler: ProxyCb<E, R, this>): this { return this; } /** * Attaches a single event listener to the specified component event * * @param event * @param handler */ protected $once<E = unknown, R = unknown>(event: string, handler: ProxyCb<E, R, this>): this { return this; } /** * Detaches an event listeners from the component * * @param [event] * @param [handler] */ protected $off(event?: CanArray<string>, handler?: Function): this { return this; } /** * Emits a component event * * @param event * @param args */ protected $emit(event: string, ...args: unknown[]): this { return this; } /** * Hook handler: the component has been created * (only for flyweight components) */ protected onCreatedHook(): void { // Loopback } /** * Hook handler: the component has been bound * (only for functional and flyweight components) */ protected onBindHook(): void { // Loopback } /** * Hook handler: the component has been mounted * (only for functional and flyweight components) */ protected onInsertedHook(): void { // Loopback } /** * Hook handler: the component has been updated * (only for functional and flyweight components) */ protected onUpdateHook(): void { // Loopback } /** * Hook handler: the component has been unbound * (only for functional and flyweight components) */ protected onUnbindHook(): void { // Loopback } } /** * A special interface to provide access to protected properties and methods outside the component. * It's used to create the "friendly classes" feature. */ export interface UnsafeComponentInterface<CTX extends ComponentInterface = ComponentInterface> { /** * Type: context type */ readonly CTX: CTX; // Don't use referring from CTX for primitive types, because it breaks TS componentId: string; // @ts-ignore (access) $componentId: CTX['$componentId']; componentName: string; instance: this; // @ts-ignore (access) meta: CTX['meta']; hook: Hook; renderGroup: string; renderCounter: number; renderTmp: Dictionary<VNode>; lastSelfReasonToRender?: Nullable<RenderReason>; lastTimeOfRender?: DOMHighResTimeStamp; $asyncLabel: symbol; $activeField: CanUndef<string>; // @ts-ignore (access) $initializer: CTX['$initializer']; // @ts-ignore (access) $renderEngine: CTX['$renderEngine']; // @ts-ignore (access) $parent: CTX['$parent']; // @ts-ignore (access) $remoteParent: CTX['$remoteParent']; // @ts-ignore (access) $children: CTX['$children']; // @ts-ignore (access) $async: CTX['$async']; // @ts-ignore (access) $attrs: CTX['$attrs']; // @ts-ignore (access) $listeners: CTX['$listeners']; // @ts-ignore (access) $refs: CTX['$refs']; // @ts-ignore (access) $refHandlers: CTX['$refHandlers']; // @ts-ignore (access) $slots: CTX['$slots']; // @ts-ignore (access) $scopedSlots: CTX['$scopedSlots']; // @ts-ignore (access) $data: CTX['$data']; // @ts-ignore (access) $fields: CTX['$fields']; // @ts-ignore (access) $systemFields: CTX['$fields']; // @ts-ignore (access) $modifiedFields: CTX['$modifiedFields']; // @ts-ignore (access) $syncLinkCache: CTX['$syncLinkCache']; // @ts-ignore (access) $createElement: CTX['$createElement']; // @ts-ignore (access) $watch: CTX['$watch']; // @ts-ignore (access) $on: CTX['$on']; // @ts-ignore (access) $once: CTX['$once']; // @ts-ignore (access) $off: CTX['$off']; // @ts-ignore (access) $emit: CTX['$emit']; // @ts-ignore (access) $set: CTX['$set']; // @ts-ignore (access) $delete: CTX['$delete']; // @ts-ignore (access) $forceUpdate: CTX['$forceUpdate']; // @ts-ignore (access) $nextTick: CTX['$nextTick']; // @ts-ignore (access) $destroy: CTX['$destroy']; // @ts-ignore (access) log: CTX['log']; // @ts-ignore (access) activate: CTX['activate']; // @ts-ignore (access) deactivate: CTX['deactivate']; // @ts-ignore (access) onCreatedHook: CTX['onCreatedHook']; // @ts-ignore (access) onBindHook: CTX['onBindHook']; // @ts-ignore (access) onInsertedHook: CTX['onInsertedHook']; // @ts-ignore (access) onUpdateHook: CTX['onUpdateHook']; // @ts-ignore (access) onUnbindHook: CTX['onUnbindHook']; // Internal render helpers // @ts-ignore (access) _c: CTX['$createElement']; _o: Function; _q: Function; _s: Function; _v: Function; _e: Function; _f: Function; _n: Function; _i: Function; _m: Function; _l: Function; _g: Function; _k: Function; _b: Function; _t: Function; _u: Function; }