UNPKG

@phnq/state

Version:
188 lines (187 loc) 8.33 kB
import { ComponentType } from 'react'; declare type GenericObject = Record<string, any>; declare type State<S> = { [K in keyof S]: S[K] | ((state: Omit<S, K>) => S[K]); } & { [key: string]: unknown; }; interface ImplicitActions<S, A> { /** * This gets called when the state provider is mounted, or if the `ressetState(true)` * action is called from a consumer. */ init?(): void; /** * This gets called when the state provider is unmounted. */ destroy?(): void; /** * If specifified, errors thrown from actions will result in this function being * called. * @param error the error that was thrown in the action. * @param action the name of the action where the error was thrown. */ onError?(error: unknown, action: keyof Actions<S, A>): void; /** * This gets called after state changes have been made. * @param changedKeys the state keys whose values changed. * @param changeInfo information about the change. */ onChange?(changedKeys: (keyof S)[], changeInfo: StateChangeInfo<S>): void; } interface StateChangeInfo<S> { /** * The previous state -- i.e. before the state changes. */ prevState: S; /** * Identifier of the change initiator. This is typically undefined which indicates an internal state change. */ source?: string; /** * Whether the state change was triggered externally. */ viaExternal: boolean; } declare type Actions<S, A> = A & ImplicitActions<S, A>; declare type ActionFunction = (...args: never[]) => void | Promise<void>; export declare type VoidActions<T> = Record<keyof T, ActionFunction>; interface GetActionsParams<S, E> { /** * Returns a copy of the current state. * @returns a copy of the current state */ getState(): S; /** * Returns a copy of the named external state. * @returns a copy of the named external state */ getState<K extends keyof E>(extStateName: K): E[K]; /** * Used to set some someset of the full state. * @param subState a subset of the full state */ setState(subState: Partial<S>): void; /** * Resets the full state to its initial value. * @param reinitialize whether or not the `init()` lifecycle method should be called. */ resetState(reinitialize?: boolean): void; } interface ChangeListener<S> { id: number; order: number; onChangeInternal(info: { changedKeys: (keyof S)[]; stateChanges: Partial<S>; newState: StateBroker<S>['state']; version: number; }): void; } interface StateBroker<S = unknown, A = unknown> { found: boolean; version: number; state: S; setState(stateChanges: Partial<S>, options?: SetStateOptions): void; actions: Readonly<Actions<S, A>>; addListener(listener: ChangeListener<S>): void; removeListener(id: number): void; } interface SetStateOptions { incremental?: boolean; source?: string; } export interface StateFactory<S = unknown, A = unknown, PR extends keyof S = never> { /** * This HOC creates a state provider by wrapping a component. The returned component's * interface will be identical to the wrapped component's interface. Descendents of this * state provider in the component hierarchy will be able to interact with its state via * `useState()` hook or the (deprecated) `consumer` HOC. * @param Wrapped the component to be wrapped. */ provider: <T extends GenericObject>(Wrapped: ComponentType<T>) => ComponentType<T>; /** * This hook returns the complete state and actions of its nearest counterpart provider * ancestor in the component hierarchy. Referencing an attribute in the returned state * implicitly subscribes the current render context to be notified when that attribute's * value changes. The "notification" is a render. For example, consider: * ```ts * const { firstName } = userState.useState(); * ``` * A render will be triggered if `firstName` changes in the state. However, suppose there * is also a value in the state for the attribute `lastName`; no render will occur as a * result of `lastName` changing. * @param alwaysRender if true, the component will re-render whenever any state changes. Use * this as a last resort since it will have a negative performance impact. */ useState(alwaysRender?: boolean): Omit<S, PR> & Readonly<A>; /** * This hook provides a low-level way of interacting with the state. State changes are conveyed * via the supplied `onStateChange` callback. The return value is a function that can be used * to affect state changes directly, bypassing the action functions. This direct access to the * state breaks the typical encapsulation conventions/protections afforded by action functions, * so use of this hook is discouraged in all but the most exceptional of circumstances. As the * name implies, this hook is intended to be used for generic synchronization tasks. * @param onStateChange a callback that will be called whenever the state changes. * @returns a function that can be used to affect state changes directly. */ useSync(onStateChange: (info: { state: S; changes: Partial<S>; }) => void): StateBroker<S, A>['setState']; /** * @deprecated * Wrapping a component with this HOC adds the ancestor provider's state attribute keys * to the wrapped component's props. * Note: this HOC is deprecated in favour of the more flexible and unobtrusive `useState()`. * @param Wrapped the component to be wrapped. */ consumer<T = unknown>(Wrapped: ComponentType<T>): ComponentType<Omit<T, keyof (Omit<S, PR> & A)>>; /** * @deprecated * Similar to `comsumer`, this HOC also wraps a component to provide access to its ancestor * provider's state, but it additionally allows you to map the state to an aribitrary list * of props. * @param mapFn */ map<T = unknown>(mapFn: (s: State<Omit<S, PR>> & Actions<Omit<S, PR>, A>) => T): (Wrapped: ComponentType<any>) => ComponentType<any>; } interface Options<S, E = unknown, P = unknown> { /** * Named imported state factories. */ imported?: Record<keyof E, StateFactory>; /** * function for adding behaviour to the provider in the form of a HOC. */ mapProvider?: MapProvider<P>; deepCompare?: (keyof S)[]; } export declare type GetActions<S, A, P extends GenericObject = GenericObject, E extends GenericObject = GenericObject> = (getActionsParams: GetActionsParams<S, E> & P) => Actions<S, A>; declare type MapProvider<P> = <T = unknown>(p: ComponentType<P>) => ComponentType<T & Omit<T, keyof P>>; /** * Creates a factory for generating state providers, consumer hooks and HOCs. A single state * factory can generate multiple providers/consumers. * @param name The name of the state. Only used for logging. * @param defaultState The initial value of the state, and derived state functions. * @param getActions Function that returns the action functions. * @returns a state factory. */ export declare function createState<S extends object, A extends VoidActions<A>, PR extends keyof S = never>(name: string, defaultState: State<S>, getActions: GetActions<S, A, GenericObject, GenericObject>): StateFactory<S, A, PR>; /** * Creates a factory for generating state providers, consumer hooks and HOCs. A single state * factory can generate multiple providers/consumers. * @param name The name of the state. Only used for logging. * @param defaultState The initial value of the state, and derived state functions. * @param options Options for the state. * @param getActions Function that returns the action functions. * @returns a state factory. */ export declare function createState<S extends object, A extends VoidActions<A>, P extends GenericObject = GenericObject, E extends GenericObject = GenericObject, PR extends keyof S = never>(name: string, options: Options<S, E, P>, defaultState: State<S>, getActions: GetActions<S, A, P, E>): StateFactory<S, A, PR>; declare global { interface Window { getAllStates: () => [string, unknown][]; logAllStates: () => void; } } export {};