Skip to content

v0.4.0

Compare
Choose a tag to compare
@LevelbossMike LevelbossMike released this 24 Sep 07:46
· 327 commits to master since this release

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.