@solid-primitives/state-machine
Version:
A primitive for creating reactive state machines.
60 lines (59 loc) • 1.63 kB
JavaScript
import { createMemo, createSignal, untrack } from "solid-js";
const EQUALS_OPTIONS = { equals: (a, b) => a.type === b.type };
/**
* Creates a reactive state machine.
*
* @param options {@link MachineOptions} object.
*
* @returns A signal with the current state object.
*
* @example
* ```ts
* const state = createMachine<{
* idle: { value: "foo"; to: "loading" };
* loading: { input: number; value: "bar"; to: "idle" };
* }>({
* initial: "idle",
* states: {
* idle(input, to) {
* return "foo";
* },
* loading(input, to) {
* setTimeout(() => to("idle"), input);
* return "bar";
* }
* }
* })
*
* state.type // "idle"
* state.value // "foo"
*
* if (state.type === "idle") {
* state.to.loading(1000)
*
* state.type // "loading"
* state.value // "bar"
* }
* ```
*/
export function createMachine(options) {
const { states, initial } = options, to = (type, value) => {
setPayload({ type, value, to });
}, [payload, setPayload] = createSignal(typeof initial === "object"
? { type: initial.type, value: initial.input, to }
: { type: initial, value: undefined, to }, EQUALS_OPTIONS);
for (const key of Object.keys(states)) {
to[key] = (input) => to(key, input);
}
const memo = createMemo(() => {
const next = payload();
next.value = untrack(() => states[next.type](next.value, to));
return next;
});
Object.defineProperties(memo, {
type: { get: () => memo().type },
value: { get: () => memo().value },
to: { value: to },
});
return memo;
}