decca
Version:
Render interfaces using pure functions and virtual DOM, kinda
93 lines (92 loc) • 2.77 kB
JavaScript
'use strict';
var id_1 = require('./id');
var createElement = require('virtual-dom/create-element');
var diff = require('virtual-dom/diff');
var patch = require('virtual-dom/patch');
var assign = require('object-assign');
/*
* 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(_a, model, build) {
var component = _a.component, props = _a.props, children = _a.children;
if (!props)
props = {};
this.component = component;
this.build = build;
// The parameters to be passed onto the component's functions.
this.model = assign({}, { props: props, children: children }, model);
}
exports.__esModule = true;
exports["default"] = Widget;
Widget.prototype.type = 'Widget';
/*
* On widget creation, do the virtual-dom createElement() dance
*/
Widget.prototype.init = function () {
var id = setId(this, id_1["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 = createElement(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 = diff(previous.tree, this.tree);
this.rootNode = patch(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);
}