narraleaf-react
Version:
A React visual novel player framework
347 lines (346 loc) • 15.5 kB
TypeScript
import { HexColor, LiveGameEventToken, NamedColor } from "../game/nlcore/types";
import { ServiceHandler } from "../game/nlcore/elements/service";
interface ITypeOf {
DataTypes: typeof DataTypes;
call: typeof TypeOf;
(value: any): DataTypes;
}
export declare enum DataTypes {
"string" = 0,
"number" = 1,
"boolean" = 2,
"object" = 3,
"array" = 4,
"function" = 5,
"symbol" = 6,
"undefined" = 7,
"null" = 8,
"date" = 9,
"regexp" = 10,
"other" = 11
}
export declare const TypeOf: ITypeOf;
/**
* @param obj1 source object
* @param obj2 this object will overwrite the source object
* @param objs
* @example
* deepMerge(defaultConfig, config);
*/
export declare function deepMerge<T = Record<string, any>>(obj1: Record<string, any>, obj2: Record<string, any>, ...objs: Record<string, any>[]): T;
export type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;
export declare class Awaitable<T = any, U = T> {
static isAwaitable<T, U = T>(obj: any): obj is Awaitable<T, U>;
static fromPromise<T>(promise: Promise<T>): Awaitable<T>;
static nothing: ((value: any) => any);
static resolve<T>(value: T): Awaitable<T>;
static delay(ms: number): Awaitable<void>;
static create<T>(handler: (awaitable: Awaitable<T>) => T): Awaitable<T>;
/**
* Creates a new `Awaitable<void>` that resolves when the provided awaitable resolves.
*
* **Note**: this approach is _**radical**_! If this Awaitable is canceled, the Promise returned by this method will never be resolved.
*
* @param awaitable The awaitable to wait for
* @returns A new awaitable that resolves when the provided awaitable resolves
*/
static wait(awaitable: Awaitable<void>): Awaitable<void>;
/**
* Creates a new `Awaitable<T>` that resolves with the first resolved value from multiple awaitables.
* All other awaitables will be cancelled when one resolves.
*
* @template T The type of the awaitables
* @param awaitables Array of awaitables to race
* @returns A new awaitable that resolves with the first resolved value
*/
static race<T>(awaitables: Awaitable<T>[]): Awaitable<T>;
/**
* Creates a new `Awaitable<T>` that forwards resolution and cancellation from/to a source awaitable.
*
* This is useful when:
* - You want to attach additional result transformation (e.g., `then → mapped result`)
* - You want to expose a new awaitable while preserving skip/cancel propagation from both sides
*
* Behavior:
* - When the source `awaitable` resolves, the new awaitable resolves with the provided `result`.
* - If either the source or the new awaitable is aborted, the other is also aborted.
*
* @template T The result type of the new awaitable.
*
* @param {Awaitable<any>} awaitable
* The source awaitable whose completion or cancellation is being tracked.
*
* @param {T} result
* The result to resolve the new awaitable with, once the source awaitable completes.
*
* @param {SkipController<T>} [skipController]
* Optional custom skip controller for the new awaitable.
* If not provided, a default controller that returns `result` will be created.
*
* @returns {Awaitable<T>} A new awaitable that resolves with `result` and mirrors skip behavior.
*/
static forward<T>(awaitable: Awaitable<any>, result: T, skipController?: SkipController<T, []>): Awaitable<T, T>;
static toPromise<T>(awaitable: Awaitable<T>): Promise<T>;
static toPromiseForce<T>(awaitable: Awaitable<T>): Promise<void>;
/**
* Resolves when any of the provided awaitables settles.
*/
static any(...awaitables: Awaitable<void>[]): Awaitable<void>;
/**
* Resolves when all of the provided awaitables settle.
*/
static all(...awaitables: Awaitable<void>[]): Awaitable<void>;
static maxListeners: number;
receiver: (value: U) => T;
result: T | undefined;
solved: boolean;
aborted: boolean;
skipController: SkipController<T, []> | undefined;
private readonly listeners;
private readonly onRegisterSkipController;
private readonly __stack?;
constructor(receiver?: (value: U) => T, skipController?: SkipController<T, []>);
registerSkipController(skipController: SkipController<T, []>): this;
resolve(value: U): void;
then(callback: (value: T) => void): this;
onSettled(callback: () => void): EventToken;
onSkipControllerRegister(callback: (skipController: SkipController<T, []>) => void): EventToken;
offSkipControllerRegister(callback: (skipController: SkipController<T, []>) => void): this;
/**
* **Note**: Calling this method won't trigger the `then` callbacks.
*/
abort(): void | T;
isSolved(): boolean;
isAborted(): boolean;
isSettled(): boolean;
private pushListener;
private offListener;
}
export declare function safeClone<T>(obj: T): T;
export type Values<T> = T[keyof T];
export declare function toHex(hex: {
r: number;
g: number;
b: number;
a?: number;
} | string): HexColor;
export type EventTypes = {
[key: string]: any[];
};
export type EventListener<T extends any[]> = (...args: T) => void | Thenable<any>;
export type EventToken<T extends EventTypes = EventTypes> = {
type?: keyof T;
listener?: EventListener<any>;
cancel: () => void;
};
export declare class EventDispatcher<T extends EventTypes, Type extends T & {
"event:EventDispatcher.register": [keyof EventTypes, EventListener<any>];
} = T & {
"event:EventDispatcher.register": [keyof EventTypes, EventListener<any>];
}> {
private events;
private maxListeners;
on<K extends StringKeyOf<Type>>(event: K, listener: EventListener<Type[K]>): EventToken;
depends(events: EventToken<T>[]): EventToken;
off<K extends keyof Type>(event: K, listener: EventListener<Type[K]>): void;
emit<K extends keyof Type>(event: K, ...args: Type[K]): number;
once<K extends StringKeyOf<Type>>(event: K, listener: EventListener<Type[K]>): EventToken;
/**
* Emit an event and wait for all listeners to resolve.
* If there's no listener, wait until a listener is registered and solved
*/
any<K extends keyof T>(event: K, ...args: Type[K]): Promise<any>;
setMaxListeners(maxListeners: number): this;
hasListeners(event: keyof T): boolean;
clear(): void;
}
/**
* Get the call stack
* @param n The number of stack frames to skip
*/
export declare function getCallStack(n?: number): string;
export declare function sleep(ms: number): Promise<void>;
export declare function deepEqual(obj1: any, obj2: any): boolean;
type SkipControllerEvents = {
"event:skipController.abort": [];
};
export declare class SkipController<_T = any, U extends Array<any> = any[]> {
private readonly abortHandler;
static EventTypes: {
[K in keyof SkipControllerEvents]: K;
};
readonly events: EventDispatcher<SkipControllerEvents>;
private aborted;
constructor(abortHandler: (...args: U) => void);
abort(...args: U): void;
isAborted(): boolean;
cancel(): void;
onAbort(listener: () => void): EventToken<EventTypes>;
}
export declare function throttle<T extends (...args: any[]) => any>(fn: T, delay: number): T;
export type PublicProperties<T> = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
export type PublicOnly<T> = Pick<T, PublicProperties<T>>;
export declare class Lock {
private locked;
private listeners;
private unlockListeners;
lock(): this;
unlock(): this;
onUnlock(listener: () => void): () => void;
offUnlock(listener: () => void): void;
nextUnlock(): Promise<void>;
isLocked(): boolean;
}
export declare class MultiLock {
private locks;
unlock(lock: Lock): Lock;
register(lock?: Lock): Lock;
off(lock: Lock): void;
nextUnlock(): Promise<void[]>;
isLocked(): boolean;
}
export declare function onlyIf<T>(condition: boolean, value: T, fallback?: object): T | object;
export declare function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): T;
export declare function entriesForEach<T extends object, V = undefined>(obj: T, handler: {
[K in keyof T]: (value: Exclude<T[K], V>, key: K) => void;
}, validate?: (value: any, key: string) => boolean): void;
type ScheduleTaskToken = {
cancel: () => void;
isCancelled: () => boolean;
};
export declare class Scheduler {
private taskToken;
scheduleTask(handler: () => void, delay: number): ScheduleTaskToken;
cancelTask(): this;
}
/**
* Cross combine two arrays
* @example
* ```typescript
* crossCombine([1, 2], ["a", "b"]); // [1, "a", 2, "b"]
* ```
*/
export declare function crossCombine<T, U>(a: T[], b: U[]): (T | U)[];
export type SelectElementFromEach<T extends string[][] | null> = T extends [infer First, ...infer Rest] ? First extends string[] ? Rest extends string[][] ? {
[K in First[number]]: [K, ...SelectElementFromEach<ExcludeEach<Rest, K>>];
}[First[number]] : [] : [] : [];
export type ExcludeEach<T extends string[][], Excluded> = T extends [infer First, ...infer Rest] ? First extends string[] ? Rest extends string[][] ? [[Exclude<First[number], Excluded>], ...ExcludeEach<Rest, Excluded>] : [] : [] : [];
export type FlexibleTuple<T extends any[]> = T extends [infer First, ...infer Rest] ? Rest extends any[] ? [First, ...FlexibleTuple<Rest>] | FlexibleTuple<Rest> : [First] : [];
export declare function moveElement<T>(arr: T[], element: T, direction: "up" | "down" | "top" | "bottom"): T[];
export declare function moveElementInArray<T>(arr: T[], element: T, newIndex: number): T[];
export declare function getImageDataUrl(src: string, options?: RequestInit): Promise<string>;
export declare class TaskPool {
private readonly concurrency;
private readonly delay;
private tasks;
constructor(concurrency: number, delay: number);
addTask(task: () => Promise<void>): void;
start(): Promise<void>;
}
export type StringKeyOf<T> = Extract<keyof T, string>;
export type ValuesWithin<T, U> = {
[K in keyof T]: T[K] extends U ? K : never;
}[keyof T];
export type BooleanValueKeyOf<T> = Extract<{
[K in keyof T]: T[K] extends boolean ? K : never;
}[keyof T], string>;
export declare function createMicroTask(t: () => (() => void) | void): () => void;
export declare function keyExcept<T extends Record<string, any>, Filtered extends Extract<keyof T, string>>(obj: T, keys: Filtered[]): Omit<T, Filtered>;
type SerializeHandlers<T> = {
[K in keyof T]?: (value: Exclude<T[K], undefined>) => any;
};
type DeserializeHandlers<T, SerializeHandler extends SerializeHandlers<T>> = {
[K in keyof T]?: SerializeHandler[K] extends ((...args: any) => any) ? (value: Exclude<ReturnType<SerializeHandler[K]>, undefined>) => T[K] : never;
};
export declare class Serializer<T extends Record<string, any>, SerializeHandler extends SerializeHandlers<T> = SerializeHandlers<T>, DeserializeHandler extends DeserializeHandlers<T, SerializeHandler> = DeserializeHandlers<T, SerializeHandler>> {
private readonly serializer;
private readonly deserializer;
constructor(serializer?: SerializeHandler, deserializer?: DeserializeHandler);
serialize(obj: T): Record<string, any>;
deserialize(obj: Record<string, any>): T;
extend<NewFields extends Record<string, any>, NewSerializeHandler extends SerializeHandlers<T & NewFields>, NewDeserializeHandler extends DeserializeHandlers<T & NewFields, NewSerializeHandler>>(newSerializer: NewSerializeHandler, newDeserializer: NewDeserializeHandler): Serializer<T & NewFields, SerializeHandler & NewSerializeHandler, DeserializeHandler & NewDeserializeHandler>;
}
export declare function isNamedColor(color: string): color is NamedColor;
type ChainedAwaitableTaskHandler = (awaitable: Awaitable<void>) => void;
export type ChainedAwaitableTask = [ChainedAwaitableTaskHandler, SkipController<void, []>?];
export declare class ChainedAwaitable extends Awaitable<void, void> {
private current;
private tasks;
constructor(skipController?: SkipController<void, []>);
addTask(task?: [handler: ChainedAwaitableTaskHandler, skipController?: SkipController<void, []>]): this;
abort(): void;
resolve(): void;
run(): this;
private onTaskComplete;
}
export declare function isAsyncFunction<T extends Array<any>, U = void>(fn: (...args: T) => U | Promise<U>): fn is (...args: T) => Promise<U>;
export type SerializableDataType = number | string | boolean | null | undefined | SerializableDataType[];
export type SerializableData = Record<string, SerializableDataType> | SerializableDataType;
export type Thenable<T> = T | Promise<T> | Awaitable<T>;
export declare function ThenableAll(thenables: Thenable<any>[]): Promise<any[]>;
export declare function onlyValidFields<T extends Record<string, any>>(obj: T): T;
/**
* Check if the object is a pure object
*
* A pure object should:
* - be an object (prototype is Object)
* - not be an array
* - no circular reference
* - sub objects should also be pure objects or serializable data
*/
export declare function isPureObject(obj: any, seen?: WeakSet<any>): boolean;
export declare class KeyGen {
private prefix;
private counter;
constructor(prefix?: string);
next(): string;
}
export declare function once<T extends (...args: any[]) => any>(fn: T): T;
export declare function randId(len?: number): string;
export declare function generateId(length?: number): string;
export declare const voidFunction: () => VoidFunction;
export declare class IdManager {
private prefix;
private counter;
constructor(prefix?: string);
generateId(): string;
}
export declare class Hooks<T extends Record<string, Array<any>>> {
private hooks;
hook<K extends keyof T>(key: K, hook: (...value: T[K]) => VoidFunction | void): LiveGameEventToken;
unhook<K extends keyof T>(key: K, hook: (...value: T[K]) => VoidFunction | void): void;
trigger<K extends keyof T>(key: K, value: T[K]): VoidFunction;
rawTrigger<K extends keyof T>(key: K, value: () => T[K]): VoidFunction;
}
type AbortifyFn<T extends any[]> = ServiceHandler<T> & {
onAbort: (handler: () => void) => AbortifyFn<T>;
};
export declare function abortify<T extends any[]>(fn: ServiceHandler<T>): AbortifyFn<T>;
export type FirstParam<T> = T extends (first: infer P, ...args: any[]) => any ? P : never;
export declare class Stack<T> {
private items;
private pushValidator;
constructor(initial?: T[]);
addPushValidator(validator: (item: T) => boolean): this;
removePushValidator(validator: (item: T) => boolean): void;
push(...items: T[]): void;
pop(): T | undefined;
peek(): T | undefined;
isEmpty(): boolean;
size(): number;
clear(): void;
toArray(): T[];
forEach(fn: (item: T) => void): void;
forEachReverse(fn: (item: T) => void): void;
map<U>(fn: (item: T) => U): U[];
get(index: number): T | undefined;
}
export type ArrayValue<T> = T extends Array<infer U> ? U : T;
export declare function filterObject<T extends Record<string, any>>(obj: T, fields: (keyof T)[]): [o: Partial<T>, filtered: (keyof T)[]];
export declare function filterObjectExcept<T extends Record<string, any>>(obj: T, fields: (keyof T)[]): [o: Partial<T>, filtered: (keyof T)[]];
export declare function fnv1a64(input: string): string;
export {};