UNPKG

@zedux/machines

Version:

Simple native state machine implementation for Zedux atoms

65 lines (64 loc) 4.67 kB
import { InjectStoreConfig } from '@zedux/atoms'; import { MachineStore } from './MachineStore.js'; import { MachineHook, MachineStateShape } from './types.js'; declare type ArrToUnion<S extends string[]> = S extends [infer K, ...infer Rest] ? Rest extends string[] ? K | ArrToUnion<Rest> : never : never; export declare type InjectMachineStoreParams<States extends MachineState[], Context extends Record<string, any> | undefined = undefined> = [ statesFactory: (state: <Name extends string>(stateName: Name) => MachineState<Context, Name>) => [...States], initialContext?: Context, config?: { guard?: (currentState: MachineStateShape<MapStatesToStateNames<States>, Context>, nextValue: MapStatesToStateNames<States>) => boolean; onTransition?: MachineHook<MapStatesToStateNames<States>, MapStatesToEvents<States, Context>, Context>; } & InjectStoreConfig ]; export interface MachineState<Context extends Record<string, any> | undefined = any, Name extends string = string, Events extends string[] = [], ChildStates extends string[] = [Name]> { on: <E extends string, S extends string>(eventName: E, nextState: S, guard?: (context: Context) => boolean) => MachineState<Context, Name, [...Events, E], [...ChildStates, S]>; onEnter: (listener: MachineHook<ArrToUnion<ChildStates>, ArrToUnion<Events>, Context>) => MachineState<Context, Name, Events, ChildStates>; onLeave: (listener: MachineHook<ArrToUnion<ChildStates>, ArrToUnion<Events>, Context>) => MachineState<Context, Name, Events, ChildStates>; stateName: Name; } declare type MapStatesToStateNames<States extends MachineState[], Context extends Record<string, any> | undefined = undefined> = States extends [infer K, ...infer Rest] ? K extends MachineState ? Rest extends MachineState[] ? StateNameType<K> | ArrToUnion<StateChildStatesType<K>> | MapStatesToStateNames<Rest, Context> : never : never : never; declare type MapStatesToEvents<States extends MachineState[], Context extends Record<string, any> | undefined = undefined> = States extends [infer K, ...infer Rest] ? K extends MachineState ? Rest extends MachineState[] ? ArrToUnion<StateEventsType<K>> | MapStatesToEvents<Rest, Context> : ArrToUnion<StateEventsType<K>> : never : never; declare type StateChildStatesType<S extends MachineState> = S extends MachineState<any, string, string[], infer ChildStates> ? ChildStates : never; declare type StateEventsType<S extends MachineState> = S extends MachineState<any, string, infer Events> ? Events : never; declare type StateNameType<S extends MachineState> = S extends MachineState<any, infer Name> ? Name : never; /** * Create a MachineStore. Pass a statesFactory * * The first state in the state list returned from your statesFactory will * become the initial state (`.value`) of the store. * * Registers an effect that listens to all store changes and calls the * configured listeners appropriately. * * ```ts * const store = injectMachineStore(state => [ * state('a') * .on('next', 'b', localGuard) * .onEnter(enterListener) * .onLeave(leaveListener), * state('b').on('next', 'a') * ], initialContext, { guard, onTransition }) * ``` * * Set a universal transition guard via the 3rd `config` object param. This * guard will be called every time a valid transition is about to occur. It will * be called with the current `.context` value and should return a boolean. * Return true to allow the transition, or any falsy value to deny it. * * Set a universal `onTransition` listener via the 3rd `config` object param. * This listener will be called every time the machine transitions to a new * state (after the state is updated). It will be called with 2 params: The * current MachineStore and the storeEffect of the action that transitioned the * store. For example, use `storeEffect.oldState.value` to see what state the * machine just transitioned from. * * @param statesFactory Required. A function. Use the received state factory to * create a list of states for the machine and specify their transitions, * guards, and listeners. * @param initialContext Optional. An object or undefined. Will be set as the * initial `.context` value of the machine store's state. * @param config Optional. An object with 2 additional properties: `guard` and * `onTransition`. */ export declare const injectMachineStore: <States extends MachineState[], Context extends Record<string, any> | undefined = undefined>(...[statesFactory, initialContext, config]: InjectMachineStoreParams<States, Context>) => MachineStore<MapStatesToStateNames<States, Context>, MapStatesToEvents<States, Context>, Context>; export {};