UNPKG

immreact

Version:

Use react classes with an immstruct structure

233 lines (173 loc) 7.04 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); 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 _immstruct2 = require('immstruct'); var _immstruct3 = _interopRequireDefault(_immstruct2); var _immutable = require('immutable'); var _immutable2 = _interopRequireDefault(_immutable); var _eventemitter = require('eventemitter3'); var _eventemitter2 = _interopRequireDefault(_eventemitter); var _flux = require('flux'); var _constants = require('./constants'); var _constants2 = _interopRequireDefault(_constants); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var _state = Symbol('state'); /** * @class * Holds data representing the current state of the application */ var State = function (_Dispatcher) { _inherits(State, _Dispatcher); /** * @constructs * A default namespace can be passed in here * @param key <String> if key is not a string it will be interpreted as initial state * @param initialState <Object> _optional_ defaults to {} */ function State(key) { var initialState = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; _classCallCheck(this, State); var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(State).call(this)); _this.onSwap = function (o, n, k) { if (!o) { _this.onUpdate(); return; } if (o && n) { // Check that a change really did happen if (!_immutable2.default.is(o.getIn(k), n.getIn(k))) { _this.onUpdate(); } } }; if (typeof key !== 'string') { initialState = key; key = _constants2.default.ROOT; } // Patch over an emitter _eventemitter2.default.call(_this); Object.assign(_this, _eventemitter2.default.prototype); // Private state immstruct structure _this[_state] = (0, _immstruct3.default)(key, _defineProperty({}, _constants2.default.COMPONENTS, {})); _this.create(key, initialState); // Use animation frame so that quick mutations to the tree are batched // this[ _state ].on( 'swap', this.onSwap ) _this[_state].on('next-animation-frame', _this.onSwap); return _this; } /** * For now just triggered an update to call the listener */ _createClass(State, [{ key: 'start', value: function start() { this.onUpdate(); } /** * update function passed back the state tree */ }, { key: 'onUpdate', value: function onUpdate() { this.emit('update', this); } /** * Check for a change and emit an update when one occurs */ }, { key: 'create', /** * Creates a new root level immutable and returns a ref to it * @param key <String> _required_ * @param value <Object> _optional_ defaults to {} */ value: function create(key) { var value = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; if (!key) { throw new Error('No key specified when creating new state root'); } // @TODO should check if key already exists this[_state].cursor().update(function (cursor) { return cursor.merge(_defineProperty({}, key, value)); }); return this[_state].reference(key); } /** * Grabs a fresh cursor to the data structure * @param args <Array>|<String> specify structure keyPath to grab */ }, { key: 'cursor', value: function cursor(args) { if (!args) { return this[_state].cursor(); } if (typeof args === 'string') { return this[_state].cursor(args); } return this[_state].cursor([].concat(_toConsumableArray(args))); } /** * Returns the dereferenced value for read-only access * @param args <Array>|<String> specify structure keyPath to grab */ }, { key: 'get', value: function get(args) { if (!args) { return this[_state].cursor().deref(); } if (typeof args === 'string') { return this[_state].cursor(args).deref(); } return this[_state].cursor([].concat(_toConsumableArray(args))).deref(); } }, { key: 'reference', value: function reference(args) { if (!args) { return this[_state].reference(); } if (typeof args === 'string') { return this[_state].reference(args); } return this[_state].reference([].concat(_toConsumableArray(args))); } /** * Returns a JSON string to save */ }, { key: 'save', value: function save() { try { return JSON.stringify(this[_state].cursor().toJSON()); } catch (err) { throw new Error(err); } } /** * Loads a JSON string into the current state */ }, { key: 'load', value: function load(state) { try { // this[ _state ].cursor().update( cursor => { // return cursor.merge( JSON.parse( state ) ) // }) this[_state].cursor().merge(JSON.parse(state)); } catch (err) { throw new Error(err); } } }]); return State; }(_flux.Dispatcher); exports.default = State;