Home Reference Source Test Repository

src/content/lib/Renderer.js

import mainLoop from 'main-loop';
import vdom from 'virtual-dom';

/**
 * @typedef {Object} RenderItem
 *
 * @property {DOMNode} node target DOMNode
 * @property {props} props props
 */


/**
 * Render
 */
export default class Renderer {

  /**
   * Constructor
   *
   * @param {Function} component virtual-dom Component Function
   */
  constructor(component) {
    this.nodes = [];
    this.component = component;
  }

  /**
   * Create virtual-dom tree and attach DOMNode
   *
   * @param {RenderItem} item item object
   * @return {{node: DOMNode, tree: Object}}
   */
  createTreeAndAttachDOM(item) {
    const tree = mainLoop(item.props, this.component, vdom);
    item.node.appendChild(tree.target);
    return {
      tree,
      parent: item.node
    };
  }

  /**
   * render
   *
   * @param {RenderItem[]} newItems render item list
   */
  render(newItems) {
    const oldNodes = this.nodes;
    const added = newItems.filter(ni => {
      return !(oldNodes.find(on => on.parent === ni.node));
    }).map(ni => this.createTreeAndAttachDOM(ni));
    const updated = oldNodes.map(on => {
      const updateItem = newItems.find(ni => ni.node === on.parent);
      if (!updateItem) {
        return null;
      }
      on.tree.update(updateItem.props);
      return on;
    }).filter(on => on);
    this.nodes = updated.concat(added);
  }
}