tippy_rails 1.2.1.3 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  })));