controlled-machine 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","sources":["../src/react.ts"],"sourcesContent":["/**\n * Controlled Machine - React Integration\n *\n * React hook for using controlled-machine in React components.\n */\n\nimport { useCallback, useRef, useEffect, useMemo } from 'react'\nimport {\n type MachineTypes,\n type Events,\n type Computed,\n type State,\n type Send,\n type EffectHelpers,\n type EffectStore,\n type Context,\n type Actions,\n type Guards,\n computeValues,\n executeActions,\n executeHandler,\n processEffects,\n clearEffectStore,\n MachineInstance,\n} from './index'\n\n// ============================================\n// useMachine Options Type\n// ============================================\n\nexport type UseMachineOptions<T extends MachineTypes> = {\n input: T['input']\n actions?: Partial<{\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in Actions<T>]: (context: Context<T>, payload?: any) => void\n }>\n guards?: Partial<{\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in Guards<T>]: (context: Context<T>, payload?: any) => boolean\n }>\n}\n\n// ============================================\n// React Hook\n// ============================================\n\nexport function useMachine<T extends MachineTypes>(\n machine: MachineInstance<T>,\n options: UseMachineOptions<T>,\n): { send: Send<Events<T>>; computed: Computed<T>; state: State<T> } {\n const { input, actions: optionsActions, guards: optionsGuards } = options\n\n // Merge actions and guards\n const mergedActions = useMemo(\n () => ({ ...machine.actions, ...optionsActions }),\n [machine.actions, optionsActions],\n )\n const mergedGuards = useMemo(\n () => ({ ...machine.guards, ...optionsGuards }) as Record<string, (context: Context<T>, payload?: unknown) => boolean>,\n [machine.guards, optionsGuards],\n )\n\n // refs for stable callbacks\n const inputRef = useRef(input)\n const machineRef = useRef(machine)\n const mergedActionsRef = useRef(mergedActions)\n const mergedGuardsRef = useRef(mergedGuards)\n const isMountedRef = useRef(true)\n\n inputRef.current = input\n machineRef.current = machine\n mergedActionsRef.current = mergedActions\n mergedGuardsRef.current = mergedGuards\n\n // compute values\n const { computed: computedDef } = machine\n const context = useMemo(\n () => computeValues(input, computedDef),\n [input, computedDef],\n )\n\n // extract computed only\n const computed = useMemo(() => {\n if (!computedDef) return {} as Computed<T>\n const result = {} as Computed<T>\n for (const key in computedDef) {\n result[key] = context[key]\n }\n return result\n }, [context, computedDef])\n\n const contextRef = useRef(context)\n contextRef.current = context\n\n const prevContextRef = useRef<Context<T>>(context)\n const effectStoreRef = useRef<EffectStore>({\n watchedValues: new Map(),\n enterCleanups: new Map(),\n changeCleanups: new Map(),\n exitCleanups: new Map(),\n })\n\n // always: auto-evaluate when context changes (synchronous, during render)\n const { always } = machine\n if (prevContextRef.current !== context && always && Object.keys(mergedActions).length > 0) {\n const actionsMap = mergedActions as Record<string, (context: Context<T>) => void>\n const guardsMap = mergedGuards as Record<string, (context: Context<T>) => boolean>\n for (const rule of always) {\n const guardFn =\n typeof rule.when === 'string' ? guardsMap[rule.when] : rule.when\n\n if (!guardFn || guardFn(context, undefined)) {\n executeActions(rule.do, actionsMap, context, undefined)\n break\n }\n }\n }\n prevContextRef.current = context\n\n // send: stable function (no deps, uses refs)\n const send: Send<Events<T>> = useCallback(\n <K extends keyof Events<T>>(\n event: K,\n ...args: Events<T>[K] extends undefined ? [] : [payload: Events<T>[K]]\n ) => {\n const currentMachine = machineRef.current\n const currentInput = inputRef.current\n const currentActions = mergedActionsRef.current\n const currentGuards = mergedGuardsRef.current\n const currentContext = computeValues(\n currentInput,\n currentMachine.computed,\n )\n const payload = args[0] as Events<T>[K]\n\n // 1. State-specific handler first\n const state = (currentContext as { state?: State<T> }).state\n if (state && currentMachine.states?.[state]?.on?.[event]) {\n const stateHandler = currentMachine.states[state].on![event]!\n executeHandler(\n stateHandler,\n currentActions ?? {},\n currentGuards,\n currentContext,\n payload,\n )\n }\n\n // 2. Global handler\n const globalHandler = currentMachine.on?.[event]\n if (globalHandler) {\n executeHandler(\n globalHandler,\n currentActions ?? {},\n currentGuards,\n currentContext,\n payload,\n )\n }\n },\n [], // no dependencies - uses refs\n )\n\n // safeSend: won't be called after unmount\n const safeSend: Send<Events<T>> = useCallback(\n <K extends keyof Events<T>>(\n event: K,\n ...args: Events<T>[K] extends undefined ? [] : [payload: Events<T>[K]]\n ) => {\n if (!isMountedRef.current) return\n send(event, ...args)\n },\n [send],\n )\n\n // effect helpers\n const effectHelpers: EffectHelpers<Events<T>> = useMemo(\n () => ({ send: safeSend }),\n [safeSend],\n )\n\n // effects: detect watch value changes\n const { effects } = machine\n useEffect(() => {\n processEffects(effects, context, effectHelpers, effectStoreRef.current)\n }, [context, effects, effectHelpers])\n\n // mount/unmount management\n useEffect(() => {\n isMountedRef.current = true\n const store = effectStoreRef.current\n return () => {\n isMountedRef.current = false\n clearEffectStore(store)\n }\n }, [])\n\n // state from context (default to empty string if not provided)\n const state = (context as { state?: State<T> }).state ?? ('' as State<T>)\n\n return { send, computed, state }\n}\n\n// Re-export types for convenience\nexport type { Send } from './index'\n"],"names":["state"],"mappings":"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"}
1
+ {"version":3,"file":"react.js","sources":["../src/react.ts"],"sourcesContent":["/**\n * Controlled Machine - React Integration\n *\n * React hook for using controlled-machine in React components.\n *\n * Features:\n * - Internal state management via React state\n * - Automatic effect processing on context changes\n * - Stable send function reference (uses refs internally)\n * - Unmount-safe callbacks\n * - Action/guard overrides via options\n *\n * @example\n * const [snapshot, send] = useMachine(counterMachine, {\n * input: { multiplier },\n * actions: { logValue: (ctx) => console.log(ctx.count) },\n * guards: { isPositive: (ctx) => ctx.count > 0 }\n * })\n */\n\nimport { useCallback, useRef, useEffect, useMemo, useState } from 'react'\nimport {\n type MachineTypes,\n type Events,\n type State,\n type Send,\n type Snapshot,\n type EffectHelpers,\n type EffectStore,\n type Context,\n type Internal,\n type Input,\n type Actions,\n type Guards,\n type AssignFn,\n buildContext,\n computeValues,\n createAssign,\n executeRuleActions,\n evaluateGuards,\n executeHandler,\n processEffects,\n clearEffectStore,\n buildSnapshot,\n MachineInstance,\n} from './index'\n\n// ============================================\n// useMachine Options Type\n// ============================================\n\n/**\n * Options for useMachine hook\n * @property input - External state to pass to the machine (React state, props, etc.)\n * @property actions - Override or add action implementations\n * @property guards - Override or add guard implementations\n */\nexport type UseMachineOptions<T extends MachineTypes> = {\n input?: Input<T>\n actions?: Partial<{\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in Actions<T>]: (context: Context<T>, payload: any, assign: AssignFn<Internal<T>>) => void\n }>\n guards?: Partial<{\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in Guards<T>]: (context: Context<T>, payload?: any) => boolean\n }>\n}\n\n// ============================================\n// React Hook - useMachine\n// ============================================\n\n/**\n * React hook for using controlled-machine\n *\n * @param machineOrFactory - Machine instance or factory function (factory ensures fresh instance per component)\n * @param options - Hook options (input, actions override, guards override)\n * @returns [snapshot, send] tuple - snapshot contains internal + computed + state, send dispatches events\n *\n * @example\n * // Basic usage\n * const [snapshot, send] = useMachine(machine, { input: { count, setCount } })\n *\n * // With factory (recommended for isolation)\n * const [snapshot, send] = useMachine(() => createCounterMachine(100), { input: {} })\n *\n * // With action/guard overrides\n * const [snapshot, send] = useMachine(machine, {\n * input: { count },\n * actions: { log: (ctx) => console.log(ctx.count) },\n * guards: { canIncrement: (ctx) => ctx.count < 10 }\n * })\n */\nexport function useMachine<T extends MachineTypes>(\n machineOrFactory: MachineInstance<T> | (() => MachineInstance<T>),\n options: UseMachineOptions<T> = {},\n): [Snapshot<T>, Send<Events<T>>] {\n const { input = {} as Input<T>, actions: optionsActions, guards: optionsGuards } = options\n\n // ---- Machine initialization ----\n // Factory pattern ensures each component gets its own machine instance\n const machine = useMemo(\n () => (typeof machineOrFactory === 'function' ? machineOrFactory() : machineOrFactory),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [], // Only run once on mount\n )\n\n // ---- Internal state (React-managed) ----\n const [internal, setInternal] = useState<Internal<T>>(() => machine.getInitialInternal())\n\n // ---- Merge machine actions/guards with options overrides ----\n const mergedActions = useMemo(\n () => ({ ...machine.actions, ...optionsActions }),\n [machine.actions, optionsActions],\n )\n const mergedGuards = useMemo(\n () => ({ ...machine.guards, ...optionsGuards }) as Record<string, (context: Context<T>, payload?: unknown) => boolean>,\n [machine.guards, optionsGuards],\n )\n\n // ---- Refs for stable callbacks (avoid stale closures) ----\n const inputRef = useRef(input)\n const internalRef = useRef(internal)\n const machineRef = useRef(machine)\n const mergedActionsRef = useRef(mergedActions)\n const mergedGuardsRef = useRef(mergedGuards)\n const isMountedRef = useRef(true)\n\n // Keep refs updated with latest values\n inputRef.current = input\n internalRef.current = internal\n machineRef.current = machine\n mergedActionsRef.current = mergedActions\n mergedGuardsRef.current = mergedGuards\n\n // ---- Build full context (input + internal + computed) ----\n const { computed: computedDef } = machine\n const context = useMemo(() => {\n const base = buildContext(input, internal)\n return computeValues(base, computedDef) as Context<T>\n }, [input, internal, computedDef])\n\n const contextRef = useRef(context)\n contextRef.current = context\n\n // Track previous context for always rules\n const prevContextRef = useRef<Context<T>>(context)\n // Effect store for tracking watched values and cleanups\n const effectStoreRef = useRef<EffectStore>({\n watchedValues: new Map(),\n enterCleanups: new Map(),\n changeCleanups: new Map(),\n exitCleanups: new Map(),\n })\n\n // ---- Internal state updater ----\n // Updates ref immediately (for subsequent assigns in same handler) + triggers re-render\n const updateInternal = useCallback((newInternal: Internal<T>) => {\n internalRef.current = newInternal // Immediate update for subsequent assigns\n setInternal(newInternal) // Trigger re-render\n }, [])\n\n // ---- Assign function (for updating internal state) ----\n const assign = useMemo(() => createAssign(() => internalRef.current, updateInternal), [updateInternal])\n const assignRef = useRef(assign)\n assignRef.current = assign\n\n // ---- Always rules (evaluated during render on context change) ----\n // getContext rebuilds context with latest internal state for fresh values after assigns\n const getContext = useCallback(() => {\n const base = buildContext(inputRef.current, internalRef.current)\n return computeValues(base, machineRef.current.computed) as Context<T>\n }, [])\n\n const { always } = machine\n if (prevContextRef.current !== context && always) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const actionsMap = mergedActions as Record<string, (context: Context<T>, payload: any, assign: AssignFn<Internal<T>>) => void>\n const guardsMap = mergedGuards as Record<string, (context: Context<T>) => boolean>\n for (const rule of always) {\n if (evaluateGuards(rule.when, guardsMap, getContext(), undefined)) {\n executeRuleActions(rule.do, actionsMap, getContext, undefined, assign)\n break // First matching rule wins\n }\n }\n }\n prevContextRef.current = context\n\n // ---- Send function (stable reference, uses refs internally) ----\n const send: Send<Events<T>> = useCallback(\n <K extends keyof Events<T>>(\n event: K,\n ...args: Events<T>[K] extends undefined ? [] : [payload: Events<T>[K]]\n ) => {\n const currentMachine = machineRef.current\n const currentActions = mergedActionsRef.current\n const currentGuards = mergedGuardsRef.current\n\n // Create fresh assign - updates ref immediately + triggers re-render\n const currentAssign = createAssign(\n () => internalRef.current,\n (newInternal) => {\n internalRef.current = newInternal\n setInternal(newInternal)\n }\n )\n\n // getContext rebuilds context with latest internal state\n const getCurrentContext = () => {\n const base = buildContext(inputRef.current, internalRef.current)\n return computeValues(base, currentMachine.computed) as Context<T>\n }\n\n const payload = args[0] as Events<T>[K]\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const actionsMap = (currentActions ?? {}) as Record<string, (ctx: Context<T>, payload: any, assign: AssignFn<Internal<T>>) => void>\n const guardsMap = currentGuards as Record<string, (ctx: Context<T>, payload?: unknown) => boolean>\n\n // 1. Execute state-specific handler (if in FSM mode)\n const currentContext = getCurrentContext()\n const state = (currentContext as { state?: State<T> }).state\n if (state && currentMachine.states?.[state]?.on?.[event]) {\n const stateHandler = currentMachine.states[state].on![event]!\n executeHandler(\n stateHandler,\n actionsMap,\n guardsMap,\n getCurrentContext,\n payload,\n currentAssign,\n )\n }\n\n // 2. Execute global handler\n const globalHandler = currentMachine.on?.[event]\n if (globalHandler) {\n executeHandler(\n globalHandler,\n actionsMap,\n guardsMap,\n getCurrentContext,\n payload,\n currentAssign,\n )\n }\n },\n [], // No dependencies - uses refs for latest values\n )\n\n // ---- Safe send (no-op after unmount) ----\n const safeSend: Send<Events<T>> = useCallback(\n <K extends keyof Events<T>>(\n event: K,\n ...args: Events<T>[K] extends undefined ? [] : [payload: Events<T>[K]]\n ) => {\n if (!isMountedRef.current) return\n send(event, ...args)\n },\n [send],\n )\n\n // ---- Effect helpers (passed to effect callbacks) ----\n const effectHelpers: EffectHelpers<Events<T>> = useMemo(\n () => ({ send: safeSend }),\n [safeSend],\n )\n\n // ---- Process effects on context change ----\n const { effects } = machine\n useEffect(() => {\n processEffects(effects, context, effectHelpers, effectStoreRef.current)\n }, [context, effects, effectHelpers])\n\n // ---- Mount/unmount lifecycle ----\n useEffect(() => {\n isMountedRef.current = true\n const store = effectStoreRef.current\n return () => {\n isMountedRef.current = false\n clearEffectStore(store) // Clean up all effect callbacks on unmount\n }\n }, [])\n\n // ---- Build snapshot (internal + computed + state) ----\n const snapshot = useMemo(\n () => buildSnapshot(internal, context, computedDef),\n [internal, context, computedDef],\n )\n\n return [snapshot, send]\n}\n\n// Re-export types for convenience\nexport type { Send } from './index'\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "controlled-machine",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "A controlled state machine where state lives outside the machine",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -65,7 +65,7 @@
65
65
  "devDependencies": {
66
66
  "@testing-library/react": "^16.3.1",
67
67
  "@types/react": "^19.2.8",
68
- "jsdom": "^27.4.0",
68
+ "jsdom": "^25.0.1",
69
69
  "react": "^19.2.3",
70
70
  "typescript": "^5.9.3",
71
71
  "vite": "^7.3.1",