v0.4.0
This release brings some development ergonomics improvements.
You can now use the matchesState
-computed-macro to check if a statechart is in a specified state without relying on writing your own computed based on Xstate's matchesState
-function. Example:
matchesState
- and debugState
-computeds
import Component from '@ember/component';
import Statechart from 'ember-statecharts/mixins/statechart';
import { matchesState } from 'ember-statecharts/computed';
export default Component.extend(Statechart, {
statechart: computed(function() {
initial: 'powerOff',
states: {
powerOff: {
on: {
power: 'powerOn'
}
},
powerOn: {
on: {
power: 'powerOff'
},
initial: 'stopped',
states: {
stopped: {},
playing: {}
}
}
}
}),
playerIsStopped: matchesState({
powerOn: 'stopped'
})
})
The matcheState
-computed is a convenience-wrapper around XState's matchesState
so please have a look at the docs for that function to get an idea of how to use it correctly.
We also added the debugState
-computed that can be used to print a string representation of the statechart's currentState
-value. This can be useful when developing and saves you from declaring the same function in your own code.
Example:
import { debugState } from 'ember-statecharts/computed';
const wat = EmberObject.extend(Statechart, {
statechart: computed(function() {
return {
initial: 'powerOff',
states: {
powerOff: {
on: {
power: 'powerOn'
}
},
powerOn: {
initial: 'stopped',
states: {
stopped: {},
playing: {}
},
on: {
power: 'powerOff'
}
}
}
};
}),
_debugState: debugState()
});
wat.get('_debugState') // => "powerOff"
wat.get('states').send('power') // => "{ powerOn: 'stopped' }"
Guard references by string
This release also adds the possibility to declare guards / conditional transitions in a DRY-way by referencing guards via strings and passing options to the statechart configuration. This allows multiple transitions to reuse the same guard functions and leads to arguably more readable statechart-configurations.
const wat = EmberObject.extend(Statechart, {
power: 1,
statechart: computed(function() {
return [
{
initial: 'powerOff',
states: {
powerOff: {
on: {
power: {
powerOn: {
cond: 'enoughPowerIsAvailable'
}
}
}
},
powerOn: {
initial: 'stopped',
states: {
stopped: {},
playing: {}
},
on: {
power: 'powerOff'
}
}
}
},
{
guards: {
enougPowerIsAvailable: (context, eventData) => {
return context.get('power') > 9000;
}
}
}
];
})
});
wat.get('states').send('power'); // won't transition power is not over 9000
wat.set('power', 9001);
wat.get('states').send('power') // will transition to `powerOn` as power is now over 9000
Please have a look at the xstate-docs to see how to get the most out of this feature.