A minimal implementation of xstate fsm for UI machines
npx @tessl/cli install tessl/npm-zag-js--core@1.22.0@zag-js/core is a minimal implementation of XState FSM (Finite State Machine) specifically designed for UI component state management. It provides a lightweight alternative to XState with essential features for building interactive UI components including finite states, transitions, context management, entry/exit actions, effects, guards, and activities.
npm install @zag-js/coreimport { createMachine, setup, createGuards, MachineSchema, Service } from "@zag-js/core";For CommonJS:
const { createMachine, setup, createGuards } = require("@zag-js/core");import { createMachine, MachineSchema } from "@zag-js/core";
// Define machine schema
interface ToggleMachine extends MachineSchema {
state: "inactive" | "active";
event: { type: "TOGGLE" };
}
// Create state machine configuration
const toggleMachine = createMachine<ToggleMachine>({
initialState: () => "inactive",
states: {
inactive: {
on: { TOGGLE: { target: "active" } }
},
active: {
on: { TOGGLE: { target: "inactive" } }
}
}
});
// toggleMachine is a configuration object that can be used with a runtime service
// (The runtime service/interpreter is provided by other packages in the Zag.js ecosystem)@zag-js/core is built around several key components:
Core machine creation and setup utilities for defining finite state machines with typed schemas, guards, and actions.
function createMachine<T extends MachineSchema>(config: Machine<T>): Machine<T>;
function setup<T extends MachineSchema>(): {
guards: GuardUtilities<T>;
createMachine: (config: Machine<T>) => Machine<T>;
choose: (transitions: Transition<T> | Transition<T>[]) => (params: Params<T>) => T["action"][] | undefined;
};
function createGuards<T extends MachineSchema>(): GuardUtilities<T>;Comprehensive type definitions for machine schemas, services, parameters, and all core interfaces required for type-safe state machine development.
interface MachineSchema {
props?: MachineBaseProps | undefined;
context?: Record<string, any> | undefined;
refs?: Record<string, any> | undefined;
computed?: Record<string, any> | undefined;
state?: string | undefined;
tag?: string | undefined;
guard?: string | undefined;
action?: string | undefined;
effect?: string | undefined;
event?: ({ type: string } & Record<string, any>) | undefined;
}
interface Service<T extends MachineSchema> {
getStatus(): MachineStatus;
state: Bindable<T["state"]> & {
matches(...values: T["state"][]): boolean;
hasTag(tag: T["tag"]): boolean;
};
context: BindableContext<T>;
send(event: EventType<T["event"]>): void;
prop: PropFn<T>;
scope: Scope;
computed: ComputedFn<T>;
refs: BindableRefs<T>;
event: EventType<T["event"]> & {
current(): EventType<T["event"]>;
previous(): EventType<T["event"]>;
};
}Helper functions for property merging, memoization, and scope management essential for UI component development.
function mergeProps<T extends Props>(...args: T[]): UnionToIntersection<TupleTypes<T[]>>;
function memo<TDeps extends any[], TDepArgs, TResult>(
getDeps: (depArgs: TDepArgs) => [...TDeps],
fn: (...args: [...TDeps]) => TResult,
opts?: { onChange?: (result: TResult) => void }
): (depArgs: TDepArgs) => TResult;
function createScope(props: Pick<Scope, "id" | "ids" | "getRootNode">): Scope;