@uuxxx/fsm-vue
v0.1.3
Published
Vue bindings for @uuxxx/fsm
Maintainers
Readme
@uuxxx/fsm-vue
Vue 3 bindings for @uuxxx/fsm — a lightweight, type-safe finite state machine library.
Installation
npm install @uuxxx/fsm-vue @uuxxx/fsm
# or
pnpm add @uuxxx/fsm-vue @uuxxx/fsm
# or
yarn add @uuxxx/fsm-vue @uuxxx/fsmQuick Start
<script setup lang="ts">
import { useFsm } from '@uuxxx/fsm-vue';
type State = 'idle' | 'loading' | 'success' | 'error';
const { state, allStates, start, succeed, fail, reset } = useFsm({
init: 'idle',
states: ['idle', 'loading', 'success', 'error'],
transitions: {
start: { from: 'idle', to: 'loading' },
succeed: { from: 'loading', to: 'success' },
fail: { from: 'loading', to: 'error' },
reset: { from: ['success', 'error'], to: 'idle' },
},
});
</script>
<template>
<p>Current state: {{ state }}</p>
<button @click="start" :disabled="state !== 'idle'">Start</button>
<button @click="reset" :disabled="state !== 'success' && state !== 'error'">Reset</button>
</template>API
useFsm(config)
A Vue composable that creates a reactive FSM instance. Accepts the same config as makeFsm from @uuxxx/fsm.
Returns
| Property | Type | Description |
| -------------------- | ------------------------------ | -------------------------------------------------- |
| state | Readonly<ShallowRef<TState>> | Reactive current state — updates on transitions |
| allStates() | () => TState[] | Returns array of all valid states |
| transition methods | From config keys | One method per transition, same signatures as core |
| plugin APIs | From plugin names | One namespace per plugin |
The state ref is readonly — it can only change through transitions, not by direct assignment.
Config
The config object is identical to @uuxxx/fsm's makeFsm. See the core documentation for full details on transitions, lifecycle hooks, plugins, and error handling.
Lifecycle Hooks
Lifecycle hooks work the same as in the core library. The onAfterTransition hook fires after the reactive state is updated:
const fsm = useFsm({
init: 'idle',
states: ['idle', 'loading', 'done'],
transitions: {
start: { from: 'idle', to: 'loading' },
finish: { from: 'loading', to: 'done' },
},
methods: {
onBeforeTransition({ from, to, transition }) {
console.log(`${from} -> ${to} via ${transition}`);
return false; // return false to cancel the transition
},
onAfterTransition({ from, to }) {
console.log(`Transitioned from ${from} to ${to}`);
},
},
});Watching State
Since state is a Vue ref, you can use it with watch, computed, and template expressions:
import { watch, computed } from 'vue';
const { state, start } = useFsm({
/* ... */
});
const isLoading = computed(() => state.value === 'loading');
watch(state, (newState, oldState) => {
console.log(`State changed: ${oldState} -> ${newState}`);
});Using with Plugins
import { useFsm } from '@uuxxx/fsm-vue';
import { historyPlugin } from '@uuxxx/fsm-plugins/history';
const fsm = useFsm({
init: 'a',
states: ['a', 'b', 'c'],
transitions: {
goto: { from: '*', to: (s: 'a' | 'b' | 'c') => s },
},
plugins: [historyPlugin()],
});
fsm.goto('b');
fsm.goto('c');
fsm.state.value; // 'c'
fsm.history.get(); // ['a', 'b', 'c']
fsm.history.back(1); // 'b' (pointer moved, FSM state unchanged)
fsm.history.canBack(); // true
fsm.goto(fsm.history.current()); // actually transition to 'b'Exports
import { useFsm, makeFsm } from '@uuxxx/fsm-vue';
import type { FsmConfig, FsmTransition, FsmPlugin, FsmLabel } from '@uuxxx/fsm-vue';| Export | Description |
| --------------- | ---------------------------------------------- |
| useFsm | Vue composable — reactive FSM |
| makeFsm | Re-export from @uuxxx/fsm — non-reactive FSM |
| FsmConfig | Config type |
| FsmTransition | Transition definition type |
| FsmPlugin | Plugin type |
| FsmLabel | State label type (string) |
