0
# Machine Creation
1
2
Core machine creation and setup utilities for defining finite state machines with typed schemas, guards, and transition logic.
3
4
## Capabilities
5
6
### Create Machine
7
8
Creates a new finite state machine from configuration with full type safety and schema validation.
9
10
```typescript { .api }
11
/**
12
* Creates a new finite state machine from configuration
13
* @param config - Machine configuration defining states, transitions, context, and behavior
14
* @returns Machine configuration (use with a runtime service to execute)
15
*/
16
function createMachine<T extends MachineSchema>(config: Machine<T>): Machine<T>;
17
18
interface Machine<T extends MachineSchema> {
19
/** Enable debug logging for state transitions */
20
debug?: boolean | undefined;
21
/** Function that returns props object for the machine */
22
props?: ((params: PropsParams<T>) => T["props"]) | undefined;
23
/** Function that returns bindable context values */
24
context?: ((params: ContextParams<T>) => {
25
[K in keyof T["context"]]: Bindable<T["context"][K]>
26
}) | undefined;
27
/** Computed values derived from context and props */
28
computed?: {
29
[K in keyof T["computed"]]: (params: ComputedParams<T>) => T["computed"][K]
30
} | undefined;
31
/** Function that returns the initial state based on props */
32
initialState: (params: { prop: PropFn<T> }) => T["state"];
33
/** Actions to execute when entering the machine */
34
entry?: ActionsOrFn<T> | undefined;
35
/** Actions to execute when exiting the machine */
36
exit?: ActionsOrFn<T> | undefined;
37
/** Effects to run while the machine is active */
38
effects?: EffectsOrFn<T> | undefined;
39
/** Function that returns refs object for DOM elements */
40
refs?: ((params: RefsParams<T>) => T["refs"]) | undefined;
41
/** Watch function called on every state change */
42
watch?: ((params: Params<T>) => void) | undefined;
43
/** Global event handlers (fallback when state doesn't handle event) */
44
on?: {
45
[E in T["event"]["type"]]?: Transition<T> | Array<Transition<T>>
46
} | undefined;
47
/** State node definitions */
48
states: {
49
[K in T["state"]]: {
50
/** Tags associated with this state */
51
tags?: T["tag"][] | undefined;
52
/** Actions to execute when entering this state */
53
entry?: ActionsOrFn<T> | undefined;
54
/** Actions to execute when exiting this state */
55
exit?: ActionsOrFn<T> | undefined;
56
/** Effects to run while in this state */
57
effects?: EffectsOrFn<T> | undefined;
58
/** Event handlers for this state */
59
on?: {
60
[E in T["event"]["type"]]?: Transition<T> | Array<Transition<T>>
61
} | undefined;
62
}
63
};
64
/** Implementation functions for guards, actions, and effects */
65
implementations?: {
66
guards?: {
67
[K in T["guard"]]: (params: Params<T>) => boolean
68
} | undefined;
69
actions?: {
70
[K in T["action"]]: (params: Params<T>) => void
71
} | undefined;
72
effects?: {
73
[K in T["effect"]]: (params: Params<T>) => void | VoidFunction
74
} | undefined;
75
} | undefined;
76
}
77
```
78
79
**Usage Examples:**
80
81
```typescript
82
import { createMachine, MachineSchema } from "@zag-js/core";
83
84
// Simple toggle machine
85
interface ToggleMachine extends MachineSchema {
86
state: "inactive" | "active";
87
event: { type: "TOGGLE" };
88
}
89
90
const toggleMachine = createMachine<ToggleMachine>({
91
initialState: () => "inactive",
92
states: {
93
inactive: {
94
on: { TOGGLE: { target: "active" } }
95
},
96
active: {
97
on: { TOGGLE: { target: "inactive" } }
98
}
99
}
100
});
101
102
// Machine with context and actions
103
interface CounterMachine extends MachineSchema {
104
state: "idle" | "counting";
105
context: { count: number; step: number };
106
event: { type: "INCREMENT" } | { type: "DECREMENT" } | { type: "SET_STEP"; step: number };
107
action: "increment" | "decrement" | "setStep";
108
}
109
110
const counterMachine = createMachine<CounterMachine>({
111
initialState: () => "idle",
112
context: ({ bindable }) => ({
113
count: bindable(() => ({ defaultValue: 0 })),
114
step: bindable(() => ({ defaultValue: 1 }))
115
}),
116
states: {
117
idle: {
118
on: {
119
INCREMENT: { target: "counting", actions: ["increment"] },
120
DECREMENT: { target: "counting", actions: ["decrement"] },
121
SET_STEP: { actions: ["setStep"] }
122
}
123
},
124
counting: {
125
on: {
126
INCREMENT: { actions: ["increment"] },
127
DECREMENT: { actions: ["decrement"] }
128
}
129
}
130
},
131
implementations: {
132
actions: {
133
increment: ({ context }) => context.set("count", (prev) => prev + context.get("step")),
134
decrement: ({ context }) => context.set("count", (prev) => prev - context.get("step")),
135
setStep: ({ context, event }) => context.set("step", event.step)
136
}
137
}
138
});
139
```
140
141
### Setup Function
142
143
Returns setup utilities for machine creation with typed guards and transition choosers.
144
145
```typescript { .api }
146
/**
147
* Returns setup utilities for machine creation with typed guards and choosers
148
* @returns Object with guards, createMachine, and choose utilities
149
*/
150
function setup<T extends MachineSchema>(): {
151
guards: GuardUtilities<T>;
152
createMachine: (config: Machine<T>) => Machine<T>;
153
choose: (transitions: Transition<T> | Transition<T>[]) => (params: Params<T>) => T["action"][] | undefined;
154
};
155
156
interface GuardUtilities<T extends MachineSchema> {
157
/** Logical AND combination of guards */
158
and(...guards: Array<GuardFn<T> | T["guard"]>): GuardFn<T>;
159
/** Logical OR combination of guards */
160
or(...guards: Array<GuardFn<T> | T["guard"]>): GuardFn<T>;
161
/** Logical NOT negation of guard */
162
not(guard: GuardFn<T> | T["guard"]): GuardFn<T>;
163
}
164
```
165
166
**Usage Examples:**
167
168
```typescript
169
import { setup, MachineSchema } from "@zag-js/core";
170
171
interface FormMachine extends MachineSchema {
172
state: "idle" | "validating" | "valid" | "invalid";
173
context: { email: string; isValid: boolean };
174
guard: "isEmailValid" | "isEmailEmpty";
175
action: "validate" | "clear";
176
}
177
178
const { guards, createMachine } = setup<FormMachine>();
179
180
const formMachine = createMachine({
181
initialState: () => "idle",
182
states: {
183
idle: {
184
on: {
185
VALIDATE: {
186
target: "validating",
187
guard: guards.not("isEmailEmpty")
188
}
189
}
190
},
191
validating: {
192
entry: ["validate"],
193
on: {
194
VALIDATION_COMPLETE: [
195
{ target: "valid", guard: "isEmailValid" },
196
{ target: "invalid", guard: guards.not("isEmailValid") }
197
]
198
}
199
},
200
valid: {
201
on: { CLEAR: { target: "idle", actions: ["clear"] } }
202
},
203
invalid: {
204
on: { CLEAR: { target: "idle", actions: ["clear"] } }
205
}
206
},
207
implementations: {
208
guards: {
209
isEmailValid: ({ context }) => /\S+@\S+\.\S+/.test(context.get("email")),
210
isEmailEmpty: ({ context }) => context.get("email").trim() === ""
211
},
212
actions: {
213
validate: ({ context, send }) => {
214
// Simulate async validation
215
setTimeout(() => send({ type: "VALIDATION_COMPLETE" }), 100);
216
},
217
clear: ({ context }) => context.set("email", "")
218
}
219
}
220
});
221
```
222
223
### Create Guards
224
225
Creates logical guard combinations for complex conditional logic in state transitions.
226
227
```typescript { .api }
228
/**
229
* Creates logical guard combinations (and, or, not)
230
* @returns Object with logical guard combination functions
231
*/
232
function createGuards<T extends MachineSchema>(): GuardUtilities<T>;
233
```
234
235
**Usage Examples:**
236
237
```typescript
238
import { createGuards, MachineSchema } from "@zag-js/core";
239
240
interface AuthMachine extends MachineSchema {
241
state: "idle" | "loading" | "success" | "error";
242
context: { user: User | null; attempts: number };
243
guard: "isLoggedIn" | "hasMaxAttempts" | "isValidUser";
244
action: "login" | "logout" | "incrementAttempts";
245
}
246
247
const guards = createGuards<AuthMachine>();
248
249
// Using guard combinations
250
const loginGuard = guards.and("isValidUser", guards.not("hasMaxAttempts"));
251
const logoutGuard = guards.or("isLoggedIn", guards.not("isValidUser"));
252
```
253
254
## Supporting Types
255
256
```typescript { .api }
257
interface Transition<T extends MachineSchema> {
258
/** Target state to transition to */
259
target?: T["state"] | undefined;
260
/** Actions to execute during transition */
261
actions?: T["action"][] | undefined;
262
/** Guard condition that must pass for transition */
263
guard?: T["guard"] | GuardFn<T> | undefined;
264
/** Allow re-entering the same state */
265
reenter?: boolean | undefined;
266
}
267
268
type ActionsOrFn<T extends MachineSchema> =
269
T["action"][] | ((params: Params<T>) => T["action"][] | undefined);
270
271
type EffectsOrFn<T extends MachineSchema> =
272
T["effect"][] | ((params: Params<T>) => T["effect"][] | undefined);
273
274
type GuardFn<T extends MachineSchema> = (params: Params<T>) => boolean;
275
276
interface PropsParams<T extends MachineSchema> {
277
props: Partial<T["props"]>;
278
scope: Scope;
279
}
280
281
interface ContextParams<T extends MachineSchema> {
282
prop: PropFn<T>;
283
bindable: BindableFn;
284
scope: Scope;
285
getContext: () => BindableContext<T>;
286
getComputed: () => ComputedFn<T>;
287
getRefs: () => BindableRefs<T>;
288
getEvent: () => EventType<T["event"]>;
289
flush: (fn: VoidFunction) => void;
290
}
291
292
interface ComputedParams<T extends MachineSchema> {
293
context: BindableContext<T>;
294
event: EventType<T["event"]>;
295
prop: PropFn<T>;
296
refs: BindableRefs<T>;
297
scope: Scope;
298
computed: ComputedFn<T>;
299
}
300
301
interface RefsParams<T extends MachineSchema> {
302
prop: PropFn<T>;
303
context: BindableContext<T>;
304
}
305
```