@zag-js/core
Advanced tools
Comparing version 0.0.0-dev-20221005155029 to 0.0.0-dev-20221031080845
1001
dist/index.js
@@ -6,2 +6,3 @@ "use strict"; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __export = (target, all) => { | ||
@@ -20,2 +21,6 @@ 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; | ||
}; | ||
@@ -46,3 +51,3 @@ // src/index.ts | ||
const res = typeof v === "function" ? v(...a) : v; | ||
return res ?? void 0; | ||
return res != null ? res : void 0; | ||
}; | ||
@@ -154,3 +159,4 @@ var cast = (v) => v; | ||
return (_a = actions.find((def) => { | ||
const guard = def.guard ?? Truthy; | ||
var _a2; | ||
const guard = (_a2 = def.guard) != null ? _a2 : Truthy; | ||
return exec(guardMap, ctx, event, meta)(guard); | ||
@@ -162,3 +168,3 @@ })) == null ? void 0 : _a.actions; | ||
function determineGuardFn(guard, guardMap) { | ||
guard = guard ?? Truthy; | ||
guard = guard != null ? guard : Truthy; | ||
return (context, event, meta) => { | ||
@@ -191,4 +197,5 @@ if (isString(guard)) { | ||
function createProxy(config) { | ||
const computedContext = config.computed ?? cast({}); | ||
const initialContext = config.context ?? cast({}); | ||
var _a, _b; | ||
const computedContext = (_a = config.computed) != null ? _a : cast({}); | ||
const initialContext = (_b = config.context) != null ? _b : cast({}); | ||
const state = (0, import_store2.proxy)({ | ||
@@ -212,5 +219,5 @@ value: "", | ||
get nextEvents() { | ||
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) ?? {}; | ||
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({ ...stateEvents, ...globalEvents }); | ||
@@ -259,5 +266,6 @@ }, | ||
return toArray(transitions).map(toTarget).find((transition) => { | ||
var _a; | ||
const determineGuard = determineGuardFn(transition.guard, guardMap); | ||
const guard = determineGuard(context, event, meta); | ||
return guard ?? transition.target ?? transition.actions; | ||
return (_a = guard != null ? guard : transition.target) != null ? _a : transition.actions; | ||
}); | ||
@@ -269,39 +277,493 @@ }; | ||
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) { | ||
var _a, _b, _c, _d, _e, _f; | ||
__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 = { ...this.config.context, ...context }; | ||
return new Machine({ ...this.config, context: newContext }, this.options); | ||
}); | ||
__publicField(this, "setActions", (actions) => { | ||
this.actionMap = { ...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 = { ...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; | ||
this.config = (0, import_json.klona)(config); | ||
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.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.state = createProxy(this.config); | ||
const event = toEvent("machine.created" /* Created */); | ||
this.executeActions((_f = this.config) == null ? void 0 : _f.created, event); | ||
this.executeActions((_l = this.config) == null ? void 0 : _l.created, event); | ||
} | ||
@@ -317,262 +779,2 @@ 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() { | ||
@@ -609,194 +811,2 @@ 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]() { | ||
@@ -811,2 +821,3 @@ return "Machine"; | ||
function mergeProps(...args) { | ||
var _a, _b; | ||
let result = {}; | ||
@@ -824,3 +835,3 @@ for (let props of args) { | ||
if (key === "style") { | ||
result[key] = Object.assign({}, result[key] ?? {}, props[key] ?? {}); | ||
result[key] = Object.assign({}, (_a = result[key]) != null ? _a : {}, (_b = props[key]) != null ? _b : {}); | ||
continue; | ||
@@ -827,0 +838,0 @@ } |
{ | ||
"name": "@zag-js/core", | ||
"version": "0.0.0-dev-20221005155029", | ||
"version": "0.0.0-dev-20221031080845", | ||
"description": "A minimal implementation of xstate fsm for UI machines", | ||
@@ -31,7 +31,7 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@zag-js/store": "0.0.0-dev-20221005155029", | ||
"@zag-js/store": "0.0.0-dev-20221031080845", | ||
"klona": "2.0.5" | ||
}, | ||
"devDependencies": { | ||
"@zag-js/utils": "0.0.0-dev-20221005155029" | ||
"@zag-js/utils": "0.0.0-dev-20221031080845" | ||
}, | ||
@@ -38,0 +38,0 @@ "scripts": { |
Sorry, the diff of this file is not supported yet
89367
2066
+ Added@zag-js/store@0.0.0-dev-20221031080845(transitive)
- Removed@zag-js/store@0.0.0-dev-20221005155029(transitive)