tippy_rails 1.2.1.3 → 2.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 628ae86f13911f10bf41b80795dd6284c6c96d09
4
- data.tar.gz: 4743dd7cd548bf141550d8d6457caaefc280ebe2
3
+ metadata.gz: 93715d9f2d32b890e33be34facd767374ebf88d5
4
+ data.tar.gz: 15b5df259c839263f5d72c0ab01557d71a58294f
5
5
  SHA512:
6
- metadata.gz: 06bc82af349599c6925cc973cb33f4ec1df0cbe566992157fa34753218d29dc0453e7d65ba117d8a5384f1c0d5bb264f73fe73bb9e8e36873d8cb0f4c2af36e4
7
- data.tar.gz: c6cb47185f8eff5dc5772e64c5ef99774709f6a6793d194cd15477547f5a00101b655c1b6c2f0e8fa4a2e67bec0f3c722c41c478be7035dbc3098ee5f2572beb
6
+ metadata.gz: 2e84863962932d9805882ff7eb3e89373b68c0ac030ce64a37bf4826cee2054ffe9be51e22ba3ce933e9697511a620b6377134fba39df4b87519ef431dcc6215
7
+ data.tar.gz: 93201f662649044b424030f643f769555311a0b50f12cee274968d8cebd72006001be0846ce379feeb2f8f349f58a36480b19434f7924feca934addcb91f9714
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tippy_rails (1.2.1.3)
4
+ tippy_rails (2.5.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,3 +1,3 @@
1
1
  module TippyRails
2
- VERSION = "1.2.1.3"
2
+ VERSION = "2.5.2"
3
3
  end
@@ -1,57 +1,54 @@
1
+ /*!
2
+ * Tippy.js v2.5.2
3
+ * (c) 2017-2018 atomiks
4
+ * MIT
5
+ */
1
6
  (function (global, factory) {
2
7
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
8
  typeof define === 'function' && define.amd ? define(factory) :
4
9
  (global.tippy = factory());
5
10
  }(this, (function () { 'use strict';
6
11
 
7
- var Browser = {};
8
-
9
- if (typeof window !== 'undefined') {
10
- Browser.SUPPORTED = 'requestAnimationFrame' in window;
11
- Browser.SUPPORTS_TOUCH = 'ontouchstart' in window;
12
- Browser.touch = false;
13
- Browser.dynamicInputDetection = true;
14
- // Chrome device/touch emulation can make this dynamic
15
- Browser.iOS = function () {
16
- return (/iPhone|iPad|iPod/.test(navigator.userAgent) && !window.MSStream
17
- );
18
- };
19
- }
12
+ var version = "2.5.2";
20
13
 
21
- /**
22
- * The global storage array which holds all data reference objects
23
- * from every instance
24
- * This allows us to hide tooltips from all instances, finding the ref when
25
- * clicking on the body, and for followCursor
26
- */
27
- var Store = [];
14
+ var isBrowser = typeof window !== 'undefined';
15
+
16
+ var isIE = isBrowser && /MSIE |Trident\//.test(navigator.userAgent);
17
+
18
+ var browser = {};
19
+
20
+ if (isBrowser) {
21
+ browser.supported = 'requestAnimationFrame' in window;
22
+ browser.supportsTouch = 'ontouchstart' in window;
23
+ browser.usingTouch = false;
24
+ browser.dynamicInputDetection = true;
25
+ browser.iOS = /iPhone|iPad|iPod/.test(navigator.platform) && !window.MSStream;
26
+ browser.onUserInputChange = function () {};
27
+ }
28
28
 
29
29
  /**
30
- * Selector constants used for grabbing elements
31
- */
32
- var Selectors = {
30
+ * Selector constants used for grabbing elements
31
+ */
32
+ var selectors = {
33
33
  POPPER: '.tippy-popper',
34
34
  TOOLTIP: '.tippy-tooltip',
35
- CONTENT: '.tippy-tooltip-content',
36
- CIRCLE: '[x-circle]',
37
- ARROW: '[x-arrow]',
38
- TOOLTIPPED_EL: '[data-tooltipped]',
39
- CONTROLLER: '[data-tippy-controller]'
35
+ CONTENT: '.tippy-content',
36
+ BACKDROP: '.tippy-backdrop',
37
+ ARROW: '.tippy-arrow',
38
+ ROUND_ARROW: '.tippy-roundarrow',
39
+ REFERENCE: '[data-tippy]'
40
40
  };
41
41
 
42
- /**
43
- * The default settings applied to each instance
44
- */
45
- var Defaults = {
42
+ var defaults = {
43
+ placement: 'top',
44
+ livePlacement: true,
45
+ trigger: 'mouseenter focus',
46
+ animation: 'shift-away',
46
47
  html: false,
47
- position: 'top',
48
- animation: 'shift',
49
48
  animateFill: true,
50
49
  arrow: false,
51
- arrowSize: 'regular',
52
50
  delay: 0,
53
- trigger: 'mouseenter focus',
54
- duration: 350,
51
+ duration: [350, 300],
55
52
  interactive: false,
56
53
  interactiveBorder: 2,
57
54
  theme: 'dark',
@@ -62,455 +59,423 @@ var Defaults = {
62
59
  multiple: false,
63
60
  followCursor: false,
64
61
  inertia: false,
65
- flipDuration: 350,
62
+ updateDuration: 350,
66
63
  sticky: false,
67
- stickyDuration: 200,
68
- appendTo: null,
64
+ appendTo: function appendTo() {
65
+ return document.body;
66
+ },
69
67
  zIndex: 9999,
70
68
  touchHold: false,
71
69
  performance: false,
72
70
  dynamicTitle: false,
73
- popperOptions: {}
71
+ flip: true,
72
+ flipBehavior: 'flip',
73
+ arrowType: 'sharp',
74
+ arrowTransform: '',
75
+ maxWidth: '',
76
+ target: null,
77
+ allowTitleHTML: true,
78
+ popperOptions: {},
79
+ createPopperInstanceOnInit: false,
80
+ onShow: function onShow() {},
81
+ onShown: function onShown() {},
82
+ onHide: function onHide() {},
83
+ onHidden: function onHidden() {}
74
84
  };
75
85
 
76
86
  /**
77
- * The keys of the defaults object for reducing down into a new object
78
- * Used in `getIndividualSettings()`
79
- */
80
- var DefaultsKeys = Browser.SUPPORTED && Object.keys(Defaults);
87
+ * The keys of the defaults object for reducing down into a new object
88
+ * Used in `getIndividualOptions()`
89
+ */
90
+ var defaultsKeys = browser.supported && Object.keys(defaults);
81
91
 
82
92
  /**
83
- * Hides all poppers
84
- * @param {Object} exclude - refData to exclude if needed
85
- */
86
- function hideAllPoppers(exclude) {
87
- Store.forEach(function (refData) {
88
- var popper = refData.popper,
89
- tippyInstance = refData.tippyInstance,
90
- _refData$settings = refData.settings,
91
- appendTo = _refData$settings.appendTo,
92
- hideOnClick = _refData$settings.hideOnClick,
93
- trigger = _refData$settings.trigger;
93
+ * Determines if a value is an object literal
94
+ * @param {*} value
95
+ * @return {Boolean}
96
+ */
97
+ function isObjectLiteral(value) {
98
+ return {}.toString.call(value) === '[object Object]';
99
+ }
94
100
 
95
- // Don't hide already hidden ones
101
+ /**
102
+ * Ponyfill for Array.from
103
+ * @param {*} value
104
+ * @return {Array}
105
+ */
106
+ function toArray(value) {
107
+ return [].slice.call(value);
108
+ }
109
+
110
+ /**
111
+ * Returns an array of elements based on the selector input
112
+ * @param {String|Element|Element[]|NodeList|Object} selector
113
+ * @return {Element[]}
114
+ */
115
+ function getArrayOfElements(selector) {
116
+ if (selector instanceof Element || isObjectLiteral(selector)) {
117
+ return [selector];
118
+ }
96
119
 
97
- if (!appendTo.contains(popper)) return;
120
+ if (selector instanceof NodeList) {
121
+ return toArray(selector);
122
+ }
98
123
 
99
- // hideOnClick can have the truthy value of 'persistent', so strict check is needed
100
- var isHideOnClick = hideOnClick === true || trigger.indexOf('focus') !== -1;
101
- var isNotCurrentRef = !exclude || popper !== exclude.popper;
124
+ if (Array.isArray(selector)) {
125
+ return selector;
126
+ }
102
127
 
103
- if (isHideOnClick && isNotCurrentRef) {
104
- tippyInstance.hide(popper);
105
- }
106
- });
128
+ try {
129
+ return toArray(document.querySelectorAll(selector));
130
+ } catch (_) {
131
+ return [];
132
+ }
107
133
  }
108
134
 
109
- var e = Element.prototype;
110
- var matches = e.matches || e.matchesSelector || e.webkitMatchesSelector || e.mozMatchesSelector || e.msMatchesSelector || function (s) {
111
- var matches = (this.document || this.ownerDocument).querySelectorAll(s),
112
- i = matches.length;
113
- while (--i >= 0 && matches.item(i) !== this) {}
114
- return i > -1;
115
- };
116
-
117
135
  /**
118
- * Ponyfill to get the closest parent element
119
- * @param {Element} element - child of parent to be returned
120
- * @param {String} parentSelector - selector to match the parent if found
121
- * @return {Element}
122
- */
123
- function closest(element, parentSelector) {
124
- var _closest = Element.prototype.closest || function (selector) {
125
- var el = this;
126
- while (el) {
127
- if (matches.call(el, selector)) {
128
- return el;
129
- }
130
- el = el.parentElement;
136
+ * Polyfills needed props/methods for a virtual reference object
137
+ * NOTE: in v3.0 this will be pure
138
+ * @param {Object} reference
139
+ */
140
+ function polyfillVirtualReferenceProps(reference) {
141
+ reference.refObj = true;
142
+ reference.attributes = reference.attributes || {};
143
+ reference.setAttribute = function (key, val) {
144
+ reference.attributes[key] = val;
145
+ };
146
+ reference.getAttribute = function (key) {
147
+ return reference.attributes[key];
148
+ };
149
+ reference.removeAttribute = function (key) {
150
+ delete reference.attributes[key];
151
+ };
152
+ reference.hasAttribute = function (key) {
153
+ return key in reference.attributes;
154
+ };
155
+ reference.addEventListener = function () {};
156
+ reference.removeEventListener = function () {};
157
+ reference.classList = {
158
+ classNames: {},
159
+ add: function add(key) {
160
+ return reference.classList.classNames[key] = true;
161
+ },
162
+ remove: function remove(key) {
163
+ delete reference.classList.classNames[key];
164
+ return true;
165
+ },
166
+ contains: function contains(key) {
167
+ return key in reference.classList.classNames;
131
168
  }
132
169
  };
133
-
134
- return _closest.call(element, parentSelector);
135
170
  }
136
171
 
137
172
  /**
138
- * Ponyfill for Array.prototype.find
139
- * @param {Array} arr
140
- * @param {Function} checkFn
141
- * @return item in the array
142
- */
143
- function find(arr, checkFn) {
144
- if (Array.prototype.find) {
145
- return arr.find(checkFn);
173
+ * Returns the supported prefixed property - only `webkit` is needed, `moz`, `ms` and `o` are obsolete
174
+ * @param {String} property
175
+ * @return {String} - browser supported prefixed property
176
+ */
177
+ function prefix(property) {
178
+ var prefixes = ['', 'webkit'];
179
+ var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
180
+
181
+ for (var i = 0; i < prefixes.length; i++) {
182
+ var _prefix = prefixes[i];
183
+ var prefixedProp = _prefix ? _prefix + upperProp : property;
184
+ if (typeof document.body.style[prefixedProp] !== 'undefined') {
185
+ return prefixedProp;
186
+ }
146
187
  }
147
188
 
148
- // use `filter` as fallback
149
- return arr.filter(checkFn)[0];
189
+ return null;
150
190
  }
151
191
 
152
192
  /**
153
- * Adds the needed event listeners
154
- */
155
- function bindEventListeners() {
156
- var touchHandler = function touchHandler() {
157
- Browser.touch = true;
193
+ * Creates a div element
194
+ * @return {Element}
195
+ */
196
+ function div() {
197
+ return document.createElement('div');
198
+ }
158
199
 
159
- if (Browser.iOS()) {
160
- document.body.classList.add('tippy-touch');
161
- }
200
+ /**
201
+ * Creates a popper element then returns it
202
+ * @param {Number} id - the popper id
203
+ * @param {String} title - the tooltip's `title` attribute
204
+ * @param {Object} options - individual options
205
+ * @return {Element} - the popper element
206
+ */
207
+ function createPopperElement(id, title, options) {
208
+ var popper = div();
209
+ popper.setAttribute('class', 'tippy-popper');
210
+ popper.setAttribute('role', 'tooltip');
211
+ popper.setAttribute('id', 'tippy-' + id);
212
+ popper.style.zIndex = options.zIndex;
213
+ popper.style.maxWidth = options.maxWidth;
214
+
215
+ var tooltip = div();
216
+ tooltip.setAttribute('class', 'tippy-tooltip');
217
+ tooltip.setAttribute('data-size', options.size);
218
+ tooltip.setAttribute('data-animation', options.animation);
219
+ tooltip.setAttribute('data-state', 'hidden');
220
+ options.theme.split(' ').forEach(function (t) {
221
+ tooltip.classList.add(t + '-theme');
222
+ });
223
+
224
+ var content = div();
225
+ content.setAttribute('class', 'tippy-content');
226
+
227
+ if (options.arrow) {
228
+ var arrow = div();
229
+ arrow.style[prefix('transform')] = options.arrowTransform;
162
230
 
163
- if (Browser.dynamicInputDetection && window.performance) {
164
- document.addEventListener('mousemove', mousemoveHandler);
231
+ if (options.arrowType === 'round') {
232
+ arrow.classList.add('tippy-roundarrow');
233
+ arrow.innerHTML = '<svg viewBox="0 0 24 8" xmlns="http://www.w3.org/2000/svg"><path d="M3 8s2.021-.015 5.253-4.218C9.584 2.051 10.797 1.007 12 1c1.203-.007 2.416 1.035 3.761 2.782C19.012 8.005 21 8 21 8H3z"/></svg>';
234
+ } else {
235
+ arrow.classList.add('tippy-arrow');
165
236
  }
166
- };
167
237
 
168
- var mousemoveHandler = function () {
169
- var time = void 0;
238
+ tooltip.appendChild(arrow);
239
+ }
170
240
 
171
- return function () {
172
- var now = performance.now();
241
+ if (options.animateFill) {
242
+ // Create animateFill circle element for animation
243
+ tooltip.setAttribute('data-animatefill', '');
244
+ var backdrop = div();
245
+ backdrop.classList.add('tippy-backdrop');
246
+ backdrop.setAttribute('data-state', 'hidden');
247
+ tooltip.appendChild(backdrop);
248
+ }
173
249
 
174
- // Chrome 60+ is 1 mousemove per rAF, use 20ms time difference
175
- if (now - time < 20) {
176
- Browser.touch = false;
177
- document.removeEventListener('mousemove', mousemoveHandler);
178
- if (!Browser.iOS()) {
179
- document.body.classList.remove('tippy-touch');
180
- }
181
- }
250
+ if (options.inertia) {
251
+ // Change transition timing function cubic bezier
252
+ tooltip.setAttribute('data-inertia', '');
253
+ }
182
254
 
183
- time = now;
184
- };
185
- }();
255
+ if (options.interactive) {
256
+ tooltip.setAttribute('data-interactive', '');
257
+ }
186
258
 
187
- var clickHandler = function clickHandler(event) {
188
- // Simulated events dispatched on the document
189
- if (!(event.target instanceof Element)) {
190
- return hideAllPoppers();
191
- }
259
+ var html = options.html;
260
+ if (html) {
261
+ var templateId = void 0;
192
262
 
193
- var el = closest(event.target, Selectors.TOOLTIPPED_EL);
194
- var popper = closest(event.target, Selectors.POPPER);
263
+ if (html instanceof Element) {
264
+ content.appendChild(html);
265
+ templateId = '#' + (html.id || 'tippy-html-template');
266
+ } else {
267
+ // trick linters: https://github.com/atomiks/tippyjs/issues/197
268
+ content[true && 'innerHTML'] = document.querySelector(html)[true && 'innerHTML'];
269
+ templateId = html;
270
+ }
195
271
 
196
- if (popper) {
197
- var ref = find(Store, function (ref) {
198
- return ref.popper === popper;
199
- });
200
- var interactive = ref.settings.interactive;
272
+ popper.setAttribute('data-html', '');
273
+ tooltip.setAttribute('data-template-id', templateId);
201
274
 
202
- if (interactive) return;
275
+ if (options.interactive) {
276
+ popper.setAttribute('tabindex', '-1');
203
277
  }
278
+ } else {
279
+ content[options.allowTitleHTML ? 'innerHTML' : 'textContent'] = title;
280
+ }
204
281
 
205
- if (el) {
206
- var _ref = find(Store, function (ref) {
207
- return ref.el === el;
208
- });
209
- var _ref$settings = _ref.settings,
210
- hideOnClick = _ref$settings.hideOnClick,
211
- multiple = _ref$settings.multiple,
212
- trigger = _ref$settings.trigger;
282
+ tooltip.appendChild(content);
283
+ popper.appendChild(tooltip);
213
284
 
214
- // Hide all poppers except the one belonging to the element that was clicked IF
215
- // `multiple` is false AND they are a touch user, OR
216
- // `multiple` is false AND it's triggered by a click
285
+ return popper;
286
+ }
217
287
 
218
- if (!multiple && Browser.touch || !multiple && trigger.indexOf('click') !== -1) {
219
- return hideAllPoppers(_ref);
220
- }
288
+ /**
289
+ * Creates a trigger by adding the necessary event listeners to the reference element
290
+ * @param {String} eventType - the custom event specified in the `trigger` setting
291
+ * @param {Element} reference
292
+ * @param {Object} handlers - the handlers for each event
293
+ * @param {Object} options
294
+ * @return {Array} - array of listener objects
295
+ */
296
+ function createTrigger(eventType, reference, handlers, options) {
297
+ var onTrigger = handlers.onTrigger,
298
+ onMouseLeave = handlers.onMouseLeave,
299
+ onBlur = handlers.onBlur,
300
+ onDelegateShow = handlers.onDelegateShow,
301
+ onDelegateHide = handlers.onDelegateHide;
221
302
 
222
- // If hideOnClick is not strictly true or triggered by a click don't hide poppers
223
- if (hideOnClick !== true || trigger.indexOf('click') !== -1) return;
224
- }
303
+ var listeners = [];
225
304
 
226
- // Don't trigger a hide for tippy controllers, and don't needlessly run loop
227
- if (closest(event.target, Selectors.CONTROLLER) || !document.querySelector(Selectors.POPPER)) return;
305
+ if (eventType === 'manual') return listeners;
228
306
 
229
- hideAllPoppers();
307
+ var on = function on(eventType, handler) {
308
+ reference.addEventListener(eventType, handler);
309
+ listeners.push({ event: eventType, handler: handler });
230
310
  };
231
311
 
232
- var blurHandler = function blurHandler(event) {
233
- var _document = document,
234
- el = _document.activeElement;
312
+ if (!options.target) {
313
+ on(eventType, onTrigger);
235
314
 
236
- if (el && el.blur && matches.call(el, Selectors.TOOLTIPPED_EL)) {
237
- el.blur();
315
+ if (browser.supportsTouch && options.touchHold) {
316
+ on('touchstart', onTrigger);
317
+ on('touchend', onMouseLeave);
238
318
  }
239
- };
319
+ if (eventType === 'mouseenter') {
320
+ on('mouseleave', onMouseLeave);
321
+ }
322
+ if (eventType === 'focus') {
323
+ on(isIE ? 'focusout' : 'blur', onBlur);
324
+ }
325
+ } else {
326
+ if (browser.supportsTouch && options.touchHold) {
327
+ on('touchstart', onDelegateShow);
328
+ on('touchend', onDelegateHide);
329
+ }
330
+ if (eventType === 'mouseenter') {
331
+ on('mouseover', onDelegateShow);
332
+ on('mouseout', onDelegateHide);
333
+ }
334
+ if (eventType === 'focus') {
335
+ on('focusin', onDelegateShow);
336
+ on('focusout', onDelegateHide);
337
+ }
338
+ if (eventType === 'click') {
339
+ on('click', onDelegateShow);
340
+ }
341
+ }
240
342
 
241
- // Hook events
242
- document.addEventListener('click', clickHandler);
243
- document.addEventListener('touchstart', touchHandler);
244
- window.addEventListener('blur', blurHandler);
343
+ return listeners;
344
+ }
245
345
 
246
- if (!Browser.SUPPORTS_TOUCH && (navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0)) {
247
- document.addEventListener('pointerdown', touchHandler);
346
+ var classCallCheck = function (instance, Constructor) {
347
+ if (!(instance instanceof Constructor)) {
348
+ throw new TypeError("Cannot call a class as a function");
248
349
  }
249
- }
350
+ };
250
351
 
251
- /**
252
- * To run a single time, once DOM is presumed to be ready
253
- * @return {Boolean} whether the function has run or not
254
- */
255
- function init() {
256
- if (init.done) return false;
257
- init.done = true;
352
+ var createClass = function () {
353
+ function defineProperties(target, props) {
354
+ for (var i = 0; i < props.length; i++) {
355
+ var descriptor = props[i];
356
+ descriptor.enumerable = descriptor.enumerable || false;
357
+ descriptor.configurable = true;
358
+ if ("value" in descriptor) descriptor.writable = true;
359
+ Object.defineProperty(target, descriptor.key, descriptor);
360
+ }
361
+ }
258
362
 
259
- // If the script is in <head>, document.body is null, so it's set in the
260
- // init function
261
- Defaults.appendTo = document.body;
363
+ return function (Constructor, protoProps, staticProps) {
364
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
365
+ if (staticProps) defineProperties(Constructor, staticProps);
366
+ return Constructor;
367
+ };
368
+ }();
262
369
 
263
- bindEventListeners();
264
370
 
265
- return true;
266
- }
267
371
 
268
- /**
269
- * Waits until next repaint to execute a fn
270
- * @return {Function}
271
- */
272
- function queueExecution(fn) {
273
- window.requestAnimationFrame(function () {
274
- setTimeout(fn, 0);
275
- });
276
- }
277
372
 
278
- /**
279
- * Returns the supported prefixed property - only `webkit` is needed, `moz`, `ms` and `o` are obsolete
280
- * @param {String} property
281
- * @return {String} - browser supported prefixed property
282
- */
283
- function prefix(property) {
284
- var prefixes = [false, 'webkit'];
285
- var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
286
373
 
287
- for (var i = 0; i < prefixes.length; i++) {
288
- var _prefix = prefixes[i];
289
- var prefixedProp = _prefix ? '' + _prefix + upperProp : property;
290
- if (typeof window.document.body.style[prefixedProp] !== 'undefined') {
291
- return prefixedProp;
374
+
375
+
376
+ var _extends = Object.assign || function (target) {
377
+ for (var i = 1; i < arguments.length; i++) {
378
+ var source = arguments[i];
379
+
380
+ for (var key in source) {
381
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
382
+ target[key] = source[key];
383
+ }
292
384
  }
293
385
  }
294
386
 
295
- return null;
296
- }
387
+ return target;
388
+ };
297
389
 
298
390
  /**
299
- * Ponyfill for Array.prototype.findIndex
300
- * @param {Array} arr
301
- * @param {Function} checkFn
302
- * @return index of the item in the array
303
- */
304
- function findIndex(arr, checkFn) {
305
- if (Array.prototype.findIndex) {
306
- return arr.findIndex(checkFn);
307
- }
391
+ * Returns an object of settings to override global settings
392
+ * @param {Element} reference
393
+ * @param {Object} instanceOptions
394
+ * @return {Object} - individual options
395
+ */
396
+ function getIndividualOptions(reference, instanceOptions) {
397
+ var options = defaultsKeys.reduce(function (acc, key) {
398
+ var val = reference.getAttribute('data-tippy-' + key.toLowerCase()) || instanceOptions[key];
308
399
 
309
- // fallback
310
- return arr.indexOf(find(arr, checkFn));
311
- }
400
+ // Convert strings to booleans
401
+ if (val === 'false') val = false;
402
+ if (val === 'true') val = true;
312
403
 
313
- /**
314
- * Removes the title from the tooltipped element
315
- * @param {Element} el
316
- */
317
- function removeTitle(el) {
318
- var title = el.getAttribute('title');
319
- el.setAttribute('data-original-title', title || 'html');
320
- el.removeAttribute('title');
321
- }
404
+ // Convert number strings to true numbers
405
+ if (isFinite(val) && !isNaN(parseFloat(val))) {
406
+ val = parseFloat(val);
407
+ }
322
408
 
323
- /**
324
- * Determines if an element is visible in the viewport
325
- * @param {Element} el
326
- * @return {Boolean}
327
- */
328
- function elementIsInViewport(el) {
329
- var rect = el.getBoundingClientRect();
409
+ // Convert array strings to actual arrays
410
+ if (key !== 'target' && typeof val === 'string' && val.trim().charAt(0) === '[') {
411
+ val = JSON.parse(val);
412
+ }
330
413
 
331
- return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
332
- }
414
+ acc[key] = val;
333
415
 
334
- /**
335
- * Triggers a document repaint or reflow for CSS transition
336
- * @param {Element} tooltip
337
- * @param {Element} circle
338
- */
339
- function triggerReflow(tooltip, circle) {
340
- // Safari needs the specific 'transform' property to be accessed
341
- circle ? window.getComputedStyle(circle)[prefix('transform')] : window.getComputedStyle(tooltip).opacity;
342
- }
416
+ return acc;
417
+ }, {});
343
418
 
344
- /**
345
- * Modifies elements' class lists
346
- * @param {Element[]} els - Array of elements
347
- * @param {Function} callback
348
- */
349
- function modifyClassList(els, callback) {
350
- els.forEach(function (el) {
351
- if (!el) return;
352
- callback(el.classList);
353
- });
419
+ return _extends({}, instanceOptions, options);
354
420
  }
355
421
 
356
422
  /**
357
- * Applies the transition duration to each element
358
- * @param {Element[]} els - Array of elements
359
- * @param {Number} duration
360
- */
361
- function applyTransitionDuration(els, duration) {
362
- els.forEach(function (el) {
363
- if (!el) return;
423
+ * Evaluates/modifies the options object for appropriate behavior
424
+ * @param {Element|Object} reference
425
+ * @param {Object} options
426
+ * @return {Object} modified/evaluated options
427
+ */
428
+ function evaluateOptions(reference, options) {
429
+ // animateFill is disabled if an arrow is true
430
+ if (options.arrow) {
431
+ options.animateFill = false;
432
+ }
364
433
 
365
- var isContent = matches.call(el, Selectors.CONTENT);
434
+ if (options.appendTo && typeof options.appendTo === 'function') {
435
+ options.appendTo = options.appendTo();
436
+ }
366
437
 
367
- var _duration = isContent ? Math.round(duration / 1.3) : duration;
438
+ if (typeof options.html === 'function') {
439
+ options.html = options.html(reference);
440
+ }
368
441
 
369
- el.style[prefix('transitionDuration')] = _duration + 'ms';
370
- });
442
+ return options;
371
443
  }
372
444
 
373
445
  /**
374
- * Determines if a popper is currently visible
375
- * @param {Element} popper
376
- * @return {Boolean}
377
- */
378
- function isVisible(popper) {
379
- return popper.style.visibility === 'visible';
446
+ * Returns inner elements of the popper element
447
+ * @param {Element} popper
448
+ * @return {Object}
449
+ */
450
+ function getInnerElements(popper) {
451
+ var select = function select(s) {
452
+ return popper.querySelector(s);
453
+ };
454
+ return {
455
+ tooltip: select(selectors.TOOLTIP),
456
+ backdrop: select(selectors.BACKDROP),
457
+ content: select(selectors.CONTENT),
458
+ arrow: select(selectors.ARROW) || select(selectors.ROUND_ARROW)
459
+ };
380
460
  }
381
461
 
382
- function noop() {}
383
-
384
462
  /**
385
- * Returns the non-shifted placement (e.g., 'bottom-start' => 'bottom')
386
- * @param {String} placement
387
- * @return {String}
388
- */
389
- function getCorePlacement(placement) {
390
- return placement.replace(/-.+/, '');
391
- }
392
-
393
- /**
394
- * Mousemove event listener callback method for follow cursor setting
395
- * @param {MouseEvent} e
396
- */
397
- function followCursorHandler(e) {
398
- var _this = this;
399
-
400
- var refData = find(Store, function (refData) {
401
- return refData.el === _this;
402
- });
403
-
404
- var popper = refData.popper,
405
- offset = refData.settings.offset;
406
-
407
-
408
- var position = getCorePlacement(popper.getAttribute('x-placement'));
409
- var halfPopperWidth = Math.round(popper.offsetWidth / 2);
410
- var halfPopperHeight = Math.round(popper.offsetHeight / 2);
411
- var viewportPadding = 5;
412
- var pageWidth = document.documentElement.offsetWidth || document.body.offsetWidth;
413
-
414
- var pageX = e.pageX,
415
- pageY = e.pageY;
416
-
417
-
418
- var x = void 0,
419
- y = void 0;
420
-
421
- switch (position) {
422
- case 'top':
423
- x = pageX - halfPopperWidth + offset;
424
- y = pageY - 2.25 * halfPopperHeight;
425
- break;
426
- case 'left':
427
- x = pageX - 2 * halfPopperWidth - 10;
428
- y = pageY - halfPopperHeight + offset;
429
- break;
430
- case 'right':
431
- x = pageX + halfPopperHeight;
432
- y = pageY - halfPopperHeight + offset;
433
- break;
434
- case 'bottom':
435
- x = pageX - halfPopperWidth + offset;
436
- y = pageY + halfPopperHeight / 1.5;
437
- break;
438
- }
439
-
440
- var isRightOverflowing = pageX + viewportPadding + halfPopperWidth + offset > pageWidth;
441
- var isLeftOverflowing = pageX - viewportPadding - halfPopperWidth + offset < 0;
442
-
443
- // Prevent left/right overflow
444
- if (position === 'top' || position === 'bottom') {
445
- if (isRightOverflowing) {
446
- x = pageWidth - viewportPadding - 2 * halfPopperWidth;
447
- }
448
-
449
- if (isLeftOverflowing) {
450
- x = viewportPadding;
451
- }
452
- }
453
-
454
- popper.style[prefix('transform')] = 'translate3d(' + x + 'px, ' + y + 'px, 0)';
455
- }
456
-
457
- /**
458
- * Returns an array of elements based on the selector input
459
- * @param {String|Element|Element[]} selector
460
- * @return {Element[]}
461
- */
462
- function getArrayOfElements(selector) {
463
- if (selector instanceof Element) {
464
- return [selector];
465
- }
466
-
467
- if (Array.isArray(selector)) {
468
- return selector;
469
- }
470
-
471
- return [].slice.call(document.querySelectorAll(selector));
472
- }
473
-
474
- /**
475
- * Prepares the callback functions for `show` and `hide` methods
476
- * @param {Object} refData - the element/popper reference data
477
- * @param {Number} duration
478
- * @param {Function} callback - callback function to fire once transitions complete
479
- */
480
- function onTransitionEnd(refData, duration, callback) {
481
- // Make callback synchronous if duration is 0
482
- if (!duration) {
483
- return callback();
484
- }
485
-
486
- var tooltip = refData.popper.querySelector(Selectors.TOOLTIP);
487
- var transitionendFired = false;
488
-
489
- var listenerCallback = function listenerCallback(e) {
490
- if (e.target !== tooltip) return;
491
-
492
- transitionendFired = true;
493
-
494
- tooltip.removeEventListener('webkitTransitionEnd', listenerCallback);
495
- tooltip.removeEventListener('transitionend', listenerCallback);
496
-
497
- callback();
498
- };
499
-
500
- // Wait for transitions to complete
501
- tooltip.addEventListener('webkitTransitionEnd', listenerCallback);
502
- tooltip.addEventListener('transitionend', listenerCallback);
503
-
504
- // transitionend listener sometimes may not fire
505
- clearTimeout(refData._transitionendTimeout);
506
- refData._transitionendTimeout = setTimeout(function () {
507
- !transitionendFired && callback();
508
- }, duration);
463
+ * Removes the title from an element, setting `data-original-title`
464
+ * appropriately
465
+ * @param {Element} el
466
+ */
467
+ function removeTitle(el) {
468
+ var title = el.getAttribute('title');
469
+ // Only set `data-original-title` attr if there is a title
470
+ if (title) {
471
+ el.setAttribute('data-original-title', title);
472
+ }
473
+ el.removeAttribute('title');
509
474
  }
510
475
 
511
476
  /**!
512
477
  * @fileOverview Kickass library to create and place poppers near their reference elements.
513
- * @version 1.11.1
478
+ * @version 1.14.3
514
479
  * @license
515
480
  * Copyright (c) 2016 Federico Zivolo and contributors
516
481
  *
@@ -532,52 +497,28 @@ function onTransitionEnd(refData, duration, callback) {
532
497
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
533
498
  * SOFTWARE.
534
499
  */
535
- var nativeHints = ['native code', '[object MutationObserverConstructor]'];
500
+ var isBrowser$1 = typeof window !== 'undefined' && typeof document !== 'undefined';
536
501
 
537
- /**
538
- * Determine if a function is implemented natively (as opposed to a polyfill).
539
- * @method
540
- * @memberof Popper.Utils
541
- * @argument {Function | undefined} fn the function to check
542
- * @returns {Boolean}
543
- */
544
- var isNative = function isNative(fn) {
545
- return nativeHints.some(function (hint) {
546
- return (fn || '').toString().indexOf(hint) > -1;
547
- });
548
- };
549
-
550
- var isBrowser = typeof window !== 'undefined';
551
502
  var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
552
503
  var timeoutDuration = 0;
553
504
  for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
554
- if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
505
+ if (isBrowser$1 && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
555
506
  timeoutDuration = 1;
556
507
  break;
557
508
  }
558
509
  }
559
510
 
560
511
  function microtaskDebounce(fn) {
561
- var scheduled = false;
562
- var i = 0;
563
- var elem = document.createElement('span');
564
-
565
- // MutationObserver provides a mechanism for scheduling microtasks, which
566
- // are scheduled *before* the next task. This gives us a way to debounce
567
- // a function but ensure it's called *before* the next paint.
568
- var observer = new MutationObserver(function () {
569
- fn();
570
- scheduled = false;
571
- });
572
-
573
- observer.observe(elem, { attributes: true });
574
-
512
+ var called = false;
575
513
  return function () {
576
- if (!scheduled) {
577
- scheduled = true;
578
- elem.setAttribute('x-index', i);
579
- i = i + 1; // don't use compund (+=) because it doesn't get optimized in V8
514
+ if (called) {
515
+ return;
580
516
  }
517
+ called = true;
518
+ window.Promise.resolve().then(function () {
519
+ called = false;
520
+ fn();
521
+ });
581
522
  };
582
523
  }
583
524
 
@@ -594,11 +535,7 @@ function taskDebounce(fn) {
594
535
  };
595
536
  }
596
537
 
597
- // It's common for MutationObserver polyfills to be seen in the wild, however
598
- // these rely on Mutation Events which only occur when an element is connected
599
- // to the DOM. The algorithm used in this module does not use a connected element,
600
- // and so we must ensure that a *native* MutationObserver is available.
601
- var supportsNativeMutationObserver = isBrowser && isNative(window.MutationObserver);
538
+ var supportsMicroTasks = isBrowser$1 && window.Promise;
602
539
 
603
540
  /**
604
541
  * Create a debounced version of a method, that's asynchronously deferred
@@ -609,7 +546,7 @@ var supportsNativeMutationObserver = isBrowser && isNative(window.MutationObserv
609
546
  * @argument {Function} fn
610
547
  * @returns {Function}
611
548
  */
612
- var debounce = supportsNativeMutationObserver ? microtaskDebounce : taskDebounce;
549
+ var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;
613
550
 
614
551
  /**
615
552
  * Check if the given variable is a function
@@ -635,7 +572,7 @@ function getStyleComputedProperty(element, property) {
635
572
  return [];
636
573
  }
637
574
  // NOTE: 1 DOM access here
638
- var css = window.getComputedStyle(element, null);
575
+ var css = getComputedStyle(element, null);
639
576
  return property ? css[property] : css;
640
577
  }
641
578
 
@@ -662,8 +599,16 @@ function getParentNode(element) {
662
599
  */
663
600
  function getScrollParent(element) {
664
601
  // Return body, `getScroll` will take care to get the correct `scrollTop` from it
665
- if (!element || ['HTML', 'BODY', '#document'].indexOf(element.nodeName) !== -1) {
666
- return window.document.body;
602
+ if (!element) {
603
+ return document.body;
604
+ }
605
+
606
+ switch (element.nodeName) {
607
+ case 'HTML':
608
+ case 'BODY':
609
+ return element.ownerDocument.body;
610
+ case '#document':
611
+ return element.body;
667
612
  }
668
613
 
669
614
  // Firefox want us to check `-x` and `-y` variations as well
@@ -673,13 +618,33 @@ function getScrollParent(element) {
673
618
  overflowX = _getStyleComputedProp.overflowX,
674
619
  overflowY = _getStyleComputedProp.overflowY;
675
620
 
676
- if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) {
621
+ if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
677
622
  return element;
678
623
  }
679
624
 
680
625
  return getScrollParent(getParentNode(element));
681
626
  }
682
627
 
628
+ var isIE11 = isBrowser$1 && !!(window.MSInputMethodContext && document.documentMode);
629
+ var isIE10 = isBrowser$1 && /MSIE 10/.test(navigator.userAgent);
630
+
631
+ /**
632
+ * Determines if the browser is Internet Explorer
633
+ * @method
634
+ * @memberof Popper.Utils
635
+ * @param {Number} version to check
636
+ * @returns {Boolean} isIE
637
+ */
638
+ function isIE$1(version) {
639
+ if (version === 11) {
640
+ return isIE11;
641
+ }
642
+ if (version === 10) {
643
+ return isIE10;
644
+ }
645
+ return isIE11 || isIE10;
646
+ }
647
+
683
648
  /**
684
649
  * Returns the offset parent of the given element
685
650
  * @method
@@ -688,12 +653,23 @@ function getScrollParent(element) {
688
653
  * @returns {Element} offset parent
689
654
  */
690
655
  function getOffsetParent(element) {
656
+ if (!element) {
657
+ return document.documentElement;
658
+ }
659
+
660
+ var noOffsetParent = isIE$1(10) ? document.body : null;
661
+
691
662
  // NOTE: 1 DOM access here
692
- var offsetParent = element && element.offsetParent;
663
+ var offsetParent = element.offsetParent;
664
+ // Skip hidden elements which don't have an offsetParent
665
+ while (offsetParent === noOffsetParent && element.nextElementSibling) {
666
+ offsetParent = (element = element.nextElementSibling).offsetParent;
667
+ }
668
+
693
669
  var nodeName = offsetParent && offsetParent.nodeName;
694
670
 
695
671
  if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
696
- return window.document.documentElement;
672
+ return element ? element.ownerDocument.documentElement : document.documentElement;
697
673
  }
698
674
 
699
675
  // .offsetParent will return the closest TD or TABLE in case
@@ -740,7 +716,7 @@ function getRoot(node) {
740
716
  function findCommonOffsetParent(element1, element2) {
741
717
  // This check is needed to avoid errors in case one of the elements isn't defined for any reason
742
718
  if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
743
- return window.document.documentElement;
719
+ return document.documentElement;
744
720
  }
745
721
 
746
722
  // Here we make sure to give as "start" the element that comes first in the DOM
@@ -788,8 +764,8 @@ function getScroll(element) {
788
764
  var nodeName = element.nodeName;
789
765
 
790
766
  if (nodeName === 'BODY' || nodeName === 'HTML') {
791
- var html = window.document.documentElement;
792
- var scrollingElement = window.document.scrollingElement || html;
767
+ var html = element.ownerDocument.documentElement;
768
+ var scrollingElement = element.ownerDocument.scrollingElement || html;
793
769
  return scrollingElement[upperSide];
794
770
  }
795
771
 
@@ -832,32 +808,17 @@ function getBordersSize(styles, axis) {
832
808
  var sideA = axis === 'x' ? 'Left' : 'Top';
833
809
  var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
834
810
 
835
- return +styles['border' + sideA + 'Width'].split('px')[0] + +styles['border' + sideB + 'Width'].split('px')[0];
811
+ return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);
836
812
  }
837
813
 
838
- /**
839
- * Tells if you are running Internet Explorer 10
840
- * @method
841
- * @memberof Popper.Utils
842
- * @returns {Boolean} isIE10
843
- */
844
- var isIE10 = undefined;
845
-
846
- var isIE10$1 = function isIE10$1() {
847
- if (isIE10 === undefined) {
848
- isIE10 = navigator.appVersion.indexOf('MSIE 10') !== -1;
849
- }
850
- return isIE10;
851
- };
852
-
853
814
  function getSize(axis, body, html, computedStyle) {
854
- return Math.max(body['offset' + axis], html['client' + axis], html['offset' + axis], isIE10$1() ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0);
815
+ return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE$1(10) ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0);
855
816
  }
856
817
 
857
818
  function getWindowSizes() {
858
- var body = window.document.body;
859
- var html = window.document.documentElement;
860
- var computedStyle = isIE10$1() && window.getComputedStyle(html);
819
+ var body = document.body;
820
+ var html = document.documentElement;
821
+ var computedStyle = isIE$1(10) && getComputedStyle(html);
861
822
 
862
823
  return {
863
824
  height: getSize('Height', body, html, computedStyle),
@@ -865,13 +826,13 @@ function getWindowSizes() {
865
826
  };
866
827
  }
867
828
 
868
- var classCallCheck = function classCallCheck(instance, Constructor) {
829
+ var classCallCheck$1 = function classCallCheck(instance, Constructor) {
869
830
  if (!(instance instanceof Constructor)) {
870
831
  throw new TypeError("Cannot call a class as a function");
871
832
  }
872
833
  };
873
834
 
874
- var createClass = function () {
835
+ var createClass$1 = function () {
875
836
  function defineProperties(target, props) {
876
837
  for (var i = 0; i < props.length; i++) {
877
838
  var descriptor = props[i];
@@ -889,7 +850,7 @@ var createClass = function () {
889
850
  };
890
851
  }();
891
852
 
892
- var defineProperty = function defineProperty(obj, key, value) {
853
+ var defineProperty$1 = function defineProperty(obj, key, value) {
893
854
  if (key in obj) {
894
855
  Object.defineProperty(obj, key, {
895
856
  value: value,
@@ -904,7 +865,7 @@ var defineProperty = function defineProperty(obj, key, value) {
904
865
  return obj;
905
866
  };
906
867
 
907
- var _extends = Object.assign || function (target) {
868
+ var _extends$1 = Object.assign || function (target) {
908
869
  for (var i = 1; i < arguments.length; i++) {
909
870
  var source = arguments[i];
910
871
 
@@ -926,7 +887,7 @@ var _extends = Object.assign || function (target) {
926
887
  * @returns {Object} ClientRect like output
927
888
  */
928
889
  function getClientRect(offsets) {
929
- return _extends({}, offsets, {
890
+ return _extends$1({}, offsets, {
930
891
  right: offsets.left + offsets.width,
931
892
  bottom: offsets.top + offsets.height
932
893
  });
@@ -945,8 +906,8 @@ function getBoundingClientRect(element) {
945
906
  // IE10 10 FIX: Please, don't ask, the element isn't
946
907
  // considered in DOM in some circumstances...
947
908
  // This isn't reproducible in IE10 compatibility mode of IE11
948
- if (isIE10$1()) {
949
- try {
909
+ try {
910
+ if (isIE$1(10)) {
950
911
  rect = element.getBoundingClientRect();
951
912
  var scrollTop = getScroll(element, 'top');
952
913
  var scrollLeft = getScroll(element, 'left');
@@ -954,10 +915,10 @@ function getBoundingClientRect(element) {
954
915
  rect.left += scrollLeft;
955
916
  rect.bottom += scrollTop;
956
917
  rect.right += scrollLeft;
957
- } catch (err) {}
958
- } else {
959
- rect = element.getBoundingClientRect();
960
- }
918
+ } else {
919
+ rect = element.getBoundingClientRect();
920
+ }
921
+ } catch (e) {}
961
922
 
962
923
  var result = {
963
924
  left: rect.left,
@@ -989,16 +950,23 @@ function getBoundingClientRect(element) {
989
950
  }
990
951
 
991
952
  function getOffsetRectRelativeToArbitraryNode(children, parent) {
992
- var isIE10 = isIE10$1();
953
+ var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
954
+
955
+ var isIE10 = isIE$1(10);
993
956
  var isHTML = parent.nodeName === 'HTML';
994
957
  var childrenRect = getBoundingClientRect(children);
995
958
  var parentRect = getBoundingClientRect(parent);
996
959
  var scrollParent = getScrollParent(children);
997
960
 
998
961
  var styles = getStyleComputedProperty(parent);
999
- var borderTopWidth = +styles.borderTopWidth.split('px')[0];
1000
- var borderLeftWidth = +styles.borderLeftWidth.split('px')[0];
962
+ var borderTopWidth = parseFloat(styles.borderTopWidth, 10);
963
+ var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);
1001
964
 
965
+ // In cases where the parent is fixed, we must ignore negative scroll in offset calc
966
+ if (fixedPosition && parent.nodeName === 'HTML') {
967
+ parentRect.top = Math.max(parentRect.top, 0);
968
+ parentRect.left = Math.max(parentRect.left, 0);
969
+ }
1002
970
  var offsets = getClientRect({
1003
971
  top: childrenRect.top - parentRect.top - borderTopWidth,
1004
972
  left: childrenRect.left - parentRect.left - borderLeftWidth,
@@ -1013,8 +981,8 @@ function getOffsetRectRelativeToArbitraryNode(children, parent) {
1013
981
  // differently when margins are applied to it. The margins are included in
1014
982
  // the box of the documentElement, in the other cases not.
1015
983
  if (!isIE10 && isHTML) {
1016
- var marginTop = +styles.marginTop.split('px')[0];
1017
- var marginLeft = +styles.marginLeft.split('px')[0];
984
+ var marginTop = parseFloat(styles.marginTop, 10);
985
+ var marginLeft = parseFloat(styles.marginLeft, 10);
1018
986
 
1019
987
  offsets.top -= borderTopWidth - marginTop;
1020
988
  offsets.bottom -= borderTopWidth - marginTop;
@@ -1026,7 +994,7 @@ function getOffsetRectRelativeToArbitraryNode(children, parent) {
1026
994
  offsets.marginLeft = marginLeft;
1027
995
  }
1028
996
 
1029
- if (isIE10 ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
997
+ if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
1030
998
  offsets = includeScroll(offsets, parent);
1031
999
  }
1032
1000
 
@@ -1034,13 +1002,15 @@ function getOffsetRectRelativeToArbitraryNode(children, parent) {
1034
1002
  }
1035
1003
 
1036
1004
  function getViewportOffsetRectRelativeToArtbitraryNode(element) {
1037
- var html = window.document.documentElement;
1005
+ var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1006
+
1007
+ var html = element.ownerDocument.documentElement;
1038
1008
  var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
1039
1009
  var width = Math.max(html.clientWidth, window.innerWidth || 0);
1040
1010
  var height = Math.max(html.clientHeight, window.innerHeight || 0);
1041
1011
 
1042
- var scrollTop = getScroll(html);
1043
- var scrollLeft = getScroll(html, 'left');
1012
+ var scrollTop = !excludeScroll ? getScroll(html) : 0;
1013
+ var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;
1044
1014
 
1045
1015
  var offset = {
1046
1016
  top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
@@ -1071,6 +1041,26 @@ function isFixed(element) {
1071
1041
  return isFixed(getParentNode(element));
1072
1042
  }
1073
1043
 
1044
+ /**
1045
+ * Finds the first parent of an element that has a transformed property defined
1046
+ * @method
1047
+ * @memberof Popper.Utils
1048
+ * @argument {Element} element
1049
+ * @returns {Element} first transformed parent or documentElement
1050
+ */
1051
+
1052
+ function getFixedPositionOffsetParent(element) {
1053
+ // This check is needed to avoid errors in case one of the elements isn't defined for any reason
1054
+ if (!element || !element.parentElement || isIE$1()) {
1055
+ return document.documentElement;
1056
+ }
1057
+ var el = element.parentElement;
1058
+ while (el && getStyleComputedProperty(el, 'transform') === 'none') {
1059
+ el = el.parentElement;
1060
+ }
1061
+ return el || document.documentElement;
1062
+ }
1063
+
1074
1064
  /**
1075
1065
  * Computed the boundaries limits and return them
1076
1066
  * @method
@@ -1079,31 +1069,35 @@ function isFixed(element) {
1079
1069
  * @param {HTMLElement} reference
1080
1070
  * @param {number} padding
1081
1071
  * @param {HTMLElement} boundariesElement - Element used to define the boundaries
1072
+ * @param {Boolean} fixedPosition - Is in fixed position mode
1082
1073
  * @returns {Object} Coordinates of the boundaries
1083
1074
  */
1084
1075
  function getBoundaries(popper, reference, padding, boundariesElement) {
1076
+ var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
1077
+
1085
1078
  // NOTE: 1 DOM access here
1079
+
1086
1080
  var boundaries = { top: 0, left: 0 };
1087
- var offsetParent = findCommonOffsetParent(popper, reference);
1081
+ var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);
1088
1082
 
1089
1083
  // Handle viewport case
1090
1084
  if (boundariesElement === 'viewport') {
1091
- boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent);
1085
+ boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);
1092
1086
  } else {
1093
1087
  // Handle other cases based on DOM element used as boundaries
1094
1088
  var boundariesNode = void 0;
1095
1089
  if (boundariesElement === 'scrollParent') {
1096
- boundariesNode = getScrollParent(getParentNode(popper));
1090
+ boundariesNode = getScrollParent(getParentNode(reference));
1097
1091
  if (boundariesNode.nodeName === 'BODY') {
1098
- boundariesNode = window.document.documentElement;
1092
+ boundariesNode = popper.ownerDocument.documentElement;
1099
1093
  }
1100
1094
  } else if (boundariesElement === 'window') {
1101
- boundariesNode = window.document.documentElement;
1095
+ boundariesNode = popper.ownerDocument.documentElement;
1102
1096
  } else {
1103
1097
  boundariesNode = boundariesElement;
1104
1098
  }
1105
1099
 
1106
- var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent);
1100
+ var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);
1107
1101
 
1108
1102
  // In case of HTML, we need a different computation
1109
1103
  if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
@@ -1175,7 +1169,7 @@ function computeAutoPlacement(placement, refRect, popper, reference, boundariesE
1175
1169
  };
1176
1170
 
1177
1171
  var sortedAreas = Object.keys(rects).map(function (key) {
1178
- return _extends({
1172
+ return _extends$1({
1179
1173
  key: key
1180
1174
  }, rects[key], {
1181
1175
  area: getArea(rects[key])
@@ -1204,11 +1198,14 @@ function computeAutoPlacement(placement, refRect, popper, reference, boundariesE
1204
1198
  * @param {Object} state
1205
1199
  * @param {Element} popper - the popper element
1206
1200
  * @param {Element} reference - the reference element (the popper will be relative to this)
1201
+ * @param {Element} fixedPosition - is in fixed position mode
1207
1202
  * @returns {Object} An object containing the offsets which will be applied to the popper
1208
1203
  */
1209
1204
  function getReferenceOffsets(state, popper, reference) {
1210
- var commonOffsetParent = findCommonOffsetParent(popper, reference);
1211
- return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent);
1205
+ var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1206
+
1207
+ var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);
1208
+ return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);
1212
1209
  }
1213
1210
 
1214
1211
  /**
@@ -1219,7 +1216,7 @@ function getReferenceOffsets(state, popper, reference) {
1219
1216
  * @returns {Object} object containing width and height properties
1220
1217
  */
1221
1218
  function getOuterSizes(element) {
1222
- var styles = window.getComputedStyle(element);
1219
+ var styles = getComputedStyle(element);
1223
1220
  var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
1224
1221
  var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
1225
1222
  var result = {
@@ -1291,7 +1288,7 @@ function getPopperOffsets(popper, referenceOffsets, placement) {
1291
1288
  * @argument value
1292
1289
  * @returns index or -1
1293
1290
  */
1294
- function find$1(arr, check) {
1291
+ function find(arr, check) {
1295
1292
  // use native find if supported
1296
1293
  if (Array.prototype.find) {
1297
1294
  return arr.find(check);
@@ -1310,7 +1307,7 @@ function find$1(arr, check) {
1310
1307
  * @argument value
1311
1308
  * @returns index or -1
1312
1309
  */
1313
- function findIndex$1(arr, prop, value) {
1310
+ function findIndex(arr, prop, value) {
1314
1311
  // use native findIndex if supported
1315
1312
  if (Array.prototype.findIndex) {
1316
1313
  return arr.findIndex(function (cur) {
@@ -1319,7 +1316,7 @@ function findIndex$1(arr, prop, value) {
1319
1316
  }
1320
1317
 
1321
1318
  // use `find` + `indexOf` if `findIndex` isn't supported
1322
- var match = find$1(arr, function (obj) {
1319
+ var match = find(arr, function (obj) {
1323
1320
  return obj[prop] === value;
1324
1321
  });
1325
1322
  return arr.indexOf(match);
@@ -1336,13 +1333,14 @@ function findIndex$1(arr, prop, value) {
1336
1333
  * @returns {dataObject}
1337
1334
  */
1338
1335
  function runModifiers(modifiers, data, ends) {
1339
- var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex$1(modifiers, 'name', ends));
1336
+ var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
1340
1337
 
1341
1338
  modifiersToRun.forEach(function (modifier) {
1342
- if (modifier.function) {
1339
+ if (modifier['function']) {
1340
+ // eslint-disable-line dot-notation
1343
1341
  console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
1344
1342
  }
1345
- var fn = modifier.function || modifier.fn;
1343
+ var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
1346
1344
  if (modifier.enabled && isFunction(fn)) {
1347
1345
  // Add properties to offsets to make them a complete clientRect object
1348
1346
  // we do this before each modifier to make sure the previous one doesn't
@@ -1373,13 +1371,14 @@ function update() {
1373
1371
  var data = {
1374
1372
  instance: this,
1375
1373
  styles: {},
1374
+ arrowStyles: {},
1376
1375
  attributes: {},
1377
1376
  flipped: false,
1378
1377
  offsets: {}
1379
1378
  };
1380
1379
 
1381
1380
  // compute reference element offsets
1382
- data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference);
1381
+ data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);
1383
1382
 
1384
1383
  // compute auto placement, store placement inside the data object,
1385
1384
  // modifiers will be able to edit `placement` if needed
@@ -1389,9 +1388,12 @@ function update() {
1389
1388
  // store the computed placement inside `originalPlacement`
1390
1389
  data.originalPlacement = data.placement;
1391
1390
 
1391
+ data.positionFixed = this.options.positionFixed;
1392
+
1392
1393
  // compute the popper offsets
1393
1394
  data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);
1394
- data.offsets.popper.position = 'absolute';
1395
+
1396
+ data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';
1395
1397
 
1396
1398
  // run the modifiers
1397
1399
  data = runModifiers(this.modifiers, data);
@@ -1431,10 +1433,10 @@ function getSupportedPropertyName(property) {
1431
1433
  var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
1432
1434
  var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
1433
1435
 
1434
- for (var i = 0; i < prefixes.length - 1; i++) {
1436
+ for (var i = 0; i < prefixes.length; i++) {
1435
1437
  var prefix = prefixes[i];
1436
1438
  var toCheck = prefix ? '' + prefix + upperProp : property;
1437
- if (typeof window.document.body.style[toCheck] !== 'undefined') {
1439
+ if (typeof document.body.style[toCheck] !== 'undefined') {
1438
1440
  return toCheck;
1439
1441
  }
1440
1442
  }
@@ -1452,9 +1454,12 @@ function destroy() {
1452
1454
  // touch DOM only if `applyStyle` modifier is enabled
1453
1455
  if (isModifierEnabled(this.modifiers, 'applyStyle')) {
1454
1456
  this.popper.removeAttribute('x-placement');
1455
- this.popper.style.left = '';
1456
1457
  this.popper.style.position = '';
1457
1458
  this.popper.style.top = '';
1459
+ this.popper.style.left = '';
1460
+ this.popper.style.right = '';
1461
+ this.popper.style.bottom = '';
1462
+ this.popper.style.willChange = '';
1458
1463
  this.popper.style[getSupportedPropertyName('transform')] = '';
1459
1464
  }
1460
1465
 
@@ -1468,9 +1473,19 @@ function destroy() {
1468
1473
  return this;
1469
1474
  }
1470
1475
 
1476
+ /**
1477
+ * Get the window associated with the element
1478
+ * @argument {Element} element
1479
+ * @returns {Window}
1480
+ */
1481
+ function getWindow(element) {
1482
+ var ownerDocument = element.ownerDocument;
1483
+ return ownerDocument ? ownerDocument.defaultView : window;
1484
+ }
1485
+
1471
1486
  function attachToScrollParents(scrollParent, event, callback, scrollParents) {
1472
1487
  var isBody = scrollParent.nodeName === 'BODY';
1473
- var target = isBody ? window : scrollParent;
1488
+ var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
1474
1489
  target.addEventListener(event, callback, { passive: true });
1475
1490
 
1476
1491
  if (!isBody) {
@@ -1488,7 +1503,7 @@ function attachToScrollParents(scrollParent, event, callback, scrollParents) {
1488
1503
  function setupEventListeners(reference, options, state, updateBound) {
1489
1504
  // Resize event listener on window
1490
1505
  state.updateBound = updateBound;
1491
- window.addEventListener('resize', state.updateBound, { passive: true });
1506
+ getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });
1492
1507
 
1493
1508
  // Scroll event listener on scroll parents
1494
1509
  var scrollElement = getScrollParent(reference);
@@ -1519,7 +1534,7 @@ function enableEventListeners() {
1519
1534
  */
1520
1535
  function removeEventListeners(reference, state) {
1521
1536
  // Remove resize event listener on window
1522
- window.removeEventListener('resize', state.updateBound);
1537
+ getWindow(reference).removeEventListener('resize', state.updateBound);
1523
1538
 
1524
1539
  // Remove scroll event listener on scroll parents
1525
1540
  state.scrollParents.forEach(function (target) {
@@ -1543,7 +1558,7 @@ function removeEventListeners(reference, state) {
1543
1558
  */
1544
1559
  function disableEventListeners() {
1545
1560
  if (this.state.eventsEnabled) {
1546
- window.cancelAnimationFrame(this.scheduleUpdate);
1561
+ cancelAnimationFrame(this.scheduleUpdate);
1547
1562
  this.state = removeEventListeners(this.reference, this.state);
1548
1563
  }
1549
1564
  }
@@ -1617,9 +1632,9 @@ function applyStyle(data) {
1617
1632
  // they will be set as HTML attributes of the element
1618
1633
  setAttributes(data.instance.popper, data.attributes);
1619
1634
 
1620
- // if the arrow style has been computed, apply the arrow style
1621
- if (data.offsets.arrow) {
1622
- setStyles(data.arrowElement, data.offsets.arrow);
1635
+ // if arrowElement is defined and arrowStyles has some properties
1636
+ if (data.arrowElement && Object.keys(data.arrowStyles).length) {
1637
+ setStyles(data.arrowElement, data.arrowStyles);
1623
1638
  }
1624
1639
 
1625
1640
  return data;
@@ -1632,12 +1647,12 @@ function applyStyle(data) {
1632
1647
  * @method
1633
1648
  * @memberof Popper.modifiers
1634
1649
  * @param {HTMLElement} reference - The reference element used to position the popper
1635
- * @param {HTMLElement} popper - The HTML element used as popper.
1650
+ * @param {HTMLElement} popper - The HTML element used as popper
1636
1651
  * @param {Object} options - Popper.js options
1637
1652
  */
1638
1653
  function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
1639
1654
  // compute reference element offsets
1640
- var referenceOffsets = getReferenceOffsets(state, popper, reference);
1655
+ var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);
1641
1656
 
1642
1657
  // compute auto placement, store placement inside the data object,
1643
1658
  // modifiers will be able to edit `placement` if needed
@@ -1648,7 +1663,7 @@ function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
1648
1663
 
1649
1664
  // Apply `position` to popper before anything else because
1650
1665
  // without the position applied we can't guarantee correct computations
1651
- setStyles(popper, { position: 'absolute' });
1666
+ setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });
1652
1667
 
1653
1668
  return options;
1654
1669
  }
@@ -1667,7 +1682,7 @@ function computeStyle(data, options) {
1667
1682
 
1668
1683
  // Remove this legacy support in Popper.js v2
1669
1684
 
1670
- var legacyGpuAccelerationOption = find$1(data.instance.modifiers, function (modifier) {
1685
+ var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
1671
1686
  return modifier.name === 'applyStyle';
1672
1687
  }).gpuAcceleration;
1673
1688
  if (legacyGpuAccelerationOption !== undefined) {
@@ -1683,11 +1698,13 @@ function computeStyle(data, options) {
1683
1698
  position: popper.position
1684
1699
  };
1685
1700
 
1686
- // floor sides to avoid blurry text
1701
+ // Avoid blurry text by using full pixel integers.
1702
+ // For pixel-perfect positioning, top/bottom prefers rounded
1703
+ // values, while left/right prefers floored values.
1687
1704
  var offsets = {
1688
1705
  left: Math.floor(popper.left),
1689
- top: Math.floor(popper.top),
1690
- bottom: Math.floor(popper.bottom),
1706
+ top: Math.round(popper.top),
1707
+ bottom: Math.round(popper.bottom),
1691
1708
  right: Math.floor(popper.right)
1692
1709
  };
1693
1710
 
@@ -1739,9 +1756,10 @@ function computeStyle(data, options) {
1739
1756
  'x-placement': data.placement
1740
1757
  };
1741
1758
 
1742
- // Update attributes and styles of `data`
1743
- data.attributes = _extends({}, attributes, data.attributes);
1744
- data.styles = _extends({}, styles, data.styles);
1759
+ // Update `data` attributes, styles and arrowStyles
1760
+ data.attributes = _extends$1({}, attributes, data.attributes);
1761
+ data.styles = _extends$1({}, styles, data.styles);
1762
+ data.arrowStyles = _extends$1({}, data.offsets.arrow, data.arrowStyles);
1745
1763
 
1746
1764
  return data;
1747
1765
  }
@@ -1757,7 +1775,7 @@ function computeStyle(data, options) {
1757
1775
  * @returns {Boolean}
1758
1776
  */
1759
1777
  function isModifierRequired(modifiers, requestingName, requestedName) {
1760
- var requesting = find$1(modifiers, function (_ref) {
1778
+ var requesting = find(modifiers, function (_ref) {
1761
1779
  var name = _ref.name;
1762
1780
  return name === requestingName;
1763
1781
  });
@@ -1782,6 +1800,8 @@ function isModifierRequired(modifiers, requestingName, requestedName) {
1782
1800
  * @returns {Object} The data object, properly modified
1783
1801
  */
1784
1802
  function arrow(data, options) {
1803
+ var _data$offsets$arrow;
1804
+
1785
1805
  // arrow depends on keepTogether in order to work
1786
1806
  if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
1787
1807
  return data;
@@ -1814,13 +1834,15 @@ function arrow(data, options) {
1814
1834
  var isVertical = ['left', 'right'].indexOf(placement) !== -1;
1815
1835
 
1816
1836
  var len = isVertical ? 'height' : 'width';
1817
- var side = isVertical ? 'top' : 'left';
1837
+ var sideCapitalized = isVertical ? 'Top' : 'Left';
1838
+ var side = sideCapitalized.toLowerCase();
1818
1839
  var altSide = isVertical ? 'left' : 'top';
1819
1840
  var opSide = isVertical ? 'bottom' : 'right';
1820
1841
  var arrowElementSize = getOuterSizes(arrowElement)[len];
1821
1842
 
1822
1843
  //
1823
- // extends keepTogether behavior making sure the popper and its reference have enough pixels in conjuction
1844
+ // extends keepTogether behavior making sure the popper and its
1845
+ // reference have enough pixels in conjuction
1824
1846
  //
1825
1847
 
1826
1848
  // top/left side
@@ -1831,20 +1853,23 @@ function arrow(data, options) {
1831
1853
  if (reference[side] + arrowElementSize > popper[opSide]) {
1832
1854
  data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
1833
1855
  }
1856
+ data.offsets.popper = getClientRect(data.offsets.popper);
1834
1857
 
1835
1858
  // compute center of the popper
1836
1859
  var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;
1837
1860
 
1838
1861
  // Compute the sideValue using the updated popper offsets
1839
- var sideValue = center - getClientRect(data.offsets.popper)[side];
1862
+ // take popper margin in account because we don't have this info available
1863
+ var css = getStyleComputedProperty(data.instance.popper);
1864
+ var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);
1865
+ var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);
1866
+ var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;
1840
1867
 
1841
1868
  // prevent arrowElement from being placed not contiguously to its popper
1842
1869
  sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);
1843
1870
 
1844
1871
  data.arrowElement = arrowElement;
1845
- data.offsets.arrow = {};
1846
- data.offsets.arrow[side] = Math.round(sideValue);
1847
- data.offsets.arrow[altSide] = ''; // make sure to unset any eventual altSide value from the DOM node
1872
+ data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty$1(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty$1(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);
1848
1873
 
1849
1874
  return data;
1850
1875
  }
@@ -1943,7 +1968,7 @@ function flip(data, options) {
1943
1968
  return data;
1944
1969
  }
1945
1970
 
1946
- var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement);
1971
+ var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);
1947
1972
 
1948
1973
  var placement = data.placement.split('-')[0];
1949
1974
  var placementOpposite = getOppositePlacement(placement);
@@ -2007,7 +2032,7 @@ function flip(data, options) {
2007
2032
 
2008
2033
  // this object contains `position`, we want to preserve it along with
2009
2034
  // any additional property we may add in the future
2010
- data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
2035
+ data.offsets.popper = _extends$1({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
2011
2036
 
2012
2037
  data = runModifiers(data.instance.modifiers, data, 'flip');
2013
2038
  }
@@ -2124,7 +2149,7 @@ function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
2124
2149
 
2125
2150
  // Detect if the offset string contains a pair of values or a single one
2126
2151
  // they could be separated by comma or space
2127
- var divider = fragments.indexOf(find$1(fragments, function (frag) {
2152
+ var divider = fragments.indexOf(find(fragments, function (frag) {
2128
2153
  return frag.search(/,|\s/) !== -1;
2129
2154
  }));
2130
2155
 
@@ -2235,7 +2260,27 @@ function preventOverflow(data, options) {
2235
2260
  boundariesElement = getOffsetParent(boundariesElement);
2236
2261
  }
2237
2262
 
2238
- var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement);
2263
+ // NOTE: DOM access here
2264
+ // resets the popper's position so that the document size can be calculated excluding
2265
+ // the size of the popper element itself
2266
+ var transformProp = getSupportedPropertyName('transform');
2267
+ var popperStyles = data.instance.popper.style; // assignment to help minification
2268
+ var top = popperStyles.top,
2269
+ left = popperStyles.left,
2270
+ transform = popperStyles[transformProp];
2271
+
2272
+ popperStyles.top = '';
2273
+ popperStyles.left = '';
2274
+ popperStyles[transformProp] = '';
2275
+
2276
+ var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);
2277
+
2278
+ // NOTE: DOM access here
2279
+ // restores the original style properties after the offsets have been computed
2280
+ popperStyles.top = top;
2281
+ popperStyles.left = left;
2282
+ popperStyles[transformProp] = transform;
2283
+
2239
2284
  options.boundaries = boundaries;
2240
2285
 
2241
2286
  var order = options.priority;
@@ -2247,7 +2292,7 @@ function preventOverflow(data, options) {
2247
2292
  if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
2248
2293
  value = Math.max(popper[placement], boundaries[placement]);
2249
2294
  }
2250
- return defineProperty({}, placement, value);
2295
+ return defineProperty$1({}, placement, value);
2251
2296
  },
2252
2297
  secondary: function secondary(placement) {
2253
2298
  var mainSide = placement === 'right' ? 'left' : 'top';
@@ -2255,13 +2300,13 @@ function preventOverflow(data, options) {
2255
2300
  if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
2256
2301
  value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
2257
2302
  }
2258
- return defineProperty({}, mainSide, value);
2303
+ return defineProperty$1({}, mainSide, value);
2259
2304
  }
2260
2305
  };
2261
2306
 
2262
2307
  order.forEach(function (placement) {
2263
2308
  var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
2264
- popper = _extends({}, popper, check[side](placement));
2309
+ popper = _extends$1({}, popper, check[side](placement));
2265
2310
  });
2266
2311
 
2267
2312
  data.offsets.popper = popper;
@@ -2292,11 +2337,11 @@ function shift(data) {
2292
2337
  var measurement = isVertical ? 'width' : 'height';
2293
2338
 
2294
2339
  var shiftOffsets = {
2295
- start: defineProperty({}, side, reference[side]),
2296
- end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
2340
+ start: defineProperty$1({}, side, reference[side]),
2341
+ end: defineProperty$1({}, side, reference[side] + reference[measurement] - popper[measurement])
2297
2342
  };
2298
2343
 
2299
- data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
2344
+ data.offsets.popper = _extends$1({}, popper, shiftOffsets[shiftvariation]);
2300
2345
  }
2301
2346
 
2302
2347
  return data;
@@ -2315,7 +2360,7 @@ function hide(data) {
2315
2360
  }
2316
2361
 
2317
2362
  var refRect = data.offsets.reference;
2318
- var bound = find$1(data.instance.modifiers, function (modifier) {
2363
+ var bound = find(data.instance.modifiers, function (modifier) {
2319
2364
  return modifier.name === 'preventOverflow';
2320
2365
  }).boundaries;
2321
2366
 
@@ -2358,7 +2403,7 @@ function inner(data) {
2358
2403
 
2359
2404
  var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;
2360
2405
 
2361
- popper[isHoriz ? 'left' : 'top'] = reference[placement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
2406
+ popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
2362
2407
 
2363
2408
  data.placement = getOppositePlacement(placement);
2364
2409
  data.offsets.popper = getClientRect(popper);
@@ -2436,6 +2481,9 @@ var modifiers = {
2436
2481
  * '10 - 5vh + 3%'
2437
2482
  * '-10px + 5vh, 5px - 6%'
2438
2483
  * ```
2484
+ * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
2485
+ * > with their reference element, unfortunately, you will have to disable the `flip` modifier.
2486
+ * > More on this [reading this issue](https://github.com/FezVrasta/popper.js/issues/373)
2439
2487
  *
2440
2488
  * @memberof modifiers
2441
2489
  * @inner
@@ -2698,6 +2746,7 @@ var modifiers = {
2698
2746
  * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper.
2699
2747
  * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
2700
2748
  * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`)
2749
+ * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow, it expects the JavaScript nomenclature (eg. `marginBottom`)
2701
2750
  * @property {Object} data.boundaries Offsets of the popper boundaries
2702
2751
  * @property {Object} data.offsets The measurements of popper, reference and arrow elements.
2703
2752
  * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
@@ -2721,13 +2770,19 @@ var modifiers = {
2721
2770
  * @static
2722
2771
  * @memberof Popper
2723
2772
  */
2724
- var Defaults$1 = {
2773
+ var Defaults = {
2725
2774
  /**
2726
2775
  * Popper's placement
2727
2776
  * @prop {Popper.placements} placement='bottom'
2728
2777
  */
2729
2778
  placement: 'bottom',
2730
2779
 
2780
+ /**
2781
+ * Set this to true if you want popper to position it self in 'fixed' mode
2782
+ * @prop {Boolean} positionFixed=false
2783
+ */
2784
+ positionFixed: false,
2785
+
2731
2786
  /**
2732
2787
  * Whether events (resize, scroll) are initially enabled
2733
2788
  * @prop {Boolean} eventsEnabled=true
@@ -2792,7 +2847,7 @@ var Popper = function () {
2792
2847
  var _this = this;
2793
2848
 
2794
2849
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2795
- classCallCheck(this, Popper);
2850
+ classCallCheck$1(this, Popper);
2796
2851
 
2797
2852
  this.scheduleUpdate = function () {
2798
2853
  return requestAnimationFrame(_this.update);
@@ -2802,7 +2857,7 @@ var Popper = function () {
2802
2857
  this.update = debounce(this.update.bind(this));
2803
2858
 
2804
2859
  // with {} we create a new object with the options inside it
2805
- this.options = _extends({}, Popper.Defaults, options);
2860
+ this.options = _extends$1({}, Popper.Defaults, options);
2806
2861
 
2807
2862
  // init state
2808
2863
  this.state = {
@@ -2812,18 +2867,18 @@ var Popper = function () {
2812
2867
  };
2813
2868
 
2814
2869
  // get reference and popper elements (allow jQuery wrappers)
2815
- this.reference = reference.jquery ? reference[0] : reference;
2816
- this.popper = popper.jquery ? popper[0] : popper;
2870
+ this.reference = reference && reference.jquery ? reference[0] : reference;
2871
+ this.popper = popper && popper.jquery ? popper[0] : popper;
2817
2872
 
2818
2873
  // Deep merge modifiers options
2819
2874
  this.options.modifiers = {};
2820
- Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
2821
- _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
2875
+ Object.keys(_extends$1({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
2876
+ _this.options.modifiers[name] = _extends$1({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
2822
2877
  });
2823
2878
 
2824
2879
  // Refactoring modifiers' list (Object => Array)
2825
2880
  this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
2826
- return _extends({
2881
+ return _extends$1({
2827
2882
  name: name
2828
2883
  }, _this.options.modifiers[name]);
2829
2884
  })
@@ -2858,7 +2913,7 @@ var Popper = function () {
2858
2913
  // class prototype and break stuff like Sinon stubs
2859
2914
 
2860
2915
 
2861
- createClass(Popper, [{
2916
+ createClass$1(Popper, [{
2862
2917
  key: 'update',
2863
2918
  value: function update$$1() {
2864
2919
  return update.call(this);
@@ -2928,1000 +2983,1278 @@ var Popper = function () {
2928
2983
 
2929
2984
  Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
2930
2985
  Popper.placements = placements;
2931
- Popper.Defaults = Defaults$1;
2986
+ Popper.Defaults = Defaults;
2932
2987
 
2933
2988
  /**
2934
- * Returns the distance taking into account the default distance due to
2935
- * the transform: translate setting in CSS
2936
- * @param {Number} distance
2937
- * @return {String}
2938
- */
2939
- function getOffsetDistanceInPx(distance) {
2940
- return -(distance - Defaults.distance) + 'px';
2989
+ * Triggers document reflow.
2990
+ * Use void because some minifiers or engines think simply accessing the property
2991
+ * is unnecessary.
2992
+ * @param {Element} popper
2993
+ */
2994
+ function reflow(popper) {
2995
+ void popper.offsetHeight;
2941
2996
  }
2942
2997
 
2943
- var classCallCheck$1 = function (instance, Constructor) {
2944
- if (!(instance instanceof Constructor)) {
2945
- throw new TypeError("Cannot call a class as a function");
2946
- }
2947
- };
2998
+ /**
2999
+ * Wrapper util for popper position updating.
3000
+ * Updates the popper's position and invokes the callback on update.
3001
+ * Hackish workaround until Popper 2.0's update() becomes sync.
3002
+ * @param {Popper} popperInstance
3003
+ * @param {Function} callback: to run once popper's position was updated
3004
+ * @param {Boolean} updateAlreadyCalled: was scheduleUpdate() already called?
3005
+ */
3006
+ function updatePopperPosition(popperInstance, callback, updateAlreadyCalled) {
3007
+ var popper = popperInstance.popper,
3008
+ options = popperInstance.options;
2948
3009
 
2949
- var createClass$1 = function () {
2950
- function defineProperties(target, props) {
2951
- for (var i = 0; i < props.length; i++) {
2952
- var descriptor = props[i];
2953
- descriptor.enumerable = descriptor.enumerable || false;
2954
- descriptor.configurable = true;
2955
- if ("value" in descriptor) descriptor.writable = true;
2956
- Object.defineProperty(target, descriptor.key, descriptor);
2957
- }
2958
- }
3010
+ var onCreate = options.onCreate;
3011
+ var onUpdate = options.onUpdate;
2959
3012
 
2960
- return function (Constructor, protoProps, staticProps) {
2961
- if (protoProps) defineProperties(Constructor.prototype, protoProps);
2962
- if (staticProps) defineProperties(Constructor, staticProps);
2963
- return Constructor;
3013
+ options.onCreate = options.onUpdate = function () {
3014
+ reflow(popper), callback && callback(), onUpdate();
3015
+ options.onCreate = onCreate;
3016
+ options.onUpdate = onUpdate;
2964
3017
  };
2965
- }();
2966
3018
 
3019
+ if (!updateAlreadyCalled) {
3020
+ popperInstance.scheduleUpdate();
3021
+ }
3022
+ }
2967
3023
 
3024
+ /**
3025
+ * Returns the core placement ('top', 'bottom', 'left', 'right') of a popper
3026
+ * @param {Element} popper
3027
+ * @return {String}
3028
+ */
3029
+ function getPopperPlacement(popper) {
3030
+ return popper.getAttribute('x-placement').replace(/-.+/, '');
3031
+ }
2968
3032
 
3033
+ /**
3034
+ * Determines if the mouse's cursor is outside the interactive border
3035
+ * @param {MouseEvent} event
3036
+ * @param {Element} popper
3037
+ * @param {Object} options
3038
+ * @return {Boolean}
3039
+ */
3040
+ function cursorIsOutsideInteractiveBorder(event, popper, options) {
3041
+ if (!popper.getAttribute('x-placement')) return true;
2969
3042
 
3043
+ var x = event.clientX,
3044
+ y = event.clientY;
3045
+ var interactiveBorder = options.interactiveBorder,
3046
+ distance = options.distance;
2970
3047
 
2971
3048
 
3049
+ var rect = popper.getBoundingClientRect();
3050
+ var placement = getPopperPlacement(popper);
3051
+ var borderWithDistance = interactiveBorder + distance;
2972
3052
 
2973
- var _extends$1 = Object.assign || function (target) {
2974
- for (var i = 1; i < arguments.length; i++) {
2975
- var source = arguments[i];
3053
+ var exceeds = {
3054
+ top: rect.top - y > interactiveBorder,
3055
+ bottom: y - rect.bottom > interactiveBorder,
3056
+ left: rect.left - x > interactiveBorder,
3057
+ right: x - rect.right > interactiveBorder
3058
+ };
2976
3059
 
2977
- for (var key in source) {
2978
- if (Object.prototype.hasOwnProperty.call(source, key)) {
2979
- target[key] = source[key];
2980
- }
2981
- }
3060
+ switch (placement) {
3061
+ case 'top':
3062
+ exceeds.top = rect.top - y > borderWithDistance;
3063
+ break;
3064
+ case 'bottom':
3065
+ exceeds.bottom = y - rect.bottom > borderWithDistance;
3066
+ break;
3067
+ case 'left':
3068
+ exceeds.left = rect.left - x > borderWithDistance;
3069
+ break;
3070
+ case 'right':
3071
+ exceeds.right = x - rect.right > borderWithDistance;
3072
+ break;
2982
3073
  }
2983
3074
 
2984
- return target;
2985
- };
3075
+ return exceeds.top || exceeds.bottom || exceeds.left || exceeds.right;
3076
+ }
2986
3077
 
2987
3078
  /**
2988
- * Creates a new popper instance
2989
- * @param {Object} refData
2990
- * @return {Object} - the popper instance
2991
- */
2992
- function createPopperInstance(refData) {
2993
- var el = refData.el,
2994
- popper = refData.popper,
2995
- _refData$settings = refData.settings,
2996
- position = _refData$settings.position,
2997
- popperOptions = _refData$settings.popperOptions,
2998
- offset = _refData$settings.offset,
2999
- distance = _refData$settings.distance,
3000
- flipDuration = _refData$settings.flipDuration;
3001
-
3079
+ * Transforms the `arrowTransform` numbers based on the placement axis
3080
+ * @param {String} type 'scale' or 'translate'
3081
+ * @param {Number[]} numbers
3082
+ * @param {Boolean} isVertical
3083
+ * @param {Boolean} isReverse
3084
+ * @return {String}
3085
+ */
3086
+ function transformNumbersBasedOnPlacementAxis(type, numbers, isVertical, isReverse) {
3087
+ if (!numbers.length) return '';
3002
3088
 
3003
- var tooltip = popper.querySelector(Selectors.TOOLTIP);
3089
+ var transforms = {
3090
+ scale: function () {
3091
+ if (numbers.length === 1) {
3092
+ return '' + numbers[0];
3093
+ } else {
3094
+ return isVertical ? numbers[0] + ', ' + numbers[1] : numbers[1] + ', ' + numbers[0];
3095
+ }
3096
+ }(),
3097
+ translate: function () {
3098
+ if (numbers.length === 1) {
3099
+ return isReverse ? -numbers[0] + 'px' : numbers[0] + 'px';
3100
+ } else {
3101
+ if (isVertical) {
3102
+ return isReverse ? numbers[0] + 'px, ' + -numbers[1] + 'px' : numbers[0] + 'px, ' + numbers[1] + 'px';
3103
+ } else {
3104
+ return isReverse ? -numbers[1] + 'px, ' + numbers[0] + 'px' : numbers[1] + 'px, ' + numbers[0] + 'px';
3105
+ }
3106
+ }
3107
+ }()
3108
+ };
3004
3109
 
3005
- var config = _extends$1({
3006
- placement: position
3007
- }, popperOptions || {}, {
3008
- modifiers: _extends$1({}, popperOptions ? popperOptions.modifiers : {}, {
3009
- flip: _extends$1({
3010
- padding: distance + 5 /* 5px from viewport boundary */
3011
- }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.flip : {}),
3012
- offset: _extends$1({
3013
- offset: offset
3014
- }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.offset : {})
3015
- }),
3016
- onUpdate: function onUpdate() {
3017
- var styles = tooltip.style;
3018
- styles.top = '';
3019
- styles.bottom = '';
3020
- styles.left = '';
3021
- styles.right = '';
3022
- styles[getCorePlacement(popper.getAttribute('x-placement'))] = getOffsetDistanceInPx(distance);
3023
- }
3024
- });
3110
+ return transforms[type];
3111
+ }
3025
3112
 
3026
- return new Popper(el, popper, config);
3113
+ /**
3114
+ * Transforms the `arrowTransform` x or y axis based on the placement axis
3115
+ * @param {String} axis 'X', 'Y', ''
3116
+ * @param {Boolean} isVertical
3117
+ * @return {String}
3118
+ */
3119
+ function transformAxis(axis, isVertical) {
3120
+ if (!axis) return '';
3121
+ var map = {
3122
+ X: 'Y',
3123
+ Y: 'X'
3124
+ };
3125
+ return isVertical ? axis : map[axis];
3027
3126
  }
3028
3127
 
3029
3128
  /**
3030
- * Appends the popper and creates a popper instance if one does not exist
3031
- * Also updates its position if need be and enables event listeners
3032
- * @param {Object} refData - the element/popper reference data
3033
- */
3034
- function mountPopper(refData) {
3035
- var el = refData.el,
3036
- popper = refData.popper,
3037
- _refData$settings = refData.settings,
3038
- appendTo = _refData$settings.appendTo,
3039
- followCursor = _refData$settings.followCursor,
3040
- flipDuration = _refData$settings.flipDuration;
3041
-
3042
- // Already on the DOM
3043
-
3044
- if (appendTo.contains(popper)) return;
3045
-
3046
- appendTo.appendChild(popper);
3047
-
3048
- if (!refData.popperInstance) {
3049
- // Create instance if it hasn't been created yet
3050
- refData.popperInstance = createPopperInstance(refData);
3051
-
3052
- // Update the popper's position whenever its content changes
3053
- // Not supported in IE10 unless polyfilled
3054
- if (window.MutationObserver) {
3055
- var styles = popper.style;
3056
- var observer = new MutationObserver(function () {
3057
- styles[prefix('transitionDuration')] = '0ms';
3058
- refData.popperInstance.update();
3059
- queueExecution(function () {
3060
- styles[prefix('transitionDuration')] = flipDuration + 'ms';
3061
- });
3062
- });
3063
- observer.observe(popper, {
3064
- childList: true,
3065
- subtree: true,
3066
- characterData: true
3067
- });
3068
- refData._mutationObserver = observer;
3069
- }
3070
- } else {
3071
- refData.popperInstance.update();
3129
+ * Computes and applies the necessary arrow transform
3130
+ * @param {Element} popper
3131
+ * @param {Element} arrow
3132
+ * @param {String} arrowTransform
3133
+ */
3134
+ function computeArrowTransform(popper, arrow, arrowTransform) {
3135
+ var placement = getPopperPlacement(popper);
3136
+ var isVertical = placement === 'top' || placement === 'bottom';
3137
+ var isReverse = placement === 'right' || placement === 'bottom';
3138
+
3139
+ var getAxis = function getAxis(re) {
3140
+ var match = arrowTransform.match(re);
3141
+ return match ? match[1] : '';
3142
+ };
3143
+
3144
+ var getNumbers = function getNumbers(re) {
3145
+ var match = arrowTransform.match(re);
3146
+ return match ? match[1].split(',').map(parseFloat) : [];
3147
+ };
3072
3148
 
3073
- if (!followCursor || Browser.touch) {
3074
- refData.popperInstance.enableEventListeners();
3149
+ var re = {
3150
+ translate: /translateX?Y?\(([^)]+)\)/,
3151
+ scale: /scaleX?Y?\(([^)]+)\)/
3152
+ };
3153
+
3154
+ var matches = {
3155
+ translate: {
3156
+ axis: getAxis(/translate([XY])/),
3157
+ numbers: getNumbers(re.translate)
3158
+ },
3159
+ scale: {
3160
+ axis: getAxis(/scale([XY])/),
3161
+ numbers: getNumbers(re.scale)
3075
3162
  }
3076
- }
3163
+ };
3077
3164
 
3078
- // Since touch is determined dynamically, followCursor setting
3079
- // is set on mount
3080
- if (followCursor && !Browser.touch) {
3081
- el.addEventListener('mousemove', followCursorHandler);
3082
- refData.popperInstance.disableEventListeners();
3083
- }
3165
+ var computedTransform = arrowTransform.replace(re.translate, 'translate' + transformAxis(matches.translate.axis, isVertical) + '(' + transformNumbersBasedOnPlacementAxis('translate', matches.translate.numbers, isVertical, isReverse) + ')').replace(re.scale, 'scale' + transformAxis(matches.scale.axis, isVertical) + '(' + transformNumbersBasedOnPlacementAxis('scale', matches.scale.numbers, isVertical, isReverse) + ')');
3166
+
3167
+ arrow.style[prefix('transform')] = computedTransform;
3084
3168
  }
3085
3169
 
3086
3170
  /**
3087
- * Updates a popper's position on each animation frame to make it stick to a moving element
3088
- * @param {Object} refData
3089
- */
3090
- function makeSticky(refData) {
3091
- var popper = refData.popper,
3092
- popperInstance = refData.popperInstance,
3093
- stickyDuration = refData.settings.stickyDuration;
3171
+ * Returns the distance taking into account the default distance due to
3172
+ * the transform: translate setting in CSS
3173
+ * @param {Number} distance
3174
+ * @return {String}
3175
+ */
3176
+ function getOffsetDistanceInPx(distance) {
3177
+ return -(distance - defaults.distance) + 'px';
3178
+ }
3179
+
3180
+ /**
3181
+ * Waits until next repaint to execute a fn
3182
+ * @param {Function} fn
3183
+ */
3184
+ function defer(fn) {
3185
+ requestAnimationFrame(function () {
3186
+ setTimeout(fn, 1);
3187
+ });
3188
+ }
3094
3189
 
3190
+ var matches = {};
3095
3191
 
3096
- var applyTransitionDuration = function applyTransitionDuration() {
3097
- return popper.style[prefix('transitionDuration')] = stickyDuration + 'ms';
3192
+ if (isBrowser) {
3193
+ var e = Element.prototype;
3194
+ matches = e.matches || e.matchesSelector || e.webkitMatchesSelector || e.mozMatchesSelector || e.msMatchesSelector || function (s) {
3195
+ var matches = (this.document || this.ownerDocument).querySelectorAll(s);
3196
+ var i = matches.length;
3197
+ while (--i >= 0 && matches.item(i) !== this) {} // eslint-disable-line no-empty
3198
+ return i > -1;
3098
3199
  };
3200
+ }
3099
3201
 
3100
- var removeTransitionDuration = function removeTransitionDuration() {
3101
- return popper.style[prefix('transitionDuration')] = '';
3202
+ var matches$1 = matches;
3203
+
3204
+ /**
3205
+ * Ponyfill to get the closest parent element
3206
+ * @param {Element} element - child of parent to be returned
3207
+ * @param {String} parentSelector - selector to match the parent if found
3208
+ * @return {Element}
3209
+ */
3210
+ function closest(element, parentSelector) {
3211
+ var fn = Element.prototype.closest || function (selector) {
3212
+ var el = this;
3213
+ while (el) {
3214
+ if (matches$1.call(el, selector)) {
3215
+ return el;
3216
+ }
3217
+ el = el.parentElement;
3218
+ }
3102
3219
  };
3103
3220
 
3104
- var updatePosition = function updatePosition() {
3105
- popperInstance && popperInstance.scheduleUpdate();
3221
+ return fn.call(element, parentSelector);
3222
+ }
3106
3223
 
3107
- applyTransitionDuration();
3224
+ /**
3225
+ * Returns the value taking into account the value being either a number or array
3226
+ * @param {Number|Array} value
3227
+ * @param {Number} index
3228
+ * @return {Number}
3229
+ */
3230
+ function getValue(value, index) {
3231
+ return Array.isArray(value) ? value[index] : value;
3232
+ }
3108
3233
 
3109
- isVisible(popper) ? window.requestAnimationFrame(updatePosition) : removeTransitionDuration();
3110
- };
3234
+ /**
3235
+ * Sets the visibility state of an element for transition to begin
3236
+ * @param {Element[]} els - array of elements
3237
+ * @param {String} type - 'visible' or 'hidden'
3238
+ */
3239
+ function setVisibilityState(els, type) {
3240
+ els.forEach(function (el) {
3241
+ if (!el) return;
3242
+ el.setAttribute('data-state', type);
3243
+ });
3244
+ }
3111
3245
 
3112
- // Wait until Popper's position has been updated initially
3113
- queueExecution(updatePosition);
3246
+ /**
3247
+ * Sets the transition property to each element
3248
+ * @param {Element[]} els - Array of elements
3249
+ * @param {String} value
3250
+ */
3251
+ function applyTransitionDuration(els, value) {
3252
+ els.filter(Boolean).forEach(function (el) {
3253
+ el.style[prefix('transitionDuration')] = value + 'ms';
3254
+ });
3114
3255
  }
3115
3256
 
3116
3257
  /**
3117
- * Returns an object of settings to override global settings
3118
- * @param {Element} el - the tooltipped element
3119
- * @param {Object} instanceSettings
3120
- * @return {Object} - individual settings
3121
- */
3122
- function getIndividualSettings(el, instanceSettings) {
3123
- var settings = DefaultsKeys.reduce(function (acc, key) {
3124
- var val = el.getAttribute('data-' + key.toLowerCase()) || instanceSettings[key];
3258
+ * Focuses an element while preventing a scroll jump if it's not entirely within the viewport
3259
+ * @param {Element} el
3260
+ */
3261
+ function focus(el) {
3262
+ var x = window.scrollX || window.pageXOffset;
3263
+ var y = window.scrollY || window.pageYOffset;
3264
+ el.focus();
3265
+ scroll(x, y);
3266
+ }
3125
3267
 
3126
- // Convert strings to booleans
3127
- if (val === 'false') val = false;
3128
- if (val === 'true') val = true;
3268
+ var key = {};
3269
+ var store = function store(data) {
3270
+ return function (k) {
3271
+ return k === key && data;
3272
+ };
3273
+ };
3129
3274
 
3130
- // Convert number strings to true numbers
3131
- if (isFinite(val) && !isNaN(parseFloat(val))) {
3132
- val = parseFloat(val);
3275
+ var Tippy = function () {
3276
+ function Tippy(config) {
3277
+ classCallCheck(this, Tippy);
3278
+
3279
+ for (var _key in config) {
3280
+ this[_key] = config[_key];
3133
3281
  }
3134
3282
 
3135
- // Convert array strings to actual arrays
3136
- if (typeof val === 'string' && val.trim().charAt(0) === '[') {
3137
- val = JSON.parse(val);
3283
+ this.state = {
3284
+ destroyed: false,
3285
+ visible: false,
3286
+ enabled: true
3287
+ };
3288
+
3289
+ this._ = store({
3290
+ mutationObservers: []
3291
+ });
3292
+ }
3293
+
3294
+ /**
3295
+ * Enables the tooltip to allow it to show or hide
3296
+ * @memberof Tippy
3297
+ * @public
3298
+ */
3299
+
3300
+
3301
+ createClass(Tippy, [{
3302
+ key: 'enable',
3303
+ value: function enable() {
3304
+ this.state.enabled = true;
3138
3305
  }
3139
3306
 
3140
- acc[key] = val;
3307
+ /**
3308
+ * Disables the tooltip from showing or hiding, but does not destroy it
3309
+ * @memberof Tippy
3310
+ * @public
3311
+ */
3141
3312
 
3142
- return acc;
3143
- }, {});
3313
+ }, {
3314
+ key: 'disable',
3315
+ value: function disable() {
3316
+ this.state.enabled = false;
3317
+ }
3144
3318
 
3145
- return _extends$1({}, instanceSettings, settings);
3146
- }
3319
+ /**
3320
+ * Shows the tooltip
3321
+ * @param {Number} duration in milliseconds
3322
+ * @memberof Tippy
3323
+ * @public
3324
+ */
3147
3325
 
3148
- /**
3149
- * Creates a popper element then returns it
3150
- * @param {Number} id - the popper id
3151
- * @param {String} title - the tooltip's `title` attribute
3152
- * @param {Object} settings - individual settings
3153
- * @return {Element} - the popper element
3154
- */
3155
- function createPopperElement(id, title, settings) {
3156
- var position = settings.position,
3157
- distance = settings.distance,
3158
- arrow = settings.arrow,
3159
- animateFill = settings.animateFill,
3160
- inertia = settings.inertia,
3161
- animation = settings.animation,
3162
- arrowSize = settings.arrowSize,
3163
- size = settings.size,
3164
- theme = settings.theme,
3165
- html = settings.html,
3166
- zIndex = settings.zIndex,
3167
- interactive = settings.interactive;
3168
-
3169
-
3170
- var popper = document.createElement('div');
3171
- popper.setAttribute('class', 'tippy-popper');
3172
- popper.setAttribute('role', 'tooltip');
3173
- popper.setAttribute('aria-hidden', 'true');
3174
- popper.setAttribute('id', 'tippy-tooltip-' + id);
3175
- popper.style.zIndex = zIndex;
3326
+ }, {
3327
+ key: 'show',
3328
+ value: function show(duration) {
3329
+ var _this = this;
3176
3330
 
3177
- var tooltip = document.createElement('div');
3178
- tooltip.setAttribute('class', 'tippy-tooltip tippy-tooltip--' + size + ' leave');
3179
- tooltip.setAttribute('data-animation', animation);
3331
+ if (this.state.destroyed || !this.state.enabled) return;
3180
3332
 
3181
- theme.split(' ').forEach(function (t) {
3182
- tooltip.classList.add(t + '-theme');
3183
- });
3333
+ var popper = this.popper,
3334
+ reference = this.reference,
3335
+ options = this.options;
3184
3336
 
3185
- if (arrow) {
3186
- // Add an arrow
3187
- var _arrow = document.createElement('div');
3188
- _arrow.setAttribute('class', 'arrow-' + arrowSize);
3189
- _arrow.setAttribute('x-arrow', '');
3190
- tooltip.appendChild(_arrow);
3191
- }
3337
+ var _getInnerElements = getInnerElements(popper),
3338
+ tooltip = _getInnerElements.tooltip,
3339
+ backdrop = _getInnerElements.backdrop,
3340
+ content = _getInnerElements.content;
3192
3341
 
3193
- if (animateFill) {
3194
- // Create animateFill circle element for animation
3195
- tooltip.setAttribute('data-animatefill', '');
3196
- var circle = document.createElement('div');
3197
- circle.setAttribute('class', 'leave');
3198
- circle.setAttribute('x-circle', '');
3199
- tooltip.appendChild(circle);
3200
- }
3342
+ // If the `dynamicTitle` option is true, the instance is allowed
3343
+ // to be created with an empty title. Make sure that the tooltip
3344
+ // content is not empty before showing it
3201
3345
 
3202
- if (inertia) {
3203
- // Change transition timing function cubic bezier
3204
- tooltip.setAttribute('data-inertia', '');
3205
- }
3206
3346
 
3207
- if (interactive) {
3208
- tooltip.setAttribute('data-interactive', '');
3209
- }
3347
+ if (options.dynamicTitle && !reference.getAttribute('data-original-title')) return;
3210
3348
 
3211
- // Tooltip content (text or HTML)
3212
- var content = document.createElement('div');
3213
- content.setAttribute('class', 'tippy-tooltip-content');
3349
+ // Do not show tooltip if reference contains 'disabled' attribute. FF fix for #221
3350
+ if (reference.hasAttribute('disabled')) return;
3214
3351
 
3215
- if (html) {
3216
- var templateId = void 0;
3352
+ // Destroy tooltip if the reference element is no longer on the DOM
3353
+ if (!reference.refObj && !document.documentElement.contains(reference)) {
3354
+ this.destroy();
3355
+ return;
3356
+ }
3217
3357
 
3218
- if (html instanceof Element) {
3219
- content.appendChild(html);
3220
- templateId = '#' + html.id || 'tippy-html-template';
3221
- } else {
3222
- content.innerHTML = document.getElementById(html.replace('#', '')).innerHTML;
3223
- templateId = html;
3358
+ options.onShow.call(popper, this);
3359
+
3360
+ duration = getValue(duration !== undefined ? duration : options.duration, 0);
3361
+
3362
+ // Prevent a transition when popper changes position
3363
+ applyTransitionDuration([popper, tooltip, backdrop], 0);
3364
+
3365
+ popper.style.visibility = 'visible';
3366
+ this.state.visible = true;
3367
+
3368
+ _mount.call(this, function () {
3369
+ if (!_this.state.visible) return;
3370
+
3371
+ if (!_hasFollowCursorBehavior.call(_this)) {
3372
+ // FIX: Arrow will sometimes not be positioned correctly. Force another update.
3373
+ _this.popperInstance.scheduleUpdate();
3374
+ }
3375
+
3376
+ // Set initial position near the cursor
3377
+ if (_hasFollowCursorBehavior.call(_this)) {
3378
+ _this.popperInstance.disableEventListeners();
3379
+ var delay = getValue(options.delay, 0);
3380
+ var lastTriggerEvent = _this._(key).lastTriggerEvent;
3381
+ if (lastTriggerEvent) {
3382
+ _this._(key).followCursorListener(delay && _this._(key).lastMouseMoveEvent ? _this._(key).lastMouseMoveEvent : lastTriggerEvent);
3383
+ }
3384
+ }
3385
+
3386
+ // Re-apply transition durations
3387
+ applyTransitionDuration([tooltip, backdrop, backdrop ? content : null], duration);
3388
+
3389
+ if (backdrop) {
3390
+ getComputedStyle(backdrop)[prefix('transform')];
3391
+ }
3392
+
3393
+ if (options.interactive) {
3394
+ reference.classList.add('tippy-active');
3395
+ }
3396
+
3397
+ if (options.sticky) {
3398
+ _makeSticky.call(_this);
3399
+ }
3400
+
3401
+ setVisibilityState([tooltip, backdrop], 'visible');
3402
+
3403
+ _onTransitionEnd.call(_this, duration, function () {
3404
+ if (!options.updateDuration) {
3405
+ tooltip.classList.add('tippy-notransition');
3406
+ }
3407
+
3408
+ if (options.interactive) {
3409
+ focus(popper);
3410
+ }
3411
+
3412
+ reference.setAttribute('aria-describedby', 'tippy-' + _this.id);
3413
+
3414
+ options.onShown.call(popper, _this);
3415
+ });
3416
+ });
3224
3417
  }
3225
3418
 
3226
- popper.classList.add('html-template');
3227
- interactive && popper.setAttribute('tabindex', '-1');
3228
- tooltip.setAttribute('data-template-id', templateId);
3229
- } else {
3230
- content.innerHTML = title;
3231
- }
3419
+ /**
3420
+ * Hides the tooltip
3421
+ * @param {Number} duration in milliseconds
3422
+ * @memberof Tippy
3423
+ * @public
3424
+ */
3232
3425
 
3233
- // Init distance. Further updates are made in the popper instance's `onUpdate()` method
3234
- tooltip.style[getCorePlacement(position)] = getOffsetDistanceInPx(distance);
3426
+ }, {
3427
+ key: 'hide',
3428
+ value: function hide(duration) {
3429
+ var _this2 = this;
3235
3430
 
3236
- tooltip.appendChild(content);
3237
- popper.appendChild(tooltip);
3431
+ if (this.state.destroyed || !this.state.enabled) return;
3238
3432
 
3239
- return popper;
3240
- }
3433
+ var popper = this.popper,
3434
+ reference = this.reference,
3435
+ options = this.options;
3241
3436
 
3242
- /**
3243
- * Creates a trigger
3244
- * @param {Object} event - the custom event specified in the `trigger` setting
3245
- * @param {Element} el - tooltipped element
3246
- * @param {Object} handlers - the handlers for each listener
3247
- * @param {Boolean} touchHold
3248
- * @return {Array} - array of listener objects
3249
- */
3250
- function createTrigger(event, el, handlers, touchHold) {
3251
- var listeners = [];
3437
+ var _getInnerElements2 = getInnerElements(popper),
3438
+ tooltip = _getInnerElements2.tooltip,
3439
+ backdrop = _getInnerElements2.backdrop,
3440
+ content = _getInnerElements2.content;
3252
3441
 
3253
- if (event === 'manual') return listeners;
3442
+ options.onHide.call(popper, this);
3254
3443
 
3255
- // Enter
3256
- el.addEventListener(event, handlers.handleTrigger);
3257
- listeners.push({
3258
- event: event,
3259
- handler: handlers.handleTrigger
3260
- });
3444
+ duration = getValue(duration !== undefined ? duration : options.duration, 1);
3445
+
3446
+ if (!options.updateDuration) {
3447
+ tooltip.classList.remove('tippy-notransition');
3448
+ }
3449
+
3450
+ if (options.interactive) {
3451
+ reference.classList.remove('tippy-active');
3452
+ }
3453
+
3454
+ popper.style.visibility = 'hidden';
3455
+ this.state.visible = false;
3456
+
3457
+ applyTransitionDuration([tooltip, backdrop, backdrop ? content : null], duration);
3458
+
3459
+ setVisibilityState([tooltip, backdrop], 'hidden');
3460
+
3461
+ if (options.interactive && options.trigger.indexOf('click') > -1) {
3462
+ focus(reference);
3463
+ }
3261
3464
 
3262
- // Leave
3263
- if (event === 'mouseenter') {
3264
- if (Browser.SUPPORTS_TOUCH && touchHold) {
3265
- el.addEventListener('touchstart', handlers.handleTrigger);
3266
- listeners.push({
3267
- event: 'touchstart',
3268
- handler: handlers.handleTrigger
3465
+ this.popperInstance.disableEventListeners();
3466
+
3467
+ /*
3468
+ * This call is deferred because sometimes when the tooltip is still transitioning in but hide()
3469
+ * is called before it finishes, the CSS transition won't reverse quickly enough, meaning
3470
+ * the CSS transition will finish 1-2 frames later, and onHidden() will run since the JS set it
3471
+ * more quickly. It should actually be onShown(). Seems to be something Chrome does, not Safari
3472
+ */
3473
+ defer(function () {
3474
+ _onTransitionEnd.call(_this2, duration, function () {
3475
+ if (_this2.state.visible || !options.appendTo.contains(popper)) return;
3476
+
3477
+ if (!_this2._(key).isPreparingToShow) {
3478
+ document.removeEventListener('mousemove', _this2._(key).followCursorListener);
3479
+ _this2._(key).lastMouseMoveEvent = null;
3480
+ }
3481
+
3482
+ reference.removeAttribute('aria-describedby');
3483
+
3484
+ options.appendTo.removeChild(popper);
3485
+
3486
+ options.onHidden.call(popper, _this2);
3487
+ });
3488
+ });
3489
+ }
3490
+
3491
+ /**
3492
+ * Destroys the tooltip instance
3493
+ * @param {Boolean} destroyTargetInstances - relevant only when destroying delegates
3494
+ * @memberof Tippy
3495
+ * @public
3496
+ */
3497
+
3498
+ }, {
3499
+ key: 'destroy',
3500
+ value: function destroy() {
3501
+ var _this3 = this;
3502
+
3503
+ var destroyTargetInstances = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
3504
+
3505
+ if (this.state.destroyed) return;
3506
+
3507
+ // Ensure the popper is hidden
3508
+ if (this.state.visible) {
3509
+ this.hide(0);
3510
+ }
3511
+
3512
+ this.listeners.forEach(function (listener) {
3513
+ _this3.reference.removeEventListener(listener.event, listener.handler);
3269
3514
  });
3270
- el.addEventListener('touchend', handlers.handleMouseleave);
3271
- listeners.push({
3272
- event: 'touchend',
3273
- handler: handlers.handleMouseleave
3515
+
3516
+ // Restore title
3517
+ if (this.title) {
3518
+ this.reference.setAttribute('title', this.title);
3519
+ }
3520
+
3521
+ delete this.reference._tippy;
3522
+
3523
+ var attributes = ['data-original-title', 'data-tippy', 'data-tippy-delegate'];
3524
+ attributes.forEach(function (attr) {
3525
+ _this3.reference.removeAttribute(attr);
3526
+ });
3527
+
3528
+ if (this.options.target && destroyTargetInstances) {
3529
+ toArray(this.reference.querySelectorAll(this.options.target)).forEach(function (child) {
3530
+ return child._tippy && child._tippy.destroy();
3531
+ });
3532
+ }
3533
+
3534
+ if (this.popperInstance) {
3535
+ this.popperInstance.destroy();
3536
+ }
3537
+
3538
+ this._(key).mutationObservers.forEach(function (observer) {
3539
+ observer.disconnect();
3274
3540
  });
3541
+
3542
+ this.state.destroyed = true;
3275
3543
  }
3544
+ }]);
3545
+ return Tippy;
3546
+ }();
3276
3547
 
3277
- el.addEventListener('mouseleave', handlers.handleMouseleave);
3278
- listeners.push({
3279
- event: 'mouseleave',
3280
- handler: handlers.handleMouseleave
3281
- });
3282
- }
3548
+ /**
3549
+ * ------------------------------------------------------------------------
3550
+ * Private methods
3551
+ * ------------------------------------------------------------------------
3552
+ * Standalone functions to be called with the instance's `this` context to make
3553
+ * them truly private and not accessible on the prototype
3554
+ */
3283
3555
 
3284
- if (event === 'focus') {
3285
- el.addEventListener('blur', handlers.handleBlur);
3286
- listeners.push({
3287
- event: 'blur',
3288
- handler: handlers.handleBlur
3289
- });
3290
- }
3556
+ /**
3557
+ * Determines if the tooltip instance has followCursor behavior
3558
+ * @return {Boolean}
3559
+ * @memberof Tippy
3560
+ * @private
3561
+ */
3562
+ function _hasFollowCursorBehavior() {
3563
+ var lastTriggerEvent = this._(key).lastTriggerEvent;
3564
+ return this.options.followCursor && !browser.usingTouch && lastTriggerEvent && lastTriggerEvent.type !== 'focus';
3565
+ }
3291
3566
 
3292
- return listeners;
3567
+ /**
3568
+ * Creates the Tippy instance for the child target of the delegate container
3569
+ * @param {Event} event
3570
+ * @memberof Tippy
3571
+ * @private
3572
+ */
3573
+ function _createDelegateChildTippy(event) {
3574
+ var targetEl = closest(event.target, this.options.target);
3575
+ if (targetEl && !targetEl._tippy) {
3576
+ var title = targetEl.getAttribute('title') || this.title;
3577
+ if (title) {
3578
+ targetEl.setAttribute('title', title);
3579
+ tippy$1(targetEl, _extends({}, this.options, { target: null }));
3580
+ _enter.call(targetEl._tippy, event);
3581
+ }
3582
+ }
3293
3583
  }
3294
3584
 
3295
3585
  /**
3296
- * Determines if the mouse's cursor is outside the interactive border
3297
- * @param {MouseEvent} event
3298
- * @param {Element} popper
3299
- * @param {Object} settings
3300
- * @return {Boolean}
3301
- */
3302
- function cursorIsOutsideInteractiveBorder(event, popper, settings) {
3303
- if (!popper.getAttribute('x-placement')) return true;
3586
+ * Method used by event listeners to invoke the show method, taking into account delays and
3587
+ * the `wait` option
3588
+ * @param {Event} event
3589
+ * @memberof Tippy
3590
+ * @private
3591
+ */
3592
+ function _enter(event) {
3593
+ var _this4 = this;
3304
3594
 
3305
- var x = event.clientX,
3306
- y = event.clientY;
3307
- var interactiveBorder = settings.interactiveBorder,
3308
- distance = settings.distance;
3595
+ var options = this.options;
3309
3596
 
3310
3597
 
3311
- var rect = popper.getBoundingClientRect();
3312
- var corePosition = getCorePlacement(popper.getAttribute('x-placement'));
3313
- var borderWithDistance = interactiveBorder + distance;
3598
+ _clearDelayTimeouts.call(this);
3314
3599
 
3315
- var exceeds = {
3316
- top: rect.top - y > interactiveBorder,
3317
- bottom: y - rect.bottom > interactiveBorder,
3318
- left: rect.left - x > interactiveBorder,
3319
- right: x - rect.right > interactiveBorder
3320
- };
3600
+ if (this.state.visible) return;
3321
3601
 
3322
- switch (corePosition) {
3323
- case 'top':
3324
- exceeds.top = rect.top - y > borderWithDistance;
3325
- break;
3326
- case 'bottom':
3327
- exceeds.bottom = y - rect.bottom > borderWithDistance;
3328
- break;
3329
- case 'left':
3330
- exceeds.left = rect.left - x > borderWithDistance;
3331
- break;
3332
- case 'right':
3333
- exceeds.right = x - rect.right > borderWithDistance;
3334
- break;
3602
+ // Is a delegate, create Tippy instance for the child target
3603
+ if (options.target) {
3604
+ _createDelegateChildTippy.call(this, event);
3605
+ return;
3606
+ }
3607
+
3608
+ this._(key).isPreparingToShow = true;
3609
+
3610
+ if (options.wait) {
3611
+ options.wait.call(this.popper, this.show.bind(this), event);
3612
+ return;
3613
+ }
3614
+
3615
+ // If the tooltip has a delay, we need to be listening to the mousemove as soon as the trigger
3616
+ // event is fired so that it's in the correct position upon mount.
3617
+ if (_hasFollowCursorBehavior.call(this)) {
3618
+ if (!this._(key).followCursorListener) {
3619
+ _setFollowCursorListener.call(this);
3620
+ }
3621
+
3622
+ var _getInnerElements3 = getInnerElements(this.popper),
3623
+ arrow = _getInnerElements3.arrow;
3624
+
3625
+ if (arrow) arrow.style.margin = '0';
3626
+ document.addEventListener('mousemove', this._(key).followCursorListener);
3335
3627
  }
3336
3628
 
3337
- return exceeds.top || exceeds.bottom || exceeds.left || exceeds.right;
3629
+ var delay = getValue(options.delay, 0);
3630
+
3631
+ if (delay) {
3632
+ this._(key).showTimeout = setTimeout(function () {
3633
+ _this4.show();
3634
+ }, delay);
3635
+ } else {
3636
+ this.show();
3637
+ }
3338
3638
  }
3339
3639
 
3340
3640
  /**
3341
- * Returns relevant listener callbacks for each ref
3342
- * @param {Element} el
3343
- * @param {Element} popper
3344
- * @param {Object} settings
3345
- * @return {Object} - relevant listener handlers
3346
- */
3347
- function getEventListenerHandlers(el, popper, settings) {
3348
- var _this = this;
3349
-
3350
- var position = settings.position,
3351
- delay = settings.delay,
3352
- duration = settings.duration,
3353
- interactive = settings.interactive,
3354
- interactiveBorder = settings.interactiveBorder,
3355
- distance = settings.distance,
3356
- hideOnClick = settings.hideOnClick,
3357
- trigger = settings.trigger,
3358
- touchHold = settings.touchHold,
3359
- touchWait = settings.touchWait;
3360
-
3361
-
3362
- var showDelay = void 0,
3363
- hideDelay = void 0;
3364
-
3365
- var clearTimeouts = function clearTimeouts() {
3366
- clearTimeout(showDelay);
3367
- clearTimeout(hideDelay);
3368
- };
3641
+ * Method used by event listeners to invoke the hide method, taking into account delays
3642
+ * @memberof Tippy
3643
+ * @private
3644
+ */
3645
+ function _leave() {
3646
+ var _this5 = this;
3369
3647
 
3370
- var _show = function _show() {
3371
- clearTimeouts();
3648
+ _clearDelayTimeouts.call(this);
3372
3649
 
3373
- // Not hidden. For clicking when it also has a `focus` event listener
3374
- if (isVisible(popper)) return;
3650
+ if (!this.state.visible) return;
3375
3651
 
3376
- var _delay = Array.isArray(delay) ? delay[0] : delay;
3652
+ this._(key).isPreparingToShow = false;
3377
3653
 
3378
- if (delay) {
3379
- showDelay = setTimeout(function () {
3380
- return _this.show(popper);
3381
- }, _delay);
3382
- } else {
3383
- _this.show(popper);
3384
- }
3385
- };
3654
+ var delay = getValue(this.options.delay, 1);
3386
3655
 
3387
- var show = function show(event) {
3388
- return _this.callbacks.wait ? _this.callbacks.wait.call(popper, _show, event) : _show();
3389
- };
3656
+ if (delay) {
3657
+ this._(key).hideTimeout = setTimeout(function () {
3658
+ if (_this5.state.visible) {
3659
+ _this5.hide();
3660
+ }
3661
+ }, delay);
3662
+ } else {
3663
+ this.hide();
3664
+ }
3665
+ }
3390
3666
 
3391
- var hide = function hide() {
3392
- clearTimeouts();
3667
+ /**
3668
+ * Returns relevant listeners for the instance
3669
+ * @return {Object} of listeners
3670
+ * @memberof Tippy
3671
+ * @private
3672
+ */
3673
+ function _getEventListeners() {
3674
+ var _this6 = this;
3393
3675
 
3394
- var _delay = Array.isArray(delay) ? delay[1] : delay;
3676
+ var onTrigger = function onTrigger(event) {
3677
+ if (!_this6.state.enabled) return;
3395
3678
 
3396
- if (delay) {
3397
- hideDelay = setTimeout(function () {
3398
- return _this.hide(popper);
3399
- }, _delay);
3400
- } else {
3401
- _this.hide(popper);
3402
- }
3403
- };
3679
+ var shouldStopEvent = browser.supportsTouch && browser.usingTouch && ['mouseenter', 'mouseover', 'focus'].indexOf(event.type) > -1;
3404
3680
 
3405
- var handleTrigger = function handleTrigger(event) {
3406
- var mouseenterTouch = event.type === 'mouseenter' && Browser.SUPPORTS_TOUCH && Browser.touch;
3681
+ if (shouldStopEvent && _this6.options.touchHold) return;
3407
3682
 
3408
- if (mouseenterTouch && touchHold) return;
3683
+ _this6._(key).lastTriggerEvent = event;
3409
3684
 
3410
3685
  // Toggle show/hide when clicking click-triggered tooltips
3411
- var isClick = event.type === 'click';
3412
- var isNotPersistent = hideOnClick !== 'persistent';
3413
-
3414
- isClick && isVisible(popper) && isNotPersistent ? hide() : show(event);
3415
-
3416
- if (mouseenterTouch && Browser.iOS() && el.click) {
3417
- el.click();
3686
+ if (event.type === 'click' && _this6.options.hideOnClick !== 'persistent' && _this6.state.visible) {
3687
+ _leave.call(_this6);
3688
+ } else {
3689
+ _enter.call(_this6, event);
3418
3690
  }
3419
- };
3420
-
3421
- var handleMouseleave = function handleMouseleave(event) {
3422
3691
 
3423
- // Don't fire 'mouseleave', use the 'touchend'
3424
- if (event.type === 'mouseleave' && Browser.SUPPORTS_TOUCH && Browser.touch && touchHold) {
3425
- return;
3692
+ // iOS prevents click events from firing
3693
+ if (shouldStopEvent && browser.iOS && _this6.reference.click) {
3694
+ _this6.reference.click();
3426
3695
  }
3696
+ };
3427
3697
 
3428
- if (interactive) {
3429
- // Temporarily handle mousemove to check if the mouse left somewhere
3430
- // other than its popper
3431
- var handleMousemove = function handleMousemove(event) {
3432
-
3433
- var triggerHide = function triggerHide() {
3434
- document.body.removeEventListener('mouseleave', hide);
3435
- document.removeEventListener('mousemove', handleMousemove);
3436
- hide();
3437
- };
3698
+ var onMouseLeave = function onMouseLeave(event) {
3699
+ if (['mouseleave', 'mouseout'].indexOf(event.type) > -1 && browser.supportsTouch && browser.usingTouch && _this6.options.touchHold) return;
3438
3700
 
3439
- var closestTooltippedEl = closest(event.target, Selectors.TOOLTIPPED_EL);
3701
+ if (_this6.options.interactive) {
3702
+ var hide = _leave.bind(_this6);
3440
3703
 
3441
- var isOverPopper = closest(event.target, Selectors.POPPER) === popper;
3442
- var isOverEl = closestTooltippedEl === el;
3443
- var isClickTriggered = trigger.indexOf('click') !== -1;
3444
- var isOverOtherTooltippedEl = closestTooltippedEl && closestTooltippedEl !== el;
3704
+ var onMouseMove = function onMouseMove(event) {
3705
+ var referenceCursorIsOver = closest(event.target, selectors.REFERENCE);
3706
+ var cursorIsOverPopper = closest(event.target, selectors.POPPER) === _this6.popper;
3707
+ var cursorIsOverReference = referenceCursorIsOver === _this6.reference;
3445
3708
 
3446
- if (isOverOtherTooltippedEl) {
3447
- return triggerHide();
3448
- }
3709
+ if (cursorIsOverPopper || cursorIsOverReference) return;
3449
3710
 
3450
- if (isOverPopper || isOverEl || isClickTriggered) return;
3711
+ if (cursorIsOutsideInteractiveBorder(event, _this6.popper, _this6.options)) {
3712
+ document.body.removeEventListener('mouseleave', hide);
3713
+ document.removeEventListener('mousemove', onMouseMove);
3451
3714
 
3452
- if (cursorIsOutsideInteractiveBorder(event, popper, settings)) {
3453
- triggerHide();
3715
+ _leave.call(_this6, onMouseMove);
3454
3716
  }
3455
3717
  };
3456
3718
 
3457
3719
  document.body.addEventListener('mouseleave', hide);
3458
- document.addEventListener('mousemove', handleMousemove);
3459
-
3720
+ document.addEventListener('mousemove', onMouseMove);
3460
3721
  return;
3461
3722
  }
3462
3723
 
3463
- // If it's not interactive, just hide it
3464
- hide();
3724
+ _leave.call(_this6);
3725
+ };
3726
+
3727
+ var onBlur = function onBlur(event) {
3728
+ if (event.target !== _this6.reference || browser.usingTouch) return;
3729
+
3730
+ if (_this6.options.interactive) {
3731
+ if (!event.relatedTarget) return;
3732
+ if (closest(event.relatedTarget, selectors.POPPER)) return;
3733
+ }
3734
+
3735
+ _leave.call(_this6);
3465
3736
  };
3466
3737
 
3467
- var handleBlur = function handleBlur(event) {
3468
- // Ignore blur on touch devices, if there is no `relatedTarget`, hide
3469
- // If the related target is a popper, ignore
3470
- if (!event.relatedTarget || Browser.touch) return;
3471
- if (closest(event.relatedTarget, Selectors.POPPER)) return;
3738
+ var onDelegateShow = function onDelegateShow(event) {
3739
+ if (closest(event.target, _this6.options.target)) {
3740
+ _enter.call(_this6, event);
3741
+ }
3742
+ };
3472
3743
 
3473
- hide();
3744
+ var onDelegateHide = function onDelegateHide(event) {
3745
+ if (closest(event.target, _this6.options.target)) {
3746
+ _leave.call(_this6);
3747
+ }
3474
3748
  };
3475
3749
 
3476
3750
  return {
3477
- handleTrigger: handleTrigger,
3478
- handleMouseleave: handleMouseleave,
3479
- handleBlur: handleBlur
3751
+ onTrigger: onTrigger,
3752
+ onMouseLeave: onMouseLeave,
3753
+ onBlur: onBlur,
3754
+ onDelegateShow: onDelegateShow,
3755
+ onDelegateHide: onDelegateHide
3480
3756
  };
3481
3757
  }
3482
3758
 
3483
- var idCounter = 1;
3484
-
3485
3759
  /**
3486
- * Creates tooltips for all el elements that match the instance's selector
3487
- * @param {Element[]} els
3488
- * @return {Object[]} Array of ref data objects
3489
- */
3490
- function createTooltips(els) {
3491
- var _this = this;
3492
-
3493
- return els.reduce(function (a, el) {
3494
- var id = idCounter;
3495
-
3496
- var settings = _this.settings.performance ? _this.settings : getIndividualSettings(el, _this.settings);
3497
- // animateFill is disabled if an arrow is true
3498
- if (settings.arrow) settings.animateFill = false;
3499
-
3500
- var html = settings.html,
3501
- trigger = settings.trigger,
3502
- touchHold = settings.touchHold;
3760
+ * Creates and returns a new popper instance
3761
+ * @return {Popper}
3762
+ * @memberof Tippy
3763
+ * @private
3764
+ */
3765
+ function _createPopperInstance() {
3766
+ var _this7 = this;
3503
3767
 
3768
+ var popper = this.popper,
3769
+ reference = this.reference,
3770
+ options = this.options;
3504
3771
 
3505
- var title = el.getAttribute('title');
3506
- if (!title && !html) return a;
3772
+ var _getInnerElements4 = getInnerElements(popper),
3773
+ tooltip = _getInnerElements4.tooltip;
3507
3774
 
3508
- el.setAttribute('data-tooltipped', '');
3509
- el.setAttribute('aria-describedby', 'tippy-tooltip-' + id);
3510
- removeTitle(el);
3775
+ var popperOptions = options.popperOptions;
3511
3776
 
3512
- var popper = createPopperElement(id, title, settings);
3513
- var handlers = getEventListenerHandlers.call(_this, el, popper, settings);
3777
+ var arrowSelector = options.arrowType === 'round' ? selectors.ROUND_ARROW : selectors.ARROW;
3778
+ var arrow = tooltip.querySelector(arrowSelector);
3514
3779
 
3515
- var listeners = [];
3780
+ var config = _extends({
3781
+ placement: options.placement
3782
+ }, popperOptions || {}, {
3783
+ modifiers: _extends({}, popperOptions ? popperOptions.modifiers : {}, {
3784
+ arrow: _extends({
3785
+ element: arrowSelector
3786
+ }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.arrow : {}),
3787
+ flip: _extends({
3788
+ enabled: options.flip,
3789
+ padding: options.distance + 5 /* 5px from viewport boundary */
3790
+ , behavior: options.flipBehavior
3791
+ }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.flip : {}),
3792
+ offset: _extends({
3793
+ offset: options.offset
3794
+ }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.offset : {})
3795
+ }),
3796
+ onCreate: function onCreate() {
3797
+ tooltip.style[getPopperPlacement(popper)] = getOffsetDistanceInPx(options.distance);
3516
3798
 
3517
- trigger.trim().split(' ').forEach(function (event) {
3518
- return listeners = listeners.concat(createTrigger(event, el, handlers, touchHold));
3519
- });
3799
+ if (arrow && options.arrowTransform) {
3800
+ computeArrowTransform(popper, arrow, options.arrowTransform);
3801
+ }
3802
+ },
3803
+ onUpdate: function onUpdate() {
3804
+ var styles = tooltip.style;
3805
+ styles.top = '';
3806
+ styles.bottom = '';
3807
+ styles.left = '';
3808
+ styles.right = '';
3809
+ styles[getPopperPlacement(popper)] = getOffsetDistanceInPx(options.distance);
3520
3810
 
3521
- a.push({
3522
- id: id,
3523
- el: el,
3524
- popper: popper,
3525
- settings: settings,
3526
- listeners: listeners,
3527
- tippyInstance: _this
3528
- });
3811
+ if (arrow && options.arrowTransform) {
3812
+ computeArrowTransform(popper, arrow, options.arrowTransform);
3813
+ }
3814
+ }
3815
+ });
3529
3816
 
3530
- idCounter++;
3817
+ _addMutationObserver.call(this, {
3818
+ target: popper,
3819
+ callback: function callback() {
3820
+ _this7.popperInstance.update();
3821
+ },
3822
+ options: {
3823
+ childList: true,
3824
+ subtree: true,
3825
+ characterData: true
3826
+ }
3827
+ });
3531
3828
 
3532
- return a;
3533
- }, []);
3829
+ return new Popper(reference, popper, config);
3534
3830
  }
3535
3831
 
3536
- /* Utility functions */
3537
- /* Core library functions */
3538
3832
  /**
3539
- * @param {String|Element|Element[]} selector
3540
- * @param {Object} settings (optional) - the object of settings to be applied to the instance
3541
- */
3542
-
3543
- var Tippy = function () {
3544
- function Tippy(selector) {
3545
- var settings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3546
- classCallCheck$1(this, Tippy);
3547
-
3548
- // Use default browser tooltip on unsupported browsers
3549
- if (!Browser.SUPPORTED) return;
3833
+ * Appends the popper element to the DOM, updating or creating the popper instance
3834
+ * @param {Function} callback
3835
+ * @memberof Tippy
3836
+ * @private
3837
+ */
3838
+ function _mount(callback) {
3839
+ var options = this.options;
3550
3840
 
3551
- // DOM is presumably mostly ready (for document.body) by instantiation time
3552
- init();
3553
3841
 
3554
- this.state = {
3555
- destroyed: false
3556
- };
3842
+ if (!this.popperInstance) {
3843
+ this.popperInstance = _createPopperInstance.call(this);
3844
+ if (!options.livePlacement) {
3845
+ this.popperInstance.disableEventListeners();
3846
+ }
3847
+ } else {
3848
+ this.popperInstance.scheduleUpdate();
3849
+ if (options.livePlacement && !_hasFollowCursorBehavior.call(this)) {
3850
+ this.popperInstance.enableEventListeners();
3851
+ }
3852
+ }
3557
3853
 
3558
- this.selector = selector;
3854
+ // If the instance previously had followCursor behavior, it will be positioned incorrectly
3855
+ // if triggered by `focus` afterwards - update the reference back to the real DOM element
3856
+ if (!_hasFollowCursorBehavior.call(this)) {
3857
+ var _getInnerElements5 = getInnerElements(this.popper),
3858
+ arrow = _getInnerElements5.arrow;
3559
3859
 
3560
- this.settings = _extends$1({}, Defaults, settings);
3860
+ if (arrow) arrow.style.margin = '';
3861
+ this.popperInstance.reference = this.reference;
3862
+ }
3561
3863
 
3562
- // DEPRECATION: `on` prefixed callbacks are now preferred over non-
3563
- // as it better indicates it's a callback function
3564
- this.callbacks = {
3565
- wait: settings.wait,
3566
- show: settings.onShow || settings.show || noop,
3567
- shown: settings.onShown || settings.shown || noop,
3568
- hide: settings.onHide || settings.hide || noop,
3569
- hidden: settings.onHidden || settings.hidden || noop
3570
- };
3864
+ updatePopperPosition(this.popperInstance, callback, true);
3571
3865
 
3572
- this.store = createTooltips.call(this, getArrayOfElements(selector));
3573
- Store.push.apply(Store, this.store);
3866
+ if (!options.appendTo.contains(this.popper)) {
3867
+ options.appendTo.appendChild(this.popper);
3574
3868
  }
3869
+ }
3575
3870
 
3576
- /**
3577
- * Returns the reference element's popper element
3578
- * @param {Element} el
3579
- * @return {Element}
3580
- */
3581
-
3582
-
3583
- createClass$1(Tippy, [{
3584
- key: 'getPopperElement',
3585
- value: function getPopperElement(el) {
3586
- try {
3587
- return find(this.store, function (refData) {
3588
- return refData.el === el;
3589
- }).popper;
3590
- } catch (e) {
3591
- console.error('[getPopperElement]: Element passed as the argument does not exist in the instance');
3592
- }
3593
- }
3594
-
3595
- /**
3596
- * Returns a popper's reference element
3597
- * @param {Element} popper
3598
- * @return {Element}
3599
- */
3871
+ /**
3872
+ * Clears the show and hide delay timeouts
3873
+ * @memberof Tippy
3874
+ * @private
3875
+ */
3876
+ function _clearDelayTimeouts() {
3877
+ var _ref = this._(key),
3878
+ showTimeout = _ref.showTimeout,
3879
+ hideTimeout = _ref.hideTimeout;
3600
3880
 
3601
- }, {
3602
- key: 'getReferenceElement',
3603
- value: function getReferenceElement(popper) {
3604
- try {
3605
- return find(this.store, function (refData) {
3606
- return refData.popper === popper;
3607
- }).el;
3608
- } catch (e) {
3609
- console.error('[getReferenceElement]: Popper passed as the argument does not exist in the instance');
3610
- }
3611
- }
3881
+ clearTimeout(showTimeout);
3882
+ clearTimeout(hideTimeout);
3883
+ }
3612
3884
 
3613
- /**
3614
- * Returns the reference data object from either the reference element or popper element
3615
- * @param {Element} x (reference element or popper)
3616
- * @return {Object}
3617
- */
3885
+ /**
3886
+ * Sets the mousemove event listener function for `followCursor` option
3887
+ * @memberof Tippy
3888
+ * @private
3889
+ */
3890
+ function _setFollowCursorListener() {
3891
+ var _this8 = this;
3892
+
3893
+ this._(key).followCursorListener = function (event) {
3894
+ var _$lastMouseMoveEvent = _this8._(key).lastMouseMoveEvent = event,
3895
+ clientX = _$lastMouseMoveEvent.clientX,
3896
+ clientY = _$lastMouseMoveEvent.clientY;
3897
+
3898
+ if (!_this8.popperInstance) return;
3899
+
3900
+ _this8.popperInstance.reference = {
3901
+ getBoundingClientRect: function getBoundingClientRect() {
3902
+ return {
3903
+ width: 0,
3904
+ height: 0,
3905
+ top: clientY,
3906
+ left: clientX,
3907
+ right: clientX,
3908
+ bottom: clientY
3909
+ };
3910
+ },
3911
+ clientWidth: 0,
3912
+ clientHeight: 0
3913
+ };
3618
3914
 
3619
- }, {
3620
- key: 'getReferenceData',
3621
- value: function getReferenceData(x) {
3622
- return find(this.store, function (refData) {
3623
- return refData.el === x || refData.popper === x;
3624
- });
3625
- }
3915
+ _this8.popperInstance.scheduleUpdate();
3916
+ };
3917
+ }
3626
3918
 
3627
- /**
3628
- * Shows a popper
3629
- * @param {Element} popper
3630
- * @param {Number} customDuration (optional)
3631
- */
3919
+ /**
3920
+ * Updates the popper's position on each animation frame
3921
+ * @memberof Tippy
3922
+ * @private
3923
+ */
3924
+ function _makeSticky() {
3925
+ var _this9 = this;
3632
3926
 
3633
- }, {
3634
- key: 'show',
3635
- value: function show(popper, customDuration) {
3636
- var _this = this;
3927
+ var applyTransitionDuration$$1 = function applyTransitionDuration$$1() {
3928
+ _this9.popper.style[prefix('transitionDuration')] = _this9.options.updateDuration + 'ms';
3929
+ };
3637
3930
 
3638
- if (this.state.destroyed) return;
3931
+ var removeTransitionDuration = function removeTransitionDuration() {
3932
+ _this9.popper.style[prefix('transitionDuration')] = '';
3933
+ };
3639
3934
 
3640
- this.callbacks.show.call(popper);
3935
+ var updatePosition = function updatePosition() {
3936
+ if (_this9.popperInstance) {
3937
+ _this9.popperInstance.update();
3938
+ }
3641
3939
 
3642
- var refData = find(this.store, function (refData) {
3643
- return refData.popper === popper;
3644
- });
3645
- var tooltip = popper.querySelector(Selectors.TOOLTIP);
3646
- var circle = popper.querySelector(Selectors.CIRCLE);
3647
- var content = popper.querySelector(Selectors.CONTENT);
3648
-
3649
- var el = refData.el,
3650
- _refData$settings = refData.settings,
3651
- appendTo = _refData$settings.appendTo,
3652
- sticky = _refData$settings.sticky,
3653
- interactive = _refData$settings.interactive,
3654
- followCursor = _refData$settings.followCursor,
3655
- flipDuration = _refData$settings.flipDuration,
3656
- duration = _refData$settings.duration,
3657
- dynamicTitle = _refData$settings.dynamicTitle;
3658
-
3659
-
3660
- if (dynamicTitle) {
3661
- var title = el.getAttribute('title');
3662
- if (title) {
3663
- content.innerHTML = title;
3664
- removeTitle(el);
3665
- }
3666
- }
3940
+ applyTransitionDuration$$1();
3667
3941
 
3668
- var _duration = customDuration !== undefined ? customDuration : Array.isArray(duration) ? duration[0] : duration;
3942
+ if (_this9.state.visible) {
3943
+ requestAnimationFrame(updatePosition);
3944
+ } else {
3945
+ removeTransitionDuration();
3946
+ }
3947
+ };
3669
3948
 
3670
- // Remove transition duration (prevent a transition when popper changes position)
3671
- applyTransitionDuration([popper, tooltip, circle], 0);
3949
+ updatePosition();
3950
+ }
3672
3951
 
3673
- mountPopper(refData);
3952
+ /**
3953
+ * Adds a mutation observer to an element and stores it in the instance
3954
+ * @param {Object}
3955
+ * @memberof Tippy
3956
+ * @private
3957
+ */
3958
+ function _addMutationObserver(_ref2) {
3959
+ var target = _ref2.target,
3960
+ callback = _ref2.callback,
3961
+ options = _ref2.options;
3674
3962
 
3675
- popper.style.visibility = 'visible';
3676
- popper.setAttribute('aria-hidden', 'false');
3963
+ if (!window.MutationObserver) return;
3677
3964
 
3678
- // Wait for popper to update position and alter x-placement
3679
- queueExecution(function () {
3680
- if (!isVisible(popper)) return;
3965
+ var observer = new MutationObserver(callback);
3966
+ observer.observe(target, options);
3681
3967
 
3682
- // Sometimes the arrow will not be in the correct position,
3683
- // force another update
3684
- if (!followCursor || Browser.touch) {
3685
- refData.popperInstance.update();
3686
- }
3968
+ this._(key).mutationObservers.push(observer);
3969
+ }
3687
3970
 
3688
- // Re-apply transition durations
3689
- applyTransitionDuration([tooltip, circle], _duration);
3690
- if (!followCursor || Browser.touch) {
3691
- applyTransitionDuration([popper], flipDuration);
3692
- }
3971
+ /**
3972
+ * Fires the callback functions once the CSS transition ends for `show` and `hide` methods
3973
+ * @param {Number} duration
3974
+ * @param {Function} callback - callback function to fire once transition completes
3975
+ * @memberof Tippy
3976
+ * @private
3977
+ */
3978
+ function _onTransitionEnd(duration, callback) {
3979
+ // Make callback synchronous if duration is 0
3980
+ if (!duration) {
3981
+ return callback();
3982
+ }
3693
3983
 
3694
- // Make content fade out a bit faster than the tooltip if `animateFill`
3695
- if (circle) content.style.opacity = 1;
3984
+ var _getInnerElements6 = getInnerElements(this.popper),
3985
+ tooltip = _getInnerElements6.tooltip;
3696
3986
 
3697
- // Interactive tooltips receive a class of 'active'
3698
- interactive && el.classList.add('active');
3987
+ var toggleListeners = function toggleListeners(action, listener) {
3988
+ if (!listener) return;
3989
+ tooltip[action + 'EventListener']('ontransitionend' in window ? 'transitionend' : 'webkitTransitionEnd', listener);
3990
+ };
3699
3991
 
3700
- // Update popper's position on every animation frame
3701
- sticky && makeSticky(refData);
3992
+ var listener = function listener(e) {
3993
+ if (e.target === tooltip) {
3994
+ toggleListeners('remove', listener);
3995
+ callback();
3996
+ }
3997
+ };
3702
3998
 
3703
- // Repaint/reflow is required for CSS transition when appending
3704
- triggerReflow(tooltip, circle);
3999
+ toggleListeners('remove', this._(key).transitionendListener);
4000
+ toggleListeners('add', listener);
3705
4001
 
3706
- modifyClassList([tooltip, circle], function (list) {
3707
- list.contains('tippy-notransition') && list.remove('tippy-notransition');
3708
- list.remove('leave');
3709
- list.add('enter');
3710
- });
4002
+ this._(key).transitionendListener = listener;
4003
+ }
3711
4004
 
3712
- // Wait for transitions to complete
3713
- onTransitionEnd(refData, _duration, function () {
3714
- if (!isVisible(popper) || refData._onShownFired) return;
4005
+ var idCounter = 1;
3715
4006
 
3716
- // Focus interactive tooltips only
3717
- interactive && popper.focus();
4007
+ /**
4008
+ * Creates tooltips for each reference element
4009
+ * @param {Element[]} els
4010
+ * @param {Object} config
4011
+ * @return {Tippy[]} Array of Tippy instances
4012
+ */
4013
+ function createTooltips(els, config) {
4014
+ return els.reduce(function (acc, reference) {
4015
+ var id = idCounter;
3718
4016
 
3719
- // Remove transitions from tooltip
3720
- tooltip.classList.add('tippy-notransition');
4017
+ var options = evaluateOptions(reference, config.performance ? config : getIndividualOptions(reference, config));
3721
4018
 
3722
- // Prevents shown() from firing more than once from early transition cancellations
3723
- refData._onShownFired = true;
4019
+ var title = reference.getAttribute('title');
3724
4020
 
3725
- _this.callbacks.shown.call(popper);
3726
- });
3727
- });
4021
+ // Don't create an instance when:
4022
+ // * the `title` attribute is falsy (null or empty string), and
4023
+ // * it's not a delegate for tooltips, and
4024
+ // * there is no html template specified, and
4025
+ // * `dynamicTitle` option is false
4026
+ if (!title && !options.target && !options.html && !options.dynamicTitle) {
4027
+ return acc;
3728
4028
  }
3729
4029
 
3730
- /**
3731
- * Hides a popper
3732
- * @param {Element} popper
3733
- * @param {Number} customDuration (optional)
3734
- */
3735
-
3736
- }, {
3737
- key: 'hide',
3738
- value: function hide(popper, customDuration) {
3739
- var _this2 = this;
4030
+ // Delegates should be highlighted as different
4031
+ reference.setAttribute(options.target ? 'data-tippy-delegate' : 'data-tippy', '');
3740
4032
 
3741
- if (this.state.destroyed) return;
4033
+ removeTitle(reference);
3742
4034
 
3743
- this.callbacks.hide.call(popper);
4035
+ var popper = createPopperElement(id, title, options);
3744
4036
 
3745
- var refData = find(this.store, function (refData) {
3746
- return refData.popper === popper;
3747
- });
3748
- var tooltip = popper.querySelector(Selectors.TOOLTIP);
3749
- var circle = popper.querySelector(Selectors.CIRCLE);
3750
- var content = popper.querySelector(Selectors.CONTENT);
4037
+ var tippy = new Tippy({
4038
+ id: id,
4039
+ reference: reference,
4040
+ popper: popper,
4041
+ options: options,
4042
+ title: title,
4043
+ popperInstance: null
4044
+ });
3751
4045
 
3752
- var el = refData.el,
3753
- _refData$settings2 = refData.settings,
3754
- appendTo = _refData$settings2.appendTo,
3755
- sticky = _refData$settings2.sticky,
3756
- interactive = _refData$settings2.interactive,
3757
- followCursor = _refData$settings2.followCursor,
3758
- html = _refData$settings2.html,
3759
- trigger = _refData$settings2.trigger,
3760
- duration = _refData$settings2.duration;
4046
+ if (options.createPopperInstanceOnInit) {
4047
+ tippy.popperInstance = _createPopperInstance.call(tippy);
4048
+ tippy.popperInstance.disableEventListeners();
4049
+ }
3761
4050
 
4051
+ var listeners = _getEventListeners.call(tippy);
4052
+ tippy.listeners = options.trigger.trim().split(' ').reduce(function (acc, eventType) {
4053
+ return acc.concat(createTrigger(eventType, reference, listeners, options));
4054
+ }, []);
4055
+
4056
+ // Update tooltip content whenever the title attribute on the reference changes
4057
+ if (options.dynamicTitle) {
4058
+ _addMutationObserver.call(tippy, {
4059
+ target: reference,
4060
+ callback: function callback() {
4061
+ var _getInnerElements = getInnerElements(popper),
4062
+ content = _getInnerElements.content;
4063
+
4064
+ var title = reference.getAttribute('title');
4065
+ if (title) {
4066
+ content[options.allowTitleHTML ? 'innerHTML' : 'textContent'] = tippy.title = title;
4067
+ removeTitle(reference);
4068
+ }
4069
+ },
4070
+
4071
+ options: {
4072
+ attributes: true
4073
+ }
4074
+ });
4075
+ }
3762
4076
 
3763
- var _duration = customDuration !== undefined ? customDuration : Array.isArray(duration) ? duration[1] : duration;
4077
+ // Shortcuts
4078
+ reference._tippy = tippy;
4079
+ popper._tippy = tippy;
4080
+ popper._reference = reference;
3764
4081
 
3765
- refData._onShownFired = false;
3766
- interactive && el.classList.remove('active');
4082
+ acc.push(tippy);
3767
4083
 
3768
- popper.style.visibility = 'hidden';
3769
- popper.setAttribute('aria-hidden', 'true');
4084
+ idCounter++;
3770
4085
 
3771
- applyTransitionDuration([tooltip, circle, circle ? content : null], _duration);
4086
+ return acc;
4087
+ }, []);
4088
+ }
3772
4089
 
3773
- if (circle) content.style.opacity = 0;
4090
+ /**
4091
+ * Hides all poppers
4092
+ * @param {Tippy} excludeTippy - tippy to exclude if needed
4093
+ */
4094
+ function hideAllPoppers(excludeTippy) {
4095
+ var poppers = toArray(document.querySelectorAll(selectors.POPPER));
3774
4096
 
3775
- modifyClassList([tooltip, circle], function (list) {
3776
- list.contains('tippy-tooltip') && list.remove('tippy-notransition');
3777
- list.remove('enter');
3778
- list.add('leave');
3779
- });
4097
+ poppers.forEach(function (popper) {
4098
+ var tippy = popper._tippy;
4099
+ if (!tippy) return;
3780
4100
 
3781
- // Re-focus click-triggered html elements
3782
- // and the tooltipped element IS in the viewport (otherwise it causes unsightly scrolling
3783
- // if the tooltip is closed and the element isn't in the viewport anymore)
3784
- if (html && trigger.indexOf('click') !== -1 && elementIsInViewport(el)) {
3785
- el.focus();
3786
- }
4101
+ var options = tippy.options;
3787
4102
 
3788
- // Wait for transitions to complete
3789
- onTransitionEnd(refData, _duration, function () {
3790
- if (isVisible(popper) || !appendTo.contains(popper)) return;
3791
4103
 
3792
- el.removeEventListener('mousemove', followCursorHandler);
4104
+ if ((options.hideOnClick === true || options.trigger.indexOf('focus') > -1) && (!excludeTippy || popper !== excludeTippy.popper)) {
4105
+ tippy.hide();
4106
+ }
4107
+ });
4108
+ }
3793
4109
 
3794
- refData.popperInstance.disableEventListeners();
4110
+ /**
4111
+ * Adds the needed event listeners
4112
+ */
4113
+ function bindEventListeners() {
4114
+ var onDocumentTouch = function onDocumentTouch() {
4115
+ if (browser.usingTouch) return;
3795
4116
 
3796
- appendTo.removeChild(popper);
4117
+ browser.usingTouch = true;
3797
4118
 
3798
- _this2.callbacks.hidden.call(popper);
3799
- });
4119
+ if (browser.iOS) {
4120
+ document.body.classList.add('tippy-touch');
3800
4121
  }
3801
4122
 
3802
- /**
3803
- * Updates a popper with new content
3804
- * @param {Element} popper
3805
- */
4123
+ if (browser.dynamicInputDetection && window.performance) {
4124
+ document.addEventListener('mousemove', onDocumentMouseMove);
4125
+ }
3806
4126
 
3807
- }, {
3808
- key: 'update',
3809
- value: function update(popper) {
3810
- if (this.state.destroyed) return;
4127
+ browser.onUserInputChange('touch');
4128
+ };
3811
4129
 
3812
- var refData = find(this.store, function (refData) {
3813
- return refData.popper === popper;
3814
- });
3815
- var content = popper.querySelector(Selectors.CONTENT);
3816
- var el = refData.el,
3817
- html = refData.settings.html;
4130
+ var onDocumentMouseMove = function () {
4131
+ var time = void 0;
3818
4132
 
4133
+ return function () {
4134
+ var now = performance.now();
3819
4135
 
3820
- if (html instanceof Element) {
3821
- console.warn('Aborted: update() should not be used if `html` is a DOM element');
3822
- return;
4136
+ // Chrome 60+ is 1 mousemove per animation frame, use 20ms time difference
4137
+ if (now - time < 20) {
4138
+ browser.usingTouch = false;
4139
+ document.removeEventListener('mousemove', onDocumentMouseMove);
4140
+ if (!browser.iOS) {
4141
+ document.body.classList.remove('tippy-touch');
4142
+ }
4143
+ browser.onUserInputChange('mouse');
3823
4144
  }
3824
4145
 
3825
- content.innerHTML = html ? document.getElementById(html.replace('#', '')).innerHTML : el.getAttribute('title') || el.getAttribute('data-original-title');
4146
+ time = now;
4147
+ };
4148
+ }();
3826
4149
 
3827
- if (!html) removeTitle(el);
4150
+ var onDocumentClick = function onDocumentClick(event) {
4151
+ // Simulated events dispatched on the document
4152
+ if (!(event.target instanceof Element)) {
4153
+ return hideAllPoppers();
3828
4154
  }
3829
4155
 
3830
- /**
3831
- * Destroys a popper
3832
- * @param {Element} popper
3833
- * @param {Boolean} _isLast - private param used by destroyAll to optimize
3834
- */
3835
-
3836
- }, {
3837
- key: 'destroy',
3838
- value: function destroy(popper, _isLast) {
3839
- var _this3 = this;
4156
+ var reference = closest(event.target, selectors.REFERENCE);
4157
+ var popper = closest(event.target, selectors.POPPER);
3840
4158
 
3841
- if (this.state.destroyed) return;
4159
+ if (popper && popper._tippy && popper._tippy.options.interactive) {
4160
+ return;
4161
+ }
3842
4162
 
3843
- var refData = find(this.store, function (refData) {
3844
- return refData.popper === popper;
3845
- });
4163
+ if (reference && reference._tippy) {
4164
+ var options = reference._tippy.options;
3846
4165
 
3847
- var el = refData.el,
3848
- popperInstance = refData.popperInstance,
3849
- listeners = refData.listeners,
3850
- _mutationObserver = refData._mutationObserver;
4166
+ var isClickTrigger = options.trigger.indexOf('click') > -1;
4167
+ var isMultiple = options.multiple;
3851
4168
 
3852
- // Ensure the popper is hidden
4169
+ // Hide all poppers except the one belonging to the element that was clicked
4170
+ if (!isMultiple && browser.usingTouch || !isMultiple && isClickTrigger) {
4171
+ return hideAllPoppers(reference._tippy);
4172
+ }
3853
4173
 
3854
- if (isVisible(popper)) {
3855
- this.hide(popper, 0);
4174
+ if (options.hideOnClick !== true || isClickTrigger) {
4175
+ return;
3856
4176
  }
4177
+ }
3857
4178
 
3858
- // Remove Tippy-only event listeners from tooltipped element
3859
- listeners.forEach(function (listener) {
3860
- return el.removeEventListener(listener.event, listener.handler);
3861
- });
4179
+ hideAllPoppers();
4180
+ };
3862
4181
 
3863
- // Restore original title
3864
- el.setAttribute('title', el.getAttribute('data-original-title'));
4182
+ var onWindowBlur = function onWindowBlur() {
4183
+ var _document = document,
4184
+ el = _document.activeElement;
3865
4185
 
3866
- el.removeAttribute('data-original-title');
3867
- el.removeAttribute('data-tooltipped');
3868
- el.removeAttribute('aria-describedby');
4186
+ if (el && el.blur && matches$1.call(el, selectors.REFERENCE)) {
4187
+ el.blur();
4188
+ }
4189
+ };
3869
4190
 
3870
- popperInstance && popperInstance.destroy();
3871
- _mutationObserver && _mutationObserver.disconnect();
4191
+ var onWindowResize = function onWindowResize() {
4192
+ toArray(document.querySelectorAll(selectors.POPPER)).forEach(function (popper) {
4193
+ var tippyInstance = popper._tippy;
4194
+ if (tippyInstance && !tippyInstance.options.livePlacement) {
4195
+ tippyInstance.popperInstance.scheduleUpdate();
4196
+ }
4197
+ });
4198
+ };
3872
4199
 
3873
- // Remove from store
3874
- Store.splice(findIndex(Store, function (refData) {
3875
- return refData.popper === popper;
3876
- }), 1);
4200
+ document.addEventListener('click', onDocumentClick);
4201
+ document.addEventListener('touchstart', onDocumentTouch);
4202
+ window.addEventListener('blur', onWindowBlur);
4203
+ window.addEventListener('resize', onWindowResize);
3877
4204
 
3878
- // Ensure filter is called only once
3879
- if (_isLast === undefined || _isLast) {
3880
- this.store = Store.filter(function (refData) {
3881
- return refData.tippyInstance === _this3;
3882
- });
3883
- }
3884
- }
4205
+ if (!browser.supportsTouch && (navigator.maxTouchPoints || navigator.msMaxTouchPoints)) {
4206
+ document.addEventListener('pointerdown', onDocumentTouch);
4207
+ }
4208
+ }
3885
4209
 
3886
- /**
3887
- * Destroys all tooltips created by the instance
3888
- */
4210
+ var eventListenersBound = false;
3889
4211
 
3890
- }, {
3891
- key: 'destroyAll',
3892
- value: function destroyAll() {
3893
- var _this4 = this;
4212
+ /**
4213
+ * Exported module
4214
+ * @param {String|Element|Element[]|NodeList|Object} selector
4215
+ * @param {Object} options
4216
+ * @param {Boolean} one - create one tooltip
4217
+ * @return {Object}
4218
+ */
4219
+ function tippy$1(selector, options, one) {
4220
+ if (browser.supported && !eventListenersBound) {
4221
+ bindEventListeners();
4222
+ eventListenersBound = true;
4223
+ }
3894
4224
 
3895
- if (this.state.destroyed) return;
4225
+ if (isObjectLiteral(selector)) {
4226
+ polyfillVirtualReferenceProps(selector);
4227
+ }
3896
4228
 
3897
- var storeLength = this.store.length;
4229
+ options = _extends({}, defaults, options);
3898
4230
 
3899
- this.store.forEach(function (_ref, index) {
3900
- var popper = _ref.popper;
4231
+ var references = getArrayOfElements(selector);
4232
+ var firstReference = references[0];
3901
4233
 
3902
- _this4.destroy(popper, index === storeLength - 1);
4234
+ return {
4235
+ selector: selector,
4236
+ options: options,
4237
+ tooltips: browser.supported ? createTooltips(one && firstReference ? [firstReference] : references, options) : [],
4238
+ destroyAll: function destroyAll() {
4239
+ this.tooltips.forEach(function (tooltip) {
4240
+ return tooltip.destroy();
3903
4241
  });
3904
-
3905
- this.store = null;
3906
- this.state.destroyed = true;
4242
+ this.tooltips = [];
3907
4243
  }
3908
- }]);
3909
- return Tippy;
3910
- }();
3911
-
3912
- function tippy$2(selector, settings) {
3913
- return new Tippy(selector, settings);
4244
+ };
3914
4245
  }
3915
4246
 
3916
- tippy$2.Browser = Browser;
3917
- tippy$2.Defaults = Defaults;
3918
- tippy$2.disableDynamicInputDetection = function () {
3919
- return Browser.dynamicInputDetection = false;
4247
+ tippy$1.version = version;
4248
+ tippy$1.browser = browser;
4249
+ tippy$1.defaults = defaults;
4250
+ tippy$1.one = function (selector, options) {
4251
+ return tippy$1(selector, options, true).tooltips[0];
3920
4252
  };
3921
- tippy$2.enableDynamicInputDetection = function () {
3922
- return Browser.dynamicInputDetection = true;
4253
+ tippy$1.disableAnimations = function () {
4254
+ defaults.updateDuration = defaults.duration = 0;
4255
+ defaults.animateFill = false;
3923
4256
  };
3924
4257
 
3925
- return tippy$2;
4258
+ return tippy$1;
3926
4259
 
3927
4260
  })));