UNPKG

decca

Version:

Render interfaces using pure functions and virtual DOM, kinda

130 lines (96 loc) 3.24 kB
'use strict'; 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 _id = require('./id'); var _id2 = _interopRequireDefault(_id); var _createElement = require('virtual-dom/create-element'); var _createElement2 = _interopRequireDefault(_createElement); var _diff = require('virtual-dom/diff'); var _diff2 = _interopRequireDefault(_diff); var _patch = require('virtual-dom/patch'); var _patch2 = _interopRequireDefault(_patch); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * A widget that represents a component. * We need to do this to hook lifecycle hooks properly. * * Consumed in virtual-dom like so: * * h('div', {}, [ new Widget(el, model, build) ]) * * widget.init() * widget.update() * widget.remove() */ function Widget(_ref, model, build) { var component = _ref.component; var props = _ref.props; var children = _ref.children; if (!props) props = {}; this.component = component; this.build = build; // The parameters to be passed onto the component's functions. this.model = _extends({ props: props, children: children }, model); } Widget.prototype.type = 'Widget'; /* * On widget creation, do the virtual-dom createElement() dance */ Widget.prototype.init = function () { var id = setId(this, (0, _id2.default)()); // Create the virtual-dom tree var el = this.component.render(this.model); this.el = el; this.tree = this.build(el); // virtual-dom vnode this.rootNode = (0, _createElement2.default)(this.tree); // DOM element this.rootNode._dekuId = id; // so future update() and destroy() can see it // Trigger trigger(this, 'onCreate'); // Export return this.rootNode; }; /* * On update, diff with the previous (also a Widget) */ Widget.prototype.update = function (previous, domNode) { setId(this, domNode._dekuId); // Re-render the component var el = this.component.render(this.model); // If it was memoized, don't patch. // Just make this widget a copy of the previous. if (previous.el === el) { this.tree = previous.tree; this.rootNode = previous.rootNode; this.el = el; return; } this.tree = this.build(el); // Patch the DOM node var delta = (0, _diff2.default)(previous.tree, this.tree); this.rootNode = (0, _patch2.default)(previous.rootNode, delta); this.el = el; trigger(this, 'onUpdate'); }; /* * On destroy, trigger the onRemove hook. */ Widget.prototype.destroy = function (domNode) { setId(this, domNode._dekuId); trigger(this, 'onRemove'); }; /* * Updates the model with things that it can have when `id` is available. * This is because `id`'s aren't always available when Widget is initialized, * so these can't be in the ctor. */ function setId(widget, id) { widget.model.path = id; return id; } /* * Trigger a Component lifecycle event. */ function trigger(widget, hook, id) { if (!widget.component[hook]) return; return widget.component[hook](widget.model); } module.exports = Widget;