text: import $ from 'jquery';
  
  var dirs = {
      x: ['width', 'left', 'right'],
      y: ['height', 'top', 'bottom']
  };
  
  export function position(element, target, attach, targetAttach, offset, targetOffset, flip, boundary) {
  
      element = $(element);
      target = $(target);
      boundary = boundary && $(boundary);
      attach = getPos(attach);
      targetAttach = getPos(targetAttach);
  
      var dim = getDimensions(element),
          targetDim = getDimensions(target),
          position = targetDim;
  
      moveTo(position, attach, dim, -1);
      moveTo(position, targetAttach, targetDim, 1);
  
      offset = getOffsets(offset, dim.width, dim.height);
      targetOffset = getOffsets(targetOffset, targetDim.width, targetDim.height);
  
      offset['x'] += targetOffset['x'];
      offset['y'] += targetOffset['y'];
  
      position.left += offset['x'];
      position.top += offset['y'];
  
      boundary = getDimensions(boundary || window);
  
      var flipped = {element: attach, target: targetAttach};
  
      if (flip) {
          $.each(dirs, (dir, [prop, align, alignFlip]) => {
  
              if (!(flip === true || ~flip.indexOf(dir))) {
                  return;
              }
  
              var elemOffset = attach[dir] === align ? -dim[prop] : attach[dir] === alignFlip ? dim[prop] : 0,
                  targetOffset = targetAttach[dir] === align ? targetDim[prop] : targetAttach[dir] === alignFlip ? -targetDim[prop] : 0;
  
              if (position[align] < boundary[align] || position[align] + dim[prop] > boundary[alignFlip]) {
  
                  var newVal = position[align] + elemOffset + targetOffset - offset[dir] * 2;
  
                  if (newVal >= boundary[align] && newVal + dim[prop] <= boundary[alignFlip]) {
                      position[align] = newVal;
  
                      ['element', 'target'].forEach((el) => {
                          flipped[el][dir] = !elemOffset
                              ? flipped[el][dir]
                              : flipped[el][dir] === dirs[dir][1]
                                  ? dirs[dir][2]
                                  : dirs[dir][1];
                      });
                  }
              }
  
          });
      }
  
      element.offset({left: position.left, top: position.top});
  
      return flipped;
  }
  
  export function getDimensions(elem) {
  
      elem = $(elem);
  
      var width = Math.round(elem.outerWidth()),
          height = Math.round(elem.outerHeight()),
          offset = elem[0].getClientRects ? elem.offset() : null,
          left = offset ? Math.round(offset.left) : elem.scrollLeft(),
          top = offset ? Math.round(offset.top) : elem.scrollTop();
  
      return {width, height, left, top, right: left + width, bottom: top + height};
  }
  
  function moveTo(position, attach, dim, factor) {
      $.each(dirs, function (dir, [prop, align, alignFlip]) {
          if (attach[dir] === alignFlip) {
              position[align] += dim[prop] * factor;
          } else if (attach[dir] === 'center') {
              position[align] += dim[prop] * factor / 2;
          }
      });
  }
  
  function getPos(pos) {
  
      var x = /left|center|right/, y = /top|center|bottom/;
  
      pos = (pos || '').split(' ');
  
      if (pos.length === 1) {
          pos = x.test(pos[0])
              ? pos.concat(['center'])
              : y.test(pos[0])
                  ? ['center'].concat(pos)
                  : ['center', 'center'];
      }
  
      return {
          x: x.test(pos[0]) ? pos[0] : 'center',
          y: y.test(pos[1]) ? pos[1] : 'center'
      };
  }
  
  function getOffsets(offsets, width, height) {
  
      offsets = (offsets || '').split(' ');
  
      return {
          x: offsets[0] ? parseFloat(offsets[0]) * (offsets[0][offsets[0].length - 1] === '%' ? width / 100 : 1) : 0,
          y: offsets[1] ? parseFloat(offsets[1]) * (offsets[1][offsets[1].length - 1] === '%' ? height / 100 : 1) : 0
      };
  }
  
  export function flipPosition(pos) {
      switch (pos) {
          case 'left':
              return 'right';
          case 'right':
              return 'left';
          case 'top':
              return 'bottom';
          case 'bottom':
              return 'top';
          default:
              return pos;
      }
  }
  