@zedux/machines
Version:
Simple native state machine implementation for Zedux atoms
65 lines (64 loc) • 4.67 kB
TypeScript
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 {};