hummingbird-me/kitsu-web

View on GitHub
lib/kitsu-shared/addon/components/occludable-area.js

Summary

Maintainability
B
4 hrs
Test Coverage
F
0%
import Component from '@ember/component';
import { get, set } from '@ember/object';
import layout from 'kitsu-shared/templates/components/occludable-area';
import observerManager from 'client/utils/observer-manager';
import { mutateDOM } from 'ember-batcher/batcher';

/**
 * Occlusion based off work from LinkedIn.
 * Original source @ https://github.com/sreedhar7/ember-occludable-components
 *
 * {{#occludable-area bufferClass="class-name"}}
 *   {{my-component}}
 * {{/occludable-area}}
 */
export default Component.extend({
  layout,
  classNames: ['occludable-area'],
  shouldRender: false,

  didInsertElement() {
    this._super(...arguments);
    const element = get(this, 'element');
    element.classList.add(get(this, 'bufferClass'));

    const observe = observerManager(this._getObserverOptions());
    this.unobserve = observe(element, entry => {
      if (entry && entry.isIntersecting) {
        this.isVisible();
        if (this.unobserve) { this.unobserve(); }
      }
    });
  },

  didRender() {
    this._super(...arguments);
    // Buffer class is no longer needed once the component has been rendered
    if (get(this, 'shouldRender')) {
      get(this, 'element').classList.remove(get(this, 'bufferClass'));
    }
  },

  willDestroyElement() {
    this._super(...arguments);
    if (this.unobserve) { this.unobserve(); }
  },

  isVisible() {
    if (get(this, 'isDestroyed')) { return; }
    mutateDOM(() => {
      if (get(this, 'isDestroyed')) { return; }
      mutateDOM(() => {
        if (get(this, 'isDestroyed')) { return; }
        set(this, 'shouldRender', true);
      });
    });
  },

  /**
   * Returns the config passed to the IntersectionObserver
   *
   * @returns {Object} RootMargin config
   */
  _getObserverOptions() {
    const defaultOptions = this._getDefaultRootMargin();
    let rootMargin = Object.assign(defaultOptions, get(this, 'rootMargin') || {});
    rootMargin = `${rootMargin.top}px ${rootMargin.right}px ${rootMargin.bottom}px ${rootMargin.left}px`;
    return { root: null, rootMargin, threshold: 0 };
  },

  _getDefaultRootMargin() {
    return { top: 0, left: 0, right: 0, bottom: 0 };
  }
});