Source: select/modules/select-list.js

/**
 * @summary aofl-select-list
 * @version 3.0.0
 * @version 3.0.0
 * @author Daniel Belisle<daniel.belisle@aofl.com>
 * @author Arian Khosravi<arian.khosravi@aofl.com>
 */
import {AoflElement} from '@aofl/element';
import styles from './select-list.css';
/**
 * Similar to select tag it supports a single select list of aofl-options.
 *
 * @memberof module:@aofl/select
 * @extends {AoflElement}
 */
class AoflSelectList extends AoflElement {
  /**
   *
   */
  constructor() {
    super();
    this.options = [];
    this.value = '';
    this.focusIndex = 0;
  }
  /**
   * @readonly
   * @type {String}
   */
  static get is() {
    return 'aofl-select-list';
  }
  /**
   * If the element losing focus is not a child of the list reset the focusIndex
   *
   * @param {Event} e
   */
  /* istanbul ignore next */
  focusoutCallback(e) {
    if (e.relatedTarget && e.relatedTarget.parentNode === this) { return; }

    this.focusIndex = 0;
  }
  /**
   * @param {Event} e
   */
  keydownCallback(e) {
    e.preventDefault();
    if (e.keyCode === 38 || (e.shiftKey && e.keyCode === 9)) { // up arrow or shift tab
      if (this.focusIndex > 0) {
        this.options[--this.focusIndex].focus();
      }
    } else if (e.keyCode === 40 || e.keyCode === 9) { // down arrow or tab
      if (this.focusIndex < this.options.length - 1) {
        this.options[++this.focusIndex].focus();
      }
    }
  }
  /**
   * @param {Event} e
   */
  mouseoverCallback(e) {
    const index = this.options.indexOf(e.target);
    if (index > -1) {
      this.focusIndex = index;
    }
  }
  /**
   * Updated selected value and dispatches a custom event with that value
   *
   * @param {Boolean} dispatch
   * @fires AoflSelectList.change
   */
  updateSelected(option, dispatch = true, init = false) {
    option.setAttribute('selected', '');
    option.selected = true;
    this.value = option.value;
    if (dispatch) {
      this.dispatchEvent(new CustomEvent('change', {composed: true, bubbles: true}));
    }
    for (let i = 0; i < this.options.length; i++) {
      if (this.options[i] !== option) {
        this.options[i].selected = false;
      }
    }
  }
  /**
   * Add an option to be selected
   *
   * @param {String} option
   */
  addOption(option) {
    this.options.push(option);

    if (this.options.length === 1) {
      this.value = option.value;
    } else if (option.selected) {
      this.updateSelected(option, false);
    }
  }
  /**
   *
   */
  connectedCallback() {
    super.connectedCallback();
    this.addEventListener('keydown', this.keydownCallback);
    this.addEventListener('focusout', this.focusoutCallback);
    this.addEventListener('mouseover', this.mouseoverCallback);
  }
  /**
   * @return {Object}
   */
  render() {
    return super.render((ctx, html) => html`<slot></slot>`, [styles]);
  }
  /**
   *
   */
  disconnectedCallback() {
    super.disconnectedCallback();
    this.removeEventListener('keydown', this.keydownCallback);
    this.removeEventListener('focusout', this.focusoutCallback);
    this.removeEventListener('mouseover', this.mouseoverCallback);
  }
}

if (window.customElements.get(AoflSelectList.is) === void 0) {
  window.customElements.define(AoflSelectList.is, AoflSelectList);
}

export default AoflSelectList;