UNPKG

@solid-primitives/state-machine

Version:
60 lines (59 loc) 1.63 kB
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; }