@zag-js/core
Advanced tools
+31
-2
@@ -34,3 +34,5 @@ "use strict"; | ||
| var STATE_DELIMITER = "."; | ||
| var ABSOLUTE_PREFIX = "#"; | ||
| var stateIndexCache = /* @__PURE__ */ new WeakMap(); | ||
| var stateIdIndexCache = /* @__PURE__ */ new WeakMap(); | ||
| function joinStatePath(parts) { | ||
@@ -42,2 +44,8 @@ return parts.join(STATE_DELIMITER); | ||
| } | ||
| function isExplicitAbsoluteStatePath(value) { | ||
| return value.startsWith(ABSOLUTE_PREFIX); | ||
| } | ||
| function stripAbsolutePrefix(value) { | ||
| return isExplicitAbsoluteStatePath(value) ? value.slice(ABSOLUTE_PREFIX.length) : value; | ||
| } | ||
| function appendStatePath(base, segment) { | ||
@@ -48,4 +56,12 @@ return base ? `${base}${STATE_DELIMITER}${segment}` : segment; | ||
| const index = /* @__PURE__ */ new Map(); | ||
| const idIndex = /* @__PURE__ */ new Map(); | ||
| const visit = (basePath, state) => { | ||
| index.set(basePath, state); | ||
| const stateId = state.id; | ||
| if (stateId) { | ||
| if (idIndex.has(stateId)) { | ||
| throw new Error(`Duplicate state id: ${stateId}`); | ||
| } | ||
| idIndex.set(stateId, basePath); | ||
| } | ||
| const childStates = state.states; | ||
@@ -63,3 +79,3 @@ if (!childStates) return; | ||
| } | ||
| return index; | ||
| return { index, idIndex }; | ||
| } | ||
@@ -69,6 +85,11 @@ function ensureStateIndex(machine) { | ||
| if (cached) return cached; | ||
| const index = buildStateIndex(machine); | ||
| const { index, idIndex } = buildStateIndex(machine); | ||
| stateIndexCache.set(machine, index); | ||
| stateIdIndexCache.set(machine, idIndex); | ||
| return index; | ||
| } | ||
| function getStatePathById(machine, stateId) { | ||
| ensureStateIndex(machine); | ||
| return stateIdIndexCache.get(machine)?.get(stateId); | ||
| } | ||
| function toSegments(value) { | ||
@@ -120,2 +141,10 @@ if (!value) return []; | ||
| const stateValue = String(value); | ||
| if (isExplicitAbsoluteStatePath(stateValue)) { | ||
| const stateId = stripAbsolutePrefix(stateValue); | ||
| const statePath = getStatePathById(machine, stateId); | ||
| if (!statePath) { | ||
| throw new Error(`Unknown state id: ${stateId}`); | ||
| } | ||
| return resolveAbsoluteStateValue(machine, statePath); | ||
| } | ||
| if (!isAbsoluteStatePath(stateValue) && source) { | ||
@@ -122,0 +151,0 @@ const sourceSegments = toSegments(source); |
+31
-2
| // src/state.ts | ||
| var STATE_DELIMITER = "."; | ||
| var ABSOLUTE_PREFIX = "#"; | ||
| var stateIndexCache = /* @__PURE__ */ new WeakMap(); | ||
| var stateIdIndexCache = /* @__PURE__ */ new WeakMap(); | ||
| function joinStatePath(parts) { | ||
@@ -10,2 +12,8 @@ return parts.join(STATE_DELIMITER); | ||
| } | ||
| function isExplicitAbsoluteStatePath(value) { | ||
| return value.startsWith(ABSOLUTE_PREFIX); | ||
| } | ||
| function stripAbsolutePrefix(value) { | ||
| return isExplicitAbsoluteStatePath(value) ? value.slice(ABSOLUTE_PREFIX.length) : value; | ||
| } | ||
| function appendStatePath(base, segment) { | ||
@@ -16,4 +24,12 @@ return base ? `${base}${STATE_DELIMITER}${segment}` : segment; | ||
| const index = /* @__PURE__ */ new Map(); | ||
| const idIndex = /* @__PURE__ */ new Map(); | ||
| const visit = (basePath, state) => { | ||
| index.set(basePath, state); | ||
| const stateId = state.id; | ||
| if (stateId) { | ||
| if (idIndex.has(stateId)) { | ||
| throw new Error(`Duplicate state id: ${stateId}`); | ||
| } | ||
| idIndex.set(stateId, basePath); | ||
| } | ||
| const childStates = state.states; | ||
@@ -31,3 +47,3 @@ if (!childStates) return; | ||
| } | ||
| return index; | ||
| return { index, idIndex }; | ||
| } | ||
@@ -37,6 +53,11 @@ function ensureStateIndex(machine) { | ||
| if (cached) return cached; | ||
| const index = buildStateIndex(machine); | ||
| const { index, idIndex } = buildStateIndex(machine); | ||
| stateIndexCache.set(machine, index); | ||
| stateIdIndexCache.set(machine, idIndex); | ||
| return index; | ||
| } | ||
| function getStatePathById(machine, stateId) { | ||
| ensureStateIndex(machine); | ||
| return stateIdIndexCache.get(machine)?.get(stateId); | ||
| } | ||
| function toSegments(value) { | ||
@@ -88,2 +109,10 @@ if (!value) return []; | ||
| const stateValue = String(value); | ||
| if (isExplicitAbsoluteStatePath(stateValue)) { | ||
| const stateId = stripAbsolutePrefix(stateValue); | ||
| const statePath = getStatePathById(machine, stateId); | ||
| if (!statePath) { | ||
| throw new Error(`Unknown state id: ${stateId}`); | ||
| } | ||
| return resolveAbsoluteStateValue(machine, statePath); | ||
| } | ||
| if (!isAbsoluteStatePath(stateValue) && source) { | ||
@@ -90,0 +119,0 @@ const sourceSegments = toSegments(source); |
+3
-1
@@ -112,4 +112,5 @@ type Dict = Record<string, any>; | ||
| type RelativeStateTarget<S extends string, Source extends string> = ChildStateKey<S, AncestorPaths<Source>>; | ||
| type StateIdTarget = `#${string}`; | ||
| interface Transition<T extends Dict, Source extends string | undefined = string | undefined> { | ||
| target?: T["state"] | (Source extends string ? RelativeStateTarget<T["state"], Source> : never) | undefined; | ||
| target?: T["state"] | StateIdTarget | (Source extends string ? RelativeStateTarget<T["state"], Source> : never) | undefined; | ||
| actions?: T["action"][] | undefined; | ||
@@ -138,2 +139,3 @@ guard?: T["guard"] | GuardFn<T> | undefined; | ||
| interface MachineState<T extends Dict, Parent extends string = string> { | ||
| id?: string | undefined; | ||
| tags?: T["tag"][] | undefined; | ||
@@ -140,0 +142,0 @@ entry?: ActionsOrFn<T> | undefined; |
+3
-1
@@ -112,4 +112,5 @@ type Dict = Record<string, any>; | ||
| type RelativeStateTarget<S extends string, Source extends string> = ChildStateKey<S, AncestorPaths<Source>>; | ||
| type StateIdTarget = `#${string}`; | ||
| interface Transition<T extends Dict, Source extends string | undefined = string | undefined> { | ||
| target?: T["state"] | (Source extends string ? RelativeStateTarget<T["state"], Source> : never) | undefined; | ||
| target?: T["state"] | StateIdTarget | (Source extends string ? RelativeStateTarget<T["state"], Source> : never) | undefined; | ||
| actions?: T["action"][] | undefined; | ||
@@ -138,2 +139,3 @@ guard?: T["guard"] | GuardFn<T> | undefined; | ||
| interface MachineState<T extends Dict, Parent extends string = string> { | ||
| id?: string | undefined; | ||
| tags?: T["tag"][] | undefined; | ||
@@ -140,0 +142,0 @@ entry?: ActionsOrFn<T> | undefined; |
+3
-3
| { | ||
| "name": "@zag-js/core", | ||
| "version": "1.35.0", | ||
| "version": "1.35.1", | ||
| "description": "A minimal implementation of xstate fsm for UI machines", | ||
@@ -28,4 +28,4 @@ "keywords": [ | ||
| "dependencies": { | ||
| "@zag-js/utils": "1.35.0", | ||
| "@zag-js/dom-query": "1.35.0" | ||
| "@zag-js/utils": "1.35.1", | ||
| "@zag-js/dom-query": "1.35.1" | ||
| }, | ||
@@ -32,0 +32,0 @@ "devDependencies": { |
+39
-0
@@ -105,2 +105,41 @@ # @zag-js/core | ||
| ### State IDs and `#id` targets | ||
| Use `id` on a state node when you want to target it explicitly from anywhere in the machine. | ||
| ```ts | ||
| import { createMachine } from "@zag-js/core" | ||
| const machine = createMachine({ | ||
| initialState() { | ||
| return "dialog" | ||
| }, | ||
| states: { | ||
| dialog: { | ||
| initial: "open", | ||
| states: { | ||
| focused: { | ||
| id: "dialogFocused", | ||
| }, | ||
| open: { | ||
| initial: "idle", | ||
| states: { | ||
| idle: { | ||
| on: { | ||
| CLOSE: { target: "#dialogFocused" }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }) | ||
| ``` | ||
| Notes: | ||
| - `#id` targets resolve by state node `id` (XState-style). | ||
| - State IDs must be unique within a machine. | ||
| ## API | ||
@@ -107,0 +146,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
62719
5.01%1137
5.57%202
23.93%0
-100%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
Updated
Updated