all files / addon/components/ polaris-popover.js

33.33% Statements 9/27
22.22% Branches 4/18
60% Functions 3/5
33.33% Lines 9/27
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182                                                                                                                                                                                                                                                                                                                                                         
import Ember from 'ember';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { htmlSafe } from '@ember/string';
import { warn } from '@ember/debug';
import layout from '../templates/components/polaris-popover';
 
const { ViewUtils } = Ember;
const ABOVE = 'above';
const BELOW = 'below';
 
/**
 * Polaris popover component.
 * See https://polaris.shopify.com/components/overlays/popover
 */
export default Component.extend({
  tagName: '',
 
  layout,
 
  /*
   * Public attributes.
   */
  /**
   * The content to display inside the popover
   *
   * This component can be used in block form,
   * in which case the block content will be used
   * instead of `text`
   *
   * @property text
   * @type {string}
   * @default null
   */
  text: null,
 
  /**
   * The preferred direction to open the popover
   *
   * @property preferredPosition
   * @type {string}
   * @default 'below'
   */
  preferredPosition: BELOW,
 
  /**
   * Show or hide the Popover
   *
   * @property active
   * @type {boolean}
   * @default false
   * TODO: not implemented
   */
  active: false,
 
  /**
   * The element type to wrap the activator with
   *
   * @property activatorWrapper
   * @type {string}
   * @default null
   * TODO: not implemented
   */
  activatorWrapper: null,
 
  /**
   * Prevent automatic focus of the first field on activation
   *
   * @property preventAutofocus
   * @type {boolean}
   * @default false
   * TODO: not implemented
   */
  preventAutofocus: false,
 
  /**
   * Automatically add wrap content in a section
   *
   * @property sectioned
   * @type {boolean}
   * @default false
   */
  sectioned: false,
 
  /**
   * Callback when popover is closed
   *
   * @property onClose
   * @type {function(source: React.ReactElement)}
   * @default null
   * TODO: not implemented
   */
  onClose: null,
 
  /*
   * Internal properties.
   */
  verticalPosition: computed('preferredPosition', {
    // If `preferredPosition` is set to `mostSpace`, the value
    // will be calculated and set when the user opens the popover.
    // The only allowed values are 'above' and 'below', so we
    // return null for anything other than those values and let
    // ember-basic-dropdown use its default value.
    get() {
      let preferredPosition = this.get('preferredPosition');
 
      Eif (preferredPosition === ABOVE || preferredPosition === BELOW) {
        return preferredPosition;
      }
 
      return null;
    },
 
    set(key, value) {
      if (value === ABOVE || value === BELOW) {
        return value;
      }
 
      return null;
    }
  }),
 
  triggerStyle: computed(function() {
    return htmlSafe(`
      display: inline-block;
      overflow: inherit;
      border: none;
    `);
  }).readOnly(),
 
  /**
   * Checks the dropdown activator's location on
   * screen to determine which vertical direction
   * has more space to open the dropdown.
   */
  getMostVerticalSpace() {
    let component;
 
    // Hack to get the component's container
    // element since this component uses `tagName: ''`
    // https://github.com/emberjs/rfcs/issues/168#issue-178381310
    if (ViewUtils && ViewUtils.getViewBounds) {
      component =  ViewUtils.getViewBounds(this).parentElement;
    } else {
      component = this._renderNode.contextualElement;
    }
 
    let activators = component.querySelectorAll('.ember-basic-dropdown-trigger');
 
    if (activators.length > 1) {
      warn(
        'Multiple popover activators found. Defaulting to `preferredPosition` of `below`',
        { id: 'ember-polaris.polaris-popover.multiple-popover-activators' }
      );
 
      return BELOW;
    }
 
    let [activator] = activators;
    let { top, bottom } = activator.getBoundingClientRect();
    let windowHeight = window.innerHeight;
    let bottomSpace = windowHeight - bottom;
 
    // Use `below` if distance is equal
    return bottomSpace >= top ? BELOW : ABOVE;
  },
 
  actions: {
    onOpen() {
      // Check to see if `preferredPosition` is set to `mostSpace`
      // onOpen, since user could have scrolled vertically since
      // the time the component originally rendered.
      let preferredPosition = this.get('preferredPosition');
 
      Iif (preferredPosition === 'mostSpace') {
        this.set('verticalPosition', this.getMostVerticalSpace());
      }
    }
  }
});