MDL-61852 lib: move popper.js to core
[moodle.git] / lib / amd / src / popper.js
1 /**!
2  * @fileOverview Kickass library to create and place poppers near their reference elements.
3  * @version 1.12.9
4  * @license
5  * Copyright (c) 2016 Federico Zivolo and contributors
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 (function (global, factory) {
26         typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
27         typeof define === 'function' && define.amd ? define(factory) :
28         (global.Popper = factory());
29 }(this, (function () { 'use strict';
31 var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
32 var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
33 var timeoutDuration = 0;
34 for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
35   if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
36     timeoutDuration = 1;
37     break;
38   }
39 }
41 function microtaskDebounce(fn) {
42   var called = false;
43   return function () {
44     if (called) {
45       return;
46     }
47     called = true;
48     window.Promise.resolve().then(function () {
49       called = false;
50       fn();
51     });
52   };
53 }
55 function taskDebounce(fn) {
56   var scheduled = false;
57   return function () {
58     if (!scheduled) {
59       scheduled = true;
60       setTimeout(function () {
61         scheduled = false;
62         fn();
63       }, timeoutDuration);
64     }
65   };
66 }
68 var supportsMicroTasks = isBrowser && window.Promise;
70 /**
71 * Create a debounced version of a method, that's asynchronously deferred
72 * but called in the minimum time possible.
73 *
74 * @method
75 * @memberof Popper.Utils
76 * @argument {Function} fn
77 * @returns {Function}
78 */
79 var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;
81 /**
82  * Check if the given variable is a function
83  * @method
84  * @memberof Popper.Utils
85  * @argument {Any} functionToCheck - variable to check
86  * @returns {Boolean} answer to: is a function?
87  */
88 function isFunction(functionToCheck) {
89   var getType = {};
90   return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
91 }
93 /**
94  * Get CSS computed property of the given element
95  * @method
96  * @memberof Popper.Utils
97  * @argument {Eement} element
98  * @argument {String} property
99  */
100 function getStyleComputedProperty(element, property) {
101   if (element.nodeType !== 1) {
102     return [];
103   }
104   // NOTE: 1 DOM access here
105   var css = getComputedStyle(element, null);
106   return property ? css[property] : css;
109 /**
110  * Returns the parentNode or the host of the element
111  * @method
112  * @memberof Popper.Utils
113  * @argument {Element} element
114  * @returns {Element} parent
115  */
116 function getParentNode(element) {
117   if (element.nodeName === 'HTML') {
118     return element;
119   }
120   return element.parentNode || element.host;
123 /**
124  * Returns the scrolling parent of the given element
125  * @method
126  * @memberof Popper.Utils
127  * @argument {Element} element
128  * @returns {Element} scroll parent
129  */
130 function getScrollParent(element) {
131   // Return body, `getScroll` will take care to get the correct `scrollTop` from it
132   if (!element) {
133     return document.body;
134   }
136   switch (element.nodeName) {
137     case 'HTML':
138     case 'BODY':
139       return element.ownerDocument.body;
140     case '#document':
141       return element.body;
142   }
144   // Firefox want us to check `-x` and `-y` variations as well
146   var _getStyleComputedProp = getStyleComputedProperty(element),
147       overflow = _getStyleComputedProp.overflow,
148       overflowX = _getStyleComputedProp.overflowX,
149       overflowY = _getStyleComputedProp.overflowY;
151   if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) {
152     return element;
153   }
155   return getScrollParent(getParentNode(element));
158 /**
159  * Returns the offset parent of the given element
160  * @method
161  * @memberof Popper.Utils
162  * @argument {Element} element
163  * @returns {Element} offset parent
164  */
165 function getOffsetParent(element) {
166   // NOTE: 1 DOM access here
167   var offsetParent = element && element.offsetParent;
168   var nodeName = offsetParent && offsetParent.nodeName;
170   if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
171     if (element) {
172       return element.ownerDocument.documentElement;
173     }
175     return document.documentElement;
176   }
178   // .offsetParent will return the closest TD or TABLE in case
179   // no offsetParent is present, I hate this job...
180   if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
181     return getOffsetParent(offsetParent);
182   }
184   return offsetParent;
187 function isOffsetContainer(element) {
188   var nodeName = element.nodeName;
190   if (nodeName === 'BODY') {
191     return false;
192   }
193   return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
196 /**
197  * Finds the root node (document, shadowDOM root) of the given element
198  * @method
199  * @memberof Popper.Utils
200  * @argument {Element} node
201  * @returns {Element} root node
202  */
203 function getRoot(node) {
204   if (node.parentNode !== null) {
205     return getRoot(node.parentNode);
206   }
208   return node;
211 /**
212  * Finds the offset parent common to the two provided nodes
213  * @method
214  * @memberof Popper.Utils
215  * @argument {Element} element1
216  * @argument {Element} element2
217  * @returns {Element} common offset parent
218  */
219 function findCommonOffsetParent(element1, element2) {
220   // This check is needed to avoid errors in case one of the elements isn't defined for any reason
221   if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
222     return document.documentElement;
223   }
225   // Here we make sure to give as "start" the element that comes first in the DOM
226   var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
227   var start = order ? element1 : element2;
228   var end = order ? element2 : element1;
230   // Get common ancestor container
231   var range = document.createRange();
232   range.setStart(start, 0);
233   range.setEnd(end, 0);
234   var commonAncestorContainer = range.commonAncestorContainer;
236   // Both nodes are inside #document
238   if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
239     if (isOffsetContainer(commonAncestorContainer)) {
240       return commonAncestorContainer;
241     }
243     return getOffsetParent(commonAncestorContainer);
244   }
246   // one of the nodes is inside shadowDOM, find which one
247   var element1root = getRoot(element1);
248   if (element1root.host) {
249     return findCommonOffsetParent(element1root.host, element2);
250   } else {
251     return findCommonOffsetParent(element1, getRoot(element2).host);
252   }
255 /**
256  * Gets the scroll value of the given element in the given side (top and left)
257  * @method
258  * @memberof Popper.Utils
259  * @argument {Element} element
260  * @argument {String} side `top` or `left`
261  * @returns {number} amount of scrolled pixels
262  */
263 function getScroll(element) {
264   var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
266   var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
267   var nodeName = element.nodeName;
269   if (nodeName === 'BODY' || nodeName === 'HTML') {
270     var html = element.ownerDocument.documentElement;
271     var scrollingElement = element.ownerDocument.scrollingElement || html;
272     return scrollingElement[upperSide];
273   }
275   return element[upperSide];
278 /*
279  * Sum or subtract the element scroll values (left and top) from a given rect object
280  * @method
281  * @memberof Popper.Utils
282  * @param {Object} rect - Rect object you want to change
283  * @param {HTMLElement} element - The element from the function reads the scroll values
284  * @param {Boolean} subtract - set to true if you want to subtract the scroll values
285  * @return {Object} rect - The modifier rect object
286  */
287 function includeScroll(rect, element) {
288   var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
290   var scrollTop = getScroll(element, 'top');
291   var scrollLeft = getScroll(element, 'left');
292   var modifier = subtract ? -1 : 1;
293   rect.top += scrollTop * modifier;
294   rect.bottom += scrollTop * modifier;
295   rect.left += scrollLeft * modifier;
296   rect.right += scrollLeft * modifier;
297   return rect;
300 /*
301  * Helper to detect borders of a given element
302  * @method
303  * @memberof Popper.Utils
304  * @param {CSSStyleDeclaration} styles
305  * Result of `getStyleComputedProperty` on the given element
306  * @param {String} axis - `x` or `y`
307  * @return {number} borders - The borders size of the given axis
308  */
310 function getBordersSize(styles, axis) {
311   var sideA = axis === 'x' ? 'Left' : 'Top';
312   var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
314   return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);
317 /**
318  * Tells if you are running Internet Explorer 10
319  * @method
320  * @memberof Popper.Utils
321  * @returns {Boolean} isIE10
322  */
323 var isIE10 = undefined;
325 var isIE10$1 = function () {
326   if (isIE10 === undefined) {
327     isIE10 = navigator.appVersion.indexOf('MSIE 10') !== -1;
328   }
329   return isIE10;
330 };
332 function getSize(axis, body, html, computedStyle) {
333   return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE10$1() ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0);
336 function getWindowSizes() {
337   var body = document.body;
338   var html = document.documentElement;
339   var computedStyle = isIE10$1() && getComputedStyle(html);
341   return {
342     height: getSize('Height', body, html, computedStyle),
343     width: getSize('Width', body, html, computedStyle)
344   };
347 var classCallCheck = function (instance, Constructor) {
348   if (!(instance instanceof Constructor)) {
349     throw new TypeError("Cannot call a class as a function");
350   }
351 };
353 var createClass = function () {
354   function defineProperties(target, props) {
355     for (var i = 0; i < props.length; i++) {
356       var descriptor = props[i];
357       descriptor.enumerable = descriptor.enumerable || false;
358       descriptor.configurable = true;
359       if ("value" in descriptor) descriptor.writable = true;
360       Object.defineProperty(target, descriptor.key, descriptor);
361     }
362   }
364   return function (Constructor, protoProps, staticProps) {
365     if (protoProps) defineProperties(Constructor.prototype, protoProps);
366     if (staticProps) defineProperties(Constructor, staticProps);
367     return Constructor;
368   };
369 }();
375 var defineProperty = function (obj, key, value) {
376   if (key in obj) {
377     Object.defineProperty(obj, key, {
378       value: value,
379       enumerable: true,
380       configurable: true,
381       writable: true
382     });
383   } else {
384     obj[key] = value;
385   }
387   return obj;
388 };
390 var _extends = Object.assign || function (target) {
391   for (var i = 1; i < arguments.length; i++) {
392     var source = arguments[i];
394     for (var key in source) {
395       if (Object.prototype.hasOwnProperty.call(source, key)) {
396         target[key] = source[key];
397       }
398     }
399   }
401   return target;
402 };
404 /**
405  * Given element offsets, generate an output similar to getBoundingClientRect
406  * @method
407  * @memberof Popper.Utils
408  * @argument {Object} offsets
409  * @returns {Object} ClientRect like output
410  */
411 function getClientRect(offsets) {
412   return _extends({}, offsets, {
413     right: offsets.left + offsets.width,
414     bottom: offsets.top + offsets.height
415   });
418 /**
419  * Get bounding client rect of given element
420  * @method
421  * @memberof Popper.Utils
422  * @param {HTMLElement} element
423  * @return {Object} client rect
424  */
425 function getBoundingClientRect(element) {
426   var rect = {};
428   // IE10 10 FIX: Please, don't ask, the element isn't
429   // considered in DOM in some circumstances...
430   // This isn't reproducible in IE10 compatibility mode of IE11
431   if (isIE10$1()) {
432     try {
433       rect = element.getBoundingClientRect();
434       var scrollTop = getScroll(element, 'top');
435       var scrollLeft = getScroll(element, 'left');
436       rect.top += scrollTop;
437       rect.left += scrollLeft;
438       rect.bottom += scrollTop;
439       rect.right += scrollLeft;
440     } catch (err) {}
441   } else {
442     rect = element.getBoundingClientRect();
443   }
445   var result = {
446     left: rect.left,
447     top: rect.top,
448     width: rect.right - rect.left,
449     height: rect.bottom - rect.top
450   };
452   // subtract scrollbar size from sizes
453   var sizes = element.nodeName === 'HTML' ? getWindowSizes() : {};
454   var width = sizes.width || element.clientWidth || result.right - result.left;
455   var height = sizes.height || element.clientHeight || result.bottom - result.top;
457   var horizScrollbar = element.offsetWidth - width;
458   var vertScrollbar = element.offsetHeight - height;
460   // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
461   // we make this check conditional for performance reasons
462   if (horizScrollbar || vertScrollbar) {
463     var styles = getStyleComputedProperty(element);
464     horizScrollbar -= getBordersSize(styles, 'x');
465     vertScrollbar -= getBordersSize(styles, 'y');
467     result.width -= horizScrollbar;
468     result.height -= vertScrollbar;
469   }
471   return getClientRect(result);
474 function getOffsetRectRelativeToArbitraryNode(children, parent) {
475   var isIE10 = isIE10$1();
476   var isHTML = parent.nodeName === 'HTML';
477   var childrenRect = getBoundingClientRect(children);
478   var parentRect = getBoundingClientRect(parent);
479   var scrollParent = getScrollParent(children);
481   var styles = getStyleComputedProperty(parent);
482   var borderTopWidth = parseFloat(styles.borderTopWidth, 10);
483   var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);
485   var offsets = getClientRect({
486     top: childrenRect.top - parentRect.top - borderTopWidth,
487     left: childrenRect.left - parentRect.left - borderLeftWidth,
488     width: childrenRect.width,
489     height: childrenRect.height
490   });
491   offsets.marginTop = 0;
492   offsets.marginLeft = 0;
494   // Subtract margins of documentElement in case it's being used as parent
495   // we do this only on HTML because it's the only element that behaves
496   // differently when margins are applied to it. The margins are included in
497   // the box of the documentElement, in the other cases not.
498   if (!isIE10 && isHTML) {
499     var marginTop = parseFloat(styles.marginTop, 10);
500     var marginLeft = parseFloat(styles.marginLeft, 10);
502     offsets.top -= borderTopWidth - marginTop;
503     offsets.bottom -= borderTopWidth - marginTop;
504     offsets.left -= borderLeftWidth - marginLeft;
505     offsets.right -= borderLeftWidth - marginLeft;
507     // Attach marginTop and marginLeft because in some circumstances we may need them
508     offsets.marginTop = marginTop;
509     offsets.marginLeft = marginLeft;
510   }
512   if (isIE10 ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
513     offsets = includeScroll(offsets, parent);
514   }
516   return offsets;
519 function getViewportOffsetRectRelativeToArtbitraryNode(element) {
520   var html = element.ownerDocument.documentElement;
521   var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
522   var width = Math.max(html.clientWidth, window.innerWidth || 0);
523   var height = Math.max(html.clientHeight, window.innerHeight || 0);
525   var scrollTop = getScroll(html);
526   var scrollLeft = getScroll(html, 'left');
528   var offset = {
529     top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
530     left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
531     width: width,
532     height: height
533   };
535   return getClientRect(offset);
538 /**
539  * Check if the given element is fixed or is inside a fixed parent
540  * @method
541  * @memberof Popper.Utils
542  * @argument {Element} element
543  * @argument {Element} customContainer
544  * @returns {Boolean} answer to "isFixed?"
545  */
546 function isFixed(element) {
547   var nodeName = element.nodeName;
548   if (nodeName === 'BODY' || nodeName === 'HTML') {
549     return false;
550   }
551   if (getStyleComputedProperty(element, 'position') === 'fixed') {
552     return true;
553   }
554   return isFixed(getParentNode(element));
557 /**
558  * Computed the boundaries limits and return them
559  * @method
560  * @memberof Popper.Utils
561  * @param {HTMLElement} popper
562  * @param {HTMLElement} reference
563  * @param {number} padding
564  * @param {HTMLElement} boundariesElement - Element used to define the boundaries
565  * @returns {Object} Coordinates of the boundaries
566  */
567 function getBoundaries(popper, reference, padding, boundariesElement) {
568   // NOTE: 1 DOM access here
569   var boundaries = { top: 0, left: 0 };
570   var offsetParent = findCommonOffsetParent(popper, reference);
572   // Handle viewport case
573   if (boundariesElement === 'viewport') {
574     boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent);
575   } else {
576     // Handle other cases based on DOM element used as boundaries
577     var boundariesNode = void 0;
578     if (boundariesElement === 'scrollParent') {
579       boundariesNode = getScrollParent(getParentNode(reference));
580       if (boundariesNode.nodeName === 'BODY') {
581         boundariesNode = popper.ownerDocument.documentElement;
582       }
583     } else if (boundariesElement === 'window') {
584       boundariesNode = popper.ownerDocument.documentElement;
585     } else {
586       boundariesNode = boundariesElement;
587     }
589     var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent);
591     // In case of HTML, we need a different computation
592     if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
593       var _getWindowSizes = getWindowSizes(),
594           height = _getWindowSizes.height,
595           width = _getWindowSizes.width;
597       boundaries.top += offsets.top - offsets.marginTop;
598       boundaries.bottom = height + offsets.top;
599       boundaries.left += offsets.left - offsets.marginLeft;
600       boundaries.right = width + offsets.left;
601     } else {
602       // for all the other DOM elements, this one is good
603       boundaries = offsets;
604     }
605   }
607   // Add paddings
608   boundaries.left += padding;
609   boundaries.top += padding;
610   boundaries.right -= padding;
611   boundaries.bottom -= padding;
613   return boundaries;
616 function getArea(_ref) {
617   var width = _ref.width,
618       height = _ref.height;
620   return width * height;
623 /**
624  * Utility used to transform the `auto` placement to the placement with more
625  * available space.
626  * @method
627  * @memberof Popper.Utils
628  * @argument {Object} data - The data object generated by update method
629  * @argument {Object} options - Modifiers configuration and options
630  * @returns {Object} The data object, properly modified
631  */
632 function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
633   var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
635   if (placement.indexOf('auto') === -1) {
636     return placement;
637   }
639   var boundaries = getBoundaries(popper, reference, padding, boundariesElement);
641   var rects = {
642     top: {
643       width: boundaries.width,
644       height: refRect.top - boundaries.top
645     },
646     right: {
647       width: boundaries.right - refRect.right,
648       height: boundaries.height
649     },
650     bottom: {
651       width: boundaries.width,
652       height: boundaries.bottom - refRect.bottom
653     },
654     left: {
655       width: refRect.left - boundaries.left,
656       height: boundaries.height
657     }
658   };
660   var sortedAreas = Object.keys(rects).map(function (key) {
661     return _extends({
662       key: key
663     }, rects[key], {
664       area: getArea(rects[key])
665     });
666   }).sort(function (a, b) {
667     return b.area - a.area;
668   });
670   var filteredAreas = sortedAreas.filter(function (_ref2) {
671     var width = _ref2.width,
672         height = _ref2.height;
673     return width >= popper.clientWidth && height >= popper.clientHeight;
674   });
676   var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;
678   var variation = placement.split('-')[1];
680   return computedPlacement + (variation ? '-' + variation : '');
683 /**
684  * Get offsets to the reference element
685  * @method
686  * @memberof Popper.Utils
687  * @param {Object} state
688  * @param {Element} popper - the popper element
689  * @param {Element} reference - the reference element (the popper will be relative to this)
690  * @returns {Object} An object containing the offsets which will be applied to the popper
691  */
692 function getReferenceOffsets(state, popper, reference) {
693   var commonOffsetParent = findCommonOffsetParent(popper, reference);
694   return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent);
697 /**
698  * Get the outer sizes of the given element (offset size + margins)
699  * @method
700  * @memberof Popper.Utils
701  * @argument {Element} element
702  * @returns {Object} object containing width and height properties
703  */
704 function getOuterSizes(element) {
705   var styles = getComputedStyle(element);
706   var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
707   var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
708   var result = {
709     width: element.offsetWidth + y,
710     height: element.offsetHeight + x
711   };
712   return result;
715 /**
716  * Get the opposite placement of the given one
717  * @method
718  * @memberof Popper.Utils
719  * @argument {String} placement
720  * @returns {String} flipped placement
721  */
722 function getOppositePlacement(placement) {
723   var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
724   return placement.replace(/left|right|bottom|top/g, function (matched) {
725     return hash[matched];
726   });
729 /**
730  * Get offsets to the popper
731  * @method
732  * @memberof Popper.Utils
733  * @param {Object} position - CSS position the Popper will get applied
734  * @param {HTMLElement} popper - the popper element
735  * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
736  * @param {String} placement - one of the valid placement options
737  * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
738  */
739 function getPopperOffsets(popper, referenceOffsets, placement) {
740   placement = placement.split('-')[0];
742   // Get popper node sizes
743   var popperRect = getOuterSizes(popper);
745   // Add position, width and height to our offsets object
746   var popperOffsets = {
747     width: popperRect.width,
748     height: popperRect.height
749   };
751   // depending by the popper placement we have to compute its offsets slightly differently
752   var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
753   var mainSide = isHoriz ? 'top' : 'left';
754   var secondarySide = isHoriz ? 'left' : 'top';
755   var measurement = isHoriz ? 'height' : 'width';
756   var secondaryMeasurement = !isHoriz ? 'height' : 'width';
758   popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
759   if (placement === secondarySide) {
760     popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
761   } else {
762     popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
763   }
765   return popperOffsets;
768 /**
769  * Mimics the `find` method of Array
770  * @method
771  * @memberof Popper.Utils
772  * @argument {Array} arr
773  * @argument prop
774  * @argument value
775  * @returns index or -1
776  */
777 function find(arr, check) {
778   // use native find if supported
779   if (Array.prototype.find) {
780     return arr.find(check);
781   }
783   // use `filter` to obtain the same behavior of `find`
784   return arr.filter(check)[0];
787 /**
788  * Return the index of the matching object
789  * @method
790  * @memberof Popper.Utils
791  * @argument {Array} arr
792  * @argument prop
793  * @argument value
794  * @returns index or -1
795  */
796 function findIndex(arr, prop, value) {
797   // use native findIndex if supported
798   if (Array.prototype.findIndex) {
799     return arr.findIndex(function (cur) {
800       return cur[prop] === value;
801     });
802   }
804   // use `find` + `indexOf` if `findIndex` isn't supported
805   var match = find(arr, function (obj) {
806     return obj[prop] === value;
807   });
808   return arr.indexOf(match);
811 /**
812  * Loop trough the list of modifiers and run them in order,
813  * each of them will then edit the data object.
814  * @method
815  * @memberof Popper.Utils
816  * @param {dataObject} data
817  * @param {Array} modifiers
818  * @param {String} ends - Optional modifier name used as stopper
819  * @returns {dataObject}
820  */
821 function runModifiers(modifiers, data, ends) {
822   var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
824   modifiersToRun.forEach(function (modifier) {
825     if (modifier['function']) {
826       // eslint-disable-line dot-notation
827       console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
828     }
829     var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
830     if (modifier.enabled && isFunction(fn)) {
831       // Add properties to offsets to make them a complete clientRect object
832       // we do this before each modifier to make sure the previous one doesn't
833       // mess with these values
834       data.offsets.popper = getClientRect(data.offsets.popper);
835       data.offsets.reference = getClientRect(data.offsets.reference);
837       data = fn(data, modifier);
838     }
839   });
841   return data;
844 /**
845  * Updates the position of the popper, computing the new offsets and applying
846  * the new style.<br />
847  * Prefer `scheduleUpdate` over `update` because of performance reasons.
848  * @method
849  * @memberof Popper
850  */
851 function update() {
852   // if popper is destroyed, don't perform any further update
853   if (this.state.isDestroyed) {
854     return;
855   }
857   var data = {
858     instance: this,
859     styles: {},
860     arrowStyles: {},
861     attributes: {},
862     flipped: false,
863     offsets: {}
864   };
866   // compute reference element offsets
867   data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference);
869   // compute auto placement, store placement inside the data object,
870   // modifiers will be able to edit `placement` if needed
871   // and refer to originalPlacement to know the original value
872   data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);
874   // store the computed placement inside `originalPlacement`
875   data.originalPlacement = data.placement;
877   // compute the popper offsets
878   data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);
879   data.offsets.popper.position = 'absolute';
881   // run the modifiers
882   data = runModifiers(this.modifiers, data);
884   // the first `update` will call `onCreate` callback
885   // the other ones will call `onUpdate` callback
886   if (!this.state.isCreated) {
887     this.state.isCreated = true;
888     this.options.onCreate(data);
889   } else {
890     this.options.onUpdate(data);
891   }
894 /**
895  * Helper used to know if the given modifier is enabled.
896  * @method
897  * @memberof Popper.Utils
898  * @returns {Boolean}
899  */
900 function isModifierEnabled(modifiers, modifierName) {
901   return modifiers.some(function (_ref) {
902     var name = _ref.name,
903         enabled = _ref.enabled;
904     return enabled && name === modifierName;
905   });
908 /**
909  * Get the prefixed supported property name
910  * @method
911  * @memberof Popper.Utils
912  * @argument {String} property (camelCase)
913  * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
914  */
915 function getSupportedPropertyName(property) {
916   var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
917   var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
919   for (var i = 0; i < prefixes.length - 1; i++) {
920     var prefix = prefixes[i];
921     var toCheck = prefix ? '' + prefix + upperProp : property;
922     if (typeof document.body.style[toCheck] !== 'undefined') {
923       return toCheck;
924     }
925   }
926   return null;
929 /**
930  * Destroy the popper
931  * @method
932  * @memberof Popper
933  */
934 function destroy() {
935   this.state.isDestroyed = true;
937   // touch DOM only if `applyStyle` modifier is enabled
938   if (isModifierEnabled(this.modifiers, 'applyStyle')) {
939     this.popper.removeAttribute('x-placement');
940     this.popper.style.left = '';
941     this.popper.style.position = '';
942     this.popper.style.top = '';
943     this.popper.style[getSupportedPropertyName('transform')] = '';
944   }
946   this.disableEventListeners();
948   // remove the popper if user explicity asked for the deletion on destroy
949   // do not use `remove` because IE11 doesn't support it
950   if (this.options.removeOnDestroy) {
951     this.popper.parentNode.removeChild(this.popper);
952   }
953   return this;
956 /**
957  * Get the window associated with the element
958  * @argument {Element} element
959  * @returns {Window}
960  */
961 function getWindow(element) {
962   var ownerDocument = element.ownerDocument;
963   return ownerDocument ? ownerDocument.defaultView : window;
966 function attachToScrollParents(scrollParent, event, callback, scrollParents) {
967   var isBody = scrollParent.nodeName === 'BODY';
968   var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
969   target.addEventListener(event, callback, { passive: true });
971   if (!isBody) {
972     attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
973   }
974   scrollParents.push(target);
977 /**
978  * Setup needed event listeners used to update the popper position
979  * @method
980  * @memberof Popper.Utils
981  * @private
982  */
983 function setupEventListeners(reference, options, state, updateBound) {
984   // Resize event listener on window
985   state.updateBound = updateBound;
986   getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });
988   // Scroll event listener on scroll parents
989   var scrollElement = getScrollParent(reference);
990   attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
991   state.scrollElement = scrollElement;
992   state.eventsEnabled = true;
994   return state;
997 /**
998  * It will add resize/scroll events and start recalculating
999  * position of the popper element when they are triggered.
1000  * @method
1001  * @memberof Popper
1002  */
1003 function enableEventListeners() {
1004   if (!this.state.eventsEnabled) {
1005     this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
1006   }
1009 /**
1010  * Remove event listeners used to update the popper position
1011  * @method
1012  * @memberof Popper.Utils
1013  * @private
1014  */
1015 function removeEventListeners(reference, state) {
1016   // Remove resize event listener on window
1017   getWindow(reference).removeEventListener('resize', state.updateBound);
1019   // Remove scroll event listener on scroll parents
1020   state.scrollParents.forEach(function (target) {
1021     target.removeEventListener('scroll', state.updateBound);
1022   });
1024   // Reset state
1025   state.updateBound = null;
1026   state.scrollParents = [];
1027   state.scrollElement = null;
1028   state.eventsEnabled = false;
1029   return state;
1032 /**
1033  * It will remove resize/scroll events and won't recalculate popper position
1034  * when they are triggered. It also won't trigger onUpdate callback anymore,
1035  * unless you call `update` method manually.
1036  * @method
1037  * @memberof Popper
1038  */
1039 function disableEventListeners() {
1040   if (this.state.eventsEnabled) {
1041     cancelAnimationFrame(this.scheduleUpdate);
1042     this.state = removeEventListeners(this.reference, this.state);
1043   }
1046 /**
1047  * Tells if a given input is a number
1048  * @method
1049  * @memberof Popper.Utils
1050  * @param {*} input to check
1051  * @return {Boolean}
1052  */
1053 function isNumeric(n) {
1054   return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
1057 /**
1058  * Set the style to the given popper
1059  * @method
1060  * @memberof Popper.Utils
1061  * @argument {Element} element - Element to apply the style to
1062  * @argument {Object} styles
1063  * Object with a list of properties and values which will be applied to the element
1064  */
1065 function setStyles(element, styles) {
1066   Object.keys(styles).forEach(function (prop) {
1067     var unit = '';
1068     // add unit if the value is numeric and is one of the following
1069     if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
1070       unit = 'px';
1071     }
1072     element.style[prop] = styles[prop] + unit;
1073   });
1076 /**
1077  * Set the attributes to the given popper
1078  * @method
1079  * @memberof Popper.Utils
1080  * @argument {Element} element - Element to apply the attributes to
1081  * @argument {Object} styles
1082  * Object with a list of properties and values which will be applied to the element
1083  */
1084 function setAttributes(element, attributes) {
1085   Object.keys(attributes).forEach(function (prop) {
1086     var value = attributes[prop];
1087     if (value !== false) {
1088       element.setAttribute(prop, attributes[prop]);
1089     } else {
1090       element.removeAttribute(prop);
1091     }
1092   });
1095 /**
1096  * @function
1097  * @memberof Modifiers
1098  * @argument {Object} data - The data object generated by `update` method
1099  * @argument {Object} data.styles - List of style properties - values to apply to popper element
1100  * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
1101  * @argument {Object} options - Modifiers configuration and options
1102  * @returns {Object} The same data object
1103  */
1104 function applyStyle(data) {
1105   // any property present in `data.styles` will be applied to the popper,
1106   // in this way we can make the 3rd party modifiers add custom styles to it
1107   // Be aware, modifiers could override the properties defined in the previous
1108   // lines of this modifier!
1109   setStyles(data.instance.popper, data.styles);
1111   // any property present in `data.attributes` will be applied to the popper,
1112   // they will be set as HTML attributes of the element
1113   setAttributes(data.instance.popper, data.attributes);
1115   // if arrowElement is defined and arrowStyles has some properties
1116   if (data.arrowElement && Object.keys(data.arrowStyles).length) {
1117     setStyles(data.arrowElement, data.arrowStyles);
1118   }
1120   return data;
1123 /**
1124  * Set the x-placement attribute before everything else because it could be used
1125  * to add margins to the popper margins needs to be calculated to get the
1126  * correct popper offsets.
1127  * @method
1128  * @memberof Popper.modifiers
1129  * @param {HTMLElement} reference - The reference element used to position the popper
1130  * @param {HTMLElement} popper - The HTML element used as popper.
1131  * @param {Object} options - Popper.js options
1132  */
1133 function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
1134   // compute reference element offsets
1135   var referenceOffsets = getReferenceOffsets(state, popper, reference);
1137   // compute auto placement, store placement inside the data object,
1138   // modifiers will be able to edit `placement` if needed
1139   // and refer to originalPlacement to know the original value
1140   var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);
1142   popper.setAttribute('x-placement', placement);
1144   // Apply `position` to popper before anything else because
1145   // without the position applied we can't guarantee correct computations
1146   setStyles(popper, { position: 'absolute' });
1148   return options;
1151 /**
1152  * @function
1153  * @memberof Modifiers
1154  * @argument {Object} data - The data object generated by `update` method
1155  * @argument {Object} options - Modifiers configuration and options
1156  * @returns {Object} The data object, properly modified
1157  */
1158 function computeStyle(data, options) {
1159   var x = options.x,
1160       y = options.y;
1161   var popper = data.offsets.popper;
1163   // Remove this legacy support in Popper.js v2
1165   var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
1166     return modifier.name === 'applyStyle';
1167   }).gpuAcceleration;
1168   if (legacyGpuAccelerationOption !== undefined) {
1169     console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');
1170   }
1171   var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;
1173   var offsetParent = getOffsetParent(data.instance.popper);
1174   var offsetParentRect = getBoundingClientRect(offsetParent);
1176   // Styles
1177   var styles = {
1178     position: popper.position
1179   };
1181   // floor sides to avoid blurry text
1182   var offsets = {
1183     left: Math.floor(popper.left),
1184     top: Math.floor(popper.top),
1185     bottom: Math.floor(popper.bottom),
1186     right: Math.floor(popper.right)
1187   };
1189   var sideA = x === 'bottom' ? 'top' : 'bottom';
1190   var sideB = y === 'right' ? 'left' : 'right';
1192   // if gpuAcceleration is set to `true` and transform is supported,
1193   //  we use `translate3d` to apply the position to the popper we
1194   // automatically use the supported prefixed version if needed
1195   var prefixedProperty = getSupportedPropertyName('transform');
1197   // now, let's make a step back and look at this code closely (wtf?)
1198   // If the content of the popper grows once it's been positioned, it
1199   // may happen that the popper gets misplaced because of the new content
1200   // overflowing its reference element
1201   // To avoid this problem, we provide two options (x and y), which allow
1202   // the consumer to define the offset origin.
1203   // If we position a popper on top of a reference element, we can set
1204   // `x` to `top` to make the popper grow towards its top instead of
1205   // its bottom.
1206   var left = void 0,
1207       top = void 0;
1208   if (sideA === 'bottom') {
1209     top = -offsetParentRect.height + offsets.bottom;
1210   } else {
1211     top = offsets.top;
1212   }
1213   if (sideB === 'right') {
1214     left = -offsetParentRect.width + offsets.right;
1215   } else {
1216     left = offsets.left;
1217   }
1218   if (gpuAcceleration && prefixedProperty) {
1219     styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
1220     styles[sideA] = 0;
1221     styles[sideB] = 0;
1222     styles.willChange = 'transform';
1223   } else {
1224     // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties
1225     var invertTop = sideA === 'bottom' ? -1 : 1;
1226     var invertLeft = sideB === 'right' ? -1 : 1;
1227     styles[sideA] = top * invertTop;
1228     styles[sideB] = left * invertLeft;
1229     styles.willChange = sideA + ', ' + sideB;
1230   }
1232   // Attributes
1233   var attributes = {
1234     'x-placement': data.placement
1235   };
1237   // Update `data` attributes, styles and arrowStyles
1238   data.attributes = _extends({}, attributes, data.attributes);
1239   data.styles = _extends({}, styles, data.styles);
1240   data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);
1242   return data;
1245 /**
1246  * Helper used to know if the given modifier depends from another one.<br />
1247  * It checks if the needed modifier is listed and enabled.
1248  * @method
1249  * @memberof Popper.Utils
1250  * @param {Array} modifiers - list of modifiers
1251  * @param {String} requestingName - name of requesting modifier
1252  * @param {String} requestedName - name of requested modifier
1253  * @returns {Boolean}
1254  */
1255 function isModifierRequired(modifiers, requestingName, requestedName) {
1256   var requesting = find(modifiers, function (_ref) {
1257     var name = _ref.name;
1258     return name === requestingName;
1259   });
1261   var isRequired = !!requesting && modifiers.some(function (modifier) {
1262     return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
1263   });
1265   if (!isRequired) {
1266     var _requesting = '`' + requestingName + '`';
1267     var requested = '`' + requestedName + '`';
1268     console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
1269   }
1270   return isRequired;
1273 /**
1274  * @function
1275  * @memberof Modifiers
1276  * @argument {Object} data - The data object generated by update method
1277  * @argument {Object} options - Modifiers configuration and options
1278  * @returns {Object} The data object, properly modified
1279  */
1280 function arrow(data, options) {
1281   var _data$offsets$arrow;
1283   // arrow depends on keepTogether in order to work
1284   if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
1285     return data;
1286   }
1288   var arrowElement = options.element;
1290   // if arrowElement is a string, suppose it's a CSS selector
1291   if (typeof arrowElement === 'string') {
1292     arrowElement = data.instance.popper.querySelector(arrowElement);
1294     // if arrowElement is not found, don't run the modifier
1295     if (!arrowElement) {
1296       return data;
1297     }
1298   } else {
1299     // if the arrowElement isn't a query selector we must check that the
1300     // provided DOM node is child of its popper node
1301     if (!data.instance.popper.contains(arrowElement)) {
1302       console.warn('WARNING: `arrow.element` must be child of its popper element!');
1303       return data;
1304     }
1305   }
1307   var placement = data.placement.split('-')[0];
1308   var _data$offsets = data.offsets,
1309       popper = _data$offsets.popper,
1310       reference = _data$offsets.reference;
1312   var isVertical = ['left', 'right'].indexOf(placement) !== -1;
1314   var len = isVertical ? 'height' : 'width';
1315   var sideCapitalized = isVertical ? 'Top' : 'Left';
1316   var side = sideCapitalized.toLowerCase();
1317   var altSide = isVertical ? 'left' : 'top';
1318   var opSide = isVertical ? 'bottom' : 'right';
1319   var arrowElementSize = getOuterSizes(arrowElement)[len];
1321   //
1322   // extends keepTogether behavior making sure the popper and its
1323   // reference have enough pixels in conjuction
1324   //
1326   // top/left side
1327   if (reference[opSide] - arrowElementSize < popper[side]) {
1328     data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
1329   }
1330   // bottom/right side
1331   if (reference[side] + arrowElementSize > popper[opSide]) {
1332     data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
1333   }
1334   data.offsets.popper = getClientRect(data.offsets.popper);
1336   // compute center of the popper
1337   var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;
1339   // Compute the sideValue using the updated popper offsets
1340   // take popper margin in account because we don't have this info available
1341   var css = getStyleComputedProperty(data.instance.popper);
1342   var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);
1343   var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);
1344   var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;
1346   // prevent arrowElement from being placed not contiguously to its popper
1347   sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);
1349   data.arrowElement = arrowElement;
1350   data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);
1352   return data;
1355 /**
1356  * Get the opposite placement variation of the given one
1357  * @method
1358  * @memberof Popper.Utils
1359  * @argument {String} placement variation
1360  * @returns {String} flipped placement variation
1361  */
1362 function getOppositeVariation(variation) {
1363   if (variation === 'end') {
1364     return 'start';
1365   } else if (variation === 'start') {
1366     return 'end';
1367   }
1368   return variation;
1371 /**
1372  * List of accepted placements to use as values of the `placement` option.<br />
1373  * Valid placements are:
1374  * - `auto`
1375  * - `top`
1376  * - `right`
1377  * - `bottom`
1378  * - `left`
1379  *
1380  * Each placement can have a variation from this list:
1381  * - `-start`
1382  * - `-end`
1383  *
1384  * Variations are interpreted easily if you think of them as the left to right
1385  * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
1386  * is right.<br />
1387  * Vertically (`left` and `right`), `start` is top and `end` is bottom.
1388  *
1389  * Some valid examples are:
1390  * - `top-end` (on top of reference, right aligned)
1391  * - `right-start` (on right of reference, top aligned)
1392  * - `bottom` (on bottom, centered)
1393  * - `auto-right` (on the side with more space available, alignment depends by placement)
1394  *
1395  * @static
1396  * @type {Array}
1397  * @enum {String}
1398  * @readonly
1399  * @method placements
1400  * @memberof Popper
1401  */
1402 var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];
1404 // Get rid of `auto` `auto-start` and `auto-end`
1405 var validPlacements = placements.slice(3);
1407 /**
1408  * Given an initial placement, returns all the subsequent placements
1409  * clockwise (or counter-clockwise).
1410  *
1411  * @method
1412  * @memberof Popper.Utils
1413  * @argument {String} placement - A valid placement (it accepts variations)
1414  * @argument {Boolean} counter - Set to true to walk the placements counterclockwise
1415  * @returns {Array} placements including their variations
1416  */
1417 function clockwise(placement) {
1418   var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1420   var index = validPlacements.indexOf(placement);
1421   var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));
1422   return counter ? arr.reverse() : arr;
1425 var BEHAVIORS = {
1426   FLIP: 'flip',
1427   CLOCKWISE: 'clockwise',
1428   COUNTERCLOCKWISE: 'counterclockwise'
1429 };
1431 /**
1432  * @function
1433  * @memberof Modifiers
1434  * @argument {Object} data - The data object generated by update method
1435  * @argument {Object} options - Modifiers configuration and options
1436  * @returns {Object} The data object, properly modified
1437  */
1438 function flip(data, options) {
1439   // if `inner` modifier is enabled, we can't use the `flip` modifier
1440   if (isModifierEnabled(data.instance.modifiers, 'inner')) {
1441     return data;
1442   }
1444   if (data.flipped && data.placement === data.originalPlacement) {
1445     // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
1446     return data;
1447   }
1449   var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement);
1451   var placement = data.placement.split('-')[0];
1452   var placementOpposite = getOppositePlacement(placement);
1453   var variation = data.placement.split('-')[1] || '';
1455   var flipOrder = [];
1457   switch (options.behavior) {
1458     case BEHAVIORS.FLIP:
1459       flipOrder = [placement, placementOpposite];
1460       break;
1461     case BEHAVIORS.CLOCKWISE:
1462       flipOrder = clockwise(placement);
1463       break;
1464     case BEHAVIORS.COUNTERCLOCKWISE:
1465       flipOrder = clockwise(placement, true);
1466       break;
1467     default:
1468       flipOrder = options.behavior;
1469   }
1471   flipOrder.forEach(function (step, index) {
1472     if (placement !== step || flipOrder.length === index + 1) {
1473       return data;
1474     }
1476     placement = data.placement.split('-')[0];
1477     placementOpposite = getOppositePlacement(placement);
1479     var popperOffsets = data.offsets.popper;
1480     var refOffsets = data.offsets.reference;
1482     // using floor because the reference offsets may contain decimals we are not going to consider here
1483     var floor = Math.floor;
1484     var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);
1486     var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
1487     var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
1488     var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
1489     var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);
1491     var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;
1493     // flip the variation if required
1494     var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
1495     var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);
1497     if (overlapsRef || overflowsBoundaries || flippedVariation) {
1498       // this boolean to detect any flip loop
1499       data.flipped = true;
1501       if (overlapsRef || overflowsBoundaries) {
1502         placement = flipOrder[index + 1];
1503       }
1505       if (flippedVariation) {
1506         variation = getOppositeVariation(variation);
1507       }
1509       data.placement = placement + (variation ? '-' + variation : '');
1511       // this object contains `position`, we want to preserve it along with
1512       // any additional property we may add in the future
1513       data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
1515       data = runModifiers(data.instance.modifiers, data, 'flip');
1516     }
1517   });
1518   return data;
1521 /**
1522  * @function
1523  * @memberof Modifiers
1524  * @argument {Object} data - The data object generated by update method
1525  * @argument {Object} options - Modifiers configuration and options
1526  * @returns {Object} The data object, properly modified
1527  */
1528 function keepTogether(data) {
1529   var _data$offsets = data.offsets,
1530       popper = _data$offsets.popper,
1531       reference = _data$offsets.reference;
1533   var placement = data.placement.split('-')[0];
1534   var floor = Math.floor;
1535   var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
1536   var side = isVertical ? 'right' : 'bottom';
1537   var opSide = isVertical ? 'left' : 'top';
1538   var measurement = isVertical ? 'width' : 'height';
1540   if (popper[side] < floor(reference[opSide])) {
1541     data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
1542   }
1543   if (popper[opSide] > floor(reference[side])) {
1544     data.offsets.popper[opSide] = floor(reference[side]);
1545   }
1547   return data;
1550 /**
1551  * Converts a string containing value + unit into a px value number
1552  * @function
1553  * @memberof {modifiers~offset}
1554  * @private
1555  * @argument {String} str - Value + unit string
1556  * @argument {String} measurement - `height` or `width`
1557  * @argument {Object} popperOffsets
1558  * @argument {Object} referenceOffsets
1559  * @returns {Number|String}
1560  * Value in pixels, or original string if no values were extracted
1561  */
1562 function toValue(str, measurement, popperOffsets, referenceOffsets) {
1563   // separate value from unit
1564   var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);
1565   var value = +split[1];
1566   var unit = split[2];
1568   // If it's not a number it's an operator, I guess
1569   if (!value) {
1570     return str;
1571   }
1573   if (unit.indexOf('%') === 0) {
1574     var element = void 0;
1575     switch (unit) {
1576       case '%p':
1577         element = popperOffsets;
1578         break;
1579       case '%':
1580       case '%r':
1581       default:
1582         element = referenceOffsets;
1583     }
1585     var rect = getClientRect(element);
1586     return rect[measurement] / 100 * value;
1587   } else if (unit === 'vh' || unit === 'vw') {
1588     // if is a vh or vw, we calculate the size based on the viewport
1589     var size = void 0;
1590     if (unit === 'vh') {
1591       size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
1592     } else {
1593       size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
1594     }
1595     return size / 100 * value;
1596   } else {
1597     // if is an explicit pixel unit, we get rid of the unit and keep the value
1598     // if is an implicit unit, it's px, and we return just the value
1599     return value;
1600   }
1603 /**
1604  * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
1605  * @function
1606  * @memberof {modifiers~offset}
1607  * @private
1608  * @argument {String} offset
1609  * @argument {Object} popperOffsets
1610  * @argument {Object} referenceOffsets
1611  * @argument {String} basePlacement
1612  * @returns {Array} a two cells array with x and y offsets in numbers
1613  */
1614 function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
1615   var offsets = [0, 0];
1617   // Use height if placement is left or right and index is 0 otherwise use width
1618   // in this way the first offset will use an axis and the second one
1619   // will use the other one
1620   var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;
1622   // Split the offset string to obtain a list of values and operands
1623   // The regex addresses values with the plus or minus sign in front (+10, -20, etc)
1624   var fragments = offset.split(/(\+|\-)/).map(function (frag) {
1625     return frag.trim();
1626   });
1628   // Detect if the offset string contains a pair of values or a single one
1629   // they could be separated by comma or space
1630   var divider = fragments.indexOf(find(fragments, function (frag) {
1631     return frag.search(/,|\s/) !== -1;
1632   }));
1634   if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
1635     console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
1636   }
1638   // If divider is found, we divide the list of values and operands to divide
1639   // them by ofset X and Y.
1640   var splitRegex = /\s*,\s*|\s+/;
1641   var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];
1643   // Convert the values with units to absolute pixels to allow our computations
1644   ops = ops.map(function (op, index) {
1645     // Most of the units rely on the orientation of the popper
1646     var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
1647     var mergeWithPrevious = false;
1648     return op
1649     // This aggregates any `+` or `-` sign that aren't considered operators
1650     // e.g.: 10 + +5 => [10, +, +5]
1651     .reduce(function (a, b) {
1652       if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
1653         a[a.length - 1] = b;
1654         mergeWithPrevious = true;
1655         return a;
1656       } else if (mergeWithPrevious) {
1657         a[a.length - 1] += b;
1658         mergeWithPrevious = false;
1659         return a;
1660       } else {
1661         return a.concat(b);
1662       }
1663     }, [])
1664     // Here we convert the string values into number values (in px)
1665     .map(function (str) {
1666       return toValue(str, measurement, popperOffsets, referenceOffsets);
1667     });
1668   });
1670   // Loop trough the offsets arrays and execute the operations
1671   ops.forEach(function (op, index) {
1672     op.forEach(function (frag, index2) {
1673       if (isNumeric(frag)) {
1674         offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
1675       }
1676     });
1677   });
1678   return offsets;
1681 /**
1682  * @function
1683  * @memberof Modifiers
1684  * @argument {Object} data - The data object generated by update method
1685  * @argument {Object} options - Modifiers configuration and options
1686  * @argument {Number|String} options.offset=0
1687  * The offset value as described in the modifier description
1688  * @returns {Object} The data object, properly modified
1689  */
1690 function offset(data, _ref) {
1691   var offset = _ref.offset;
1692   var placement = data.placement,
1693       _data$offsets = data.offsets,
1694       popper = _data$offsets.popper,
1695       reference = _data$offsets.reference;
1697   var basePlacement = placement.split('-')[0];
1699   var offsets = void 0;
1700   if (isNumeric(+offset)) {
1701     offsets = [+offset, 0];
1702   } else {
1703     offsets = parseOffset(offset, popper, reference, basePlacement);
1704   }
1706   if (basePlacement === 'left') {
1707     popper.top += offsets[0];
1708     popper.left -= offsets[1];
1709   } else if (basePlacement === 'right') {
1710     popper.top += offsets[0];
1711     popper.left += offsets[1];
1712   } else if (basePlacement === 'top') {
1713     popper.left += offsets[0];
1714     popper.top -= offsets[1];
1715   } else if (basePlacement === 'bottom') {
1716     popper.left += offsets[0];
1717     popper.top += offsets[1];
1718   }
1720   data.popper = popper;
1721   return data;
1724 /**
1725  * @function
1726  * @memberof Modifiers
1727  * @argument {Object} data - The data object generated by `update` method
1728  * @argument {Object} options - Modifiers configuration and options
1729  * @returns {Object} The data object, properly modified
1730  */
1731 function preventOverflow(data, options) {
1732   var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);
1734   // If offsetParent is the reference element, we really want to
1735   // go one step up and use the next offsetParent as reference to
1736   // avoid to make this modifier completely useless and look like broken
1737   if (data.instance.reference === boundariesElement) {
1738     boundariesElement = getOffsetParent(boundariesElement);
1739   }
1741   var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement);
1742   options.boundaries = boundaries;
1744   var order = options.priority;
1745   var popper = data.offsets.popper;
1747   var check = {
1748     primary: function primary(placement) {
1749       var value = popper[placement];
1750       if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
1751         value = Math.max(popper[placement], boundaries[placement]);
1752       }
1753       return defineProperty({}, placement, value);
1754     },
1755     secondary: function secondary(placement) {
1756       var mainSide = placement === 'right' ? 'left' : 'top';
1757       var value = popper[mainSide];
1758       if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
1759         value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
1760       }
1761       return defineProperty({}, mainSide, value);
1762     }
1763   };
1765   order.forEach(function (placement) {
1766     var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
1767     popper = _extends({}, popper, check[side](placement));
1768   });
1770   data.offsets.popper = popper;
1772   return data;
1775 /**
1776  * @function
1777  * @memberof Modifiers
1778  * @argument {Object} data - The data object generated by `update` method
1779  * @argument {Object} options - Modifiers configuration and options
1780  * @returns {Object} The data object, properly modified
1781  */
1782 function shift(data) {
1783   var placement = data.placement;
1784   var basePlacement = placement.split('-')[0];
1785   var shiftvariation = placement.split('-')[1];
1787   // if shift shiftvariation is specified, run the modifier
1788   if (shiftvariation) {
1789     var _data$offsets = data.offsets,
1790         reference = _data$offsets.reference,
1791         popper = _data$offsets.popper;
1793     var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
1794     var side = isVertical ? 'left' : 'top';
1795     var measurement = isVertical ? 'width' : 'height';
1797     var shiftOffsets = {
1798       start: defineProperty({}, side, reference[side]),
1799       end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
1800     };
1802     data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
1803   }
1805   return data;
1808 /**
1809  * @function
1810  * @memberof Modifiers
1811  * @argument {Object} data - The data object generated by update method
1812  * @argument {Object} options - Modifiers configuration and options
1813  * @returns {Object} The data object, properly modified
1814  */
1815 function hide(data) {
1816   if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
1817     return data;
1818   }
1820   var refRect = data.offsets.reference;
1821   var bound = find(data.instance.modifiers, function (modifier) {
1822     return modifier.name === 'preventOverflow';
1823   }).boundaries;
1825   if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
1826     // Avoid unnecessary DOM access if visibility hasn't changed
1827     if (data.hide === true) {
1828       return data;
1829     }
1831     data.hide = true;
1832     data.attributes['x-out-of-boundaries'] = '';
1833   } else {
1834     // Avoid unnecessary DOM access if visibility hasn't changed
1835     if (data.hide === false) {
1836       return data;
1837     }
1839     data.hide = false;
1840     data.attributes['x-out-of-boundaries'] = false;
1841   }
1843   return data;
1846 /**
1847  * @function
1848  * @memberof Modifiers
1849  * @argument {Object} data - The data object generated by `update` method
1850  * @argument {Object} options - Modifiers configuration and options
1851  * @returns {Object} The data object, properly modified
1852  */
1853 function inner(data) {
1854   var placement = data.placement;
1855   var basePlacement = placement.split('-')[0];
1856   var _data$offsets = data.offsets,
1857       popper = _data$offsets.popper,
1858       reference = _data$offsets.reference;
1860   var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;
1862   var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;
1864   popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
1866   data.placement = getOppositePlacement(placement);
1867   data.offsets.popper = getClientRect(popper);
1869   return data;
1872 /**
1873  * Modifier function, each modifier can have a function of this type assigned
1874  * to its `fn` property.<br />
1875  * These functions will be called on each update, this means that you must
1876  * make sure they are performant enough to avoid performance bottlenecks.
1877  *
1878  * @function ModifierFn
1879  * @argument {dataObject} data - The data object generated by `update` method
1880  * @argument {Object} options - Modifiers configuration and options
1881  * @returns {dataObject} The data object, properly modified
1882  */
1884 /**
1885  * Modifiers are plugins used to alter the behavior of your poppers.<br />
1886  * Popper.js uses a set of 9 modifiers to provide all the basic functionalities
1887  * needed by the library.
1888  *
1889  * Usually you don't want to override the `order`, `fn` and `onLoad` props.
1890  * All the other properties are configurations that could be tweaked.
1891  * @namespace modifiers
1892  */
1893 var modifiers = {
1894   /**
1895    * Modifier used to shift the popper on the start or end of its reference
1896    * element.<br />
1897    * It will read the variation of the `placement` property.<br />
1898    * It can be one either `-end` or `-start`.
1899    * @memberof modifiers
1900    * @inner
1901    */
1902   shift: {
1903     /** @prop {number} order=100 - Index used to define the order of execution */
1904     order: 100,
1905     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
1906     enabled: true,
1907     /** @prop {ModifierFn} */
1908     fn: shift
1909   },
1911   /**
1912    * The `offset` modifier can shift your popper on both its axis.
1913    *
1914    * It accepts the following units:
1915    * - `px` or unitless, interpreted as pixels
1916    * - `%` or `%r`, percentage relative to the length of the reference element
1917    * - `%p`, percentage relative to the length of the popper element
1918    * - `vw`, CSS viewport width unit
1919    * - `vh`, CSS viewport height unit
1920    *
1921    * For length is intended the main axis relative to the placement of the popper.<br />
1922    * This means that if the placement is `top` or `bottom`, the length will be the
1923    * `width`. In case of `left` or `right`, it will be the height.
1924    *
1925    * You can provide a single value (as `Number` or `String`), or a pair of values
1926    * as `String` divided by a comma or one (or more) white spaces.<br />
1927    * The latter is a deprecated method because it leads to confusion and will be
1928    * removed in v2.<br />
1929    * Additionally, it accepts additions and subtractions between different units.
1930    * Note that multiplications and divisions aren't supported.
1931    *
1932    * Valid examples are:
1933    * ```
1934    * 10
1935    * '10%'
1936    * '10, 10'
1937    * '10%, 10'
1938    * '10 + 10%'
1939    * '10 - 5vh + 3%'
1940    * '-10px + 5vh, 5px - 6%'
1941    * ```
1942    * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
1943    * > with their reference element, unfortunately, you will have to disable the `flip` modifier.
1944    * > More on this [reading this issue](https://github.com/FezVrasta/popper.js/issues/373)
1945    *
1946    * @memberof modifiers
1947    * @inner
1948    */
1949   offset: {
1950     /** @prop {number} order=200 - Index used to define the order of execution */
1951     order: 200,
1952     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
1953     enabled: true,
1954     /** @prop {ModifierFn} */
1955     fn: offset,
1956     /** @prop {Number|String} offset=0
1957      * The offset value as described in the modifier description
1958      */
1959     offset: 0
1960   },
1962   /**
1963    * Modifier used to prevent the popper from being positioned outside the boundary.
1964    *
1965    * An scenario exists where the reference itself is not within the boundaries.<br />
1966    * We can say it has "escaped the boundaries" — or just "escaped".<br />
1967    * In this case we need to decide whether the popper should either:
1968    *
1969    * - detach from the reference and remain "trapped" in the boundaries, or
1970    * - if it should ignore the boundary and "escape with its reference"
1971    *
1972    * When `escapeWithReference` is set to`true` and reference is completely
1973    * outside its boundaries, the popper will overflow (or completely leave)
1974    * the boundaries in order to remain attached to the edge of the reference.
1975    *
1976    * @memberof modifiers
1977    * @inner
1978    */
1979   preventOverflow: {
1980     /** @prop {number} order=300 - Index used to define the order of execution */
1981     order: 300,
1982     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
1983     enabled: true,
1984     /** @prop {ModifierFn} */
1985     fn: preventOverflow,
1986     /**
1987      * @prop {Array} [priority=['left','right','top','bottom']]
1988      * Popper will try to prevent overflow following these priorities by default,
1989      * then, it could overflow on the left and on top of the `boundariesElement`
1990      */
1991     priority: ['left', 'right', 'top', 'bottom'],
1992     /**
1993      * @prop {number} padding=5
1994      * Amount of pixel used to define a minimum distance between the boundaries
1995      * and the popper this makes sure the popper has always a little padding
1996      * between the edges of its container
1997      */
1998     padding: 5,
1999     /**
2000      * @prop {String|HTMLElement} boundariesElement='scrollParent'
2001      * Boundaries used by the modifier, can be `scrollParent`, `window`,
2002      * `viewport` or any DOM element.
2003      */
2004     boundariesElement: 'scrollParent'
2005   },
2007   /**
2008    * Modifier used to make sure the reference and its popper stay near eachothers
2009    * without leaving any gap between the two. Expecially useful when the arrow is
2010    * enabled and you want to assure it to point to its reference element.
2011    * It cares only about the first axis, you can still have poppers with margin
2012    * between the popper and its reference element.
2013    * @memberof modifiers
2014    * @inner
2015    */
2016   keepTogether: {
2017     /** @prop {number} order=400 - Index used to define the order of execution */
2018     order: 400,
2019     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2020     enabled: true,
2021     /** @prop {ModifierFn} */
2022     fn: keepTogether
2023   },
2025   /**
2026    * This modifier is used to move the `arrowElement` of the popper to make
2027    * sure it is positioned between the reference element and its popper element.
2028    * It will read the outer size of the `arrowElement` node to detect how many
2029    * pixels of conjuction are needed.
2030    *
2031    * It has no effect if no `arrowElement` is provided.
2032    * @memberof modifiers
2033    * @inner
2034    */
2035   arrow: {
2036     /** @prop {number} order=500 - Index used to define the order of execution */
2037     order: 500,
2038     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2039     enabled: true,
2040     /** @prop {ModifierFn} */
2041     fn: arrow,
2042     /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */
2043     element: '[x-arrow]'
2044   },
2046   /**
2047    * Modifier used to flip the popper's placement when it starts to overlap its
2048    * reference element.
2049    *
2050    * Requires the `preventOverflow` modifier before it in order to work.
2051    *
2052    * **NOTE:** this modifier will interrupt the current update cycle and will
2053    * restart it if it detects the need to flip the placement.
2054    * @memberof modifiers
2055    * @inner
2056    */
2057   flip: {
2058     /** @prop {number} order=600 - Index used to define the order of execution */
2059     order: 600,
2060     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2061     enabled: true,
2062     /** @prop {ModifierFn} */
2063     fn: flip,
2064     /**
2065      * @prop {String|Array} behavior='flip'
2066      * The behavior used to change the popper's placement. It can be one of
2067      * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
2068      * placements (with optional variations).
2069      */
2070     behavior: 'flip',
2071     /**
2072      * @prop {number} padding=5
2073      * The popper will flip if it hits the edges of the `boundariesElement`
2074      */
2075     padding: 5,
2076     /**
2077      * @prop {String|HTMLElement} boundariesElement='viewport'
2078      * The element which will define the boundaries of the popper position,
2079      * the popper will never be placed outside of the defined boundaries
2080      * (except if keepTogether is enabled)
2081      */
2082     boundariesElement: 'viewport'
2083   },
2085   /**
2086    * Modifier used to make the popper flow toward the inner of the reference element.
2087    * By default, when this modifier is disabled, the popper will be placed outside
2088    * the reference element.
2089    * @memberof modifiers
2090    * @inner
2091    */
2092   inner: {
2093     /** @prop {number} order=700 - Index used to define the order of execution */
2094     order: 700,
2095     /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */
2096     enabled: false,
2097     /** @prop {ModifierFn} */
2098     fn: inner
2099   },
2101   /**
2102    * Modifier used to hide the popper when its reference element is outside of the
2103    * popper boundaries. It will set a `x-out-of-boundaries` attribute which can
2104    * be used to hide with a CSS selector the popper when its reference is
2105    * out of boundaries.
2106    *
2107    * Requires the `preventOverflow` modifier before it in order to work.
2108    * @memberof modifiers
2109    * @inner
2110    */
2111   hide: {
2112     /** @prop {number} order=800 - Index used to define the order of execution */
2113     order: 800,
2114     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2115     enabled: true,
2116     /** @prop {ModifierFn} */
2117     fn: hide
2118   },
2120   /**
2121    * Computes the style that will be applied to the popper element to gets
2122    * properly positioned.
2123    *
2124    * Note that this modifier will not touch the DOM, it just prepares the styles
2125    * so that `applyStyle` modifier can apply it. This separation is useful
2126    * in case you need to replace `applyStyle` with a custom implementation.
2127    *
2128    * This modifier has `850` as `order` value to maintain backward compatibility
2129    * with previous versions of Popper.js. Expect the modifiers ordering method
2130    * to change in future major versions of the library.
2131    *
2132    * @memberof modifiers
2133    * @inner
2134    */
2135   computeStyle: {
2136     /** @prop {number} order=850 - Index used to define the order of execution */
2137     order: 850,
2138     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2139     enabled: true,
2140     /** @prop {ModifierFn} */
2141     fn: computeStyle,
2142     /**
2143      * @prop {Boolean} gpuAcceleration=true
2144      * If true, it uses the CSS 3d transformation to position the popper.
2145      * Otherwise, it will use the `top` and `left` properties.
2146      */
2147     gpuAcceleration: true,
2148     /**
2149      * @prop {string} [x='bottom']
2150      * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
2151      * Change this if your popper should grow in a direction different from `bottom`
2152      */
2153     x: 'bottom',
2154     /**
2155      * @prop {string} [x='left']
2156      * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
2157      * Change this if your popper should grow in a direction different from `right`
2158      */
2159     y: 'right'
2160   },
2162   /**
2163    * Applies the computed styles to the popper element.
2164    *
2165    * All the DOM manipulations are limited to this modifier. This is useful in case
2166    * you want to integrate Popper.js inside a framework or view library and you
2167    * want to delegate all the DOM manipulations to it.
2168    *
2169    * Note that if you disable this modifier, you must make sure the popper element
2170    * has its position set to `absolute` before Popper.js can do its work!
2171    *
2172    * Just disable this modifier and define you own to achieve the desired effect.
2173    *
2174    * @memberof modifiers
2175    * @inner
2176    */
2177   applyStyle: {
2178     /** @prop {number} order=900 - Index used to define the order of execution */
2179     order: 900,
2180     /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2181     enabled: true,
2182     /** @prop {ModifierFn} */
2183     fn: applyStyle,
2184     /** @prop {Function} */
2185     onLoad: applyStyleOnLoad,
2186     /**
2187      * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
2188      * @prop {Boolean} gpuAcceleration=true
2189      * If true, it uses the CSS 3d transformation to position the popper.
2190      * Otherwise, it will use the `top` and `left` properties.
2191      */
2192     gpuAcceleration: undefined
2193   }
2194 };
2196 /**
2197  * The `dataObject` is an object containing all the informations used by Popper.js
2198  * this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
2199  * @name dataObject
2200  * @property {Object} data.instance The Popper.js instance
2201  * @property {String} data.placement Placement applied to popper
2202  * @property {String} data.originalPlacement Placement originally defined on init
2203  * @property {Boolean} data.flipped True if popper has been flipped by flip modifier
2204  * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper.
2205  * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
2206  * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`)
2207  * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow, it expects the JavaScript nomenclature (eg. `marginBottom`)
2208  * @property {Object} data.boundaries Offsets of the popper boundaries
2209  * @property {Object} data.offsets The measurements of popper, reference and arrow elements.
2210  * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
2211  * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
2212  * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
2213  */
2215 /**
2216  * Default options provided to Popper.js constructor.<br />
2217  * These can be overriden using the `options` argument of Popper.js.<br />
2218  * To override an option, simply pass as 3rd argument an object with the same
2219  * structure of this object, example:
2220  * ```
2221  * new Popper(ref, pop, {
2222  *   modifiers: {
2223  *     preventOverflow: { enabled: false }
2224  *   }
2225  * })
2226  * ```
2227  * @type {Object}
2228  * @static
2229  * @memberof Popper
2230  */
2231 var Defaults = {
2232   /**
2233    * Popper's placement
2234    * @prop {Popper.placements} placement='bottom'
2235    */
2236   placement: 'bottom',
2238   /**
2239    * Whether events (resize, scroll) are initially enabled
2240    * @prop {Boolean} eventsEnabled=true
2241    */
2242   eventsEnabled: true,
2244   /**
2245    * Set to true if you want to automatically remove the popper when
2246    * you call the `destroy` method.
2247    * @prop {Boolean} removeOnDestroy=false
2248    */
2249   removeOnDestroy: false,
2251   /**
2252    * Callback called when the popper is created.<br />
2253    * By default, is set to no-op.<br />
2254    * Access Popper.js instance with `data.instance`.
2255    * @prop {onCreate}
2256    */
2257   onCreate: function onCreate() {},
2259   /**
2260    * Callback called when the popper is updated, this callback is not called
2261    * on the initialization/creation of the popper, but only on subsequent
2262    * updates.<br />
2263    * By default, is set to no-op.<br />
2264    * Access Popper.js instance with `data.instance`.
2265    * @prop {onUpdate}
2266    */
2267   onUpdate: function onUpdate() {},
2269   /**
2270    * List of modifiers used to modify the offsets before they are applied to the popper.
2271    * They provide most of the functionalities of Popper.js
2272    * @prop {modifiers}
2273    */
2274   modifiers: modifiers
2275 };
2277 /**
2278  * @callback onCreate
2279  * @param {dataObject} data
2280  */
2282 /**
2283  * @callback onUpdate
2284  * @param {dataObject} data
2285  */
2287 // Utils
2288 // Methods
2289 var Popper = function () {
2290   /**
2291    * Create a new Popper.js instance
2292    * @class Popper
2293    * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper
2294    * @param {HTMLElement} popper - The HTML element used as popper.
2295    * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
2296    * @return {Object} instance - The generated Popper.js instance
2297    */
2298   function Popper(reference, popper) {
2299     var _this = this;
2301     var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2302     classCallCheck(this, Popper);
2304     this.scheduleUpdate = function () {
2305       return requestAnimationFrame(_this.update);
2306     };
2308     // make update() debounced, so that it only runs at most once-per-tick
2309     this.update = debounce(this.update.bind(this));
2311     // with {} we create a new object with the options inside it
2312     this.options = _extends({}, Popper.Defaults, options);
2314     // init state
2315     this.state = {
2316       isDestroyed: false,
2317       isCreated: false,
2318       scrollParents: []
2319     };
2321     // get reference and popper elements (allow jQuery wrappers)
2322     this.reference = reference && reference.jquery ? reference[0] : reference;
2323     this.popper = popper && popper.jquery ? popper[0] : popper;
2325     // Deep merge modifiers options
2326     this.options.modifiers = {};
2327     Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
2328       _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
2329     });
2331     // Refactoring modifiers' list (Object => Array)
2332     this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
2333       return _extends({
2334         name: name
2335       }, _this.options.modifiers[name]);
2336     })
2337     // sort the modifiers by order
2338     .sort(function (a, b) {
2339       return a.order - b.order;
2340     });
2342     // modifiers have the ability to execute arbitrary code when Popper.js get inited
2343     // such code is executed in the same order of its modifier
2344     // they could add new properties to their options configuration
2345     // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
2346     this.modifiers.forEach(function (modifierOptions) {
2347       if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
2348         modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
2349       }
2350     });
2352     // fire the first update to position the popper in the right place
2353     this.update();
2355     var eventsEnabled = this.options.eventsEnabled;
2356     if (eventsEnabled) {
2357       // setup event listeners, they will take care of update the position in specific situations
2358       this.enableEventListeners();
2359     }
2361     this.state.eventsEnabled = eventsEnabled;
2362   }
2364   // We can't use class properties because they don't get listed in the
2365   // class prototype and break stuff like Sinon stubs
2368   createClass(Popper, [{
2369     key: 'update',
2370     value: function update$$1() {
2371       return update.call(this);
2372     }
2373   }, {
2374     key: 'destroy',
2375     value: function destroy$$1() {
2376       return destroy.call(this);
2377     }
2378   }, {
2379     key: 'enableEventListeners',
2380     value: function enableEventListeners$$1() {
2381       return enableEventListeners.call(this);
2382     }
2383   }, {
2384     key: 'disableEventListeners',
2385     value: function disableEventListeners$$1() {
2386       return disableEventListeners.call(this);
2387     }
2389     /**
2390      * Schedule an update, it will run on the next UI update available
2391      * @method scheduleUpdate
2392      * @memberof Popper
2393      */
2396     /**
2397      * Collection of utilities useful when writing custom modifiers.
2398      * Starting from version 1.7, this method is available only if you
2399      * include `popper-utils.js` before `popper.js`.
2400      *
2401      * **DEPRECATION**: This way to access PopperUtils is deprecated
2402      * and will be removed in v2! Use the PopperUtils module directly instead.
2403      * Due to the high instability of the methods contained in Utils, we can't
2404      * guarantee them to follow semver. Use them at your own risk!
2405      * @static
2406      * @private
2407      * @type {Object}
2408      * @deprecated since version 1.8
2409      * @member Utils
2410      * @memberof Popper
2411      */
2413   }]);
2414   return Popper;
2415 }();
2417 /**
2418  * The `referenceObject` is an object that provides an interface compatible with Popper.js
2419  * and lets you use it as replacement of a real DOM node.<br />
2420  * You can use this method to position a popper relatively to a set of coordinates
2421  * in case you don't have a DOM node to use as reference.
2422  *
2423  * ```
2424  * new Popper(referenceObject, popperNode);
2425  * ```
2426  *
2427  * NB: This feature isn't supported in Internet Explorer 10
2428  * @name referenceObject
2429  * @property {Function} data.getBoundingClientRect
2430  * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
2431  * @property {number} data.clientWidth
2432  * An ES6 getter that will return the width of the virtual reference element.
2433  * @property {number} data.clientHeight
2434  * An ES6 getter that will return the height of the virtual reference element.
2435  */
2438 Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
2439 Popper.placements = placements;
2440 Popper.Defaults = Defaults;
2442 return Popper;
2444 })));
2445 //# sourceMappingURL=popper.js.map