greena13/react-hotkeys

View on GitHub
src/lib/definitions/ComponentTree.js

Summary

Maintainability
A
0 mins
Test Coverage
import Registry from '../shared/Registry';
import without from '../../utils/collection/without';
import isUndefined from '../../utils/isUndefined';

/**
 * @typedef {Object} ComponentRegistryEntry
 * @property {ComponentId[]} childIds List of ids of the children of a component
 * @property {ComponentId|null} parentIds Id of the parent component
 */

/**
 * Registry of hot keys components, mapping children to their parents and vice versa
 * @class
 */
class ComponentTree extends Registry {
  constructor() {
    super();

    this.clearRootId();
  }

  hasRoot() {
    return !this.isRootId(null);
  }

  isRootId(componentId) {
    return componentId === this.rootId
  }

  clearRootId() {
    this.rootId = null;
  }

  /**
   * Register a component
   * @param {ComponentId} componentId Id of the component to register
   * @param {KeyMap} keyMap - Map of actions to key expressions
   * @returns {void}
   */
  add(componentId, keyMap) {
    super.set(componentId, {
      childIds: [],
      parentId: null,
      keyMap
    });
  }

  /**
   * Updates an existing component's key map
   * @param {ComponentId} componentId Id of the component to register
   * @param {KeyMap} keyMap - Map of actions to key expressions
   * @returns {void}
   */
  update(componentId, keyMap) {
    const component = super.get(componentId);
    super.set(componentId, {...component, keyMap});
  }

  /**
   * Set the parent ID of a component
   * @param {ComponentId} componentId Id of the component
   * @param {ComponentId} parentId Id of the parent
   * @returns {void}
   */
  setParent(componentId, parentId) {
    if (!isUndefined(parentId)) {
      this.get(componentId).parentId = parentId;
      this._addChildId(parentId, componentId);
    } else {
      this.rootId = componentId;
    }
  }

  /**
   * Deregister a component
   * @param {ComponentId} componentId Id of the component to remove
   * @returns {void}
   */
  remove(componentId) {
    const parentId = this._getParentId(componentId);

    this._removeChildId(parentId, componentId);

    super.remove(componentId);
  }

  /********************************************************************************
   * Private methods
   ********************************************************************************/

  _getParentId(componentId) {
    const component = this.get(componentId);
    return component && component.parentId;
  }

  _addChildId(parentId, componentId) {
    this.get(parentId).childIds.push(componentId);
  }

  _removeChildId(parentId, childId) {
    const parent = this.get(parentId);

    if (parent) {
      parent.childIds = without(parent.childIds, childId);
    }
  }
}

export default ComponentTree;