@zag-js/core
Advanced tools
Comparing version 0.1.8 to 0.1.9
@@ -1,6 +0,428 @@ | ||
export { proxy, ref, snapshot, subscribe } from "@zag-js/store"; | ||
export { choose, guards } from "./guard-utils"; | ||
export * from "./machine"; | ||
export { mergeProps } from "./merge-props"; | ||
export type { ContextFrom, EventFrom, StateFrom } from "./type-utils"; | ||
export type { StateMachine } from "./types"; | ||
export { proxy, ref, snapshot, subscribe } from '@zag-js/store'; | ||
declare type Dict<T = any> = Record<string, T>; | ||
declare type MaybeArray<T> = T | T[]; | ||
declare type VoidFunction = () => void; | ||
declare type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B; | ||
declare type WritableKey<T> = { | ||
[P in keyof T]: IfEquals<{ | ||
[Q in P]: T[P]; | ||
}, { | ||
-readonly [Q in P]: T[P]; | ||
}, P, never>; | ||
}[keyof T]; | ||
declare type Writable<T> = Pick<T, WritableKey<T>>; | ||
declare type Computed<T> = Omit<T, WritableKey<T>>; | ||
declare namespace StateMachine { | ||
type Context<V, C> = V & Readonly<C>; | ||
type TComputedContext<T> = { | ||
[K in keyof Computed<T>]: (ctx: Omit<T, K>) => T[K]; | ||
}; | ||
type UserContext<TContext> = Partial<Writable<TContext>>; | ||
type ContextListener<TContext extends Dict> = (context: TContext) => void; | ||
type EventObject = { | ||
type: string; | ||
}; | ||
type Event<TEvent extends EventObject = EventObject> = TEvent["type"] | TEvent; | ||
interface AnyEventObject extends EventObject { | ||
[key: string]: any; | ||
} | ||
type Send<TEvent extends EventObject = AnyEventObject> = (event: Event<TEvent>) => void; | ||
type EventListener<TEvent extends EventObject = AnyEventObject> = (event: TEvent) => void; | ||
type ExtractEvent<TEvent extends EventObject, K> = K extends TEvent["type"] ? Extract<TEvent, { | ||
type: K; | ||
}> : EventObject; | ||
type Expression<TContext extends Dict, TEvent extends EventObject, TReturn> = (context: TContext, event: TEvent) => TReturn; | ||
type Meta<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
state: State<TContext, TState>; | ||
guards: Dict; | ||
send: Send<TEvent>; | ||
self: Self<TContext, TState, TEvent>; | ||
getState: () => State<TContext, TState, TEvent>; | ||
getAction: (key: string) => ExpressionWithMeta<TContext, TState, TEvent, void>; | ||
getGuard: (key: string) => GuardExpression<TContext, TState, TEvent>; | ||
}; | ||
type ExpressionWithMeta<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject, TReturn> = (context: TContext, event: TEvent, meta: Meta<TContext, TState, TEvent>) => TReturn; | ||
type Action<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = string | ExpressionWithMeta<TContext, TState, TEvent, void>; | ||
type Actions<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = ChooseHelper<TContext, TState, TEvent> | MaybeArray<Action<TContext, TState, TEvent>>; | ||
type PureActions<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = MaybeArray<Action<TContext, TState, TEvent>>; | ||
type ActionMap<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
[action: string]: ExpressionWithMeta<TContext, TState, TEvent, void>; | ||
}; | ||
type Activity<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = string | ExpressionWithMeta<TContext, TState, TEvent, VoidFunction | void | undefined>; | ||
type Activities<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = MaybeArray<Activity<TContext, TState, TEvent>>; | ||
type ActivityMap<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
[activity: string]: ExpressionWithMeta<TContext, TState, TEvent, VoidFunction | void | undefined>; | ||
}; | ||
type TransitionDefinition<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
target?: TState["value"]; | ||
actions?: Actions<TContext, TState, TEvent>; | ||
guard?: Guard<TContext, TState, TEvent>; | ||
internal?: boolean; | ||
}; | ||
type DelayExpression<TContext, TEvent extends EventObject> = Expression<TContext, TEvent, number>; | ||
type Delay<TContext extends Dict, TEvent extends EventObject> = string | number | DelayExpression<TContext, TEvent>; | ||
type DelayMap<TContext extends Dict, TEvent extends EventObject> = { | ||
[delay: string]: number | DelayExpression<TContext, TEvent>; | ||
}; | ||
type DelayedTransition<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = TransitionDefinition<TContext, TState, TEvent> & { | ||
/** | ||
* The time to delay the event, in milliseconds. | ||
*/ | ||
delay?: Delay<TContext, TEvent>; | ||
}; | ||
type DelayedTransitions<TContext, TState extends StateSchema, TEvent extends EventObject> = Record<string | number, TState["value"] | MaybeArray<TransitionDefinition<TContext, TState, TEvent>>> | Array<DelayedTransition<TContext, TState, TEvent>>; | ||
/** | ||
* a transition can be a string (e.g "off") or a full definition object | ||
* { target: "off", actions: [...], guard: "isEmpty" } | ||
*/ | ||
type Transition<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = TState["value"] | TransitionDefinition<TContext, TState, TEvent>; | ||
/** | ||
* Transition can be a string (representing the `target`), an object or an array of possible | ||
* transitions with `guard` to determine the selected transition | ||
*/ | ||
type Transitions<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = Transition<TContext, TState, TEvent> | Array<TransitionDefinition<TContext, TState, TEvent>>; | ||
type TransitionDefinitionMap<TContext, TState extends StateSchema, TEvent extends EventObject> = { | ||
[K in TEvent["type"]]?: TState["value"] | MaybeArray<TransitionDefinition<TContext, TState, ExtractEvent<TEvent, K>>>; | ||
}; | ||
interface StateNode<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> { | ||
/** | ||
* The type of this state node. | ||
*/ | ||
type?: "final"; | ||
/** | ||
* The tags for the state node. | ||
*/ | ||
tags?: MaybeArray<TState["tags"] extends string ? TState["tags"] : string>; | ||
/** | ||
* The activities to be started upon entering the state node, | ||
* and stopped upon exiting the state node. | ||
*/ | ||
activities?: Activities<TContext, TState, TEvent>; | ||
/** | ||
* The mapping of event types to their potential transition(s). | ||
*/ | ||
on?: TransitionDefinitionMap<TContext, TState, TEvent>; | ||
/** | ||
* The action(s) to be executed upon entering the state node. | ||
*/ | ||
entry?: Actions<TContext, TState, TEvent>; | ||
/** | ||
* The action(s) to be executed upon exiting the state node. | ||
*/ | ||
exit?: Actions<TContext, TState, TEvent>; | ||
/** | ||
* The meta data associated with this state node. | ||
*/ | ||
meta?: string | Dict; | ||
/** | ||
* The mapping (or array) of delays (in `ms`) to their potential transition(s) to run after | ||
* the specified delay. Uses `setTimeout` under the hood. | ||
*/ | ||
after?: DelayedTransitions<TContext, TState, TEvent>; | ||
/** | ||
* The mapping (or array) of intervals (in `ms`) to their potential actions(s) to run at interval. | ||
* Uses `setInterval` under the hood. | ||
*/ | ||
every?: Record<string | number, Actions<TContext, TState, TEvent>> | Array<{ | ||
delay?: number | string | Expression<TContext, TEvent, number>; | ||
actions: Actions<TContext, TState, TEvent>; | ||
guard?: Guard<TContext, TState, TEvent>; | ||
}>; | ||
} | ||
type GuardMeta<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
state: Pick<State<TContext, TState, TEvent>, "matches">; | ||
}; | ||
type GuardExpression<TContext, TState extends StateSchema, TEvent extends EventObject, TReturn = boolean> = (context: TContext, event: TEvent, guardMeta: GuardMeta<TContext, TState, TEvent>) => TReturn; | ||
type GuardHelper<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
predicate: (guards: Dict) => GuardExpression<TContext, TState, TEvent>; | ||
}; | ||
type ChooseHelper<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
predicate: (guards: Dict) => GuardExpression<TContext, TState, TEvent, PureActions<TContext, TState, TEvent> | undefined>; | ||
}; | ||
type Guard<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = string | GuardExpression<TContext, TState, TEvent> | GuardHelper<TContext, TState, TEvent>; | ||
type GuardMap<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> = { | ||
[guard: string]: GuardExpression<TContext, TState, TEvent>; | ||
}; | ||
type StateSchema = { | ||
value: string; | ||
tags?: string; | ||
}; | ||
type StateInitObject<TContext, TState extends StateSchema> = { | ||
context: TContext; | ||
value: TState["value"]; | ||
}; | ||
type StateInit<TContext, TState extends StateSchema> = TState["value"] | StateInitObject<TContext, TState>; | ||
type StateListener<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject = EventObject> = (state: State<TContext, TState, TEvent>) => void; | ||
interface StateInfo<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> { | ||
reenter: boolean; | ||
changed: boolean; | ||
transition: TransitionDefinition<TContext, TState, TEvent> | undefined; | ||
stateNode: StateNode<TContext, TState, TEvent> | undefined; | ||
target: TState["value"]; | ||
} | ||
interface MachineConfig<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> { | ||
/** | ||
* Function called whenever the state receives an event through its send method | ||
*/ | ||
onEvent?: Actions<TContext, TState, TEvent>; | ||
/** | ||
* Function called synchronously after the machine has been instantiated, | ||
* before it is started. | ||
*/ | ||
created?: Actions<TContext, TState, TEvent>; | ||
/** | ||
* The actions to run when the machine has started. This is usually | ||
* called in the `beforeMount`, `onMount` or `useLayoutEffect` lifecycle methods. | ||
*/ | ||
entry?: Actions<TContext, TState, TEvent>; | ||
/** | ||
* The actions to run when the machine has stopped. This is usually | ||
* called in the `onUnmount` or `useLayoutEffect` cleanup lifecycle methods. | ||
*/ | ||
exit?: Actions<TContext, TState, TEvent>; | ||
/** | ||
* The root level activities to run when the machine is started | ||
*/ | ||
activities?: Activities<TContext, TState, TEvent>; | ||
/** | ||
* The unique identifier for the invoked machine. | ||
*/ | ||
id?: string; | ||
/** | ||
* The extended state used to store `data` for your machine | ||
*/ | ||
context?: Writable<TContext>; | ||
/** | ||
* A generic way to react to context value changes | ||
*/ | ||
watch?: { | ||
[K in keyof TContext]?: PureActions<TContext, TState, TEvent>; | ||
}; | ||
/** | ||
* The computed properties based on the state | ||
*/ | ||
computed?: Partial<TComputedContext<TContext>>; | ||
/** | ||
* The initial state to start with | ||
*/ | ||
initial?: TState["value"]; | ||
/** | ||
* The mapping of state node keys to their state node configurations (recursive). | ||
*/ | ||
states?: Partial<Record<TState["value"], StateNode<TContext, TState, TEvent>>>; | ||
/** | ||
* Mapping events to transitions | ||
*/ | ||
on?: TransitionDefinitionMap<TContext, TState, TEvent>; | ||
} | ||
interface State<TContext extends Dict, TState extends StateSchema = StateSchema, TEvent extends EventObject = EventObject> { | ||
value: TState["value"] | null; | ||
previousValue: TState["value"] | null; | ||
event: TEvent; | ||
previousEvent: TEvent; | ||
context: TContext; | ||
done: boolean; | ||
can(event: string): boolean; | ||
matches(...value: TState["value"][]): boolean; | ||
hasTag(value: TState["tags"]): boolean; | ||
nextEvents: string[]; | ||
changed: boolean; | ||
tags: TState["tags"][]; | ||
} | ||
interface MachineOptions<TContext extends Dict, TState extends StateSchema, TEvent extends EventObject> { | ||
debug?: boolean; | ||
guards?: GuardMap<TContext, TState, TEvent>; | ||
actions?: ActionMap<TContext, TState, TEvent>; | ||
delays?: DelayMap<TContext, TEvent>; | ||
activities?: ActivityMap<TContext, TState, TEvent>; | ||
sync?: boolean; | ||
/** | ||
* Notify `useSnapshot` to execute state update synchronously within `valtio`. | ||
* Useful if this component has an input element. | ||
* | ||
* @see Valtio https://github.com/pmndrs/valtio#update-synchronously | ||
*/ | ||
hookSync?: boolean; | ||
} | ||
type HookOptions<TContext, TState extends StateSchema, TEvent extends EventObject> = { | ||
actions?: ActionMap<TContext, TState, TEvent>; | ||
state?: StateInit<TContext, TState>; | ||
context?: UserContext<TContext>; | ||
}; | ||
type Self<TContext, TState extends StateSchema, TEvent extends EventObject> = { | ||
id: string; | ||
send: (event: Event<TEvent>) => void; | ||
sendParent: (evt: AnyEventObject) => void; | ||
sendChild: (evt: Event<TEvent>, to: string | ((ctx: TContext) => string)) => void; | ||
stop: VoidFunction; | ||
stopChild: (id: string) => void; | ||
spawn<T>(src: T | (() => T), id?: string): T; | ||
state: State<TContext, TState, TEvent>; | ||
}; | ||
} | ||
declare enum MachineStatus { | ||
NotStarted = "Not Started", | ||
Running = "Running", | ||
Stopped = "Stopped" | ||
} | ||
declare enum MachineType { | ||
Machine = "machine", | ||
Actor = "machine.actor" | ||
} | ||
declare function or<TContext, TState extends StateMachine.StateSchema, TEvent extends StateMachine.EventObject>(...conditions: Array<StateMachine.Guard<TContext, TState, TEvent>>): StateMachine.GuardHelper<TContext, TState, TEvent>; | ||
declare function and<TContext, TState extends StateMachine.StateSchema, TEvent extends StateMachine.EventObject>(...conditions: Array<StateMachine.Guard<TContext, TState, TEvent>>): StateMachine.GuardHelper<TContext, TState, TEvent>; | ||
declare function not<TContext, TState extends StateMachine.StateSchema, TEvent extends StateMachine.EventObject>(condition: StateMachine.Guard<TContext, TState, TEvent>): StateMachine.GuardHelper<TContext, TState, TEvent>; | ||
declare function stateIn<TContext, TState extends StateMachine.StateSchema, TEvent extends StateMachine.EventObject>(...values: TState["value"][]): StateMachine.GuardExpression<TContext, TState, TEvent>; | ||
declare const guards: { | ||
or: typeof or; | ||
and: typeof and; | ||
not: typeof not; | ||
stateIn: typeof stateIn; | ||
}; | ||
declare function choose<TContext, TState extends StateMachine.StateSchema, TEvent extends StateMachine.EventObject = StateMachine.AnyEventObject>(actions: Array<{ | ||
guard?: StateMachine.Guard<TContext, TState, TEvent>; | ||
actions: StateMachine.PureActions<TContext, TState, TEvent>; | ||
}>): StateMachine.ChooseHelper<TContext, TState, TEvent>; | ||
declare class Machine<TContext extends Dict, TState extends StateMachine.StateSchema, TEvent extends StateMachine.EventObject = StateMachine.AnyEventObject> { | ||
status: MachineStatus; | ||
readonly state: StateMachine.State<TContext, TState, TEvent>; | ||
initialState: StateMachine.StateInfo<TContext, TState, TEvent> | undefined; | ||
id: string; | ||
type: MachineType; | ||
private activityEvents; | ||
private delayedEvents; | ||
private stateListeners; | ||
private contextListeners; | ||
private eventListeners; | ||
private doneListeners; | ||
private contextWatchers; | ||
private removeStateListener; | ||
private removeEventListener; | ||
private removeContextListener; | ||
private parent?; | ||
private children; | ||
private guardMap; | ||
private actionMap; | ||
private delayMap; | ||
private activityMap; | ||
private sync; | ||
options: StateMachine.MachineOptions<TContext, TState, TEvent>; | ||
config: StateMachine.MachineConfig<TContext, TState, TEvent>; | ||
constructor(config: StateMachine.MachineConfig<TContext, TState, TEvent>, options?: StateMachine.MachineOptions<TContext, TState, TEvent>); | ||
private get stateSnapshot(); | ||
getState(): StateMachine.State<TContext, TState, TEvent>; | ||
private get contextSnapshot(); | ||
start: (init?: StateMachine.StateInit<TContext, TState>) => this; | ||
private setupContextWatchers; | ||
stop: () => this | undefined; | ||
private stopEventListeners; | ||
private stopContextListeners; | ||
private stopStateListeners; | ||
private stopContextWatchers; | ||
private stopDelayedEvents; | ||
private stopActivities; | ||
/** | ||
* Function to send event to spawned child machine or actor | ||
*/ | ||
sendChild: (evt: StateMachine.Event<StateMachine.AnyEventObject>, to: string | ((ctx: TContext) => string)) => void; | ||
/** | ||
* Function to stop a running child machine or actor | ||
*/ | ||
stopChild: (id: string) => void; | ||
removeChild: (id: string) => void; | ||
private stopChildren; | ||
private setParent; | ||
spawn: <TContext_1 extends Dict<any>, TState_1 extends StateMachine.StateSchema, TEvent_1 extends StateMachine.EventObject = StateMachine.AnyEventObject>(src: MachineSrc<TContext_1, TState_1, TEvent_1>, id?: string) => Machine<TContext_1, TState_1, TEvent_1>; | ||
private addActivityCleanup; | ||
private setState; | ||
/** | ||
* To used within side effects for React or Vue to update context | ||
*/ | ||
setContext: (context: Partial<Writable<TContext>> | undefined) => void; | ||
withContext: (context: Partial<Writable<TContext>>) => Machine<TContext, TState, TEvent>; | ||
setActions: (actions: Partial<StateMachine.MachineOptions<TContext, TState, TEvent>>["actions"]) => void; | ||
private getStateNode; | ||
private getNextStateInfo; | ||
private getActionFromDelayedTransition; | ||
/** | ||
* All `after` events leverage `setTimeout` and `clearTimeout`, | ||
* we invoke the `clearTimeout` on exit and `setTimeout` on entry. | ||
* | ||
* To achieve this, we split the `after` defintion into `entry` and `exit` | ||
* functions and append them to the state's `entry` and `exit` actions | ||
*/ | ||
private getDelayedEventActions; | ||
/** | ||
* A reference to the instance methods of the machine. | ||
* Useful when spawning child machines and managing the communication between them. | ||
*/ | ||
private get self(); | ||
private get meta(); | ||
private get guardMeta(); | ||
/** | ||
* Function to executes defined actions. It can accept actions as string | ||
* (referencing `options.actions`) or actual functions. | ||
*/ | ||
private executeActions; | ||
/** | ||
* Function to execute running activities and registers | ||
* their cleanup function internally (to be called later on when we exit the state) | ||
*/ | ||
private executeActivities; | ||
/** | ||
* Normalizes the `every` definition to transition. `every` can be: | ||
* - An array of possible actions to run (we need to pick the first match based on guard) | ||
* - An object of intervals and actions | ||
*/ | ||
private createEveryActivities; | ||
private setEvent; | ||
private performExitEffects; | ||
private performEntryEffects; | ||
private performTransitionEffects; | ||
/** | ||
* Performs all the requires side-effects or reactions when | ||
* we move from state A => state B. | ||
* | ||
* The Effect order: | ||
* Exit actions (current state) => Transition actions => Go to state => Entry actions (next state) | ||
*/ | ||
private performStateChangeEffects; | ||
private determineTransition; | ||
/** | ||
* Function to send event to parent machine from spawned child | ||
*/ | ||
sendParent: (evt: StateMachine.Event<StateMachine.AnyEventObject>) => void; | ||
private log; | ||
/** | ||
* Function to send an event to current machine | ||
*/ | ||
send: (evt: StateMachine.Event<TEvent>) => void; | ||
transition: (state: TState["value"] | StateMachine.StateInfo<TContext, TState, TEvent> | null, evt: StateMachine.Event<TEvent>) => StateMachine.StateNode<TContext, TState, TEvent> | undefined; | ||
subscribe: (listener: StateMachine.StateListener<TContext, TState, TEvent>) => () => void; | ||
onDone: (listener: StateMachine.StateListener<TContext, TState, TEvent>) => this; | ||
onTransition: (listener: StateMachine.StateListener<TContext, TState, TEvent>) => this; | ||
onChange: (listener: StateMachine.ContextListener<TContext>) => this; | ||
onEvent: (listener: StateMachine.EventListener<TEvent>) => this; | ||
get [Symbol.toStringTag](): string; | ||
} | ||
declare type MachineSrc<TContext extends Dict, TState extends StateMachine.StateSchema, TEvent extends StateMachine.EventObject = StateMachine.AnyEventObject> = Machine<TContext, TState, TEvent> | (() => Machine<TContext, TState, TEvent>); | ||
declare type AnyMachine = Machine<Dict, StateMachine.StateSchema, StateMachine.AnyEventObject>; | ||
declare const createMachine: <TContext extends Dict<any>, TState extends StateMachine.StateSchema = StateMachine.StateSchema, TEvent extends StateMachine.EventObject = StateMachine.AnyEventObject>(config: StateMachine.MachineConfig<TContext, TState, TEvent>, options?: StateMachine.MachineOptions<TContext, TState, TEvent> | undefined) => Machine<TContext, TState, TEvent>; | ||
interface Props { | ||
[key: string]: any; | ||
} | ||
declare type TupleTypes<T extends any[]> = T[number]; | ||
declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; | ||
declare function mergeProps<T extends Props>(...args: T[]): UnionToIntersection<TupleTypes<T[]>>; | ||
declare type AnyFunction = (...args: any[]) => any; | ||
declare type ReturnTypeOrValue<T> = T extends AnyFunction ? ReturnType<T> : T; | ||
declare type StateFrom<T> = ReturnTypeOrValue<T> extends infer R ? R extends Machine<infer TContext, infer TState, infer TEvent> ? StateMachine.State<TContext, TState, TEvent> : never : never; | ||
declare type ContextFrom<T> = ReturnTypeOrValue<T> extends infer R ? R extends Machine<infer TContext, any, any> ? TContext : never : never; | ||
declare type EventFrom<T> = ReturnTypeOrValue<T> extends infer R ? R extends Machine<any, any, infer TEvent> ? TEvent : never : never; | ||
export { AnyMachine, ContextFrom, EventFrom, Machine, MachineSrc, StateFrom, StateMachine, choose, createMachine, guards, mergeProps }; |
1001
dist/index.js
"use strict"; | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __export = (target, all) => { | ||
@@ -36,6 +19,2 @@ for (var name in all) | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
var __publicField = (obj, key, value) => { | ||
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); | ||
return value; | ||
}; | ||
@@ -66,3 +45,3 @@ // src/index.ts | ||
const res = typeof v === "function" ? v(...a) : v; | ||
return res != null ? res : void 0; | ||
return res ?? void 0; | ||
}; | ||
@@ -84,3 +63,3 @@ var cast = (v) => v; | ||
})(); | ||
var isDev = () => void 0 !== "production"; | ||
var isDev = () => process.env.NODE_ENV !== "production"; | ||
var isArray = (v) => Array.isArray(v); | ||
@@ -94,3 +73,3 @@ var isObject = (v) => !(v == null || typeof v !== "object" || isArray(v)); | ||
const c = a.length === 2 ? a[0] : true; | ||
if (c && void 0 !== "production") { | ||
if (c && process.env.NODE_ENV !== "production") { | ||
console.warn(m); | ||
@@ -102,3 +81,3 @@ } | ||
const c = a.length === 2 ? a[0] : true; | ||
if (c && void 0 !== "production") { | ||
if (c && process.env.NODE_ENV !== "production") { | ||
throw new Error(m); | ||
@@ -173,4 +152,3 @@ } | ||
return (_a = actions.find((def) => { | ||
var _a2; | ||
const guard = (_a2 = def.guard) != null ? _a2 : Truthy; | ||
const guard = def.guard ?? Truthy; | ||
return exec(guardMap, ctx, event, meta)(guard); | ||
@@ -182,3 +160,3 @@ })) == null ? void 0 : _a.actions; | ||
function determineGuardFn(guard, guardMap) { | ||
guard = guard != null ? guard : Truthy; | ||
guard = guard ?? Truthy; | ||
return (context, event, meta) => { | ||
@@ -211,5 +189,4 @@ if (isString(guard)) { | ||
function createProxy(config) { | ||
var _a, _b; | ||
const computedContext = (_a = config.computed) != null ? _a : cast({}); | ||
const initialContext = (_b = config.context) != null ? _b : cast({}); | ||
const computedContext = config.computed ?? cast({}); | ||
const initialContext = config.context ?? cast({}); | ||
const state = (0, import_store2.proxy)({ | ||
@@ -233,6 +210,6 @@ value: "", | ||
get nextEvents() { | ||
var _a2, _b2, _c, _d; | ||
const stateEvents = (_c = (_b2 = (_a2 = config.states) == null ? void 0 : _a2[this.value]) == null ? void 0 : _b2["on"]) != null ? _c : {}; | ||
const globalEvents = (_d = config == null ? void 0 : config.on) != null ? _d : {}; | ||
return Object.keys(__spreadValues(__spreadValues({}, stateEvents), globalEvents)); | ||
var _a, _b; | ||
const stateEvents = ((_b = (_a = config.states) == null ? void 0 : _a[this.value]) == null ? void 0 : _b["on"]) ?? {}; | ||
const globalEvents = (config == null ? void 0 : config.on) ?? {}; | ||
return Object.keys({ ...stateEvents, ...globalEvents }); | ||
}, | ||
@@ -277,6 +254,5 @@ get changed() { | ||
return toArray(transitions).map(toTarget).find((transition) => { | ||
var _a; | ||
const determineGuard = determineGuardFn(transition.guard, guardMap); | ||
const guard = determineGuard(context, event, meta); | ||
return (_a = guard != null ? guard : transition.target) != null ? _a : transition.actions; | ||
return guard ?? transition.target ?? transition.actions; | ||
}); | ||
@@ -288,475 +264,39 @@ }; | ||
var Machine = class { | ||
status = "Not Started" /* NotStarted */; | ||
state; | ||
initialState; | ||
id; | ||
type = "machine" /* Machine */; | ||
activityEvents = /* @__PURE__ */ new Map(); | ||
delayedEvents = /* @__PURE__ */ new Map(); | ||
stateListeners = /* @__PURE__ */ new Set(); | ||
contextListeners = /* @__PURE__ */ new Set(); | ||
eventListeners = /* @__PURE__ */ new Set(); | ||
doneListeners = /* @__PURE__ */ new Set(); | ||
contextWatchers = /* @__PURE__ */ new Set(); | ||
removeStateListener = noop; | ||
removeEventListener = noop; | ||
removeContextListener = noop; | ||
parent; | ||
children = /* @__PURE__ */ new Map(); | ||
guardMap; | ||
actionMap; | ||
delayMap; | ||
activityMap; | ||
sync; | ||
options; | ||
config; | ||
constructor(config, options) { | ||
__publicField(this, "status", "Not Started" /* NotStarted */); | ||
__publicField(this, "state"); | ||
__publicField(this, "initialState"); | ||
__publicField(this, "id"); | ||
__publicField(this, "type", "machine" /* Machine */); | ||
__publicField(this, "activityEvents", /* @__PURE__ */ new Map()); | ||
__publicField(this, "delayedEvents", /* @__PURE__ */ new Map()); | ||
__publicField(this, "stateListeners", /* @__PURE__ */ new Set()); | ||
__publicField(this, "contextListeners", /* @__PURE__ */ new Set()); | ||
__publicField(this, "eventListeners", /* @__PURE__ */ new Set()); | ||
__publicField(this, "doneListeners", /* @__PURE__ */ new Set()); | ||
__publicField(this, "contextWatchers", /* @__PURE__ */ new Set()); | ||
__publicField(this, "removeStateListener", noop); | ||
__publicField(this, "removeEventListener", noop); | ||
__publicField(this, "removeContextListener", noop); | ||
__publicField(this, "parent"); | ||
__publicField(this, "children", /* @__PURE__ */ new Map()); | ||
__publicField(this, "guardMap"); | ||
__publicField(this, "actionMap"); | ||
__publicField(this, "delayMap"); | ||
__publicField(this, "activityMap"); | ||
__publicField(this, "sync"); | ||
__publicField(this, "options"); | ||
__publicField(this, "config"); | ||
__publicField(this, "start", (init) => { | ||
if (this.status === "Running" /* Running */) { | ||
return this; | ||
} | ||
this.status = "Running" /* Running */; | ||
this.removeStateListener = (0, import_store3.subscribe)(this.state, () => { | ||
this.stateListeners.forEach((listener) => { | ||
listener(this.stateSnapshot); | ||
}); | ||
}, this.sync); | ||
this.removeEventListener = subscribeKey(this.state, "event", (event2) => { | ||
this.executeActions(this.config.onEvent, event2); | ||
this.eventListeners.forEach((listener) => { | ||
listener(event2); | ||
}); | ||
}, this.sync); | ||
this.removeContextListener = (0, import_store3.subscribe)(this.state.context, () => { | ||
this.log("Context:", this.contextSnapshot); | ||
this.contextListeners.forEach((listener) => { | ||
listener(this.contextSnapshot); | ||
}); | ||
}, this.sync || this.options.debug); | ||
this.setupContextWatchers(); | ||
this.executeActivities(toEvent("machine.start" /* Start */), toArray(this.config.activities), "machine.start" /* Start */); | ||
this.executeActions(this.config.entry, toEvent("machine.start" /* Start */)); | ||
const event = toEvent("machine.init" /* Init */); | ||
const target = isObject(init) ? init.value : init; | ||
const context = isObject(init) ? init.context : void 0; | ||
if (context) { | ||
this.setContext(context); | ||
} | ||
const transition = { | ||
target: target != null ? target : this.config.initial | ||
}; | ||
const next = this.getNextStateInfo(transition, event); | ||
this.initialState = next; | ||
this.performStateChangeEffects(this.state.value, next, event); | ||
return this; | ||
}); | ||
__publicField(this, "setupContextWatchers", () => { | ||
var _a; | ||
for (const [key, fn] of Object.entries((_a = this.config.watch) != null ? _a : {})) { | ||
this.contextWatchers.add(subscribeKey(this.state.context, key, () => { | ||
this.executeActions(fn, this.state.event); | ||
})); | ||
} | ||
}); | ||
__publicField(this, "stop", () => { | ||
if (this.status === "Stopped" /* Stopped */) | ||
return; | ||
this.performExitEffects(this.state.value, toEvent("machine.stop" /* Stop */)); | ||
this.executeActions(this.config.exit, toEvent("machine.stop" /* Stop */)); | ||
this.setState(""); | ||
this.setEvent("machine.stop" /* Stop */); | ||
this.stopStateListeners(); | ||
this.stopChildren(); | ||
this.stopActivities(); | ||
this.stopDelayedEvents(); | ||
this.stopContextWatchers(); | ||
this.stopEventListeners(); | ||
this.stopContextListeners(); | ||
this.status = "Stopped" /* Stopped */; | ||
return this; | ||
}); | ||
__publicField(this, "stopEventListeners", () => { | ||
this.eventListeners.clear(); | ||
this.removeEventListener(); | ||
}); | ||
__publicField(this, "stopContextListeners", () => { | ||
this.contextListeners.clear(); | ||
this.removeContextListener(); | ||
}); | ||
__publicField(this, "stopStateListeners", () => { | ||
this.removeStateListener(); | ||
this.stateListeners.clear(); | ||
}); | ||
__publicField(this, "stopContextWatchers", () => { | ||
this.contextWatchers.forEach((fn) => fn()); | ||
this.contextWatchers.clear(); | ||
}); | ||
__publicField(this, "stopDelayedEvents", () => { | ||
this.delayedEvents.forEach((state) => { | ||
state.forEach((stop) => stop()); | ||
}); | ||
this.delayedEvents.clear(); | ||
}); | ||
__publicField(this, "stopActivities", (state) => { | ||
var _a, _b; | ||
if (state) { | ||
(_a = this.activityEvents.get(state)) == null ? void 0 : _a.forEach((stop) => stop()); | ||
(_b = this.activityEvents.get(state)) == null ? void 0 : _b.clear(); | ||
this.activityEvents.delete(state); | ||
} else { | ||
this.activityEvents.forEach((state2) => { | ||
state2.forEach((stop) => stop()); | ||
state2.clear(); | ||
}); | ||
this.activityEvents.clear(); | ||
} | ||
}); | ||
__publicField(this, "sendChild", (evt, to) => { | ||
const event = toEvent(evt); | ||
const id = runIfFn(to, this.contextSnapshot); | ||
const child = this.children.get(id); | ||
if (!child) { | ||
invariant(`[@zag-js/core] Cannot send '${event.type}' event to unknown child`); | ||
} | ||
child.send(event); | ||
}); | ||
__publicField(this, "stopChild", (id) => { | ||
if (!this.children.has(id)) { | ||
invariant(`[@zag-js/core > stop-child] Cannot stop unknown child ${id}`); | ||
} | ||
this.children.get(id).stop(); | ||
this.children.delete(id); | ||
}); | ||
__publicField(this, "removeChild", (id) => { | ||
this.children.delete(id); | ||
}); | ||
__publicField(this, "stopChildren", () => { | ||
this.children.forEach((child) => child.stop()); | ||
this.children.clear(); | ||
}); | ||
__publicField(this, "setParent", (parent) => { | ||
this.parent = parent; | ||
}); | ||
__publicField(this, "spawn", (src, id) => { | ||
const actor = runIfFn(src); | ||
if (id) | ||
actor.id = id; | ||
actor.type = "machine.actor" /* Actor */; | ||
actor.setParent(this); | ||
this.children.set(actor.id, cast(actor)); | ||
actor.onDone(() => { | ||
this.removeChild(actor.id); | ||
}).start(); | ||
return cast((0, import_store3.ref)(actor)); | ||
}); | ||
__publicField(this, "addActivityCleanup", (state, cleanup) => { | ||
var _a; | ||
if (!state) | ||
return; | ||
if (!this.activityEvents.has(state)) { | ||
this.activityEvents.set(state, /* @__PURE__ */ new Set([cleanup])); | ||
} else { | ||
(_a = this.activityEvents.get(state)) == null ? void 0 : _a.add(cleanup); | ||
} | ||
}); | ||
__publicField(this, "setState", (target) => { | ||
this.state.previousValue = this.state.value; | ||
this.state.value = target; | ||
const stateNode = this.getStateNode(target); | ||
if (target == null) { | ||
clear(this.state.tags); | ||
} else { | ||
this.state.tags = toArray(stateNode == null ? void 0 : stateNode.tags); | ||
} | ||
}); | ||
__publicField(this, "setContext", (context) => { | ||
if (!context) | ||
return; | ||
for (const key in context) { | ||
this.state.context[key] = context[key]; | ||
} | ||
}); | ||
__publicField(this, "withContext", (context) => { | ||
const newContext = __spreadValues(__spreadValues({}, this.config.context), context); | ||
return new Machine(__spreadProps(__spreadValues({}, this.config), { context: newContext }), this.options); | ||
}); | ||
__publicField(this, "setActions", (actions) => { | ||
this.actionMap = __spreadValues(__spreadValues({}, this.actionMap), actions); | ||
}); | ||
__publicField(this, "getStateNode", (state) => { | ||
var _a; | ||
if (!state) | ||
return; | ||
return (_a = this.config.states) == null ? void 0 : _a[state]; | ||
}); | ||
__publicField(this, "getNextStateInfo", (transitions, event) => { | ||
var _a; | ||
const transition = this.determineTransition(transitions, event); | ||
const isTargetless = !(transition == null ? void 0 : transition.target); | ||
const target = (_a = transition == null ? void 0 : transition.target) != null ? _a : this.state.value; | ||
const changed = this.state.value !== target; | ||
const stateNode = this.getStateNode(target); | ||
const reenter = !isTargetless && !changed && !(transition == null ? void 0 : transition.internal); | ||
const info = { | ||
reenter, | ||
transition, | ||
stateNode, | ||
target, | ||
changed | ||
}; | ||
this.log("NextState:", `[${event.type}]`, this.state.value, "---->", info.target); | ||
return info; | ||
}); | ||
__publicField(this, "getActionFromDelayedTransition", (transition) => { | ||
const event = toEvent("machine.after" /* After */); | ||
const determineDelay = determineDelayFn(transition.delay, this.delayMap); | ||
const delay = determineDelay(this.contextSnapshot, event); | ||
let id; | ||
return { | ||
entry: () => { | ||
id = globalThis.setTimeout(() => { | ||
const next = this.getNextStateInfo(transition, event); | ||
this.performStateChangeEffects(this.state.value, next, event); | ||
}, delay); | ||
}, | ||
exit: () => { | ||
globalThis.clearTimeout(id); | ||
} | ||
}; | ||
}); | ||
__publicField(this, "getDelayedEventActions", (state) => { | ||
const stateNode = this.getStateNode(state); | ||
const event = toEvent("machine.after" /* After */); | ||
if (!stateNode || !stateNode.after) | ||
return; | ||
const entries = []; | ||
const exits = []; | ||
if (isArray(stateNode.after)) { | ||
const transition = this.determineTransition(stateNode.after, event); | ||
if (!transition) | ||
return; | ||
const actions = this.getActionFromDelayedTransition(transition); | ||
entries.push(actions.entry); | ||
exits.push(actions.exit); | ||
} else if (isObject(stateNode.after)) { | ||
for (const delay in stateNode.after) { | ||
const transition = stateNode.after[delay]; | ||
let resolvedTransition = {}; | ||
if (isArray(transition)) { | ||
const picked = this.determineTransition(transition, event); | ||
if (picked) | ||
resolvedTransition = picked; | ||
} else if (isString(transition)) { | ||
resolvedTransition = { target: transition, delay }; | ||
} else { | ||
resolvedTransition = __spreadProps(__spreadValues({}, transition), { delay }); | ||
} | ||
const actions = this.getActionFromDelayedTransition(resolvedTransition); | ||
entries.push(actions.entry); | ||
exits.push(actions.exit); | ||
} | ||
} | ||
return { entries, exits }; | ||
}); | ||
__publicField(this, "executeActions", (actions, event) => { | ||
var _a; | ||
const _actions = determineActionsFn(actions, this.guardMap)(this.contextSnapshot, event, this.guardMeta); | ||
for (const action of toArray(_actions)) { | ||
const fn = isString(action) ? (_a = this.actionMap) == null ? void 0 : _a[action] : action; | ||
warn(isString(action) && !fn, `[@zag-js/core > execute-actions] No implementation found for action: \`${action}\``); | ||
fn == null ? void 0 : fn(this.state.context, event, this.meta); | ||
} | ||
}); | ||
__publicField(this, "executeActivities", (event, activities, state) => { | ||
var _a; | ||
for (const activity of activities) { | ||
const fn = isString(activity) ? (_a = this.activityMap) == null ? void 0 : _a[activity] : activity; | ||
if (!fn) { | ||
warn(`[@zag-js/core > execute-activity] No implementation found for activity: \`${activity}\``); | ||
continue; | ||
} | ||
const cleanup = fn(this.state.context, event, this.meta); | ||
if (cleanup) { | ||
this.addActivityCleanup(state != null ? state : this.state.value, cleanup); | ||
} | ||
} | ||
}); | ||
__publicField(this, "createEveryActivities", (every, callbackfn) => { | ||
if (!every) | ||
return; | ||
const event = toEvent("machine.every" /* Every */); | ||
if (isArray(every)) { | ||
const picked = toArray(every).find((transition) => { | ||
const delayOrFn = transition.delay; | ||
const determineDelay2 = determineDelayFn(delayOrFn, this.delayMap); | ||
const delay2 = determineDelay2(this.contextSnapshot, event); | ||
const determineGuard = determineGuardFn(transition.guard, this.guardMap); | ||
const guard = determineGuard(this.contextSnapshot, event, this.guardMeta); | ||
return guard != null ? guard : delay2 != null; | ||
}); | ||
if (!picked) | ||
return; | ||
const determineDelay = determineDelayFn(picked.delay, this.delayMap); | ||
const delay = determineDelay(this.contextSnapshot, event); | ||
const activity = () => { | ||
const id = globalThis.setInterval(() => { | ||
this.executeActions(picked.actions, event); | ||
}, delay); | ||
return () => { | ||
globalThis.clearInterval(id); | ||
}; | ||
}; | ||
callbackfn(activity); | ||
} else { | ||
for (const interval in every) { | ||
const actions = every == null ? void 0 : every[interval]; | ||
const determineDelay = determineDelayFn(interval, this.delayMap); | ||
const delay = determineDelay(this.contextSnapshot, event); | ||
const activity = () => { | ||
const id = globalThis.setInterval(() => { | ||
this.executeActions(actions, event); | ||
}, delay); | ||
return () => { | ||
globalThis.clearInterval(id); | ||
}; | ||
}; | ||
callbackfn(activity); | ||
} | ||
} | ||
}); | ||
__publicField(this, "setEvent", (event) => { | ||
this.state.previousEvent = this.state.event; | ||
this.state.event = (0, import_store3.ref)(toEvent(event)); | ||
}); | ||
__publicField(this, "performExitEffects", (current, event) => { | ||
const currentState = this.state.value; | ||
if (currentState === "") | ||
return; | ||
const stateNode = current ? this.getStateNode(current) : void 0; | ||
this.stopActivities(currentState); | ||
const _exit = determineActionsFn(stateNode == null ? void 0 : stateNode.exit, this.guardMap)(this.contextSnapshot, event, this.guardMeta); | ||
const exitActions = toArray(_exit); | ||
const afterExitActions = this.delayedEvents.get(currentState); | ||
if (afterExitActions) { | ||
exitActions.push(...afterExitActions); | ||
} | ||
this.executeActions(exitActions, event); | ||
this.eventListeners.clear(); | ||
}); | ||
__publicField(this, "performEntryEffects", (next, event) => { | ||
const stateNode = this.getStateNode(next); | ||
const activities = toArray(stateNode == null ? void 0 : stateNode.activities); | ||
this.createEveryActivities(stateNode == null ? void 0 : stateNode.every, (activity) => { | ||
activities.unshift(activity); | ||
}); | ||
if (activities.length > 0) { | ||
this.executeActivities(event, activities); | ||
} | ||
const _entry = determineActionsFn(stateNode == null ? void 0 : stateNode.entry, this.guardMap)(this.contextSnapshot, event, this.guardMeta); | ||
const entryActions = toArray(_entry); | ||
const afterActions = this.getDelayedEventActions(next); | ||
if ((stateNode == null ? void 0 : stateNode.after) && afterActions) { | ||
this.delayedEvents.set(next, afterActions == null ? void 0 : afterActions.exits); | ||
entryActions.push(...afterActions.entries); | ||
} | ||
this.executeActions(entryActions, event); | ||
if ((stateNode == null ? void 0 : stateNode.type) === "final") { | ||
this.state.done = true; | ||
this.doneListeners.forEach((listener) => { | ||
listener(this.stateSnapshot); | ||
}); | ||
this.stop(); | ||
} | ||
}); | ||
__publicField(this, "performTransitionEffects", (transitions, event) => { | ||
const transition = this.determineTransition(transitions, event); | ||
this.executeActions(transition == null ? void 0 : transition.actions, event); | ||
}); | ||
__publicField(this, "performStateChangeEffects", (current, next, event) => { | ||
this.setEvent(event); | ||
const changed = next.changed || next.reenter; | ||
if (changed) { | ||
this.performExitEffects(current, event); | ||
} | ||
this.performTransitionEffects(next.transition, event); | ||
this.setState(next.target); | ||
if (changed) { | ||
this.performEntryEffects(next.target, event); | ||
} | ||
}); | ||
__publicField(this, "determineTransition", (transition, event) => { | ||
const fn = determineTransitionFn(transition, this.guardMap); | ||
return fn == null ? void 0 : fn(this.contextSnapshot, event, this.guardMeta); | ||
}); | ||
__publicField(this, "sendParent", (evt) => { | ||
var _a; | ||
if (!this.parent) { | ||
invariant("[@zag-js/core > send-parent] Cannot send event to an unknown parent"); | ||
} | ||
const event = toEvent(evt); | ||
(_a = this.parent) == null ? void 0 : _a.send(event); | ||
}); | ||
__publicField(this, "log", (...args) => { | ||
if (isDev() && this.options.debug) { | ||
console.log(...args); | ||
} | ||
}); | ||
__publicField(this, "send", (evt) => { | ||
const event = toEvent(evt); | ||
this.transition(this.state.value, event); | ||
}); | ||
__publicField(this, "transition", (state, evt) => { | ||
var _a, _b, _c; | ||
const stateNode = isString(state) ? this.getStateNode(state) : state == null ? void 0 : state.stateNode; | ||
const event = toEvent(evt); | ||
if (!stateNode && !this.config.on) { | ||
const msg = this.status === "Stopped" /* Stopped */ ? "[@zag-js/core > transition] Cannot transition a stopped machine" : `[@zag-js/core > transition] State does not have a definition for \`state\`: ${state}, \`event\`: ${event.type}`; | ||
warn(msg); | ||
return; | ||
} | ||
const transitions = (_c = (_a = stateNode == null ? void 0 : stateNode.on) == null ? void 0 : _a[event.type]) != null ? _c : (_b = this.config.on) == null ? void 0 : _b[event.type]; | ||
const next = this.getNextStateInfo(transitions, event); | ||
this.performStateChangeEffects(this.state.value, next, event); | ||
return next.stateNode; | ||
}); | ||
__publicField(this, "subscribe", (listener) => { | ||
this.stateListeners.add(listener); | ||
if (this.status === "Running" /* Running */) { | ||
listener(this.stateSnapshot); | ||
} | ||
return () => { | ||
this.stateListeners.delete(listener); | ||
}; | ||
}); | ||
__publicField(this, "onDone", (listener) => { | ||
this.doneListeners.add(listener); | ||
return this; | ||
}); | ||
__publicField(this, "onTransition", (listener) => { | ||
this.stateListeners.add(listener); | ||
if (this.status === "Running" /* Running */) { | ||
listener(this.stateSnapshot); | ||
} | ||
return this; | ||
}); | ||
__publicField(this, "onChange", (listener) => { | ||
this.contextListeners.add(listener); | ||
return this; | ||
}); | ||
__publicField(this, "onEvent", (listener) => { | ||
this.eventListeners.add(listener); | ||
return this; | ||
}); | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l; | ||
var _a, _b, _c, _d, _e, _f; | ||
this.config = (0, import_json.klona)(config); | ||
this.options = (0, import_json.klona)(options != null ? options : {}); | ||
this.id = (_a = this.config.id) != null ? _a : `machine-${uuid()}`; | ||
this.guardMap = (_c = (_b = this.options) == null ? void 0 : _b.guards) != null ? _c : {}; | ||
this.actionMap = (_e = (_d = this.options) == null ? void 0 : _d.actions) != null ? _e : {}; | ||
this.delayMap = (_g = (_f = this.options) == null ? void 0 : _f.delays) != null ? _g : {}; | ||
this.activityMap = (_i = (_h = this.options) == null ? void 0 : _h.activities) != null ? _i : {}; | ||
this.sync = (_k = (_j = this.options) == null ? void 0 : _j.sync) != null ? _k : false; | ||
this.options = (0, import_json.klona)(options ?? {}); | ||
this.id = this.config.id ?? `machine-${uuid()}`; | ||
this.guardMap = ((_a = this.options) == null ? void 0 : _a.guards) ?? {}; | ||
this.actionMap = ((_b = this.options) == null ? void 0 : _b.actions) ?? {}; | ||
this.delayMap = ((_c = this.options) == null ? void 0 : _c.delays) ?? {}; | ||
this.activityMap = ((_d = this.options) == null ? void 0 : _d.activities) ?? {}; | ||
this.sync = ((_e = this.options) == null ? void 0 : _e.sync) ?? false; | ||
this.state = createProxy(this.config); | ||
const event = toEvent("machine.created" /* Created */); | ||
this.executeActions((_l = this.config) == null ? void 0 : _l.created, event); | ||
this.executeActions((_f = this.config) == null ? void 0 : _f.created, event); | ||
} | ||
@@ -772,2 +312,247 @@ get stateSnapshot() { | ||
} | ||
start = (init) => { | ||
if (this.status === "Running" /* Running */) { | ||
return this; | ||
} | ||
this.status = "Running" /* Running */; | ||
this.removeStateListener = (0, import_store3.subscribe)(this.state, () => { | ||
this.stateListeners.forEach((listener) => { | ||
listener(this.stateSnapshot); | ||
}); | ||
}, this.sync); | ||
this.removeEventListener = subscribeKey(this.state, "event", (event2) => { | ||
this.executeActions(this.config.onEvent, event2); | ||
this.eventListeners.forEach((listener) => { | ||
listener(event2); | ||
}); | ||
}, this.sync); | ||
this.removeContextListener = (0, import_store3.subscribe)(this.state.context, () => { | ||
this.log("Context:", this.contextSnapshot); | ||
this.contextListeners.forEach((listener) => { | ||
listener(this.contextSnapshot); | ||
}); | ||
}, this.sync || this.options.debug); | ||
this.setupContextWatchers(); | ||
this.executeActivities(toEvent("machine.start" /* Start */), toArray(this.config.activities), "machine.start" /* Start */); | ||
this.executeActions(this.config.entry, toEvent("machine.start" /* Start */)); | ||
const event = toEvent("machine.init" /* Init */); | ||
const target = isObject(init) ? init.value : init; | ||
const context = isObject(init) ? init.context : void 0; | ||
if (context) { | ||
this.setContext(context); | ||
} | ||
const transition = { | ||
target: target ?? this.config.initial | ||
}; | ||
const next = this.getNextStateInfo(transition, event); | ||
this.initialState = next; | ||
this.performStateChangeEffects(this.state.value, next, event); | ||
return this; | ||
}; | ||
setupContextWatchers = () => { | ||
for (const [key, fn] of Object.entries(this.config.watch ?? {})) { | ||
this.contextWatchers.add(subscribeKey(this.state.context, key, () => { | ||
this.executeActions(fn, this.state.event); | ||
})); | ||
} | ||
}; | ||
stop = () => { | ||
if (this.status === "Stopped" /* Stopped */) | ||
return; | ||
this.performExitEffects(this.state.value, toEvent("machine.stop" /* Stop */)); | ||
this.executeActions(this.config.exit, toEvent("machine.stop" /* Stop */)); | ||
this.setState(""); | ||
this.setEvent("machine.stop" /* Stop */); | ||
this.stopStateListeners(); | ||
this.stopChildren(); | ||
this.stopActivities(); | ||
this.stopDelayedEvents(); | ||
this.stopContextWatchers(); | ||
this.stopEventListeners(); | ||
this.stopContextListeners(); | ||
this.status = "Stopped" /* Stopped */; | ||
return this; | ||
}; | ||
stopEventListeners = () => { | ||
this.eventListeners.clear(); | ||
this.removeEventListener(); | ||
}; | ||
stopContextListeners = () => { | ||
this.contextListeners.clear(); | ||
this.removeContextListener(); | ||
}; | ||
stopStateListeners = () => { | ||
this.removeStateListener(); | ||
this.stateListeners.clear(); | ||
}; | ||
stopContextWatchers = () => { | ||
this.contextWatchers.forEach((fn) => fn()); | ||
this.contextWatchers.clear(); | ||
}; | ||
stopDelayedEvents = () => { | ||
this.delayedEvents.forEach((state) => { | ||
state.forEach((stop) => stop()); | ||
}); | ||
this.delayedEvents.clear(); | ||
}; | ||
stopActivities = (state) => { | ||
var _a, _b; | ||
if (state) { | ||
(_a = this.activityEvents.get(state)) == null ? void 0 : _a.forEach((stop) => stop()); | ||
(_b = this.activityEvents.get(state)) == null ? void 0 : _b.clear(); | ||
this.activityEvents.delete(state); | ||
} else { | ||
this.activityEvents.forEach((state2) => { | ||
state2.forEach((stop) => stop()); | ||
state2.clear(); | ||
}); | ||
this.activityEvents.clear(); | ||
} | ||
}; | ||
sendChild = (evt, to) => { | ||
const event = toEvent(evt); | ||
const id = runIfFn(to, this.contextSnapshot); | ||
const child = this.children.get(id); | ||
if (!child) { | ||
invariant(`[@zag-js/core] Cannot send '${event.type}' event to unknown child`); | ||
} | ||
child.send(event); | ||
}; | ||
stopChild = (id) => { | ||
if (!this.children.has(id)) { | ||
invariant(`[@zag-js/core > stop-child] Cannot stop unknown child ${id}`); | ||
} | ||
this.children.get(id).stop(); | ||
this.children.delete(id); | ||
}; | ||
removeChild = (id) => { | ||
this.children.delete(id); | ||
}; | ||
stopChildren = () => { | ||
this.children.forEach((child) => child.stop()); | ||
this.children.clear(); | ||
}; | ||
setParent = (parent) => { | ||
this.parent = parent; | ||
}; | ||
spawn = (src, id) => { | ||
const actor = runIfFn(src); | ||
if (id) | ||
actor.id = id; | ||
actor.type = "machine.actor" /* Actor */; | ||
actor.setParent(this); | ||
this.children.set(actor.id, cast(actor)); | ||
actor.onDone(() => { | ||
this.removeChild(actor.id); | ||
}).start(); | ||
return cast((0, import_store3.ref)(actor)); | ||
}; | ||
addActivityCleanup = (state, cleanup) => { | ||
var _a; | ||
if (!state) | ||
return; | ||
if (!this.activityEvents.has(state)) { | ||
this.activityEvents.set(state, /* @__PURE__ */ new Set([cleanup])); | ||
} else { | ||
(_a = this.activityEvents.get(state)) == null ? void 0 : _a.add(cleanup); | ||
} | ||
}; | ||
setState = (target) => { | ||
this.state.previousValue = this.state.value; | ||
this.state.value = target; | ||
const stateNode = this.getStateNode(target); | ||
if (target == null) { | ||
clear(this.state.tags); | ||
} else { | ||
this.state.tags = toArray(stateNode == null ? void 0 : stateNode.tags); | ||
} | ||
}; | ||
setContext = (context) => { | ||
if (!context) | ||
return; | ||
for (const key in context) { | ||
this.state.context[key] = context[key]; | ||
} | ||
}; | ||
withContext = (context) => { | ||
const newContext = { ...this.config.context, ...context }; | ||
return new Machine({ ...this.config, context: newContext }, this.options); | ||
}; | ||
setActions = (actions) => { | ||
this.actionMap = { ...this.actionMap, ...actions }; | ||
}; | ||
getStateNode = (state) => { | ||
var _a; | ||
if (!state) | ||
return; | ||
return (_a = this.config.states) == null ? void 0 : _a[state]; | ||
}; | ||
getNextStateInfo = (transitions, event) => { | ||
const transition = this.determineTransition(transitions, event); | ||
const isTargetless = !(transition == null ? void 0 : transition.target); | ||
const target = (transition == null ? void 0 : transition.target) ?? this.state.value; | ||
const changed = this.state.value !== target; | ||
const stateNode = this.getStateNode(target); | ||
const reenter = !isTargetless && !changed && !(transition == null ? void 0 : transition.internal); | ||
const info = { | ||
reenter, | ||
transition, | ||
stateNode, | ||
target, | ||
changed | ||
}; | ||
this.log("NextState:", `[${event.type}]`, this.state.value, "---->", info.target); | ||
return info; | ||
}; | ||
getActionFromDelayedTransition = (transition) => { | ||
const event = toEvent("machine.after" /* After */); | ||
const determineDelay = determineDelayFn(transition.delay, this.delayMap); | ||
const delay = determineDelay(this.contextSnapshot, event); | ||
let id; | ||
return { | ||
entry: () => { | ||
id = globalThis.setTimeout(() => { | ||
const next = this.getNextStateInfo(transition, event); | ||
this.performStateChangeEffects(this.state.value, next, event); | ||
}, delay); | ||
}, | ||
exit: () => { | ||
globalThis.clearTimeout(id); | ||
} | ||
}; | ||
}; | ||
getDelayedEventActions = (state) => { | ||
const stateNode = this.getStateNode(state); | ||
const event = toEvent("machine.after" /* After */); | ||
if (!stateNode || !stateNode.after) | ||
return; | ||
const entries = []; | ||
const exits = []; | ||
if (isArray(stateNode.after)) { | ||
const transition = this.determineTransition(stateNode.after, event); | ||
if (!transition) | ||
return; | ||
const actions = this.getActionFromDelayedTransition(transition); | ||
entries.push(actions.entry); | ||
exits.push(actions.exit); | ||
} else if (isObject(stateNode.after)) { | ||
for (const delay in stateNode.after) { | ||
const transition = stateNode.after[delay]; | ||
let resolvedTransition = {}; | ||
if (isArray(transition)) { | ||
const picked = this.determineTransition(transition, event); | ||
if (picked) | ||
resolvedTransition = picked; | ||
} else if (isString(transition)) { | ||
resolvedTransition = { target: transition, delay }; | ||
} else { | ||
resolvedTransition = { ...transition, delay }; | ||
} | ||
const actions = this.getActionFromDelayedTransition(resolvedTransition); | ||
entries.push(actions.entry); | ||
exits.push(actions.exit); | ||
} | ||
} | ||
return { entries, exits }; | ||
}; | ||
get self() { | ||
@@ -804,2 +589,191 @@ const _self = this; | ||
} | ||
executeActions = (actions, event) => { | ||
var _a; | ||
const _actions = determineActionsFn(actions, this.guardMap)(this.contextSnapshot, event, this.guardMeta); | ||
for (const action of toArray(_actions)) { | ||
const fn = isString(action) ? (_a = this.actionMap) == null ? void 0 : _a[action] : action; | ||
warn(isString(action) && !fn, `[@zag-js/core > execute-actions] No implementation found for action: \`${action}\``); | ||
fn == null ? void 0 : fn(this.state.context, event, this.meta); | ||
} | ||
}; | ||
executeActivities = (event, activities, state) => { | ||
var _a; | ||
for (const activity of activities) { | ||
const fn = isString(activity) ? (_a = this.activityMap) == null ? void 0 : _a[activity] : activity; | ||
if (!fn) { | ||
warn(`[@zag-js/core > execute-activity] No implementation found for activity: \`${activity}\``); | ||
continue; | ||
} | ||
const cleanup = fn(this.state.context, event, this.meta); | ||
if (cleanup) { | ||
this.addActivityCleanup(state ?? this.state.value, cleanup); | ||
} | ||
} | ||
}; | ||
createEveryActivities = (every, callbackfn) => { | ||
if (!every) | ||
return; | ||
const event = toEvent("machine.every" /* Every */); | ||
if (isArray(every)) { | ||
const picked = toArray(every).find((transition) => { | ||
const delayOrFn = transition.delay; | ||
const determineDelay2 = determineDelayFn(delayOrFn, this.delayMap); | ||
const delay2 = determineDelay2(this.contextSnapshot, event); | ||
const determineGuard = determineGuardFn(transition.guard, this.guardMap); | ||
const guard = determineGuard(this.contextSnapshot, event, this.guardMeta); | ||
return guard ?? delay2 != null; | ||
}); | ||
if (!picked) | ||
return; | ||
const determineDelay = determineDelayFn(picked.delay, this.delayMap); | ||
const delay = determineDelay(this.contextSnapshot, event); | ||
const activity = () => { | ||
const id = globalThis.setInterval(() => { | ||
this.executeActions(picked.actions, event); | ||
}, delay); | ||
return () => { | ||
globalThis.clearInterval(id); | ||
}; | ||
}; | ||
callbackfn(activity); | ||
} else { | ||
for (const interval in every) { | ||
const actions = every == null ? void 0 : every[interval]; | ||
const determineDelay = determineDelayFn(interval, this.delayMap); | ||
const delay = determineDelay(this.contextSnapshot, event); | ||
const activity = () => { | ||
const id = globalThis.setInterval(() => { | ||
this.executeActions(actions, event); | ||
}, delay); | ||
return () => { | ||
globalThis.clearInterval(id); | ||
}; | ||
}; | ||
callbackfn(activity); | ||
} | ||
} | ||
}; | ||
setEvent = (event) => { | ||
this.state.previousEvent = this.state.event; | ||
this.state.event = (0, import_store3.ref)(toEvent(event)); | ||
}; | ||
performExitEffects = (current, event) => { | ||
const currentState = this.state.value; | ||
if (currentState === "") | ||
return; | ||
const stateNode = current ? this.getStateNode(current) : void 0; | ||
this.stopActivities(currentState); | ||
const _exit = determineActionsFn(stateNode == null ? void 0 : stateNode.exit, this.guardMap)(this.contextSnapshot, event, this.guardMeta); | ||
const exitActions = toArray(_exit); | ||
const afterExitActions = this.delayedEvents.get(currentState); | ||
if (afterExitActions) { | ||
exitActions.push(...afterExitActions); | ||
} | ||
this.executeActions(exitActions, event); | ||
this.eventListeners.clear(); | ||
}; | ||
performEntryEffects = (next, event) => { | ||
const stateNode = this.getStateNode(next); | ||
const activities = toArray(stateNode == null ? void 0 : stateNode.activities); | ||
this.createEveryActivities(stateNode == null ? void 0 : stateNode.every, (activity) => { | ||
activities.unshift(activity); | ||
}); | ||
if (activities.length > 0) { | ||
this.executeActivities(event, activities); | ||
} | ||
const _entry = determineActionsFn(stateNode == null ? void 0 : stateNode.entry, this.guardMap)(this.contextSnapshot, event, this.guardMeta); | ||
const entryActions = toArray(_entry); | ||
const afterActions = this.getDelayedEventActions(next); | ||
if ((stateNode == null ? void 0 : stateNode.after) && afterActions) { | ||
this.delayedEvents.set(next, afterActions == null ? void 0 : afterActions.exits); | ||
entryActions.push(...afterActions.entries); | ||
} | ||
this.executeActions(entryActions, event); | ||
if ((stateNode == null ? void 0 : stateNode.type) === "final") { | ||
this.state.done = true; | ||
this.doneListeners.forEach((listener) => { | ||
listener(this.stateSnapshot); | ||
}); | ||
this.stop(); | ||
} | ||
}; | ||
performTransitionEffects = (transitions, event) => { | ||
const transition = this.determineTransition(transitions, event); | ||
this.executeActions(transition == null ? void 0 : transition.actions, event); | ||
}; | ||
performStateChangeEffects = (current, next, event) => { | ||
this.setEvent(event); | ||
const changed = next.changed || next.reenter; | ||
if (changed) { | ||
this.performExitEffects(current, event); | ||
} | ||
this.performTransitionEffects(next.transition, event); | ||
this.setState(next.target); | ||
if (changed) { | ||
this.performEntryEffects(next.target, event); | ||
} | ||
}; | ||
determineTransition = (transition, event) => { | ||
const fn = determineTransitionFn(transition, this.guardMap); | ||
return fn == null ? void 0 : fn(this.contextSnapshot, event, this.guardMeta); | ||
}; | ||
sendParent = (evt) => { | ||
var _a; | ||
if (!this.parent) { | ||
invariant("[@zag-js/core > send-parent] Cannot send event to an unknown parent"); | ||
} | ||
const event = toEvent(evt); | ||
(_a = this.parent) == null ? void 0 : _a.send(event); | ||
}; | ||
log = (...args) => { | ||
if (isDev() && this.options.debug) { | ||
console.log(...args); | ||
} | ||
}; | ||
send = (evt) => { | ||
const event = toEvent(evt); | ||
this.transition(this.state.value, event); | ||
}; | ||
transition = (state, evt) => { | ||
var _a, _b; | ||
const stateNode = isString(state) ? this.getStateNode(state) : state == null ? void 0 : state.stateNode; | ||
const event = toEvent(evt); | ||
if (!stateNode && !this.config.on) { | ||
const msg = this.status === "Stopped" /* Stopped */ ? "[@zag-js/core > transition] Cannot transition a stopped machine" : `[@zag-js/core > transition] State does not have a definition for \`state\`: ${state}, \`event\`: ${event.type}`; | ||
warn(msg); | ||
return; | ||
} | ||
const transitions = ((_a = stateNode == null ? void 0 : stateNode.on) == null ? void 0 : _a[event.type]) ?? ((_b = this.config.on) == null ? void 0 : _b[event.type]); | ||
const next = this.getNextStateInfo(transitions, event); | ||
this.performStateChangeEffects(this.state.value, next, event); | ||
return next.stateNode; | ||
}; | ||
subscribe = (listener) => { | ||
this.stateListeners.add(listener); | ||
if (this.status === "Running" /* Running */) { | ||
listener(this.stateSnapshot); | ||
} | ||
return () => { | ||
this.stateListeners.delete(listener); | ||
}; | ||
}; | ||
onDone = (listener) => { | ||
this.doneListeners.add(listener); | ||
return this; | ||
}; | ||
onTransition = (listener) => { | ||
this.stateListeners.add(listener); | ||
if (this.status === "Running" /* Running */) { | ||
listener(this.stateSnapshot); | ||
} | ||
return this; | ||
}; | ||
onChange = (listener) => { | ||
this.contextListeners.add(listener); | ||
return this; | ||
}; | ||
onEvent = (listener) => { | ||
this.eventListeners.add(listener); | ||
return this; | ||
}; | ||
get [Symbol.toStringTag]() { | ||
@@ -814,3 +788,2 @@ return "Machine"; | ||
function mergeProps(...args) { | ||
var _a, _b; | ||
let result = {}; | ||
@@ -828,3 +801,3 @@ for (let props of args) { | ||
if (key === "style") { | ||
result[key] = Object.assign({}, (_a = result[key]) != null ? _a : {}, (_b = props[key]) != null ? _b : {}); | ||
result[key] = Object.assign({}, result[key] ?? {}, props[key] ?? {}); | ||
continue; | ||
@@ -842,1 +815,13 @@ } | ||
} | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
Machine, | ||
choose, | ||
createMachine, | ||
guards, | ||
mergeProps, | ||
proxy, | ||
ref, | ||
snapshot, | ||
subscribe | ||
}); |
{ | ||
"name": "@zag-js/core", | ||
"version": "0.1.8", | ||
"version": "0.1.9", | ||
"description": "A minimal implementation of xstate fsm for UI machines", | ||
@@ -24,11 +24,2 @@ "keywords": [ | ||
], | ||
"scripts": { | ||
"build:fast": "zag build", | ||
"start": "zag build --watch", | ||
"build": "zag build --prod", | ||
"test": "jest --config ../../jest.config.js --rootDir . --passWithNoTests", | ||
"lint": "eslint src --ext .ts,.tsx", | ||
"test:ci": "yarn test --ci --runInBand", | ||
"test:watch": "yarn test --watch --updateSnapshot" | ||
}, | ||
"publishConfig": { | ||
@@ -41,6 +32,18 @@ "access": "public" | ||
"dependencies": { | ||
"@zag-js/store": "0.1.0", | ||
"@zag-js/utils": "0.1.2", | ||
"@zag-js/store": "0.1.1", | ||
"klona": "2.0.5" | ||
}, | ||
"devDependencies": { | ||
"@zag-js/utils": "0.1.3" | ||
}, | ||
"scripts": { | ||
"build-fast": "tsup src/index.ts --format=esm,cjs", | ||
"start": "pnpm build --watch", | ||
"build": "tsup src/index.ts --format=esm,cjs --dts", | ||
"test": "jest --config ../../jest.config.js --rootDir . --passWithNoTests", | ||
"lint": "eslint src --ext .ts,.tsx", | ||
"test-ci": "pnpm test --ci --runInBand", | ||
"test-watch": "pnpm test --watch -u", | ||
"typecheck": "tsc --noEmit" | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2
82193
1
6
1993
7
+ Added@zag-js/store@0.1.1(transitive)
- Removed@zag-js/utils@0.1.2
- Removed@zag-js/store@0.1.0(transitive)
- Removed@zag-js/utils@0.1.2(transitive)
Updated@zag-js/store@0.1.1