microstates / ember

@microstates/ember - Official Microstates bindings for Ember.js
https://ember-microstates.netlify.com
MIT License
70 stars 12 forks source link

Aligning this with latest microstate.js #68

Closed knownasilya closed 5 years ago

knownasilya commented 6 years ago

I'd love to get this to work with that library. What would that look like?


Current implementation happening here: https://github.com/cowboyd/ember-microstates/pull/69

taras commented 6 years ago

@knownasilya I'll be happy to help you make this happen.

Microstates changed quite a bit, so we'll need to rethink the APIs in Ember. The original version of microstates was not composable, so it was mostly about providing operations for primitive types. With new composable microstates, you can represent the state of an entire application in a microstate. I'm not sure if people will end up using microstates this way but it would be possible.

One possibility would be to have an API that's similar to @microstates/react.

class MyApp {
  counter = Number;
}
{{#state type=MyApp value=(hash counter=1 )) as |app|}}
  {{app.state.counter}}
  <button {{action app.counter.increment}}>1++</button>
{{/state}}

To implement this, would be pretty easy. You need to create a microstate from the Type and value and then add a middleware that would set the state of the component.

It'd look something like this,

import Component from '@ember/component';
import Microstate from 'microstates';

export default Component.extend({
  layout: hbs`{{yield microstate}}`,

  init() {
    this._super(...arguments);

    let Type = this.get('type');
    let value = this.get('value');

    // create initial microstate from Type and value
    let initial = Microstate.create(Type, value);

    let middleware = next => (microstate, transition, args) => {

      // when a transition is called, compute the next microstate
      let nextMicrostate = next(microstate, transition, args);

      // set the internal state of the component to the next state
      this.set('microstate', nextMicrostate);

      return nextMicrostate;
    }

    // map the initial microstate and add the middleware into the tree
    let withMiddleware = Microstate.map(tree => tree.use(middleware), initial);

    // set the components state to microstate with middleware in it
    this.set('microstate', withMiddleware);
  }
});

You might also want to allow the use of Microstate.from API. It allows to turn any POJO into a microstate. So, you do something like, Microstate.from({ a: { b: [ 1, 2, 3 ] }) and this will allow you to transition the object using built-in transitions.

let state = Microstate.from({ a: { b: [ 1, 2, 3 ] });
let next = state.a.b[1].increment();
next.valueOf();
//> { a: { b: [ 1, 3, 3 ] } }
// the number ^^ is incremented

This might look like,

{{#state from=whatever as |app|}}

{{/state}}

Let me know if you'd like to pair on this at any point. I'm always happy to.

knownasilya commented 6 years ago

With the above proposed changes would that remove the need for the helpers currently in this addon? Or would that work well together?

taras commented 6 years ago

Yes, this would be in place of the helper(helpers would need to be removed).

knownasilya commented 6 years ago

I'll submit a PR for the first use case, at least to get something going.

taras commented 6 years ago

Let me know if you’d like help.

knownasilya commented 6 years ago

Started work here https://github.com/knownasilya/ember-microstates/blob/update/addon/components/state-for.js Still need to get it importing the microstates lib.

taras commented 6 years ago

Looking good. @sivakumar-kailasam created this https://github.com/sivakumar-kailasam/glimmer-microstates-sample it's for an older version of microstates, but it might help.

taras commented 5 years ago

Resolved by #72