{"version":3,"file":"tippy-bundle.iife.min.js","sources":["../src/constants.ts","../src/utils.ts","../src/bindGlobalEventListeners.ts","../src/browser.ts","../src/props.ts","../src/popper.ts","../src/createTippy.ts","../src/index.ts","../src/addons/delegate.ts","../src/plugins/animateFill.ts","../src/plugins/followCursor.ts","../src/plugins/inlinePositioning.ts","../src/plugins/sticky.ts","../build/bundle-iife.js","../src/css.ts","../src/addons/createSingleton.ts"],"sourcesContent":["export const PASSIVE = {passive: true};\n\nexport const ROUND_ARROW =\n '';\n\nexport const IOS_CLASS = `__NAMESPACE_PREFIX__-iOS`;\nexport const POPPER_CLASS = `__NAMESPACE_PREFIX__-popper`;\nexport const TOOLTIP_CLASS = `__NAMESPACE_PREFIX__-tooltip`;\nexport const CONTENT_CLASS = `__NAMESPACE_PREFIX__-content`;\nexport const BACKDROP_CLASS = `__NAMESPACE_PREFIX__-backdrop`;\nexport const ARROW_CLASS = `__NAMESPACE_PREFIX__-arrow`;\nexport const SVG_ARROW_CLASS = `__NAMESPACE_PREFIX__-svg-arrow`;\n\nexport const POPPER_SELECTOR = `.${POPPER_CLASS}`;\nexport const TOOLTIP_SELECTOR = `.${TOOLTIP_CLASS}`;\nexport const CONTENT_SELECTOR = `.${CONTENT_CLASS}`;\nexport const BACKDROP_SELECTOR = `.${BACKDROP_CLASS}`;\nexport const ARROW_SELECTOR = `.${ARROW_CLASS}`;\nexport const SVG_ARROW_SELECTOR = `.${SVG_ARROW_CLASS}`;\n","import {ReferenceElement, Targets, BasePlacement} from './types';\nimport Popper from 'popper.js';\n\n/**\n * Triggers reflow\n */\nexport function reflow(element: HTMLElement): void {\n void element.offsetHeight;\n}\n\n/**\n * Sets the innerHTML of an element\n */\nexport function setInnerHTML(element: Element, html: string): void {\n element[innerHTML()] = html;\n}\n\n/**\n * Determines if the value is a reference element\n */\nexport function isReferenceElement(value: any): value is ReferenceElement {\n return !!(value && value._tippy && value._tippy.reference === value);\n}\n\n/**\n * Safe .hasOwnProperty check, for prototype-less objects\n */\nexport function hasOwnProperty(obj: object, key: string): boolean {\n return {}.hasOwnProperty.call(obj, key);\n}\n\n/**\n * Returns an array of elements based on the value\n */\nexport function getArrayOfElements(value: Targets): Element[] {\n if (isElement(value)) {\n return [value];\n }\n\n if (isNodeList(value)) {\n return arrayFrom(value);\n }\n\n if (Array.isArray(value)) {\n return value;\n }\n\n return arrayFrom(document.querySelectorAll(value));\n}\n\n/**\n * Returns a value at a given index depending on if it's an array or number\n */\nexport function getValueAtIndexOrReturn(\n value: T | [T | null, T | null],\n index: number,\n defaultValue: T | [T, T],\n): T {\n if (Array.isArray(value)) {\n const v = value[index];\n return v == null\n ? Array.isArray(defaultValue)\n ? defaultValue[index]\n : defaultValue\n : v;\n }\n\n return value;\n}\n\n/**\n * Prevents errors from being thrown while accessing nested modifier objects\n * in `popperOptions`\n */\nexport function getModifier(obj: any, key: string): any {\n return obj && obj.modifiers && obj.modifiers[key];\n}\n\n/**\n * Determines if the value is of type\n */\nexport function isType(value: any, type: string): boolean {\n const str = {}.toString.call(value);\n return str.indexOf('[object') === 0 && str.indexOf(`${type}]`) > -1;\n}\n\n/**\n * Determines if the value is of type Element\n */\nexport function isElement(value: any): value is Element {\n return isType(value, 'Element');\n}\n\n/**\n * Determines if the value is of type NodeList\n */\nexport function isNodeList(value: any): value is NodeList {\n return isType(value, 'NodeList');\n}\n\n/**\n * Determines if the value is of type MouseEvent\n */\nexport function isMouseEvent(value: any): value is MouseEvent {\n return isType(value, 'MouseEvent');\n}\n\n/**\n * Firefox extensions don't allow setting .innerHTML directly, this will trick\n * it\n */\nexport function innerHTML(): 'innerHTML' {\n return 'innerHTML';\n}\n\n/**\n * Evaluates a function if one, or returns the value\n */\nexport function invokeWithArgsOrReturn(value: any, args: any[]): any {\n return typeof value === 'function' ? value(...args) : value;\n}\n\n/**\n * Sets a popperInstance modifier's property to a value\n */\nexport function setModifierValue(\n modifiers: any[],\n name: string,\n property: string,\n value: unknown,\n): void {\n modifiers.filter(m => m.name === name)[0][property] = value;\n}\n\n/**\n * Returns a new `div` element\n */\nexport function div(): HTMLDivElement {\n return document.createElement('div');\n}\n\n/**\n * Applies a transition duration to a list of elements\n */\nexport function setTransitionDuration(\n els: (HTMLDivElement | null)[],\n value: number,\n): void {\n els.forEach(el => {\n if (el) {\n el.style.transitionDuration = `${value}ms`;\n }\n });\n}\n\n/**\n * Sets the visibility state to elements so they can begin to transition\n */\nexport function setVisibilityState(\n els: (HTMLDivElement | null)[],\n state: 'visible' | 'hidden',\n): void {\n els.forEach(el => {\n if (el) {\n el.setAttribute('data-state', state);\n }\n });\n}\n\n/**\n * Debounce utility. To avoid bloating bundle size, we're only passing 1\n * argument here, a more generic function would pass all arguments. Only\n * `onMouseMove` uses this which takes the event object for now.\n */\nexport function debounce(\n fn: (arg: T) => void,\n ms: number,\n): (arg: T) => void {\n // Avoid wrapping in `setTimeout` if ms is 0 anyway\n if (ms === 0) {\n return fn;\n }\n\n let timeout: any;\n\n return (arg): void => {\n clearTimeout(timeout);\n timeout = setTimeout(() => {\n fn(arg);\n }, ms);\n };\n}\n\n/**\n * Preserves the original function invocation when another function replaces it\n */\nexport function preserveInvocation(\n originalFn: undefined | ((...args: any) => void),\n currentFn: undefined | ((...args: any) => void),\n args: T[],\n): void {\n if (originalFn && originalFn !== currentFn) {\n originalFn(...args);\n }\n}\n\n/**\n * Deletes properties from an object (pure)\n */\nexport function removeProperties(obj: T, keys: Array): Partial {\n const clone = {...obj};\n keys.forEach(key => {\n delete clone[key];\n });\n return clone;\n}\n\n/**\n * Ponyfill for Array.from - converts iterable values to an array\n */\nexport function arrayFrom(value: ArrayLike): any[] {\n return [].slice.call(value);\n}\n\n/**\n * Works like Element.prototype.closest, but uses a callback instead\n */\nexport function closestCallback(\n element: Element | null,\n callback: Function,\n): Element | null {\n while (element) {\n if (callback(element)) {\n return element;\n }\n\n element = element.parentElement;\n }\n\n return null;\n}\n\n/**\n * Determines if an array or string includes a string\n */\nexport function includes(a: string[] | string, b: string): boolean {\n return a.indexOf(b) > -1;\n}\n\n/**\n * Creates an array from string of values separated by whitespace\n */\nexport function splitBySpaces(value: string): string[] {\n return value.split(/\\s+/).filter(Boolean);\n}\n\n/**\n * Returns the `nextValue` if `nextValue` is not `undefined`, otherwise returns\n * `currentValue`\n */\nexport function useIfDefined(nextValue: any, currentValue: any): any {\n return nextValue !== undefined ? nextValue : currentValue;\n}\n\n/**\n * Converts a value that's an array or single value to an array\n */\nexport function normalizeToArray(value: T | T[]): T[] {\n return ([] as T[]).concat(value);\n}\n\n/**\n * Returns the ownerDocument of the first available element, otherwise global\n * document\n */\nexport function getOwnerDocument(\n elementOrElements: Element | Element[],\n): Document {\n const [element] = normalizeToArray(elementOrElements);\n return element ? element.ownerDocument || document : document;\n}\n\n/**\n * Adds item to array if array does not contain it\n */\nexport function pushIfUnique(arr: T[], value: T): void {\n if (arr.indexOf(value) === -1) {\n arr.push(value);\n }\n}\n\n/**\n * Adds `px` if value is a number, or returns it directly\n */\nexport function appendPxIfNumber(value: string | number): string {\n return typeof value === 'number' ? `${value}px` : value;\n}\n\n/**\n * Filters out duplicate elements in an array\n */\nexport function unique(arr: T[]): T[] {\n return arr.filter((item, index) => arr.indexOf(item) === index);\n}\n\n/**\n * Returns number from number or CSS units string\n */\nexport function getNumber(value: string | number): number {\n return typeof value === 'number' ? value : parseFloat(value);\n}\n\n/**\n * Gets number or CSS string units in pixels (e.g. `1rem` -> 16)\n */\nexport function getUnitsInPx(doc: Document, value: string | number): number {\n const isRem = typeof value === 'string' && includes(value, 'rem');\n const html = doc.documentElement;\n const rootFontSize = 16;\n\n if (html && isRem) {\n return (\n parseFloat(getComputedStyle(html).fontSize || String(rootFontSize)) *\n getNumber(value)\n );\n }\n\n return getNumber(value);\n}\n\n/**\n * Adds the `distancePx` value to the placement of a Popper.Padding object\n */\nexport function getComputedPadding(\n basePlacement: BasePlacement,\n padding: number | Popper.Padding = 5,\n distancePx: number,\n): Popper.Padding {\n const freshPaddingObject = {top: 0, right: 0, bottom: 0, left: 0};\n const keys = Object.keys(freshPaddingObject) as BasePlacement[];\n\n return keys.reduce((obj, key) => {\n obj[key] = typeof padding === 'number' ? padding : (padding as any)[key];\n\n if (basePlacement === key) {\n obj[key] =\n typeof padding === 'number'\n ? padding + distancePx\n : (padding as any)[basePlacement] + distancePx;\n }\n\n return obj;\n }, freshPaddingObject);\n}\n","import {PASSIVE} from './constants';\nimport {isReferenceElement} from './utils';\n\nexport const currentInput = {isTouch: false};\nlet lastMouseMoveTime = 0;\n\n/**\n * When a `touchstart` event is fired, it's assumed the user is using touch\n * input. We'll bind a `mousemove` event listener to listen for mouse input in\n * the future. This way, the `isTouch` property is fully dynamic and will handle\n * hybrid devices that use a mix of touch + mouse input.\n */\nexport function onDocumentTouchStart(): void {\n if (currentInput.isTouch) {\n return;\n }\n\n currentInput.isTouch = true;\n\n if (window.performance) {\n document.addEventListener('mousemove', onDocumentMouseMove);\n }\n}\n\n/**\n * When two `mousemove` event are fired consecutively within 20ms, it's assumed\n * the user is using mouse input again. `mousemove` can fire on touch devices as\n * well, but very rarely that quickly.\n */\nexport function onDocumentMouseMove(): void {\n const now = performance.now();\n\n if (now - lastMouseMoveTime < 20) {\n currentInput.isTouch = false;\n\n document.removeEventListener('mousemove', onDocumentMouseMove);\n }\n\n lastMouseMoveTime = now;\n}\n\n/**\n * When an element is in focus and has a tippy, leaving the tab/window and\n * returning causes it to show again. For mouse users this is unexpected, but\n * for keyboard use it makes sense.\n * TODO: find a better technique to solve this problem\n */\nexport function onWindowBlur(): void {\n const activeElement = document.activeElement as HTMLElement | null;\n\n if (isReferenceElement(activeElement)) {\n const instance = activeElement._tippy!;\n\n if (activeElement.blur && !instance.state.isVisible) {\n activeElement.blur();\n }\n }\n}\n\n/**\n * Adds the needed global event listeners\n */\nexport default function bindGlobalEventListeners(): void {\n document.addEventListener('touchstart', onDocumentTouchStart, {\n ...PASSIVE,\n capture: true,\n });\n window.addEventListener('blur', onWindowBlur);\n}\n","import {currentInput} from './bindGlobalEventListeners';\nimport {IOS_CLASS} from './constants';\n\nexport const isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\nconst ua = isBrowser ? navigator.userAgent : '';\n\nexport const isIE = /MSIE |Trident\\//.test(ua);\nexport const isUCBrowser = /UCBrowser\\//.test(ua);\nexport const isIOS = isBrowser && /iPhone|iPad|iPod/.test(navigator.platform);\n\nexport function updateIOSClass(isAdd: boolean): void {\n const shouldAdd = isAdd && isIOS && currentInput.isTouch;\n document.body.classList[shouldAdd ? 'add' : 'remove'](IOS_CLASS);\n}\n","import {Props, DefaultProps, ReferenceElement, Plugin, Tippy} from './types';\nimport {\n invokeWithArgsOrReturn,\n hasOwnProperty,\n includes,\n removeProperties,\n} from './utils';\nimport {warnWhen} from './validation';\nimport {PropsV4} from './types-internal';\n\nconst pluginProps = {\n animateFill: false,\n followCursor: false,\n inlinePositioning: false,\n sticky: false,\n};\n\nexport const defaultProps: DefaultProps = {\n allowHTML: true,\n animation: 'fade',\n appendTo: () => document.body,\n aria: 'describedby',\n arrow: true,\n boundary: 'scrollParent',\n content: '',\n delay: 0,\n distance: 10,\n duration: [300, 250],\n flip: true,\n flipBehavior: 'flip',\n flipOnUpdate: false,\n hideOnClick: true,\n ignoreAttributes: false,\n inertia: false,\n interactive: false,\n interactiveBorder: 2,\n interactiveDebounce: 0,\n lazy: true,\n maxWidth: 350,\n multiple: false,\n offset: 0,\n onAfterUpdate() {},\n onBeforeUpdate() {},\n onCreate() {},\n onDestroy() {},\n onHidden() {},\n onHide() {},\n onMount() {},\n onShow() {},\n onShown() {},\n onTrigger() {},\n onUntrigger() {},\n placement: 'top',\n plugins: [],\n popperOptions: {},\n role: 'tooltip',\n showOnCreate: false,\n theme: '',\n touch: true,\n trigger: 'mouseenter focus',\n triggerTarget: null,\n updateDuration: 0,\n zIndex: 9999,\n ...pluginProps,\n};\n\nconst defaultKeys = Object.keys(defaultProps);\n\n/**\n * If the setProps() method encounters one of these, the popperInstance must be\n * recreated\n */\nexport const POPPER_INSTANCE_DEPENDENCIES: Array = [\n 'arrow',\n 'boundary',\n 'distance',\n 'flip',\n 'flipBehavior',\n 'flipOnUpdate',\n 'offset',\n 'placement',\n 'popperOptions',\n];\n\n/**\n * Mutates the defaultProps object by setting the props specified\n */\nexport const setDefaultProps: Tippy['setDefaultProps'] = partialProps => {\n if (__DEV__) {\n validateProps(partialProps, []);\n }\n\n const keys = Object.keys(partialProps) as Array;\n keys.forEach(key => {\n (defaultProps as any)[key] = partialProps[key];\n });\n};\n\n/**\n * Returns an extended props object including plugin props\n */\nexport function getExtendedPassedProps(\n passedProps: Partial & Record,\n): Partial {\n const plugins = passedProps.plugins || [];\n const pluginProps = plugins.reduce>((acc, plugin) => {\n const {name, defaultValue} = plugin;\n\n if (name) {\n acc[name] =\n passedProps[name] !== undefined ? passedProps[name] : defaultValue;\n }\n\n return acc;\n }, {});\n\n return {\n ...passedProps,\n ...pluginProps,\n };\n}\n\n/**\n * Returns an object of optional props from data-tippy-* attributes\n */\nexport function getDataAttributeProps(\n reference: ReferenceElement,\n plugins: Plugin[],\n): Record {\n const propKeys = plugins\n ? Object.keys(getExtendedPassedProps({...defaultProps, plugins}))\n : defaultKeys;\n\n const props = propKeys.reduce(\n (acc: Partial & Record, key) => {\n const valueAsString = (\n reference.getAttribute(`data-tippy-${key}`) || ''\n ).trim();\n\n if (!valueAsString) {\n return acc;\n }\n\n if (key === 'content') {\n acc[key] = valueAsString;\n } else {\n try {\n acc[key] = JSON.parse(valueAsString);\n } catch (e) {\n acc[key] = valueAsString;\n }\n }\n\n return acc;\n },\n {},\n );\n\n return props;\n}\n\n/**\n * Evaluates the props object by merging data attributes and disabling\n * conflicting props where necessary\n */\nexport function evaluateProps(\n reference: ReferenceElement,\n props: Props,\n): Props {\n const out = {\n ...props,\n content: invokeWithArgsOrReturn(props.content, [reference]),\n ...(props.ignoreAttributes\n ? {}\n : getDataAttributeProps(reference, props.plugins)),\n };\n\n if (out.interactive) {\n out.aria = null;\n }\n\n return out;\n}\n\n/**\n * Validates props with the valid `defaultProps` object\n */\nexport function validateProps(\n partialProps: Partial = {},\n plugins: Plugin[] = [],\n): void {\n const keys = Object.keys(partialProps) as Array;\n keys.forEach(prop => {\n const value = partialProps[prop];\n\n const didSpecifyPlacementInPopperOptions =\n prop === 'popperOptions' &&\n value !== null &&\n typeof value === 'object' &&\n hasOwnProperty(value, 'placement');\n\n const nonPluginProps = removeProperties(defaultProps, [\n 'animateFill',\n 'followCursor',\n 'inlinePositioning',\n 'sticky',\n ]);\n\n // These props have custom warnings\n const customWarningProps = [\n 'a11y',\n 'arrowType',\n 'showOnInit',\n 'size',\n 'target',\n 'touchHold',\n ];\n\n let didPassUnknownProp =\n !hasOwnProperty(nonPluginProps, prop) &&\n !includes(customWarningProps, prop);\n\n // Check if the prop exists in `plugins`\n if (didPassUnknownProp) {\n didPassUnknownProp =\n plugins.filter(plugin => plugin.name === prop).length === 0;\n }\n\n warnWhen(\n prop === 'target',\n [\n 'The `target` prop was removed in v5 and replaced with the delegate() addon',\n 'in order to conserve bundle size.',\n 'See: https://atomiks.github.io/tippyjs/addons/#event-delegation',\n ].join(' '),\n );\n\n warnWhen(\n prop === 'a11y',\n [\n 'The `a11y` prop was removed in v5. Make sure the element you are giving a',\n 'tippy to is natively focusable, such as