.'].join(' '));
warnWhen(prop === 'showOnInit', 'The `showOnInit` prop was renamed to `showOnCreate` in v5.');
warnWhen(prop === 'arrowType', ['The `arrowType` prop was removed in v5 in favor of overloading the `arrow`', 'prop.', '\n\n', '"round" string was replaced with importing the string from the package.', '\n\n', "* import {roundArrow} from 'tippy.js'; (ESM version)\n", '* const {roundArrow} = tippy; (IIFE CDN version)', '\n\n', 'Before: {arrow: true, arrowType: "round"}\n', 'After: {arrow: roundArrow}`'].join(' '));
warnWhen(prop === 'touchHold', ['The `touchHold` prop was removed in v5 in favor of overloading the `touch`', 'prop.', '\n\n', 'Before: {touchHold: true}\n', 'After: {touch: "hold"}'].join(' '));
warnWhen(prop === 'size', ['The `size` prop was removed in v5. Instead, use a theme that specifies', 'CSS padding and font-size properties.'].join(' '));
warnWhen(prop === 'theme' && value === 'google', 'The included theme "google" was renamed to "material" in v5.');
warnWhen(didSpecifyPlacementInPopperOptions, ['Specifying placement in `popperOptions` is not supported. Use the base-level', '`placement` prop instead.', '\n\n', 'Before: {popperOptions: {placement: "bottom"}}\n', 'After: {placement: "bottom"}'].join(' '));
warnWhen(didPassUnknownProp, ["`" + prop + "`", "is not a valid prop. You may have spelled it incorrectly, or if it's a", 'plugin, forgot to pass it in an array as props.plugins.', '\n\n', 'In v5, the following props were turned into plugins:', '\n\n', '* animateFill\n', '* followCursor\n', '* sticky', '\n\n', 'All props: https://atomiks.github.io/tippyjs/all-props/\n', 'Plugins: https://atomiks.github.io/tippyjs/plugins/'].join(' '));
});
}
/**
* Returns the popper's placement, ignoring shifting (top-start, etc)
*/
function getBasePlacement(placement) {
return placement.split('-')[0];
}
/**
* Adds `data-inertia` attribute
*/
function addInertia(tooltip) {
tooltip.setAttribute('data-inertia', '');
}
/**
* Removes `data-inertia` attribute
*/
function removeInertia(tooltip) {
tooltip.removeAttribute('data-inertia');
}
/**
* Adds interactive-related attributes
*/
function addInteractive(tooltip) {
tooltip.setAttribute('data-interactive', '');
}
/**
* Removes interactive-related attributes
*/
function removeInteractive(tooltip) {
tooltip.removeAttribute('data-interactive');
}
/**
* Sets the content of a tooltip
*/
function setContent(contentEl, props) {
if (isElement(props.content)) {
setInnerHTML(contentEl, '');
contentEl.appendChild(props.content);
} else if (typeof props.content !== 'function') {
var key = props.allowHTML ? 'innerHTML' : 'textContent';
contentEl[key] = props.content;
}
}
/**
* Returns the child elements of a popper element
*/
function getChildren(popper) {
return {
tooltip: popper.querySelector(TOOLTIP_SELECTOR),
content: popper.querySelector(CONTENT_SELECTOR),
arrow: popper.querySelector(ARROW_SELECTOR) || popper.querySelector(SVG_ARROW_SELECTOR)
};
}
/**
* Creates an arrow element and returns it
*/
function createArrowElement(arrow) {
var arrowElement = div();
if (arrow === true) {
arrowElement.className = ARROW_CLASS;
} else {
arrowElement.className = SVG_ARROW_CLASS;
if (isElement(arrow)) {
arrowElement.appendChild(arrow);
} else {
setInnerHTML(arrowElement, arrow);
}
}
return arrowElement;
}
/**
* Constructs the popper element and returns it
*/
function createPopperElement(id, props) {
var popper = div();
popper.className = POPPER_CLASS;
popper.style.position = 'absolute';
popper.style.top = '0';
popper.style.left = '0';
var tooltip = div();
tooltip.className = TOOLTIP_CLASS;
tooltip.id = "tippy-" + id;
tooltip.setAttribute('data-state', 'hidden');
tooltip.setAttribute('tabindex', '-1');
updateTheme(tooltip, 'add', props.theme);
var content = div();
content.className = CONTENT_CLASS;
content.setAttribute('data-state', 'hidden');
if (props.interactive) {
addInteractive(tooltip);
}
if (props.arrow) {
tooltip.setAttribute('data-arrow', '');
tooltip.appendChild(createArrowElement(props.arrow));
}
if (props.inertia) {
addInertia(tooltip);
}
setContent(content, props);
tooltip.appendChild(content);
popper.appendChild(tooltip);
updatePopperElement(popper, props, props);
return popper;
}
/**
* Updates the popper element based on the new props
*/
function updatePopperElement(popper, prevProps, nextProps) {
var _getChildren = getChildren(popper),
tooltip = _getChildren.tooltip,
content = _getChildren.content,
arrow = _getChildren.arrow;
popper.style.zIndex = '' + nextProps.zIndex;
tooltip.setAttribute('data-animation', nextProps.animation);
tooltip.style.maxWidth = appendPxIfNumber(nextProps.maxWidth);
if (nextProps.role) {
tooltip.setAttribute('role', nextProps.role);
} else {
tooltip.removeAttribute('role');
}
if (prevProps.content !== nextProps.content) {
setContent(content, nextProps);
} // arrow
if (!prevProps.arrow && nextProps.arrow) {
// false to true
tooltip.appendChild(createArrowElement(nextProps.arrow));
tooltip.setAttribute('data-arrow', '');
} else if (prevProps.arrow && !nextProps.arrow) {
// true to false
tooltip.removeChild(arrow);
tooltip.removeAttribute('data-arrow');
} else if (prevProps.arrow !== nextProps.arrow) {
// true to 'round' or vice-versa
tooltip.removeChild(arrow);
tooltip.appendChild(createArrowElement(nextProps.arrow));
} // interactive
if (!prevProps.interactive && nextProps.interactive) {
addInteractive(tooltip);
} else if (prevProps.interactive && !nextProps.interactive) {
removeInteractive(tooltip);
} // inertia
if (!prevProps.inertia && nextProps.inertia) {
addInertia(tooltip);
} else if (prevProps.inertia && !nextProps.inertia) {
removeInertia(tooltip);
} // theme
if (prevProps.theme !== nextProps.theme) {
updateTheme(tooltip, 'remove', prevProps.theme);
updateTheme(tooltip, 'add', nextProps.theme);
}
}
/**
* Add/remove transitionend listener from tooltip
*/
function updateTransitionEndListener(tooltip, action, listener) {
['transitionend', 'webkitTransitionEnd'].forEach(function (event) {
tooltip[action + 'EventListener'](event, listener);
});
}
/**
* Adds/removes theme from tooltip's classList
*/
function updateTheme(tooltip, action, theme) {
splitBySpaces(theme).forEach(function (name) {
tooltip.classList[action](name + "-theme");
});
}
/**
* Determines if the mouse cursor is outside of the popper's interactive border
* region
*/
function isCursorOutsideInteractiveBorder(popperTreeData, event) {
var clientX = event.clientX,
clientY = event.clientY;
return popperTreeData.every(function (_ref) {
var popperRect = _ref.popperRect,
tooltipRect = _ref.tooltipRect,
interactiveBorder = _ref.interactiveBorder;
// Get min/max bounds of both the popper and tooltip rects due to
// `distance` offset
var mergedRect = {
top: Math.min(popperRect.top, tooltipRect.top),
right: Math.max(popperRect.right, tooltipRect.right),
bottom: Math.max(popperRect.bottom, tooltipRect.bottom),
left: Math.min(popperRect.left, tooltipRect.left)
};
var exceedsTop = mergedRect.top - clientY > interactiveBorder;
var exceedsBottom = clientY - mergedRect.bottom > interactiveBorder;
var exceedsLeft = mergedRect.left - clientX > interactiveBorder;
var exceedsRight = clientX - mergedRect.right > interactiveBorder;
return exceedsTop || exceedsBottom || exceedsLeft || exceedsRight;
});
}
var idCounter = 1;
var mouseMoveListeners = [];
/**
* Used by `hideAll()`
*/
var mountedInstances = [];
/**
* Creates and returns a Tippy object. We're using a closure pattern instead of
* a class so that the exposed object API is clean without private members
* prefixed with `_`.
*/
function createTippy(reference, passedProps) {
var props = evaluateProps(reference, _extends({}, defaultProps, {}, getExtendedPassedProps(passedProps))); // If the reference shouldn't have multiple tippys, return null early
if (!props.multiple && reference._tippy) {
return null;
}
/* ======================= 🔒 Private members 🔒 ======================= */
var showTimeout;
var hideTimeout;
var scheduleHideAnimationFrame;
var isBeingDestroyed = false;
var isVisibleFromClick = false;
var didHideDueToDocumentMouseDown = false;
var popperUpdates = 0;
var lastTriggerEvent;
var currentMountCallback;
var currentTransitionEndListener;
var listeners = [];
var debouncedOnMouseMove = debounce(onMouseMove, props.interactiveDebounce);
var currentTarget; // Support iframe contexts
// Static check that assumes any of the `triggerTarget` or `reference`
// nodes will never change documents, even when they are updated
var doc = getOwnerDocument(props.triggerTarget || reference);
/* ======================= 🔑 Public members 🔑 ======================= */
var id = idCounter++;
var popper = createPopperElement(id, props);
var popperChildren = getChildren(popper);
var popperInstance = null;
var plugins = unique(props.plugins); // These two elements are static
var tooltip = popperChildren.tooltip,
content = popperChildren.content;
var transitionableElements = [tooltip, content];
var state = {
// The current real placement (`data-placement` attribute)
currentPlacement: null,
// Is the instance currently enabled?
isEnabled: true,
// Is the tippy currently showing and not transitioning out?
isVisible: false,
// Has the instance been destroyed?
isDestroyed: false,
// Is the tippy currently mounted to the DOM?
isMounted: false,
// Has the tippy finished transitioning in?
isShown: false
};
var instance = {
// properties
id: id,
reference: reference,
popper: popper,
popperChildren: popperChildren,
popperInstance: popperInstance,
props: props,
state: state,
plugins: plugins,
// methods
clearDelayTimeouts: clearDelayTimeouts,
setProps: setProps,
setContent: setContent,
show: show,
hide: hide,
enable: enable,
disable: disable,
destroy: destroy
};
/* ==================== Initial instance mutations =================== */
reference._tippy = instance;
popper._tippy = instance;
var pluginsHooks = plugins.map(function (plugin) {
return plugin.fn(instance);
});
var hadAriaExpandedAttributeOnCreate = reference.hasAttribute('aria-expanded');
addListenersToTriggerTarget();
handleAriaExpandedAttribute();
if (!props.lazy) {
createPopperInstance();
}
invokeHook('onCreate', [instance]);
if (props.showOnCreate) {
scheduleShow();
} // Prevent a tippy with a delay from hiding if the cursor left then returned
// before it started hiding
popper.addEventListener('mouseenter', function () {
if (instance.props.interactive && instance.state.isVisible) {
instance.clearDelayTimeouts();
}
});
let interactiveArea = popper;
if ( instance.props.centerHorizontal === true ) {
interactiveArea = content;
}
interactiveArea.addEventListener('mouseleave', function (event) {
if (instance.props.interactive && includes(instance.props.trigger, 'mouseenter')) {
debouncedOnMouseMove(event);
doc.addEventListener('mousemove', debouncedOnMouseMove);
}
});
return instance;
/* ======================= 🔒 Private methods 🔒 ======================= */
function getNormalizedTouchSettings() {
var touch = instance.props.touch;
return Array.isArray(touch) ? touch : [touch, 0];
}
function getIsCustomTouchBehavior() {
return getNormalizedTouchSettings()[0] === 'hold';
}
function getCurrentTarget() {
return currentTarget || reference;
}
function getDelay(isShow) {
// For touch or keyboard input, force `0` delay for UX reasons
// Also if the instance is mounted but not visible (transitioning out),
// ignore delay
if (instance.state.isMounted && !instance.state.isVisible || currentInput.isTouch || lastTriggerEvent && lastTriggerEvent.type === 'focus') {
return 0;
}
return getValueAtIndexOrReturn(instance.props.delay, isShow ? 0 : 1, defaultProps.delay);
}
function invokeHook(hook, args, shouldInvokePropsHook) {
if (shouldInvokePropsHook === void 0) {
shouldInvokePropsHook = true;
}
pluginsHooks.forEach(function (pluginHooks) {
if (hasOwnProperty(pluginHooks, hook)) {
// @ts-ignore
pluginHooks[hook].apply(pluginHooks, args);
}
});
if (shouldInvokePropsHook) {
var _instance$props;
// @ts-ignore
(_instance$props = instance.props)[hook].apply(_instance$props, args);
}
}
function handleAriaDescribedByAttribute() {
var aria = instance.props.aria;
if (!aria) {
return;
}
var attr = "aria-" + aria;
var id = tooltip.id;
var nodes = normalizeToArray(instance.props.triggerTarget || reference);
nodes.forEach(function (node) {
var currentValue = node.getAttribute(attr);
if (instance.state.isVisible) {
node.setAttribute(attr, currentValue ? currentValue + " " + id : id);
} else {
var nextValue = currentValue && currentValue.replace(id, '').trim();
if (nextValue) {
node.setAttribute(attr, nextValue);
} else {
node.removeAttribute(attr);
}
}
});
}
function handleAriaExpandedAttribute() {
// If the user has specified `aria-expanded` on their reference when the
// instance was created, we have to assume they're controlling it externally
// themselves
if (hadAriaExpandedAttributeOnCreate) {
return;
}
var nodes = normalizeToArray(instance.props.triggerTarget || reference);
nodes.forEach(function (node) {
if (instance.props.interactive) {
node.setAttribute('aria-expanded', instance.state.isVisible && node === getCurrentTarget() ? 'true' : 'false');
} else {
node.removeAttribute('aria-expanded');
}
});
}
function cleanupInteractiveMouseListeners() {
doc.body.removeEventListener('mouseleave', scheduleHide);
doc.removeEventListener('mousemove', debouncedOnMouseMove);
mouseMoveListeners = mouseMoveListeners.filter(function (listener) {
return listener !== debouncedOnMouseMove;
});
}
function onDocumentMouseDown(event) {
let interactiveArea = popper;
if ( instance.props.centerHorizontal === true ) {
interactiveArea = content;
}
// Clicked on interactive popper
if (instance.props.interactive && interactiveArea.contains(event.target)) {
return;
} // Clicked on the event listeners target
if (getCurrentTarget().contains(event.target)) {
if (currentInput.isTouch) {
return;
}
if (instance.state.isVisible && includes(instance.props.trigger, 'click')) {
return;
}
}
if (instance.props.hideOnClick === true) {
isVisibleFromClick = false;
instance.clearDelayTimeouts();
instance.hide(); // `mousedown` event is fired right before `focus` if pressing the
// currentTarget. This lets a tippy with `focus` trigger know that it
// should not show
didHideDueToDocumentMouseDown = true;
setTimeout(function () {
didHideDueToDocumentMouseDown = false;
}); // The listener gets added in `scheduleShow()`, but this may be hiding it
// before it shows, and hide()'s early bail-out behavior can prevent it
// from being cleaned up
if (!instance.state.isMounted) {
removeDocumentMouseDownListener();
}
}
}
function addDocumentMouseDownListener() {
doc.addEventListener('mousedown', onDocumentMouseDown, true);
}
function removeDocumentMouseDownListener() {
doc.removeEventListener('mousedown', onDocumentMouseDown, true);
}
function onTransitionedOut(duration, callback) {
onTransitionEnd(duration, function () {
if (!instance.state.isVisible && popper.parentNode && popper.parentNode.contains(popper)) {
callback();
}
});
}
function onTransitionedIn(duration, callback) {
onTransitionEnd(duration, callback);
}
function onTransitionEnd(duration, callback) {
function listener(event) {
if (event.target === tooltip) {
updateTransitionEndListener(tooltip, 'remove', listener);
callback();
}
} // Make callback synchronous if duration is 0
// `transitionend` won't fire otherwise
if (duration === 0) {
return callback();
}
updateTransitionEndListener(tooltip, 'remove', currentTransitionEndListener);
updateTransitionEndListener(tooltip, 'add', listener);
currentTransitionEndListener = listener;
}
function on(eventType, handler, options) {
if (options === void 0) {
options = false;
}
var nodes = normalizeToArray(instance.props.triggerTarget || reference);
nodes.forEach(function (node) {
node.addEventListener(eventType, handler, options);
listeners.push({
node: node,
eventType: eventType,
handler: handler,
options: options
});
});
}
function addListenersToTriggerTarget() {
if (getIsCustomTouchBehavior()) {
on('touchstart', onTrigger, PASSIVE);
on('touchend', onMouseLeave, PASSIVE);
}
splitBySpaces(instance.props.trigger).forEach(function (eventType) {
if (eventType === 'manual') {
return;
}
on(eventType, onTrigger);
switch (eventType) {
case 'mouseenter':
on('mouseleave', onMouseLeave);
break;
case 'focus':
on(isIE ? 'focusout' : 'blur', onBlurOrFocusOut);
break;
case 'focusin':
on('focusout', onBlurOrFocusOut);
break;
}
});
}
function removeListenersFromTriggerTarget() {
listeners.forEach(function (_ref) {
var node = _ref.node,
eventType = _ref.eventType,
handler = _ref.handler,
options = _ref.options;
node.removeEventListener(eventType, handler, options);
});
listeners = [];
}
function onTrigger(event) {
var shouldScheduleClickHide = false;
if (!instance.state.isEnabled || isEventListenerStopped(event) || didHideDueToDocumentMouseDown) {
return;
}
lastTriggerEvent = event;
currentTarget = event.currentTarget;
handleAriaExpandedAttribute();
if (!instance.state.isVisible && isMouseEvent(event)) {
// If scrolling, `mouseenter` events can be fired if the cursor lands
// over a new target, but `mousemove` events don't get fired. This
// causes interactive tooltips to get stuck open until the cursor is
// moved
mouseMoveListeners.forEach(function (listener) {
return listener(event);
});
} // Toggle show/hide when clicking click-triggered tooltips
if (event.type === 'click' && (!includes(instance.props.trigger, 'mouseenter') || isVisibleFromClick) && instance.props.hideOnClick !== false && instance.state.isVisible) {
shouldScheduleClickHide = true;
} else {
var _getNormalizedTouchSe = getNormalizedTouchSettings(),
value = _getNormalizedTouchSe[0],
duration = _getNormalizedTouchSe[1];
if (currentInput.isTouch && value === 'hold' && duration) {
// We can hijack the show timeout here, it will be cleared by
// `scheduleHide()` when necessary
showTimeout = setTimeout(function () {
scheduleShow(event);
}, duration);
} else {
scheduleShow(event);
}
}
if (event.type === 'click') {
isVisibleFromClick = !shouldScheduleClickHide;
}
if (shouldScheduleClickHide) {
scheduleHide(event);
}
}
function onMouseMove(event) {
var isCursorOverReferenceOrPopper = closestCallback(event.target, function (el) {
let interactiveArea = popper;
if ( instance.props.centerHorizontal === true ) {
interactiveArea = content;
}
return el === reference || el === interactiveArea;
});
if (event.type === 'mousemove' && isCursorOverReferenceOrPopper) {
return;
}
var popperTreeData = arrayFrom(popper.querySelectorAll(POPPER_SELECTOR)).concat(popper).map(function (popper) {
var instance = popper._tippy;
var tooltip = instance.popperChildren.tooltip;
var interactiveBorder = instance.props.interactiveBorder;
if ( instance.props.centerHorizontal === true ) {
popper = popperChildren.content;
tooltip = popperChildren.content;
}
return {
popperRect: popper.getBoundingClientRect(),
tooltipRect: tooltip.getBoundingClientRect(),
interactiveBorder: interactiveBorder
};
});
if (isCursorOutsideInteractiveBorder(popperTreeData, event)) {
cleanupInteractiveMouseListeners();
scheduleHide(event);
}
}
function onMouseLeave(event) {
if (isEventListenerStopped(event)) {
return;
}
if (includes(instance.props.trigger, 'click') && isVisibleFromClick) {
return;
}
if (instance.props.interactive) {
doc.body.addEventListener('mouseleave', scheduleHide);
doc.addEventListener('mousemove', debouncedOnMouseMove);
pushIfUnique(mouseMoveListeners, debouncedOnMouseMove);
debouncedOnMouseMove(event);
return;
}
scheduleHide(event);
}
function onBlurOrFocusOut(event) {
if (!includes(instance.props.trigger, 'focusin') && event.target !== getCurrentTarget()) {
return;
} // If focus was moved to within the popper
if (instance.props.interactive && event.relatedTarget && popper.contains(event.relatedTarget)) {
return;
}
scheduleHide(event);
}
function isEventListenerStopped(event) {
var supportsTouch = 'ontouchstart' in window;
var isTouchEvent = includes(event.type, 'touch');
var isCustomTouch = getIsCustomTouchBehavior();
return supportsTouch && currentInput.isTouch && isCustomTouch && !isTouchEvent || currentInput.isTouch && !isCustomTouch && isTouchEvent;
}
function createPopperInstance() {
var popperOptions = instance.props.popperOptions;
var arrow = instance.popperChildren.arrow;
var flipModifier = getModifier(popperOptions, 'flip');
var preventOverflowModifier = getModifier(popperOptions, 'preventOverflow');
var distancePx;
function applyMutations(data) {
var prevPlacement = instance.state.currentPlacement;
instance.state.currentPlacement = data.placement;
if (instance.props.flip && !instance.props.flipOnUpdate) {
if (data.flipped) {
instance.popperInstance.options.placement = data.placement;
}
setModifierValue(instance.popperInstance.modifiers, 'flip', 'enabled', false);
}
tooltip.setAttribute('data-placement', data.placement);
if (data.attributes['x-out-of-boundaries'] !== false) {
tooltip.setAttribute('data-out-of-boundaries', '');
} else {
tooltip.removeAttribute('data-out-of-boundaries');
}
var basePlacement = getBasePlacement(data.placement);
var isVerticalPlacement = includes(['top', 'bottom'], basePlacement);
var isSecondaryPlacement = includes(['bottom', 'right'], basePlacement); // Apply `distance` prop
tooltip.style.top = '0';
tooltip.style.left = '0';
tooltip.style[isVerticalPlacement ? 'top' : 'left'] = (isSecondaryPlacement ? 1 : -1) * distancePx + 'px'; // Careful not to cause an infinite loop here
// Fixes https://github.com/FezVrasta/popper.js/issues/784
if (prevPlacement && prevPlacement !== data.placement) {
instance.popperInstance.update();
}
}
var config = _extends({
eventsEnabled: false,
placement: instance.props.placement
}, popperOptions, {
modifiers: _extends({}, popperOptions && popperOptions.modifiers, {
// We can't use `padding` on the popper el because of these bugs when
// flipping from a vertical to horizontal placement or vice-versa,
// there is severe flickering.
// https://github.com/FezVrasta/popper.js/issues/720
// This workaround increases bundle size by 250B minzip unfortunately,
// due to need to custom compute the distance (since Popper rect does
// not get affected by the inner tooltip's distance offset)
tippyDistance: {
enabled: true,
order: 0,
fn: function fn(data) {
// `html` fontSize may change while `popperInstance` is alive
// e.g. on resize in media queries
distancePx = getUnitsInPx(doc, instance.props.distance);
var basePlacement = getBasePlacement(data.placement);
var computedPreventOverflowPadding = getComputedPadding(basePlacement, preventOverflowModifier && preventOverflowModifier.padding, distancePx);
var computedFlipPadding = getComputedPadding(basePlacement, flipModifier && flipModifier.padding, distancePx);
var instanceModifiers = instance.popperInstance.modifiers;
setModifierValue(instanceModifiers, 'preventOverflow', 'padding', computedPreventOverflowPadding);
setModifierValue(instanceModifiers, 'flip', 'padding', computedFlipPadding);
return data;
}
},
preventOverflow: _extends({
boundariesElement: instance.props.boundary
}, preventOverflowModifier),
flip: _extends({
enabled: instance.props.flip,
behavior: instance.props.flipBehavior
}, flipModifier),
arrow: _extends({
element: arrow,
enabled: !!arrow
}, getModifier(popperOptions, 'arrow')),
offset: _extends({
offset: instance.props.offset
}, getModifier(popperOptions, 'offset'))
}),
onCreate: function onCreate(data) {
applyMutations(data);
preserveInvocation(popperOptions && popperOptions.onCreate, config.onCreate, [data]);
runMountCallback();
},
onUpdate: function onUpdate(data) {
applyMutations(data);
preserveInvocation(popperOptions && popperOptions.onUpdate, config.onUpdate, [data]);
runMountCallback();
}
});
instance.popperInstance = new Popper(reference, popper, config);
}
function runMountCallback() {
// Only invoke currentMountCallback after 2 updates
// This fixes some bugs in Popper.js (TODO: aim for only 1 update)
if (popperUpdates === 0) {
popperUpdates++; // 1
instance.popperInstance.update();
} else if (currentMountCallback && popperUpdates === 1) {
popperUpdates++; // 2
reflow(popper);
currentMountCallback();
}
}
function mount() {
// The mounting callback (`currentMountCallback`) is only run due to a
// popperInstance update/create
popperUpdates = 0;
var appendTo = instance.props.appendTo;
var parentNode; // By default, we'll append the popper to the triggerTargets's parentNode so
// it's directly after the reference element so the elements inside the
// tippy can be tabbed to
// If there are clipping issues, the user can specify a different appendTo
// and ensure focus management is handled correctly manually
var node = getCurrentTarget();
if (instance.props.interactive && appendTo === defaultProps.appendTo || appendTo === 'parent') {
parentNode = node.parentNode;
} else {
parentNode = invokeWithArgsOrReturn(appendTo, [node]);
} // The popper element needs to exist on the DOM before its position can be
// updated as Popper.js needs to read its dimensions
if (!parentNode.contains(popper)) {
parentNode.appendChild(popper);
}
{
// Accessibility check
warnWhen(instance.props.interactive && appendTo === defaultProps.appendTo && node.nextElementSibling !== popper, ['Interactive tippy element may not be accessible via keyboard navigation', 'because it is not directly after the reference element in the DOM source', 'order.', '\n\n', 'Using a wrapper or tag around the reference element solves', 'this by creating a new parentNode context.', '\n\n', 'Specifying `appendTo: document.body` silences this warning, but it', 'assumes you are using a focus management solution to handle keyboard', 'navigation.', '\n\n', 'See: https://atomiks.github.io/tippyjs/accessibility/#interactivity'].join(' '));
}
setModifierValue(instance.popperInstance.modifiers, 'flip', 'enabled', instance.props.flip);
instance.popperInstance.enableEventListeners(); // Mounting callback invoked in `onUpdate`
instance.popperInstance.update();
}
function scheduleShow(event) {
instance.clearDelayTimeouts();
if (!instance.popperInstance) {
createPopperInstance();
}
if (event) {
invokeHook('onTrigger', [instance, event]);
}
addDocumentMouseDownListener();
var delay = getDelay(true);
if (delay) {
showTimeout = setTimeout(function () {
instance.show();
}, delay);
} else {
instance.show();
}
}
function scheduleHide(event) {
instance.clearDelayTimeouts();
invokeHook('onUntrigger', [instance, event]);
if (!instance.state.isVisible) {
removeDocumentMouseDownListener();
return;
} // For interactive tippies, scheduleHide is added to a document.body handler
// from onMouseLeave so must intercept scheduled hides from mousemove/leave
// events when trigger contains mouseenter and click, and the tip is
// currently shown as a result of a click.
if (includes(instance.props.trigger, 'mouseenter') && includes(instance.props.trigger, 'click') && includes(['mouseleave', 'mousemove'], event.type) && isVisibleFromClick) {
return;
}
var delay = getDelay(false);
if (delay) {
hideTimeout = setTimeout(function () {
if (instance.state.isVisible) {
instance.hide();
}
}, delay);
} else {
// Fixes a `transitionend` problem when it fires 1 frame too
// late sometimes, we don't want hide() to be called.
scheduleHideAnimationFrame = requestAnimationFrame(function () {
instance.hide();
});
}
}
/* ======================= 🔑 Public methods 🔑 ======================= */
function enable() {
instance.state.isEnabled = true;
}
function disable() {
// Disabling the instance should also hide it
// https://github.com/atomiks/tippy.js-react/issues/106
instance.hide();
instance.state.isEnabled = false;
}
function clearDelayTimeouts() {
clearTimeout(showTimeout);
clearTimeout(hideTimeout);
cancelAnimationFrame(scheduleHideAnimationFrame);
}
function setProps(partialProps) {
{
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('setProps'));
}
if (instance.state.isDestroyed) {
return;
}
{
validateProps(partialProps, plugins);
warnWhen(partialProps.plugins ? partialProps.plugins.length !== plugins.length || plugins.some(function (p, i) {
if (partialProps.plugins && partialProps.plugins[i]) {
return p !== partialProps.plugins[i];
} else {
return true;
}
}) : false, "Cannot update plugins");
}
invokeHook('onBeforeUpdate', [instance, partialProps]);
removeListenersFromTriggerTarget();
var prevProps = instance.props;
var nextProps = evaluateProps(reference, _extends({}, instance.props, {}, partialProps, {
ignoreAttributes: true
}));
nextProps.ignoreAttributes = useIfDefined(partialProps.ignoreAttributes, prevProps.ignoreAttributes);
instance.props = nextProps;
addListenersToTriggerTarget();
if (prevProps.interactiveDebounce !== nextProps.interactiveDebounce) {
cleanupInteractiveMouseListeners();
debouncedOnMouseMove = debounce(onMouseMove, nextProps.interactiveDebounce);
}
updatePopperElement(popper, prevProps, nextProps);
instance.popperChildren = getChildren(popper); // Ensure stale aria-expanded attributes are removed
if (prevProps.triggerTarget && !nextProps.triggerTarget) {
normalizeToArray(prevProps.triggerTarget).forEach(function (node) {
node.removeAttribute('aria-expanded');
});
} else if (nextProps.triggerTarget) {
reference.removeAttribute('aria-expanded');
}
handleAriaExpandedAttribute();
if (instance.popperInstance) {
if (POPPER_INSTANCE_DEPENDENCIES.some(function (prop) {
return hasOwnProperty(partialProps, prop) && partialProps[prop] !== prevProps[prop];
})) {
var currentReference = instance.popperInstance.reference;
instance.popperInstance.destroy();
createPopperInstance();
instance.popperInstance.reference = currentReference;
if (instance.state.isVisible) {
instance.popperInstance.enableEventListeners();
}
} else {
instance.popperInstance.update();
}
}
invokeHook('onAfterUpdate', [instance, partialProps]);
}
function setContent(content) {
instance.setProps({
content: content
});
}
function show(duration) {
if (duration === void 0) {
duration = getValueAtIndexOrReturn(instance.props.duration, 0, defaultProps.duration);
}
{
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('show'));
} // Early bail-out
var isAlreadyVisible = instance.state.isVisible;
var isDestroyed = instance.state.isDestroyed;
var isDisabled = !instance.state.isEnabled;
var isTouchAndTouchDisabled = currentInput.isTouch && !instance.props.touch;
if (isAlreadyVisible || isDestroyed || isDisabled || isTouchAndTouchDisabled) {
return;
} // Normalize `disabled` behavior across browsers.
// Firefox allows events on disabled elements, but Chrome doesn't.
// Using a wrapper element (i.e. ) is recommended.
if (getCurrentTarget().hasAttribute('disabled')) {
return;
}
if (!instance.popperInstance) {
createPopperInstance();
}
invokeHook('onShow', [instance], false);
if (instance.props.onShow(instance) === false) {
return;
}
addDocumentMouseDownListener();
popper.style.visibility = 'visible';
instance.state.isVisible = true; // Prevent a transition of the popper from its previous position and of the
// elements at a different placement
// Check if the tippy was fully unmounted before `show()` was called, to
// allow for smooth transition for `createSingleton()`
if (!instance.state.isMounted) {
setTransitionDuration(transitionableElements.concat(popper), 0);
}
currentMountCallback = function currentMountCallback() {
if (!instance.state.isVisible) {
return;
}
setTransitionDuration([popper], instance.props.updateDuration);
setTransitionDuration(transitionableElements, duration);
setVisibilityState(transitionableElements, 'visible');
handleAriaDescribedByAttribute();
handleAriaExpandedAttribute();
pushIfUnique(mountedInstances, instance);
updateIOSClass(true);
instance.state.isMounted = true;
invokeHook('onMount', [instance]);
onTransitionedIn(duration, function () {
instance.state.isShown = true;
invokeHook('onShown', [instance]);
});
};
mount();
}
function hide(duration) {
if (duration === void 0) {
duration = getValueAtIndexOrReturn(instance.props.duration, 1, defaultProps.duration);
}
{
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('hide'));
} // Early bail-out
var isAlreadyHidden = !instance.state.isVisible && !isBeingDestroyed;
var isDestroyed = instance.state.isDestroyed;
var isDisabled = !instance.state.isEnabled && !isBeingDestroyed;
if (isAlreadyHidden || isDestroyed || isDisabled) {
return;
}
invokeHook('onHide', [instance], false);
if (instance.props.onHide(instance) === false && !isBeingDestroyed) {
return;
}
removeDocumentMouseDownListener();
popper.style.visibility = 'hidden';
instance.state.isVisible = false;
instance.state.isShown = false;
setTransitionDuration(transitionableElements, duration);
setVisibilityState(transitionableElements, 'hidden');
handleAriaDescribedByAttribute();
handleAriaExpandedAttribute();
onTransitionedOut(duration, function () {
instance.popperInstance.disableEventListeners();
instance.popperInstance.options.placement = instance.props.placement;
popper.parentNode.removeChild(popper);
mountedInstances = mountedInstances.filter(function (i) {
return i !== instance;
});
if (mountedInstances.length === 0) {
updateIOSClass(false);
}
instance.state.isMounted = false;
invokeHook('onHidden', [instance]);
});
}
function destroy() {
{
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('destroy'));
}
if (instance.state.isDestroyed) {
return;
}
isBeingDestroyed = true;
instance.clearDelayTimeouts();
instance.hide(0);
removeListenersFromTriggerTarget();
delete reference._tippy;
if (instance.popperInstance) {
instance.popperInstance.destroy();
}
isBeingDestroyed = false;
instance.state.isDestroyed = true;
invokeHook('onDestroy', [instance]);
}
}
function tippy(targets, optionalProps,
/** @deprecated use Props.plugins */
plugins) {
if (optionalProps === void 0) {
optionalProps = {};
}
if (plugins === void 0) {
plugins = [];
}
plugins = defaultProps.plugins.concat(optionalProps.plugins || plugins);
{
validateTargets(targets);
validateProps(optionalProps, plugins);
}
bindGlobalEventListeners();
var passedProps = _extends({}, optionalProps, {
plugins: plugins
});
var elements = getArrayOfElements(targets);
{
var isSingleContentElement = isElement(passedProps.content);
var isMoreThanOneReferenceElement = elements.length > 1;
warnWhen(isSingleContentElement && isMoreThanOneReferenceElement, ['tippy() was passed an Element as the `content` prop, but more than one tippy', 'instance was created by this invocation. This means the content element will', 'only be appended to the last tippy instance.', '\n\n', 'Instead, pass the .innerHTML of the element, or use a function that returns a', 'cloned version of the element instead.', '\n\n', '1) content: element.innerHTML\n', '2) content: () => element.cloneNode(true)'].join(' '));
}
var instances = elements.reduce(function (acc, reference) {
var instance = reference && createTippy(reference, passedProps);
if (instance) {
acc.push(instance);
}
return acc;
}, []);
return isElement(targets) ? instances[0] : instances;
}
tippy.version = version;
tippy.defaultProps = defaultProps;
tippy.setDefaultProps = setDefaultProps;
tippy.currentInput = currentInput;
/**
* Hides all visible poppers on the document
*/
var hideAll = function hideAll(_temp) {
var _ref = _temp === void 0 ? {} : _temp,
excludedReferenceOrInstance = _ref.exclude,
duration = _ref.duration;
mountedInstances.forEach(function (instance) {
var isExcluded = false;
if (excludedReferenceOrInstance) {
isExcluded = isReferenceElement(excludedReferenceOrInstance) ? instance.reference === excludedReferenceOrInstance : instance.popper === excludedReferenceOrInstance.popper;
}
if (!isExcluded) {
instance.hide(duration);
}
});
};
/**
* Re-uses a single tippy element for many different tippy instances.
* Replaces v4's `tippy.group()`.
*/
var createSingleton = function createSingleton(tippyInstances, optionalProps,
/** @deprecated use Props.plugins */
plugins) {
if (optionalProps === void 0) {
optionalProps = {};
}
if (plugins === void 0) {
plugins = [];
}
{
errorWhen(!Array.isArray(tippyInstances), ['The first argument passed to createSingleton() must be an array of tippy', 'instances. The passed value was', String(tippyInstances)].join(' '));
}
plugins = optionalProps.plugins || plugins;
tippyInstances.forEach(function (instance) {
instance.disable();
});
var userAria = _extends({}, defaultProps, {}, optionalProps).aria;
var currentAria;
var currentTarget;
var shouldSkipUpdate = false;
var references = tippyInstances.map(function (instance) {
return instance.reference;
});
var singleton = {
fn: function fn(instance) {
function handleAriaDescribedByAttribute(isShow) {
if (!currentAria) {
return;
}
var attr = "aria-" + currentAria;
if (isShow && !instance.props.interactive) {
currentTarget.setAttribute(attr, instance.popperChildren.tooltip.id);
} else {
currentTarget.removeAttribute(attr);
}
}
return {
onAfterUpdate: function onAfterUpdate(_, _ref) {
var aria = _ref.aria;
// Ensure `aria` for the singleton instance stays `null`, while
// changing the `userAria` value
if (aria !== undefined && aria !== userAria) {
if (!shouldSkipUpdate) {
userAria = aria;
} else {
shouldSkipUpdate = true;
instance.setProps({
aria: null
});
shouldSkipUpdate = false;
}
}
},
onDestroy: function onDestroy() {
tippyInstances.forEach(function (instance) {
instance.enable();
});
},
onMount: function onMount() {
handleAriaDescribedByAttribute(true);
},
onUntrigger: function onUntrigger() {
handleAriaDescribedByAttribute(false);
},
onTrigger: function onTrigger(_, event) {
var target = event.currentTarget;
var index = references.indexOf(target); // bail-out
if (target === currentTarget) {
return;
}
currentTarget = target;
currentAria = userAria;
if (instance.state.isVisible) {
handleAriaDescribedByAttribute(true);
}
instance.popperInstance.reference = target;
instance.setContent(tippyInstances[index].props.content);
}
};
}
};
return tippy(div(), _extends({}, optionalProps, {
plugins: [singleton].concat(plugins),
aria: null,
triggerTarget: references
}));
};
var BUBBLING_EVENTS_MAP = {
mouseover: 'mouseenter',
focusin: 'focus',
click: 'click'
};
/**
* Creates a delegate instance that controls the creation of tippy instances
* for child elements (`target` CSS selector).
*/
function delegate(targets, props,
/** @deprecated use Props.plugins */
plugins) {
if (plugins === void 0) {
plugins = [];
}
{
errorWhen(!(props && props.target), ['You must specity a `target` prop indicating a CSS selector string matching', 'the target elements that should receive a tippy.'].join(' '));
}
plugins = props.plugins || plugins;
var listeners = [];
var childTippyInstances = [];
var target = props.target;
var nativeProps = removeProperties(props, ['target']);
var parentProps = _extends({}, nativeProps, {
plugins: plugins,
trigger: 'manual'
});
var childProps = _extends({}, nativeProps, {
plugins: plugins,
showOnCreate: true
});
var returnValue = tippy(targets, parentProps);
var normalizedReturnValue = normalizeToArray(returnValue);
function onTrigger(event) {
if (!event.target) {
return;
}
var targetNode = event.target.closest(target);
if (!targetNode) {
return;
} // Get relevant trigger with fallbacks:
// 1. Check `data-tippy-trigger` attribute on target node
// 2. Fallback to `trigger` passed to `delegate()`
// 3. Fallback to `defaultProps.trigger`
var trigger = targetNode.getAttribute('data-tippy-trigger') || props.trigger || defaultProps.trigger; // Only create the instance if the bubbling event matches the trigger type
if (!includes(trigger, BUBBLING_EVENTS_MAP[event.type])) {
return;
}
var instance = tippy(targetNode, childProps);
if (instance) {
childTippyInstances = childTippyInstances.concat(instance);
}
}
function on(node, eventType, handler, options) {
if (options === void 0) {
options = false;
}
node.addEventListener(eventType, handler, options);
listeners.push({
node: node,
eventType: eventType,
handler: handler,
options: options
});
}
function addEventListeners(instance) {
var reference = instance.reference;
on(reference, 'mouseover', onTrigger);
on(reference, 'focusin', onTrigger);
on(reference, 'click', onTrigger);
}
function removeEventListeners() {
listeners.forEach(function (_ref) {
var node = _ref.node,
eventType = _ref.eventType,
handler = _ref.handler,
options = _ref.options;
node.removeEventListener(eventType, handler, options);
});
listeners = [];
}
function applyMutations(instance) {
var originalDestroy = instance.destroy;
instance.destroy = function (shouldDestroyChildInstances) {
if (shouldDestroyChildInstances === void 0) {
shouldDestroyChildInstances = true;
}
if (shouldDestroyChildInstances) {
childTippyInstances.forEach(function (instance) {
instance.destroy();
});
}
childTippyInstances = [];
removeEventListeners();
originalDestroy();
};
addEventListeners(instance);
}
normalizedReturnValue.forEach(applyMutations);
return returnValue;
}
var animateFill = {
name: 'animateFill',
defaultValue: false,
fn: function fn(instance) {
var _instance$popperChild = instance.popperChildren,
tooltip = _instance$popperChild.tooltip,
content = _instance$popperChild.content;
var backdrop = instance.props.animateFill ? createBackdropElement() : null;
function addBackdropToPopperChildren() {
instance.popperChildren.backdrop = backdrop;
}
return {
onCreate: function onCreate() {
if (backdrop) {
addBackdropToPopperChildren();
tooltip.insertBefore(backdrop, tooltip.firstElementChild);
tooltip.setAttribute('data-animatefill', '');
tooltip.style.overflow = 'hidden';
instance.setProps({
animation: 'shift-away',
arrow: false
});
}
},
onMount: function onMount() {
if (backdrop) {
var transitionDuration = tooltip.style.transitionDuration;
var duration = Number(transitionDuration.replace('ms', '')); // The content should fade in after the backdrop has mostly filled the
// tooltip element. `clip-path` is the other alternative but is not
// well-supported and is buggy on some devices.
content.style.transitionDelay = Math.round(duration / 10) + "ms";
backdrop.style.transitionDuration = transitionDuration;
setVisibilityState([backdrop], 'visible'); // Warn if the stylesheets are not loaded
{
warnWhen(getComputedStyle(backdrop).position !== 'absolute', "The `tippy.js/dist/backdrop.css` stylesheet has not been\n imported!\n \n The `animateFill` plugin requires this stylesheet to work.");
warnWhen(getComputedStyle(tooltip).transform === 'none', "The `tippy.js/animations/shift-away.css` stylesheet has not\n been imported!\n \n The `animateFill` plugin requires this stylesheet to work.");
}
}
},
onShow: function onShow() {
if (backdrop) {
backdrop.style.transitionDuration = '0ms';
}
},
onHide: function onHide() {
if (backdrop) {
setVisibilityState([backdrop], 'hidden');
}
},
onAfterUpdate: function onAfterUpdate() {
// With this type of prop, it's highly unlikely it will be changed
// dynamically. We'll leave out the diff/update logic it to save bytes.
// `popperChildren` is assigned a new object onAfterUpdate
addBackdropToPopperChildren();
}
};
}
};
function createBackdropElement() {
var backdrop = div();
backdrop.className = BACKDROP_CLASS;
setVisibilityState([backdrop], 'hidden');
return backdrop;
}
var followCursor = {
name: 'followCursor',
defaultValue: false,
fn: function fn(instance) {
var reference = instance.reference,
popper = instance.popper;
var originalReference = null; // Support iframe contexts
// Static check that assumes any of the `triggerTarget` or `reference`
// nodes will never change documents, even when they are updated
var doc = getOwnerDocument(instance.props.triggerTarget || reference); // Internal state
var lastMouseMoveEvent;
var mouseCoords = null;
var isInternallySettingControlledProp = false; // These are controlled by this plugin, so we need to store the user's
// original prop value
var userProps = instance.props;
function setUserProps(props) {
var keys = Object.keys(props);
keys.forEach(function (prop) {
userProps[prop] = useIfDefined(props[prop], userProps[prop]);
});
}
function getIsManual() {
return instance.props.trigger.trim() === 'manual';
}
function getIsEnabled() {
// #597
var isValidMouseEvent = getIsManual() ? true : // Check if a keyboard "click"
mouseCoords !== null && !(mouseCoords.clientX === 0 && mouseCoords.clientY === 0);
return instance.props.followCursor && isValidMouseEvent;
}
function getIsInitialBehavior() {
return currentInput.isTouch || instance.props.followCursor === 'initial' && instance.state.isVisible;
}
function resetReference() {
if (instance.popperInstance && originalReference) {
instance.popperInstance.reference = originalReference;
}
}
function handlePlacement() {
// Due to `getVirtualOffsets()`, we need to reverse the placement if it's
// shifted (start -> end, and vice-versa)
// Early bail-out
if (!getIsEnabled() && instance.props.placement === userProps.placement) {
return;
}
var placement = userProps.placement;
var shift = placement.split('-')[1];
isInternallySettingControlledProp = true;
instance.setProps({
placement: getIsEnabled() && shift ? placement.replace(shift, shift === 'start' ? 'end' : 'start') : placement
});
isInternallySettingControlledProp = false;
}
function handlePopperListeners() {
if (!instance.popperInstance) {
return;
} // Popper's scroll listeners make sense for `true` only. TODO: work out
// how to only listen horizontal scroll for "horizontal" and vertical
// scroll for "vertical"
if (getIsEnabled() && getIsInitialBehavior()) {
instance.popperInstance.disableEventListeners();
}
}
function handleMouseMoveListener() {
if (getIsEnabled()) {
addListener();
} else {
resetReference();
}
}
function triggerLastMouseMove() {
if (getIsEnabled()) {
onMouseMove(lastMouseMoveEvent);
}
}
function addListener() {
doc.addEventListener('mousemove', onMouseMove);
}
function removeListener() {
doc.removeEventListener('mousemove', onMouseMove);
}
function onMouseMove(event) {
var _lastMouseMoveEvent = lastMouseMoveEvent = event,
clientX = _lastMouseMoveEvent.clientX,
clientY = _lastMouseMoveEvent.clientY;
if (!instance.popperInstance || !instance.state.currentPlacement) {
return;
} // If the instance is interactive, avoid updating the position unless it's
// over the reference element
var isCursorOverReference = closestCallback(event.target, function (el) {
return el === reference;
});
var followCursor = instance.props.followCursor;
var isHorizontal = followCursor === 'horizontal';
var isVertical = followCursor === 'vertical';
var isVerticalPlacement = includes(['top', 'bottom'], getBasePlacement(instance.state.currentPlacement)); // The virtual reference needs some size to prevent itself from overflowing
var _getVirtualOffsets = getVirtualOffsets(popper, isVerticalPlacement),
size = _getVirtualOffsets.size,
x = _getVirtualOffsets.x,
y = _getVirtualOffsets.y;
if (isCursorOverReference || !instance.props.interactive) {
// Preserve custom position ReferenceObjects, which may not be the
// original targets reference passed as an argument
if (originalReference === null) {
originalReference = instance.popperInstance.reference;
}
instance.popperInstance.reference = {
referenceNode: reference,
// These `client` values don't get used by Popper.js if they are 0
clientWidth: 0,
clientHeight: 0,
getBoundingClientRect: function getBoundingClientRect() {
var rect = reference.getBoundingClientRect();
return {
width: isVerticalPlacement ? size : 0,
height: isVerticalPlacement ? 0 : size,
top: (isHorizontal ? rect.top : clientY) - y,
bottom: (isHorizontal ? rect.bottom : clientY) + y,
left: (isVertical ? rect.left : clientX) - x,
right: (isVertical ? rect.right : clientX) + x
};
}
};
instance.popperInstance.update();
}
if (getIsInitialBehavior()) {
removeListener();
}
}
return {
onAfterUpdate: function onAfterUpdate(_, partialProps) {
if (!isInternallySettingControlledProp) {
setUserProps(partialProps);
if (partialProps.placement) {
handlePlacement();
}
} // A new placement causes the popperInstance to be recreated
if (partialProps.placement) {
handlePopperListeners();
} // Wait for `.update()` to set `instance.state.currentPlacement` to
// the new placement
requestAnimationFrame(triggerLastMouseMove);
},
onMount: function onMount() {
triggerLastMouseMove();
handlePopperListeners();
},
onShow: function onShow() {
if (getIsManual()) {
// Since there's no trigger event to use, we have to use these as
// baseline coords
mouseCoords = {
clientX: 0,
clientY: 0
}; // Ensure `lastMouseMoveEvent` doesn't access any other properties
// of a MouseEvent here
lastMouseMoveEvent = mouseCoords;
handlePlacement();
handleMouseMoveListener();
}
},
onTrigger: function onTrigger(_, event) {
// Tapping on touch devices can trigger `mouseenter` then `focus`
if (mouseCoords) {
return;
}
if (isMouseEvent(event)) {
mouseCoords = {
clientX: event.clientX,
clientY: event.clientY
};
lastMouseMoveEvent = event;
}
handlePlacement();
handleMouseMoveListener();
},
onUntrigger: function onUntrigger() {
// If untriggered before showing (`onHidden` will never be invoked)
if (!instance.state.isVisible) {
removeListener();
mouseCoords = null;
}
},
onHidden: function onHidden() {
removeListener();
resetReference();
mouseCoords = null;
}
};
}
};
function getVirtualOffsets(popper, isVerticalPlacement) {
var size = isVerticalPlacement ? popper.offsetWidth : popper.offsetHeight;
return {
size: size,
x: isVerticalPlacement ? size : 0,
y: isVerticalPlacement ? 0 : size
};
}
// position. This will require the `followCursor` plugin's fixes for overflow
// due to using event.clientX/Y values. (normalizedPlacement, getVirtualOffsets)
var inlinePositioning = {
name: 'inlinePositioning',
defaultValue: false,
fn: function fn(instance) {
var reference = instance.reference;
function getIsEnabled() {
return !!instance.props.inlinePositioning;
}
return {
onHidden: function onHidden() {
if (getIsEnabled()) {
instance.popperInstance.reference = reference;
}
},
onShow: function onShow() {
if (!getIsEnabled()) {
return;
}
instance.popperInstance.reference = {
referenceNode: reference,
// These `client` values don't get used by Popper.js if they are 0
clientWidth: 0,
clientHeight: 0,
getBoundingClientRect: function getBoundingClientRect() {
return getInlineBoundingClientRect(instance.state.currentPlacement && getBasePlacement(instance.state.currentPlacement), reference.getBoundingClientRect(), arrayFrom(reference.getClientRects()));
}
};
}
};
}
};
function getInlineBoundingClientRect(currentBasePlacement, boundingRect, clientRects) {
// Not an inline element, or placement is not yet known
if (clientRects.length < 2 || currentBasePlacement === null) {
return boundingRect;
}
switch (currentBasePlacement) {
case 'top':
case 'bottom':
{
var firstRect = clientRects[0];
var lastRect = clientRects[clientRects.length - 1];
var isTop = currentBasePlacement === 'top';
var top = firstRect.top;
var bottom = lastRect.bottom;
var left = isTop ? firstRect.left : lastRect.left;
var right = isTop ? firstRect.right : lastRect.right;
var width = right - left;
var height = bottom - top;
return {
top: top,
bottom: bottom,
left: left,
right: right,
width: width,
height: height
};
}
case 'left':
case 'right':
{
var minLeft = Math.min.apply(Math, clientRects.map(function (rects) {
return rects.left;
}));
var maxRight = Math.max.apply(Math, clientRects.map(function (rects) {
return rects.right;
}));
var measureRects = clientRects.filter(function (rect) {
return currentBasePlacement === 'left' ? rect.left === minLeft : rect.right === maxRight;
});
var _top = measureRects[0].top;
var _bottom = measureRects[measureRects.length - 1].bottom;
var _left = minLeft;
var _right = maxRight;
var _width = _right - _left;
var _height = _bottom - _top;
return {
top: _top,
bottom: _bottom,
left: _left,
right: _right,
width: _width,
height: _height
};
}
default:
{
return boundingRect;
}
}
}
var sticky = {
name: 'sticky',
defaultValue: false,
fn: function fn(instance) {
var reference = instance.reference,
popper = instance.popper;
function getReference() {
return instance.popperInstance ? instance.popperInstance.reference : reference;
}
function shouldCheck(value) {
return instance.props.sticky === true || instance.props.sticky === value;
}
var prevRefRect = null;
var prevPopRect = null;
function updatePosition() {
var currentRefRect = shouldCheck('reference') ? getReference().getBoundingClientRect() : null;
var currentPopRect = shouldCheck('popper') ? popper.getBoundingClientRect() : null;
if (currentRefRect && areRectsDifferent(prevRefRect, currentRefRect) || currentPopRect && areRectsDifferent(prevPopRect, currentPopRect)) {
instance.popperInstance.update();
}
prevRefRect = currentRefRect;
prevPopRect = currentPopRect;
if (instance.state.isMounted) {
requestAnimationFrame(updatePosition);
}
}
return {
onMount: function onMount() {
if (instance.props.sticky) {
updatePosition();
}
}
};
}
};
function areRectsDifferent(rectA, rectB) {
if (rectA && rectB) {
return rectA.top !== rectB.top || rectA.right !== rectB.right || rectA.bottom !== rectB.bottom || rectA.left !== rectB.left;
}
return true;
}
if (isBrowser) {
injectCSS(css);
}
tippy.setDefaultProps({
plugins: [animateFill, followCursor, inlinePositioning, sticky]
});
tippy.createSingleton = createSingleton;
tippy.delegate = delegate;
tippy.hideAll = hideAll;
tippy.roundArrow = ROUND_ARROW;
return tippy;
}(Popperv1));