microstates-todomvc-model
Version:
Microstates Model for TodoMVC Component
185 lines (156 loc) • 6.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _microstates = require('microstates');
var MS = _interopRequireWildcard(_microstates);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* TodoMVC is a Microstate model.
*
* This model provides state structure and transitions necessary to create build a functional TodoMVC app your own view layer.
*
* A Microstate model is a value and type description. The type description is used to interpret the value
* and generate state and transitions for the value. The state will be bound to the template and rendered.
* Transitions will be used to create actions that will transition the state and update the DOM tree.
*
* Types describe:
* 1. The structure of the state that the type represents.
* 2. The custom transitions that can be performed on this type.
* 3. The computed properties that should be applied to the state object that's derived from this type.
*/
var TodoMVC = function () {
function TodoMVC() {
_classCallCheck(this, TodoMVC);
this.todos = MS.Array;
}
/**
* COMPOSED TYPES
*
* Composed types describe the structure of the microstate and how the composed value can be transitioned.
* In this example, we're only composing an array into this microstate, but we can compose microstates of any
* depth. Microstates will know how to transition that structure.
*/
_createClass(TodoMVC, [{
key: 'completeTodo',
/**
* CUSTOM TRANSITIONS
*
* Custom transitions allow to define operations that are specific to the domain of the data that the microstate represents.
* Transitions are similar to Redux reducers in that they are pure functions that receive state and return new state.
*
* When a transition is invoked, the transition function has access to the following:
* 1. current state of the the microstate via the first argument - unlike Redux, this state is already initialized, so you do not need to define initial value.
* 2. arguments passed to the transition as the rest of the argument after the first argument
* 3. context object is a microstate constructor for performing batched transitions on the microstate's state
*/
/**
* Change the status of a todo item to be completed
* @param {TodoMVC} current state
* @param {Object} todo
*/
value: function completeTodo(current, todo) {
/**
* microstates doesn't support transitioning state that is composed into an array (yet).
* We can transition the array, but not values in that array. We're planning
* to add this feature in the future but we need to figure out how to do that properly.
*
* Find the todo that we want to update and replace it with new item that has completed true.
*/
return this().todos.replace(todo, _extends({}, todo, {
completed: true
}));
}
/**
* Change the text of a todo item
* @param {TodoMVC} current
* @param {Object} todo
* @param {String} text
*/
}, {
key: 'editTodo',
value: function editTodo(current, todo, text) {
// Find the todo that we want to update and replace it with new item with changed text.
return this().todos.replace(todo, _extends({}, todo, {
text: text
}));
}
/**
* Remote a todo item from the list
* @param {TodoMVC} current
* @param {Object} todo
*/
}, {
key: 'deleteTodo',
value: function deleteTodo(current, todo) {
// Filter here is a transition on todos array.
return this().todos.filter(function (item) {
return item !== todo;
});
}
/**
* Add a todo item to the list
* @param {TodoMVC} current
* @param {String} text
*/
}, {
key: 'addTodo',
value: function addTodo(current, text) {
// Push is transition on todos array.
return this().todos.push({
text: text,
id: current.nextId,
completed: false
});
}
/**
* Remove all items that have completed status
*/
}, {
key: 'clearCompleted',
value: function clearCompleted() {
return this().todos.filter(function (_ref) {
var completed = _ref.completed;
return !completed;
});
}
}, {
key: 'completedCount',
/**
* Getters
*
* Getters are applied to the state that's generated from a type. The context of a getter is the state object.
* This gives developer access to composed states on this microstate. It can be used to derive values.
*
* In Redux world, this would be similar to Reselect except Microstates doesn't currently support memoization.
* We're planning to apply several levels of memoization in the future.
*/
/**
* Number completed items
* @type Number
*/
get: function get() {
// in computed properties, `this` references state object which has composed state values on it.
return this.todos.filter(function (_ref2) {
var completed = _ref2.completed;
return completed;
}).length;
}
/**
* Next id in order
* @type Number
*/
}, {
key: 'nextId',
get: function get() {
return this.todos.reduce(function (maxId, todo) {
return Math.max(todo.id, maxId);
}, -1) + 1;
}
}]);
return TodoMVC;
}();
exports.default = TodoMVC;