Source: element/modules/decorators.js

/**
 * @summary decorators
 * @version 3.0.0
 * @since 3.0.0
 * @author Arian Khosravi<arian.khosravi@aofl.com>
 */
import {storeInstance} from '@aofl/store';
import {get, has} from '@aofl/object-utils';
import {property as litProperty, customElement as litCustomElement} from 'lit-element/lib/decorators';

/**
 * @memberof module:@aofl/element
 * @private
 * @type {Object}
 */
const MapStateDeclaration = {
  store: storeInstance,
  mapState: ''
};

/**
 * extends lit-element's property decorator and adds support for map state to @aofl/store.
 *
 * @memberof module:@aofl/element
 *
 * @param {Object} options
 * @param {Boolean|String} options.attribute
 * @param {TypeHint} options.type
 * @param {Function} options.converter
 * @param {Boolean} options.reflect
 * @param {Function} options.hasChanged
 * @param {Boolean} options.noAccessor
 * @param {Store} options.store,
 * @param {String} options.mapState
 * @return {Object}
 */
export function property(options = MapStateDeclaration) {
  const _options = Object.assign({}, MapStateDeclaration, options);

  return (protoOrDescriptor, name) => {
    const propertyDecorator = litProperty(_options);
    const descriptor = propertyDecorator(protoOrDescriptor, name);

    return Object.assign({}, descriptor, {
      initializer() {
        /* istanbul ignore next */
        if (typeof descriptor.initializer === 'function') {
          descriptor.initializer.call(this);
        }

        /* istanbul ignore next */
        if (_options.mapState !== '') {
          const updateValue = () => {
            const state = _options.store.state;
            if (has(state, _options.mapState)) {
              this[protoOrDescriptor.key] = get(state, _options.mapState);
            } else {
              this[protoOrDescriptor.key] = get(_options.store, _options.mapState);
            }
          };

          updateValue();
          const unsubscribe = _options.store.subscribe(updateValue);
          this._observedPropertiesMap.set(protoOrDescriptor.key, unsubscribe);
        }
      }
    });
  };
}


/**
 * extends lit-element's custom-element decorator and prevents an error being thrown when
 * the element is already defined when hot module replacement is enabled.
 *
 * @memberof module:@aofl/element
 * @param {String} tagName
 * @return {Object}
 */
export function customElement(tagName) {
  return (descriptor) => {
    if (window.customElements.get(tagName) !== void 0) {
      return descriptor;
    }
    return litCustomElement(tagName)(descriptor);
  };
}