Reference Source

coral-spectrum/coral-base-list/src/scripts/BaseListItem.js

/**
 * Copyright 2019 Adobe. All rights reserved.
 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. You may obtain a copy
 * of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
 * OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

import {BaseLabellable} from '../../../coral-base-labellable';
import {Icon} from '../../../coral-component-icon';
import {transform, validate} from '../../../coral-utils';

const CLASSNAME = '_coral-Menu-item';

/**
 @base BaseListItem
 @classdesc The base element for List Item components
 */
const BaseListItem = (superClass) => class extends BaseLabellable(superClass) {
  /** @ignore */
  constructor() {
    super();

    // Templates
    this._elements = {
      // Fetch or create the content zone element
      content: this.querySelector('coral-list-item-content') || document.createElement('coral-list-item-content')
    };

    super._observeLabel();
  }

  /**
   The content of the help item.

   @type {ListItemContent}
   @contentzone
   */
  get content() {
    return this._getContentZone(this._elements.content);
  }

  set content(value) {
    this._setContentZone('content', value, {
      handle: 'content',
      tagName: 'coral-list-item-content',
      insert: (content) => {
        content.classList.add(`${CLASSNAME}Label`);
        this.appendChild(content);
        super._toggleIconAriaHidden();
      }
    });
  }

  /**
   Whether this item is disabled.

   @default false
   @type {Boolean}
   @htmlattribute disabled
   @htmlattributereflected
   */
  get disabled() {
    return this._disabled || false;
  }

  set disabled(value) {
    value = transform.booleanAttr(value);
    this._reflectAttribute('disabled', value);
    
    if(validate.valueMustChange(this._disabled, value)) {
      this._disabled = value;
      this.classList.toggle('is-disabled', value);
      this[value ? 'setAttribute' : 'removeAttribute']('aria-disabled', value);
    }
  }

  /**
   The icon to display. See {@link Icon}.

   @type {String}
   @default ""
   @htmlattribute icon
   */
  get icon() {
    const el = this._getIconElement();
    return el.icon;
  }

  set icon(value) {
    const el = this._getIconElement();
    if (transform.string(value) === '') {
      el.remove();
    } else {
      this.insertBefore(el, this.firstChild);
    }

    el.icon = value;

    super._toggleIconAriaHidden();
  }

  _getIconElement() {
    if (!this._elements.icon) {
      this._elements.icon = this.querySelector('._coral-Menu-item-icon') || new Icon();
      this._elements.icon.size = Icon.size.SMALL;
      this._elements.icon.classList.add('_coral-Menu-item-icon');
    }
    return this._elements.icon;
  }

  get _contentZones() {
    return {'coral-list-item-content': 'content'};
  }

  /** @ignore */
  static get observedAttributes() {
    return super.observedAttributes.concat(['disabled', 'icon']);
  }

  /** @ignore */
  render() {
    super.render();

    this.classList.add(CLASSNAME);

    // The attribute that makes different types of list items co-exist
    // This is also used for event delegation
    this.setAttribute('coral-list-item', '');

    // Fetch or create the content content zone element
    const content = this._elements.content;

    // This stops the content zone from being voracious
    if (!content.parentNode) {
      // move the contents of the item into the content zone
      while (this.firstChild) {
        content.appendChild(this.firstChild);
      }
    }

    // Assign the content zones, moving them into place in the process
    this.icon = this.icon;
    this.content = content;
  }
};

export default BaseListItem;