[
  {
    "path": ".config/.prettierignore",
    "content": "../build\n../dist\n../headless\n../website/public\n../website/.cache\n../animations\n../themes"
  },
  {
    "path": ".config/babel.config.js",
    "content": "module.exports = {\n  presets: [\n    ['@babel/env', {loose: true, useBuiltIns: 'entry', corejs: 3}],\n    '@babel/typescript',\n  ],\n  plugins: ['dev-expression'],\n  env: {\n    test: {\n      presets: [\n        ['@babel/env', {targets: {node: 'current'}}],\n        '@babel/typescript',\n      ],\n    },\n  },\n};\n"
  },
  {
    "path": ".config/eslint.config.js",
    "content": "module.exports = {\n  env: {\n    browser: true,\n    node: true,\n    jest: true,\n    es6: true,\n  },\n  globals: {\n    __DEV__: true,\n  },\n  extends: [\n    'eslint:recommended',\n    'plugin:@typescript-eslint/recommended',\n    'prettier',\n    'prettier/@typescript-eslint',\n  ],\n  plugins: ['@typescript-eslint'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: './tsconfig.json',\n  },\n  rules: {\n    'no-prototype-builtins': 'off',\n    '@typescript-eslint/no-use-before-define': ['error', {functions: false}],\n    '@typescript-eslint/no-non-null-assertion': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n    '@typescript-eslint/array-type': 'off',\n    '@typescript-eslint/no-empty-function': 'off',\n    '@typescript-eslint/ban-ts-ignore': 'off',\n    '@typescript-eslint/ban-ts-comment': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n  },\n  ignorePatterns: [\n    'node_modules',\n    'build',\n    'animations',\n    'themes',\n    'test',\n    'headless',\n    'website',\n    'dist',\n    'coverage',\n  ],\n};\n"
  },
  {
    "path": ".config/jest-puppeteer.config.js",
    "content": "require('dotenv').config();\n\nconst getConfig = require('jest-puppeteer-docker/lib/config');\nconst baseConfig = getConfig();\n\nmodule.exports = {\n  browser: 'chromium',\n  launch: {\n    dumpio: false,\n    headless: process.env.HEADLESS !== 'false',\n    args: ['--no-sandbox', '--disable-setuid-sandbox'],\n  },\n  server: {\n    command: 'yarn build:visual && yarn serve',\n    port: 5000,\n    launchTimeout: 20000,\n  },\n  ...baseConfig,\n};\n"
  },
  {
    "path": ".config/jest.config.js",
    "content": "// https://github.com/smooth-code/jest-puppeteer/issues/160#issuecomment-491975158\nprocess.env.JEST_PUPPETEER_CONFIG = require.resolve(\n  './jest-puppeteer.config.js'\n);\n\nconst jestPuppeteerDocker = require('jest-puppeteer-docker/jest-preset');\n\nmodule.exports = {\n  testMatch: ['<rootDir>/test/**/*.test.js'],\n  testTimeout: 30000,\n  globals: {\n    __DEV__: true,\n  },\n  setupFiles: ['dotenv/config'],\n  reporters: ['default', require.resolve('../test/image-reporter.js')],\n  ...jestPuppeteerDocker,\n  testEnvironment: 'jest-environment-jsdom-fourteen',\n  setupFilesAfterEnv: [\n    require.resolve('../test/setup.js'),\n    ...jestPuppeteerDocker.setupFilesAfterEnv,\n  ],\n};\n"
  },
  {
    "path": ".config/rollup.config.js",
    "content": "import babel from 'rollup-plugin-babel';\nimport json from 'rollup-plugin-json';\nimport resolve from 'rollup-plugin-node-resolve';\nimport cssOnly from 'rollup-plugin-css-only';\nimport replace from 'rollup-plugin-replace';\nimport sass from 'rollup-plugin-sass';\nimport serve from 'rollup-plugin-serve';\nimport livereload from 'rollup-plugin-livereload';\nimport {terser} from 'rollup-plugin-terser';\nimport pkg from '../package.json';\n\nconst NAMESPACE_PREFIX = process.env.NAMESPACE || 'tippy';\n\nconst plugins = {\n  babel: babel({extensions: ['.js', '.ts']}),\n  replaceNamespace: replace({\n    __NAMESPACE_PREFIX__: NAMESPACE_PREFIX,\n  }),\n  replaceEnvProduction: replace({\n    'process.env.NODE_ENV': JSON.stringify('production'),\n  }),\n  replaceEnvDevelopment: replace({\n    'process.env.NODE_ENV': JSON.stringify('development'),\n  }),\n  minify: terser(),\n  resolve: resolve({extensions: ['.js', '.ts']}),\n  css: cssOnly({output: false}),\n  json: json(),\n};\n\nconst prodCommonPlugins = [\n  plugins.replaceNamespace,\n  plugins.resolve,\n  plugins.json,\n];\n\nconst pluginConfigs = {\n  base: [plugins.babel, ...prodCommonPlugins],\n  bundle: [plugins.babel, ...prodCommonPlugins, plugins.css],\n  umdBase: [plugins.babel, plugins.replaceEnvDevelopment, ...prodCommonPlugins],\n  umdBaseMin: [\n    plugins.babel,\n    plugins.replaceEnvProduction,\n    ...prodCommonPlugins,\n    plugins.minify,\n  ],\n  umdBundle: [\n    plugins.babel,\n    plugins.replaceEnvDevelopment,\n    ...prodCommonPlugins,\n    plugins.css,\n  ],\n  umdBundleMin: [\n    plugins.babel,\n    plugins.replaceEnvProduction,\n    ...prodCommonPlugins,\n    plugins.minify,\n    plugins.css,\n  ],\n};\n\nconst banner = `/**!\n* tippy.js v${pkg.version}\n* (c) 2017-${new Date().getFullYear()} atomiks\n* MIT License\n*/`;\n\nconst commonUMDOutputOptions = {\n  globals: {'@popperjs/core': 'Popper'},\n  format: 'umd',\n  name: 'tippy',\n  sourcemap: true,\n};\n\nconst prodConfig = [\n  {\n    input: 'build/base-umd.js',\n    plugins: pluginConfigs.umdBase,\n    external: ['@popperjs/core'],\n    output: {\n      ...commonUMDOutputOptions,\n      file: 'dist/tippy.umd.js',\n      banner,\n    },\n  },\n  {\n    input: 'build/bundle-umd.js',\n    plugins: pluginConfigs.umdBundle,\n    external: ['@popperjs/core'],\n    output: {\n      ...commonUMDOutputOptions,\n      file: 'dist/tippy-bundle.umd.js',\n      banner,\n    },\n  },\n  {\n    input: 'build/base-umd.js',\n    plugins: pluginConfigs.umdBaseMin,\n    external: ['@popperjs/core'],\n    output: {\n      ...commonUMDOutputOptions,\n      file: 'dist/tippy.umd.min.js',\n    },\n  },\n  {\n    input: 'build/bundle-umd.js',\n    plugins: pluginConfigs.umdBundleMin,\n    external: ['@popperjs/core'],\n    output: {\n      ...commonUMDOutputOptions,\n      file: 'dist/tippy-bundle.umd.min.js',\n    },\n  },\n  {\n    input: 'build/base.js',\n    plugins: pluginConfigs.bundle,\n    external: ['@popperjs/core'],\n    output: {\n      file: 'dist/tippy.esm.js',\n      format: 'esm',\n      banner,\n      sourcemap: true,\n    },\n  },\n  {\n    input: 'build/headless.js',\n    plugins: pluginConfigs.base,\n    external: ['@popperjs/core'],\n    output: {\n      file: 'headless/dist/tippy-headless.esm.js',\n      format: 'esm',\n      banner,\n      sourcemap: true,\n    },\n  },\n  {\n    input: 'build/base.js',\n    plugins: pluginConfigs.bundle,\n    external: ['@popperjs/core'],\n    output: {\n      file: 'dist/tippy.cjs.js',\n      format: 'cjs',\n      exports: 'named',\n      banner,\n      sourcemap: true,\n    },\n  },\n  {\n    input: 'build/headless.js',\n    plugins: pluginConfigs.base,\n    external: ['@popperjs/core'],\n    output: {\n      file: 'headless/dist/tippy-headless.cjs.js',\n      format: 'cjs',\n      exports: 'named',\n      banner,\n      sourcemap: true,\n    },\n  },\n  {\n    input: 'build/headless-umd.js',\n    plugins: pluginConfigs.umdBase,\n    external: ['@popperjs/core'],\n    output: {\n      ...commonUMDOutputOptions,\n      file: 'headless/dist/tippy-headless.umd.js',\n    },\n  },\n  {\n    input: 'build/headless-umd.js',\n    plugins: pluginConfigs.umdBaseMin,\n    external: ['@popperjs/core'],\n    output: {\n      ...commonUMDOutputOptions,\n      file: 'headless/dist/tippy-headless.umd.min.js',\n    },\n  },\n];\n\n// Calling the `serve()` plugin causes the process to hang, so we need to delay\n// its evaluation\nconst configs = {\n  dev: () => ({\n    input: 'test/visual/tests.js',\n    plugins: [\n      plugins.babel,\n      plugins.json,\n      plugins.resolve,\n      replace({__DEV__: 'true'}),\n      plugins.replaceEnvDevelopment,\n      sass({output: true}),\n      serve({\n        contentBase: 'test/visual',\n        port: 1234,\n      }),\n      livereload(),\n    ],\n    output: {\n      file: 'test/visual/dist/bundle.js',\n      format: 'iife',\n    },\n  }),\n  test: () => ({\n    input: 'test/visual/tests.js',\n    plugins: [\n      plugins.babel,\n      plugins.json,\n      plugins.resolve,\n      replace({__DEV__: 'true'}),\n      plugins.replaceEnvDevelopment,\n      sass({output: true}),\n    ],\n    output: {\n      file: 'test/visual/dist/bundle.js',\n      format: 'iife',\n    },\n  }),\n};\n\nconst func = configs[process.env.NODE_ENV];\n\nexport default func ? func() : prodConfig;\n"
  },
  {
    "path": ".editorconfig",
    "content": "# https://editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [atomiks]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: 🐞 Bug report\nabout: Something is broken\ntitle: ''\nlabels: \"\\U0001F41B bug, \\U0001F6A7 unconfirmed\"\nassignees: ''\n---\n\n## Bug description\n\nA clear and concise description of what the bug is.\n\n## Reproduction\n\n<!-- Please create a CodePen to reproduce the bug. It can be difficult to understand the problem otherwise. It should be reproduced exclusively using Tippy.js on CodePen. -->\n\nCodePen link: https://codepen.io/atomiks/pen/yvwQyZ\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: 👋 Stack Overflow\n    url: https://stackoverflow.com/questions/tagged/tippyjs\n    about: Having trouble with Tippy? Try asking on Stack Overflow!\n  - name: 💬 Discussions\n    url: https://github.com/atomiks/tippyjs/discussions\n    about: Talk with others about Tippy, its usage and future!\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: ✨ Feature request\nabout: Suggest a feature\ntitle: ''\nlabels: \"\\U0001F48E enhancement\"\nassignees: ''\n---\n\n## Problem\n\nA clear and concise description of what the problem is.\n\n## Solution\n\nA clear and concise description of what you want to happen.\n"
  },
  {
    "path": ".github/workflows/cd.yml",
    "content": "name: CD\non: [push]\nenv:\n  CI: true\n\njobs:\n  publish:\n    if:\n      ${{ startsWith(github.event.commits[0].message, 'docs:') ||\n      startsWith(github.event.commits[0].message, 'release:') }}\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: ./website\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n      - name: Build\n        run: |\n          npm install\n          npm run clean\n          npm run build:ci\n      - name: Deploy to GitHub Pages\n        uses: crazy-max/ghaction-github-pages@v2\n        with:\n          target_branch: gh-pages\n          build_dir: ./website/public\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non: [push, pull_request]\nenv:\n  CI: true\n  PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true\n\njobs:\n  checks:\n    name: Linting and Type checking\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v1\n      - run: npm install\n      - run: npm run lint\n      - run: npm run test:types\n\n  dom-tests:\n    name: Unit and Integration\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v1\n      - uses: mujo-code/puppeteer-headful@master\n      - run: npm install\n      - run: npm run test:dom\n\n  functional-tests:\n    name: Chromium Functional\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v1\n      - uses: mujo-code/puppeteer-headful@master\n      - run: npm install\n      - run: npm run test:functional\n        env:\n          PUPPETEER_BROWSER: chromium\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\ncoverage/\n.devserver/\nnode_modules/\ndist/\n/themes\n/animations\nindex.d.ts\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017-present atomiks\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "MIGRATION_GUIDE.md",
    "content": "# Migration Guide\n\n- [5.x to 6.x](#5x-to-6x)\n- [4.x to 5.x](#4x-to-5x)\n\n---\n\n# 5.x to 6.x\n\nPopper.js was updated to v2. The `instance.popperInstance` and `popperOptions`\nAPIs have changed. You can\n[view its documentation here](https://popper.js.org/docs/v2/).\n\n## Imports\n\n`iife` was replaced with `umd` (Rollup chunking has been removed).\n\n## HTML Content\n\nTo protect against XSS by default, `allowHTML` is now `false` by default. If\nyou're passing strings of HTML to `content`, you must set `allowHTML: true`.\n\n## Themes\n\n### If you were creating custom themes\n\n<details>\n<summary>View details</summary>\n\n`.tippy-tooltip` has become `.tippy-box`, and theming is done via an attribute\nnow, to match the other props.\n\nThe following:\n\n```css\n.tippy-tooltip.tomato-theme {\n  background-color: tomato;\n}\n```\n\nHas become:\n\n```css\n.tippy-box[data-theme~='tomato'] {\n  background-color: tomato;\n}\n```\n\n> The `~=` attribute operator allows you to specify mutliple theme names like\n> before with class names.\n\nFor `.tippy-arrow`, you'll need to specify its color on the `::before`\npseudo-element.\n\nThe following:\n\n```css\n.tippy-tooltip.tomato-theme[data-placement^='top'] > .tippy-arrow {\n  border-top-color: tomato;\n}\n```\n\nHas become:\n\n```css\n.tippy-box[data-theme~='tomato'][data-placement^='top'] > .tippy-arrow::before {\n  border-top-color: tomato;\n}\n```\n\nIn addition, if you were altering the pixel values, it may need to be adjusted.\n\nIn addition, Popper 2 changed some attribute names.\n\nThis:\n\n```css\n.tippy-tooltip[data-out-of-boundaries] {\n  visibility: hidden;\n}\n```\n\nHas become:\n\n```css\n.tippy-box[data-reference-hidden] {\n  visibility: hidden;\n}\n```\n\n</details>\n\n### If you were targeting `.tippy-popper`\n\n<details>\n<summary>View details</summary>\n\n`.tippy-popper` is no longer a selector, and is considered an implementation\ndetail for the most part now. `[data-tippy-root]` attribute selector replaces it\nif necessary.\n\n</details>\n\n## Instance\n\n### If you were using `instance.popperChildren`\n\n<details>\n<summary>View details</summary>\n\nThis no longer exists due to the user's ability to specify any structured DOM\nwith `render()` (Headless Tippy).\n\nTo access the `.tippy-box` element with the default render function\n(`.tippy-tooltip` in v5):\n\n```js\nconst box = instance.popper.firstElementChild;\n```\n\n</details>\n\n## Methods\n\n### If you were using `.show()` or `.hide()` with a duration argument\n\n<details>\n<summary>View details</summary>\n\nThese no longer take a duration argument. Instead, use\n`.setProps({duration: ...})` before calling them if necessary.\n\nTo replicate `.hide(0)`:\n\n```js\ninstance.unmount();\n```\n\n</details>\n\n## Props\n\n### If you were using `boundary`\n\n<details>\n<summary>View details</summary>\n\nOften, this was to solve a problem in Popper 1, where you set\n`boundary: \"window\"`. This is no longer necessary. If you'd like to change it\nanyway, you can set it in `popperOptions`:\n\n```js\ntippy(targets, {\n  popperOptions: {\n    modifiers: [\n      {\n        name: 'preventOverflow',\n        options: {\n          // equivalent to boundary: 'window' in v1, usually NOT necessary in v2\n          rootBoundary: 'document',\n        },\n      },\n    ],\n  },\n});\n```\n\n</details>\n\n### If you were using `distance` or `offset`\n\n<details>\n<summary>View details</summary>\n\nThese have been merged into a single `offset` prop, to match Popper 2's new API.\n\nThe following:\n\n```js\ntippy(targets, {\n  offset: 5,\n  distance: 10,\n});\n```\n\nHas become:\n\n```js\ntippy(targets, {\n  offset: [5, 10],\n});\n```\n\nThis tuple also directly replaces `offset: \"5, 10\"`.\n\n</details>\n\n### If you were using `flip`, `flipBehavior`, or `flipOnUpdate`\n\n<details>\n<summary>View details</summary>\n\nAll of these have been removed. To configure these, specify them in\n`popperOptions`:\n\n```js\ntippy(targets, {\n  placement: 'bottom',\n  popperOptions: {\n    modifiers: [\n      {\n        name: 'flip',\n        // flip: false\n        enabled: false,\n        options: {\n          // flipBehavior: ['bottom', 'right', 'top']\n          fallbackPlacements: ['right', 'top'],\n        },\n      },\n    ],\n  },\n});\n```\n\n`flipOnUpdate` has no replacement yet. It's always `true`.\n\n</details>\n\n### If you were using `aria`\n\n<details>\n<summary>View details</summary>\n\nThis has become an object to allow for better configurability. By default Tippy\nwill infer what to use (`auto`), but this can be overridden.\n\nTypes:\n\n```ts\ninterface Props {\n  // ...\n  aria: {\n    content?: 'auto' | 'describedby' | 'labelledby' | null;\n    expanded?: 'auto' | boolean;\n  };\n}\n```\n\n```js\ntippy(targets, {\n  aria: {\n    // `null` when interactive is enabled\n    content: 'auto', // `aria-*` attribute\n    // `true` when interactive is enabled\n    expanded: 'auto', // `aria-expanded` attribute\n  },\n});\n```\n\n</details>\n\n### If you were using `multiple` or relying on its behavior\n\n<details>\n<summary>View details</summary>\n\nDue to static typing issues, it's been removed. Calling `tippy()` again on the\nsame element will now always create a new tippy for it. Avoid calling `tippy()`\nmultiple times on the same reference if you don't want multiple tippies created\nfor it.\n\n</details>\n\n### If you were using `updateDuration`\n\n<details>\n<summary>View details</summary>\n\nIt's now `moveTransition`, which is a whole transition string. This allows you\nto specify the easing function.\n\n```js\ntippy(targets, {\n  moveTransition: 'transform 0.2s ease-out',\n});\n```\n\n</details>\n\n### If you were using `lazy`\n\n<details>\n<summary>View details</summary>\n\nIt's been removed. The `popperInstance` is now created and destroyed on\nmount/unmount. If you were using this for ReferenceObjects, see below.\n\nThe following:\n\n```js\ntippy(targets, {\n  lazy: false,\n  onCreate(instance) {\n    instance.popperInstance.reference = {\n      clientWidth: 0,\n      clientHeight: 0,\n      getBoundingClientRect() {\n        return {\n          // ...\n        };\n      },\n    };\n  },\n});\n```\n\nHas become a single prop:\n\n```js\ntippy(targets, {\n  getReferenceClientRect: () => ({\n    // ...\n  }),\n});\n```\n\nThis implements Popper 2's\n[Virtual Elements API](https://popper.js.org/docs/v2/virtual-elements/).\n\n</details>\n\n## IE11\n\nIE11 is not supported by default anymore, but can be polyfilled. View the\nBrowser Support page on the documentation for details.\n\n---\n\n# 4.x to 5.x\n\n### Node\n\nMake sure you have DEV warnings enabled by setting `NODE_ENV=development` and\nensuring your bundler replaces `process.env.NODE_ENV` with the string\n`\"development\"`.\n\n- **webpack**: via `mode` option\n- **Rollup**: via `rollup-plugin-replace`\n- **Parcel**: automatic\n- **Browserify/Gulp/Grunt/others**:\n  [View details](https://vuejs.org/v2/guide/deployment.html#With-Build-Tools)\n\n### Browser\n\n```html\n<script src=\"https://unpkg.com/popper.js@1\"></script>\n<!-- Specify development file -->\n<script src=\"https://unpkg.com/tippy.js@5/dist/tippy-bundle.iife.js\"></script>\n<!-- \nWhen you're finished, you can remove everything after @5 \n(or when deploying for production) \n<script src=\"https://unpkg.com/tippy.js@5\"></script>\n-->\n```\n\n## Imports\n\nPreviously, the default import injected the CSS stylesheet into `<head>`:\n\n```js\nimport tippy from 'tippy.js';\n```\n\nIn v5, this import is now side-effect free to work better with dependencies when\nusers have CSP enabled or using frameworks that control the `<head>`.\n\nYou should import the CSS separately:\n\n```js\nimport tippy from 'tippy.js';\nimport 'tippy.js/dist/tippy.css';\n```\n\nYou can however opt-in to use the injected CSS version, just like v4:\n\n```js\n// Just like v4\nimport tippy from 'tippy.js/dist/tippy-bundle.esm';\n\n// Or CommonJS:\nconst tippy = require('tippy.js/dist/tippy-bundle.cjs');\n```\n\n## `data-tippy` attribute\n\nThis technique of auto initialization was removed to keep the import side-effect\nfree. Initializing via the `tippy()` constructor is required.\n\n## Animations\n\n### If you want the `animateFill` effect back (it's no longer default)\n\n<details>\n<summary>View details</summary>\n\nNode:\n\n```js\nimport tippy, {animateFill} from 'tippy.js';\nimport 'tippy.js/dist/tippy.css';\n\n// These stylesheets are required for it to work\nimport 'tippy.js/dist/backdrop.css';\nimport 'tippy.js/animations/shift-away.css';\n\ntippy(targets, {\n  animateFill: true,\n  plugins: [animateFill],\n});\n```\n\nBrowser:\n\n```html\n<link rel=\"stylesheet\" href=\"https://unpkg.com/tippy.js@5/dist/backdrop.css\" />\n<link\n  rel=\"stylesheet\"\n  href=\"https://unpkg.com/tippy.js@5/animations/shift-away.css\"\n/>\n<script src=\"https://unpkg.com/popper.js@1\"></script>\n<script src=\"https://unpkg.com/tippy.js@5\"></script>\n<script>\n  tippy(targets, {\n    content: 'tooltip',\n    animateFill: true,\n  });\n</script>\n```\n\n</details>\n\n### If you were using default animations or creating custom animations\n\n<details>\n<summary>View details</summary>\n\n- Make sure your `visible` state has no translation (of 0px, instead of 10px\n  like before).\n- `shift-away`, `shift-toward`, `scale` and `perspective` need to be imported\n  separately now.\n\nNode:\n\n```js\nimport 'tippy.js/animations/scale.css';\n```\n\nBrowser:\n\n```html\n<link\n  rel=\"stylesheet\"\n  href=\"https://unpkg.com/tippy.js@5/animations/scale.css\"\n/>\n```\n\n</details>\n\n## Props\n\n### If you were using `interactive: true`\n\n<details>\n<summary>View details</summary>\n\nWhen using `interactive: true`, the tippy may be invisible or appear cut off if\nyour reference element is in a container with:\n\n- `position` (e.g. fixed, absolute, sticky)\n- `overflow: hidden`\n\nTo fix add the following prop (recommended):\n\n```js\ntippy(reference, {\n  // ...\n  popperOptions: {\n    positionFixed: true,\n  },\n});\n```\n\nOr, if the above causes issues:\n\n```js\ntippy(reference, {\n  // ...\n  appendTo: document.body,\n});\n```\n\n⚠️ For the latter, you need to be employing focus mangement for accessibility.\n\n</details>\n\n### If you were using `arrowType: 'round'`\n\n<details>\n<summary>View details</summary>\n\nImport the `svg-arrow` CSS, and the `roundArrow` string, and use the `arrow`\nprop instead.\n\nNode:\n\n```js\nimport {roundArrow} from 'tippy.js';\nimport 'tippy.js/dist/svg-arrow.css';\n\ntippy(targets, {\n  arrow: roundArrow,\n});\n```\n\nBrowser:\n\n```html\n<link rel=\"stylesheet\" href=\"https://unpkg.com/tippy.js@5/dist/svg-arrow.css\" />\n<script>\n  tippy(targets, {\n    arrow: tippy.roundArrow,\n  });\n</script>\n```\n\n</details>\n\n### If you were using `followCursor`\n\n<details>\n<summary>View details</summary>\n\nNode:\n\n```js\nimport tippy, {followCursor} from 'tippy.js';\n\ntippy('button', {\n  followCursor: true,\n  plugins: [followCursor],\n});\n```\n\nBrowser:\n\n(Works as before.)\n\n</details>\n\n### If you were using `sticky`\n\n<details>\n<summary>View details</summary>\n\nNode:\n\n```js\nimport tippy, {sticky} from 'tippy.js';\n\ntippy('button', {\n  sticky: true,\n  plugins: [sticky],\n});\n```\n\nBrowser:\n\n(Works as before.)\n\n</details>\n\n### If you were using `target`\n\n<details>\n<summary>View details</summary>\n\nUse `delegate()`.\n\nNode:\n\n```js\nimport tippy, {delegate} from 'tippy.js';\n\ndelegate('#parent', {target: 'button'});\n```\n\nBrowser:\n\n```html\n<script src=\"https://unpkg.com/popper.js@1\"></script>\n<script src=\"https://unpkg.com/tippy.js@5\"></script>\n<script>\n  tippy.delegate('#parent', {target: 'button'});\n</script>\n```\n\n</details>\n\n### If you were using `showOnInit`\n\n<details>\n<summary>View details</summary>\n\nIt's now named `showOnCreate`, to match the `onCreate` lifecycle hook\n\n</details>\n\n### If you were using `size`\n\n<details>\n<summary>View details</summary>\n\nIt's been removed, as it's more flexible to just use a theme and specify the\n`font-size` and `padding` properties.\n\n</details>\n\n### If you were using `touchHold`\n\n<details>\n<summary>View details</summary>\n\nUse `touch: \"hold\"` instead.\n\n</details>\n\n### If you were using `a11y`\n\n<details>\n<summary>View details</summary>\n\nEnsure non-focusable elements have `tabindex=\"0\"` added to them. Otherwise, use\nnatively focusable elements everywhere possible.\n\n</details>\n\n### If you were using `wait`\n\n<details>\n<summary>View details</summary>\n\nUse the `onTrigger` and `onUntrigger` lifecycles and temporarily disable the\ninstance.\n\n```js\ntippy(targets, {\n  onTrigger(instance) {\n    instance.disable();\n    // Make your async call...\n    // Once finished:\n    instance.enable();\n    instance.show();\n  },\n  onUntrigger(instance) {\n    // Re-enable the instance here depending on the async cancellation logic\n    instance.enable();\n  },\n});\n```\n\n</details>\n\n## Instances\n\n### If you were using `instance.set()`\n\n<details>\n<summary>View details</summary>\n\n```diff\n- instance.set({});\n+ instance.setProps({});\n```\n\n</details>\n\n## Static methods\n\n### If you were using `tippy.setDefaults()`\n\n<details>\n<summary>View details</summary>\n\n```diff\n- tippy.defaults;\n+ tippy.defaultProps;\n```\n\n```diff\n- tippy.setDefaults({});\n+ tippy.setDefaultProps({});\n```\n\n</details>\n\n### If you were using `tippy.hideAll()`\n\n<details>\n<summary>View details</summary>\n\nIn ESM/CJS contexts, it's no longer attached to `tippy`\n\nNode:\n\n```js\nimport {hideAll} from 'tippy.js';\n\nhideAll();\n```\n\nBrowser:\n\n(Works as before.)\n\n</details>\n\n### If you were using `tippy.group()`\n\n<details>\n<summary>View details</summary>\n\nUse `createSingleton()`.\n\nNode:\n\n```js\nimport tippy, {createSingleton} from 'tippy.js';\n\ncreateSingleton(tippy('button'), {delay: 1000});\n```\n\nBrowser:\n\n```html\n<script src=\"https://unpkg.com/popper.js@1\"></script>\n<script src=\"https://unpkg.com/tippy.js@5\"></script>\n<script>\n  tippy.createSingleton(tippy('button'), {delay: 1000});\n</script>\n```\n\n</details>\n\n## Themes\n\n### If you were using the included themes\n\n<details>\n<summary>View details</summary>\n\n- `google` is now `material`\n\n</details>\n\n### If you were creating custom themes\n\n<details>\n<summary>View details</summary>\n\n- `[x-placement]` attribute is now `[data-placement]`\n- `[x-out-of-boundaries]` is now `[data-out-of-boundaries]`\n- `.tippy-roundarrow` is now `.tippy-svg-arrow`\n- `.tippy-tooltip` no longer has `padding` on it, rather the `.tippy-content`\n  selector does.\n- `.tippy-tooltip` no longer has `text-align: center`\n\n</details>\n\n## Other\n\n### If you were using virtual reference objects\n\n<details>\n<summary>View details</summary>\n\nSet `instance.popperInstance.reference = ReferenceObject` in the `onTrigger`\nlifecycle, or `onCreate` with `lazy: false`.\n\n</details>\n\n## Types\n\n<details>\n<summary>View details</summary>\n\n- `Props` is not `Partial` anymore, it's `Required`\n- `Options` removed (use `Partial<Props>`)\n- `BasicPlacement` renamed to `BasePlacement`\n\n</details>\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <img alt=\"Tippy.js logo\" src=\"https://github.com/atomiks/tippyjs/raw/master/logo.png\" height=\"117\" />\n</div>\n\n<div align=\"center\">\n  <h1>Tippy.js</h1>\n  <p>The complete tooltip, popover, dropdown, and menu solution for the web</p>\n  <a href=\"https://www.npmjs.com/package/tippy.js\">\n   <img src=\"https://img.shields.io/npm/dm/tippy.js.svg?color=%235599ff&style=for-the-badge\" alt=\"npm Downloads per Month\">\n  <a>\n  <a href=\"https://github.com/atomiks/tippyjs/blob/master/LICENSE\">\n    <img src=\"https://img.shields.io/npm/l/tippy.js.svg?color=%23c677cf&style=for-the-badge\" alt=\"MIT License\">\n  </a>\n  <br>\n  <br>\n</div>\n\n## Demo and Documentation\n\n➡️ **[View the latest demo & docs here](https://atomiks.github.io/tippyjs/)**\n\n[Migration Guide](https://github.com/atomiks/tippyjs/blob/master/MIGRATION_GUIDE.md)\n\n## Installation\n\n### Package Managers\n\n```bash\n# npm\nnpm i tippy.js\n\n# Yarn\nyarn add tippy.js\n```\n\nImport the `tippy` constructor and the core CSS:\n\n```js\nimport tippy from 'tippy.js';\nimport 'tippy.js/dist/tippy.css';\n```\n\n### CDN\n\n```html\n<script src=\"https://unpkg.com/@popperjs/core@2\"></script>\n<script src=\"https://unpkg.com/tippy.js@6\"></script>\n```\n\nThe core CSS comes bundled with the default unpkg import.\n\n## Usage\n\nFor detailed usage information,\n[visit the docs](https://atomiks.github.io/tippyjs/v6/getting-started/).\n\n## Component Wrappers\n\n- React: [@tippyjs/react](https://github.com/atomiks/tippyjs-react) (official)\n- Ember: [ember-tippy](https://github.com/nag5000/ember-tippy) (unofficial)\n\n## License\n\nMIT\n"
  },
  {
    "path": "build/animations/perspective-extreme.js",
    "content": "import '../../src/scss/animations/perspective-extreme.scss';\n"
  },
  {
    "path": "build/animations/perspective-subtle.js",
    "content": "import '../../src/scss/animations/perspective-subtle.scss';\n"
  },
  {
    "path": "build/animations/perspective.js",
    "content": "import '../../src/scss/animations/perspective.scss';\n"
  },
  {
    "path": "build/animations/scale-extreme.js",
    "content": "import '../../src/scss/animations/scale-extreme.scss';\n"
  },
  {
    "path": "build/animations/scale-subtle.js",
    "content": "import '../../src/scss/animations/scale-subtle.scss';\n"
  },
  {
    "path": "build/animations/scale.js",
    "content": "import '../../src/scss/animations/scale.scss';\n"
  },
  {
    "path": "build/animations/shift-away-extreme.js",
    "content": "import '../../src/scss/animations/shift-away-extreme.scss';\n"
  },
  {
    "path": "build/animations/shift-away-subtle.js",
    "content": "import '../../src/scss/animations/shift-away-subtle.scss';\n"
  },
  {
    "path": "build/animations/shift-away.js",
    "content": "import '../../src/scss/animations/shift-away.scss';\n"
  },
  {
    "path": "build/animations/shift-toward-extreme.js",
    "content": "import '../../src/scss/animations/shift-toward-extreme.scss';\n"
  },
  {
    "path": "build/animations/shift-toward-subtle.js",
    "content": "import '../../src/scss/animations/shift-toward-subtle.scss';\n"
  },
  {
    "path": "build/animations/shift-toward.js",
    "content": "import '../../src/scss/animations/shift-toward.scss';\n"
  },
  {
    "path": "build/base-umd.js",
    "content": "import tippy, {hideAll} from '../src';\nimport createSingleton from '../src/addons/createSingleton';\nimport delegate from '../src/addons/delegate';\nimport animateFill from '../src/plugins/animateFill';\nimport followCursor from '../src/plugins/followCursor';\nimport inlinePositioning from '../src/plugins/inlinePositioning';\nimport sticky from '../src/plugins/sticky';\nimport {ROUND_ARROW} from '../src/constants';\nimport {render} from '../src/template';\n\ntippy.setDefaultProps({\n  plugins: [animateFill, followCursor, inlinePositioning, sticky],\n  render,\n});\n\ntippy.createSingleton = createSingleton;\ntippy.delegate = delegate;\ntippy.hideAll = hideAll;\ntippy.roundArrow = ROUND_ARROW;\n\nexport default tippy;\n"
  },
  {
    "path": "build/base.js",
    "content": "import tippy from '../src';\nimport {render} from '../src/template';\n\ntippy.setDefaultProps({render});\n\nexport {default, hideAll} from '../src';\nexport {default as createSingleton} from '../src/addons/createSingleton';\nexport {default as delegate} from '../src/addons/delegate';\nexport {default as animateFill} from '../src/plugins/animateFill';\nexport {default as followCursor} from '../src/plugins/followCursor';\nexport {default as inlinePositioning} from '../src/plugins/inlinePositioning';\nexport {default as sticky} from '../src/plugins/sticky';\nexport {ROUND_ARROW as roundArrow} from '../src/constants';\n"
  },
  {
    "path": "build/bundle-umd.js",
    "content": "import css from '../dist/tippy.css';\nimport {injectCSS} from '../src/css';\nimport {isBrowser} from '../src/browser';\nimport tippy, {hideAll} from '../src';\nimport createSingleton from '../src/addons/createSingleton';\nimport delegate from '../src/addons/delegate';\nimport animateFill from '../src/plugins/animateFill';\nimport followCursor from '../src/plugins/followCursor';\nimport inlinePositioning from '../src/plugins/inlinePositioning';\nimport sticky from '../src/plugins/sticky';\nimport {ROUND_ARROW} from '../src/constants';\nimport {render} from '../src/template';\n\nif (isBrowser) {\n  injectCSS(css);\n}\n\ntippy.setDefaultProps({\n  plugins: [animateFill, followCursor, inlinePositioning, sticky],\n  render,\n});\n\ntippy.createSingleton = createSingleton;\ntippy.delegate = delegate;\ntippy.hideAll = hideAll;\ntippy.roundArrow = ROUND_ARROW;\n\nexport default tippy;\n"
  },
  {
    "path": "build/css/backdrop.js",
    "content": "import '../../src/scss/backdrop.scss';\n"
  },
  {
    "path": "build/css/border.js",
    "content": "import '../../src/scss/border.scss';\n"
  },
  {
    "path": "build/css/svg-arrow.js",
    "content": "import '../../src/scss/svg-arrow.scss';\n"
  },
  {
    "path": "build/css/tippy.js",
    "content": "import '../../src/scss/index.scss';\n"
  },
  {
    "path": "build/headless-umd.js",
    "content": "import tippy, {hideAll} from '../src';\nimport createSingleton from '../src/addons/createSingleton';\nimport delegate from '../src/addons/delegate';\nimport animateFill from '../src/plugins/animateFill';\nimport followCursor from '../src/plugins/followCursor';\nimport inlinePositioning from '../src/plugins/inlinePositioning';\nimport sticky from '../src/plugins/sticky';\nimport {ROUND_ARROW} from '../src/constants';\n\ntippy.setDefaultProps({\n  plugins: [animateFill, followCursor, inlinePositioning, sticky],\n  animation: false,\n});\n\ntippy.createSingleton = createSingleton;\ntippy.delegate = delegate;\ntippy.hideAll = hideAll;\ntippy.roundArrow = ROUND_ARROW;\n\nexport default tippy;\n"
  },
  {
    "path": "build/headless.js",
    "content": "import tippy from '../src';\n\nexport {hideAll} from '../src';\nexport {default as createSingleton} from '../src/addons/createSingleton';\nexport {default as delegate} from '../src/addons/delegate';\nexport {default as animateFill} from '../src/plugins/animateFill';\nexport {default as followCursor} from '../src/plugins/followCursor';\nexport {default as inlinePositioning} from '../src/plugins/inlinePositioning';\nexport {default as sticky} from '../src/plugins/sticky';\nexport {ROUND_ARROW as roundArrow} from '../src/constants';\n\ntippy.setDefaultProps({animation: false});\n\nexport default tippy;\n"
  },
  {
    "path": "build/index.js",
    "content": "// This file builds the CSS dist files. The main `rollup.config.js` builds the\n// JS dist files.\n\n/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require('fs');\nconst {rollup} = require('rollup');\nconst babel = require('rollup-plugin-babel');\nconst sass = require('rollup-plugin-sass');\nconst postcss = require('postcss');\nconst autoprefixer = require('autoprefixer');\nconst cssnano = require('cssnano');\nconst resolve = require('rollup-plugin-node-resolve');\nconst json = require('rollup-plugin-json');\nconst cssOnly = require('rollup-plugin-css-only');\nconst replace = require('rollup-plugin-replace');\n\nconst NAMESPACE_PREFIX = process.env.NAMESPACE || 'tippy';\nconst THEME = process.env.THEME;\n\nconst BASE_OUTPUT_CONFIG = {\n  name: 'tippy',\n  globals: {'popper.js': 'Popper'},\n  sourcemap: true,\n};\n\nconst PLUGINS = {\n  babel: babel({\n    exclude: 'node_modules/**',\n    extensions: ['.js', '.ts'],\n  }),\n  replaceNamespace: replace({\n    __NAMESPACE_PREFIX__: NAMESPACE_PREFIX,\n  }),\n  resolve: resolve({extensions: ['.js', '.ts']}),\n  css: cssOnly({output: false}),\n  json: json(),\n};\n\nconst PLUGIN_CONFIG = [\n  PLUGINS.babel,\n  PLUGINS.replaceNamespace,\n  PLUGINS.resolve,\n  PLUGINS.json,\n  PLUGINS.css,\n];\n\nfunction createPluginSCSS(output, shouldInjectNodeEnvTheme = false) {\n  let data = `$namespace-prefix: ${NAMESPACE_PREFIX};`;\n\n  if (shouldInjectNodeEnvTheme && THEME) {\n    data += `@import './themes/${THEME}.scss';`;\n  }\n\n  return sass({\n    output,\n    options: {data},\n    processor(css) {\n      return postcss([autoprefixer, cssnano])\n        .process(css, {from: undefined})\n        .then((result) => result.css);\n    },\n  });\n}\n\nfunction createRollupConfig(inputFile, plugins) {\n  return {\n    input: `./build/${inputFile}`,\n    external: ['popper.js'],\n    plugins,\n  };\n}\n\nasync function build() {\n  // Create `index.d.ts` file from `src/types.ts`\n  fs.copyFileSync('./src/types.ts', './index.d.ts');\n\n  // Create base CSS files\n  for (const filename of fs.readdirSync(`./build/css`)) {\n    const cssConfig = createRollupConfig(\n      `css/${filename}`,\n      PLUGIN_CONFIG.concat(\n        createPluginSCSS(`./dist/${filename.replace('.js', '.css')}`, true)\n      )\n    );\n    const cssBundle = await rollup(cssConfig);\n    await cssBundle.write({\n      ...BASE_OUTPUT_CONFIG,\n      sourcemap: false,\n      format: 'umd',\n      file: './index.js',\n    });\n  }\n\n  // Themes + animations\n  for (const folder of ['themes', 'animations']) {\n    for (const filename of fs.readdirSync(`./build/${folder}`)) {\n      const filenameWithCSSExtension = filename.replace('.js', '.css');\n      const outputFile = `./${folder}/${filenameWithCSSExtension}`;\n\n      const config = createRollupConfig(\n        `${folder}/${filename}`,\n        PLUGIN_CONFIG.concat(createPluginSCSS(outputFile))\n      );\n      const bundle = await rollup(config);\n      await bundle.write({\n        ...BASE_OUTPUT_CONFIG,\n        format: 'umd',\n        sourcemap: false,\n        file: 'index.js',\n      });\n    }\n  }\n\n  fs.unlinkSync('./index.js');\n}\n\nbuild();\n"
  },
  {
    "path": "build/themes/light-border.js",
    "content": "import '../../src/scss/themes/light-border.scss';\n"
  },
  {
    "path": "build/themes/light.js",
    "content": "import '../../src/scss/themes/light.scss';\n"
  },
  {
    "path": "build/themes/material.js",
    "content": "import '../../src/scss/themes/material.scss';\n"
  },
  {
    "path": "build/themes/translucent.js",
    "content": "import '../../src/scss/themes/translucent.scss';\n"
  },
  {
    "path": "headless/package.json",
    "content": "{\n  \"name\": \"tippy-headless\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"description\": \"Headless rendering for Tippy.js\",\n  \"types\": \"../index.d.ts\",\n  \"main\": \"dist/tippy-headless.cjs.js\",\n  \"module\": \"dist/tippy-headless.esm.js\",\n  \"unpkg\": \"dist/tippy-headless.umd.min.js\",\n  \"sideEffects\": false,\n  \"files\": [\n    \"dist/\"\n  ],\n  \"author\": \"atomiks\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "index.test-d.ts",
    "content": "import {expectType} from 'tsd';\nimport tippy, {\n  Instance,\n  Props,\n  Tippy,\n  LifecycleHooks,\n  delegate,\n  DelegateInstance,\n  createSingleton,\n  Plugin,\n  animateFill,\n  followCursor,\n  inlinePositioning,\n  sticky,\n  hideAll,\n  roundArrow,\n  CreateSingletonInstance,\n} from './src/types';\n\ninterface CustomProps {\n  custom: number;\n}\n\ntype FilteredProps = CustomProps &\n  Omit<Props, keyof CustomProps | keyof LifecycleHooks>;\n\ntype ExtendedProps = FilteredProps & LifecycleHooks<FilteredProps>;\n\ndeclare const tippyExtended: Tippy<ExtendedProps>;\n\nconst singleTarget = document.createElement('div');\nconst mulitpleTargets = document.querySelectorAll('div');\n\nexpectType<Instance>(tippy(singleTarget));\nexpectType<Instance>(tippy(singleTarget, {content: 'hello'}));\n\nexpectType<Instance[]>(tippy(mulitpleTargets));\nexpectType<Instance[]>(tippy(mulitpleTargets, {content: 'hello'}));\n\nexpectType<DelegateInstance>(delegate(singleTarget, {target: '.child'}));\nexpectType<DelegateInstance>(\n  delegate(singleTarget, {target: '.child', content: 'hello'})\n);\n\nexpectType<DelegateInstance[]>(delegate(mulitpleTargets, {target: '.child'}));\nexpectType<DelegateInstance[]>(\n  delegate(mulitpleTargets, {target: '.child', content: 'hello'})\n);\n\nconst tippyInstances = [tippy(singleTarget), tippy(singleTarget)];\nconst singleton = createSingleton(tippyInstances);\n\nexpectType<CreateSingletonInstance>(createSingleton(tippyInstances));\nexpectType<CreateSingletonInstance>(\n  createSingleton(tippyInstances, {content: 'hello'})\n);\nexpectType<CreateSingletonInstance>(\n  createSingleton(tippyInstances, {overrides: ['content']})\n);\nexpectType<(instances: Instance<any>[]) => void>(singleton.setInstances);\n\n// TODO: I want to assert that these *don't* error, but `tsd` does not provide\n// such a function(?)\ncreateSingleton(tippyExtended('button'));\nsingleton.setInstances(tippyExtended('button'));\n\nexpectType<Instance>(\n  tippy(singleTarget, {\n    plugins: [animateFill, followCursor, inlinePositioning, sticky],\n  })\n);\n\nconst customPlugin: Plugin<ExtendedProps> = {\n  name: 'custom',\n  defaultValue: 42,\n  fn(instance) {\n    expectType<Instance<ExtendedProps>>(instance);\n    expectType<number>(instance.props.custom);\n\n    return {};\n  },\n};\n\nexpectType<Instance<ExtendedProps>>(\n  tippyExtended(singleTarget, {\n    custom: 42,\n    plugins: [customPlugin],\n  })\n);\n\nexpectType<void>(hideAll({duration: 50, exclude: tippy(singleTarget)}));\n\nexpectType<string>(roundArrow);\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"tippy.js\",\n  \"version\": \"6.3.7\",\n  \"description\": \"The complete tooltip, popover, dropdown, and menu solution for the web\",\n  \"main\": \"dist/tippy.cjs.js\",\n  \"module\": \"dist/tippy.esm.js\",\n  \"unpkg\": \"dist/tippy-bundle.umd.min.js\",\n  \"types\": \"index.d.ts\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"author\": \"atomiks\",\n  \"contributors\": [\n    \"Brett Zamir\"\n  ],\n  \"license\": \"MIT\",\n  \"bugs\": \"https://github.com/atomiks/tippyjs/issues\",\n  \"homepage\": \"https://atomiks.github.io/tippyjs/\",\n  \"keywords\": [\n    \"tooltip\",\n    \"popover\",\n    \"popper\",\n    \"dropdown\",\n    \"popup\",\n    \"tippy\",\n    \"tippy.js\"\n  ],\n  \"files\": [\n    \"dist/\",\n    \"animations/\",\n    \"themes/\",\n    \"headless/\",\n    \"index.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/atomiks/tippyjs.git\"\n  },\n  \"scripts\": {\n    \"dev\": \"cross-env NODE_ENV=dev rollup -c .config/rollup.config.js --watch\",\n    \"build\": \"node build/index.js && rollup -c .config/rollup.config.js && bundlesize\",\n    \"build:visual\": \"cross-env NODE_ENV=test rollup -c .config/rollup.config.js\",\n    \"serve\": \"serve test/visual\",\n    \"test:dom\": \"jest unit integration --coverage\",\n    \"test:functional\": \"jest functional\",\n    \"test:types\": \"tsc && tsd\",\n    \"test\": \"yarn test:types && yarn test:dom && yarn test:functional\",\n    \"lint\": \"eslint . --ext .ts,.js\",\n    \"format\": \"prettier --write \\\"**/*.{js,ts,json,md,mdx,scss,css}\\\" --ignore-path .config/.prettierignore\",\n    \"clean\": \"rimraf dist/ themes/ animations/ coverage/ .devserver/ .cache/ ./index.d.ts\",\n    \"prepare\": \"yarn clean && yarn build\"\n  },\n  \"babel\": {\n    \"extends\": \"./.config/babel.config\"\n  },\n  \"jest\": {\n    \"preset\": \"./.config/jest.config\"\n  },\n  \"eslintConfig\": {\n    \"extends\": \"./.config/eslint.config\"\n  },\n  \"prettier\": {\n    \"singleQuote\": true,\n    \"bracketSpacing\": false,\n    \"proseWrap\": \"always\"\n  },\n  \"browserslist\": [\n    \"> 0.5%\",\n    \"not dead\",\n    \"not safari < 8\"\n  ],\n  \"bundlesize\": [\n    {\n      \"path\": \"dist/tippy-bundle.umd.min.js\",\n      \"maxSize\": \"10 kB\"\n    },\n    {\n      \"path\": \"headless/dist/tippy-headless.umd.min.js\",\n      \"maxSize\": \"10 kB\"\n    },\n    {\n      \"path\": \"dist/tippy.umd.min.js\",\n      \"maxSize\": \"10 kB\"\n    },\n    {\n      \"path\": \"dist/tippy.css\",\n      \"maxSize\": \"5 kB\"\n    }\n  ],\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\"\n    }\n  },\n  \"lint-staged\": {\n    \"src/**/*.ts\": [\n      \"jest --findRelatedTests\",\n      \"eslint . --ext .ts,.js\",\n      \"git add\"\n    ],\n    \"{build,src,test,website/src}/**/*.{ts,js,json,css,scss,md}\": [\n      \"prettier --write\",\n      \"git add\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.8.3\",\n    \"@babel/preset-env\": \"^7.8.3\",\n    \"@babel/preset-typescript\": \"^7.13.0\",\n    \"@testing-library/dom\": \"^6.11.0\",\n    \"@types/node\": \"^12.12.25\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.16.1\",\n    \"@typescript-eslint/parser\": \"^4.16.1\",\n    \"autoprefixer\": \"^9.7.4\",\n    \"babel-jest\": \"^25.3.0\",\n    \"babel-plugin-dev-expression\": \"^0.2.2\",\n    \"bundlesize\": \"^0.18.0\",\n    \"colorette\": \"^1.1.0\",\n    \"core-js\": \"^3.6.4\",\n    \"cross-env\": \"^7.0.0\",\n    \"cssnano\": \"^4.1.10\",\n    \"dotenv\": \"^8.2.0\",\n    \"eslint\": \"^6.8.0\",\n    \"eslint-config-prettier\": \"^6.9.0\",\n    \"husky\": \"^3.1.0\",\n    \"jest\": \"^25.3.0\",\n    \"jest-environment-jsdom-fourteen\": \"^1.0.1\",\n    \"jest-image-snapshot\": \"^2.12.0\",\n    \"jest-puppeteer\": \"^4.4.0\",\n    \"jest-puppeteer-docker\": \"^1.3.2\",\n    \"lint-staged\": \"^9.5.0\",\n    \"postcss\": \"^7.0.26\",\n    \"poster\": \"0.0.9\",\n    \"prettier\": \"^2.0.1\",\n    \"promise\": \"^8.0.3\",\n    \"puppeteer\": \"^2.1.1\",\n    \"rimraf\": \"^3.0.0\",\n    \"rollup\": \"^1.29.1\",\n    \"rollup-plugin-babel\": \"^4.3.3\",\n    \"rollup-plugin-commonjs\": \"^10.0.2\",\n    \"rollup-plugin-css-only\": \"^1.0.0\",\n    \"rollup-plugin-json\": \"^4.0.0\",\n    \"rollup-plugin-livereload\": \"^1.0.4\",\n    \"rollup-plugin-node-resolve\": \"^5.2.0\",\n    \"rollup-plugin-replace\": \"^2.2.0\",\n    \"rollup-plugin-sass\": \"^1.2.2\",\n    \"rollup-plugin-serve\": \"^1.0.1\",\n    \"rollup-plugin-terser\": \"^5.2.0\",\n    \"sass\": \"^1.25.0\",\n    \"serve\": \"^11.3.0\",\n    \"tsd\": \"^0.14.0\",\n    \"typescript\": \"^4.2.2\"\n  },\n  \"dependencies\": {\n    \"@popperjs/core\": \"^2.9.0\"\n  }\n}\n"
  },
  {
    "path": "src/_babel.d.ts",
    "content": "declare const __DEV__: boolean;\n"
  },
  {
    "path": "src/addons/createSingleton.ts",
    "content": "import tippy from '..';\nimport {div} from '../dom-utils';\nimport {\n  CreateSingleton,\n  Plugin,\n  CreateSingletonProps,\n  ReferenceElement,\n  CreateSingletonInstance,\n  Instance,\n  Props,\n} from '../types';\nimport {normalizeToArray, removeProperties} from '../utils';\nimport {errorWhen} from '../validation';\nimport {applyStyles, Modifier} from '@popperjs/core';\n\n// The default `applyStyles` modifier has a cleanup function that gets called\n// every time the popper is destroyed (i.e. a new target), removing the styles\n// and causing transitions to break for singletons when the console is open, but\n// most notably for non-transform styles being used, `gpuAcceleration: false`.\nconst applyStylesModifier: Modifier<'applyStyles', Record<string, unknown>> = {\n  ...applyStyles,\n  effect({state}) {\n    const initialStyles = {\n      popper: {\n        position: state.options.strategy,\n        left: '0',\n        top: '0',\n        margin: '0',\n      },\n      arrow: {\n        position: 'absolute',\n      },\n      reference: {},\n    };\n\n    Object.assign(state.elements.popper.style, initialStyles.popper);\n    state.styles = initialStyles;\n\n    if (state.elements.arrow) {\n      Object.assign(state.elements.arrow.style, initialStyles.arrow);\n    }\n\n    // intentionally return no cleanup function\n    // return () => { ... }\n  },\n};\n\nconst createSingleton: CreateSingleton = (\n  tippyInstances,\n  optionalProps = {}\n) => {\n  /* istanbul ignore else */\n  if (__DEV__) {\n    errorWhen(\n      !Array.isArray(tippyInstances),\n      [\n        'The first argument passed to createSingleton() must be an array of',\n        'tippy instances. The passed value was',\n        String(tippyInstances),\n      ].join(' ')\n    );\n  }\n\n  let individualInstances = tippyInstances;\n  let references: Array<ReferenceElement> = [];\n  let triggerTargets: Array<Element> = [];\n  let currentTarget: Element | null;\n  let overrides = optionalProps.overrides;\n  let interceptSetPropsCleanups: Array<() => void> = [];\n  let shownOnCreate = false;\n\n  function setTriggerTargets(): void {\n    triggerTargets = individualInstances\n      .map((instance) =>\n        normalizeToArray(instance.props.triggerTarget || instance.reference)\n      )\n      .reduce((acc, item) => acc.concat(item), []);\n  }\n\n  function setReferences(): void {\n    references = individualInstances.map((instance) => instance.reference);\n  }\n\n  function enableInstances(isEnabled: boolean): void {\n    individualInstances.forEach((instance) => {\n      if (isEnabled) {\n        instance.enable();\n      } else {\n        instance.disable();\n      }\n    });\n  }\n\n  function interceptSetProps(singleton: Instance): Array<() => void> {\n    return individualInstances.map((instance) => {\n      const originalSetProps = instance.setProps;\n\n      instance.setProps = (props): void => {\n        originalSetProps(props);\n\n        if (instance.reference === currentTarget) {\n          singleton.setProps(props);\n        }\n      };\n\n      return (): void => {\n        instance.setProps = originalSetProps;\n      };\n    });\n  }\n\n  // have to pass singleton, as it maybe undefined on first call\n  function prepareInstance(\n    singleton: Instance,\n    target: ReferenceElement\n  ): void {\n    const index = triggerTargets.indexOf(target);\n\n    // bail-out\n    if (target === currentTarget) {\n      return;\n    }\n\n    currentTarget = target;\n\n    const overrideProps: Partial<Props> = (overrides || [])\n      .concat('content')\n      .reduce((acc, prop) => {\n        (acc as any)[prop] = individualInstances[index].props[prop];\n        return acc;\n      }, {});\n\n    singleton.setProps({\n      ...overrideProps,\n      getReferenceClientRect:\n        typeof overrideProps.getReferenceClientRect === 'function'\n          ? overrideProps.getReferenceClientRect\n          : (): ClientRect => references[index]?.getBoundingClientRect(),\n    });\n  }\n\n  enableInstances(false);\n  setReferences();\n  setTriggerTargets();\n\n  const plugin: Plugin = {\n    fn() {\n      return {\n        onDestroy(): void {\n          enableInstances(true);\n        },\n        onHidden(): void {\n          currentTarget = null;\n        },\n        onClickOutside(instance): void {\n          if (instance.props.showOnCreate && !shownOnCreate) {\n            shownOnCreate = true;\n            currentTarget = null;\n          }\n        },\n        onShow(instance): void {\n          if (instance.props.showOnCreate && !shownOnCreate) {\n            shownOnCreate = true;\n            prepareInstance(instance, references[0]);\n          }\n        },\n        onTrigger(instance, event): void {\n          prepareInstance(instance, event.currentTarget as Element);\n        },\n      };\n    },\n  };\n\n  const singleton = tippy(div(), {\n    ...removeProperties(optionalProps, ['overrides']),\n    plugins: [plugin, ...(optionalProps.plugins || [])],\n    triggerTarget: triggerTargets,\n    popperOptions: {\n      ...optionalProps.popperOptions,\n      modifiers: [\n        ...(optionalProps.popperOptions?.modifiers || []),\n        applyStylesModifier,\n      ],\n    },\n  }) as CreateSingletonInstance<CreateSingletonProps>;\n\n  const originalShow = singleton.show;\n\n  singleton.show = (target?: ReferenceElement | Instance | number): void => {\n    originalShow();\n\n    // first time, showOnCreate or programmatic call with no params\n    // default to showing first instance\n    if (!currentTarget && target == null) {\n      return prepareInstance(singleton, references[0]);\n    }\n\n    // triggered from event (do nothing as prepareInstance already called by onTrigger)\n    // programmatic call with no params when already visible (do nothing again)\n    if (currentTarget && target == null) {\n      return;\n    }\n\n    // target is index of instance\n    if (typeof target === 'number') {\n      return (\n        references[target] && prepareInstance(singleton, references[target])\n      );\n    }\n\n    // target is a child tippy instance\n    if (individualInstances.indexOf(target as Instance) >= 0) {\n      const ref = (target as Instance).reference;\n      return prepareInstance(singleton, ref);\n    }\n\n    // target is a ReferenceElement\n    if (references.indexOf(target as ReferenceElement) >= 0) {\n      return prepareInstance(singleton, target as ReferenceElement);\n    }\n  };\n\n  singleton.showNext = (): void => {\n    const first = references[0];\n    if (!currentTarget) {\n      return singleton.show(0);\n    }\n    const index = references.indexOf(currentTarget);\n    singleton.show(references[index + 1] || first);\n  };\n\n  singleton.showPrevious = (): void => {\n    const last = references[references.length - 1];\n    if (!currentTarget) {\n      return singleton.show(last);\n    }\n    const index = references.indexOf(currentTarget);\n    const target = references[index - 1] || last;\n    singleton.show(target);\n  };\n\n  const originalSetProps = singleton.setProps;\n\n  singleton.setProps = (props): void => {\n    overrides = props.overrides || overrides;\n    originalSetProps(props);\n  };\n\n  singleton.setInstances = (nextInstances): void => {\n    enableInstances(true);\n    interceptSetPropsCleanups.forEach((fn) => fn());\n\n    individualInstances = nextInstances;\n\n    enableInstances(false);\n    setReferences();\n    setTriggerTargets();\n    interceptSetPropsCleanups = interceptSetProps(singleton);\n\n    singleton.setProps({triggerTarget: triggerTargets});\n  };\n\n  interceptSetPropsCleanups = interceptSetProps(singleton);\n\n  return singleton;\n};\n\nexport default createSingleton;\n"
  },
  {
    "path": "src/addons/delegate.ts",
    "content": "import tippy from '..';\nimport {TOUCH_OPTIONS} from '../constants';\nimport {defaultProps} from '../props';\nimport {Instance, Props, Targets} from '../types';\nimport {ListenerObject} from '../types-internal';\nimport {normalizeToArray, removeProperties} from '../utils';\nimport {errorWhen} from '../validation';\n\nconst BUBBLING_EVENTS_MAP = {\n  mouseover: 'mouseenter',\n  focusin: 'focus',\n  click: 'click',\n};\n\n/**\n * Creates a delegate instance that controls the creation of tippy instances\n * for child elements (`target` CSS selector).\n */\nfunction delegate(\n  targets: Targets,\n  props: Partial<Props> & {target: string}\n): Instance | Instance[] {\n  /* istanbul ignore else */\n  if (__DEV__) {\n    errorWhen(\n      !(props && props.target),\n      [\n        'You must specity a `target` prop indicating a CSS selector string matching',\n        'the target elements that should receive a tippy.',\n      ].join(' ')\n    );\n  }\n\n  let listeners: ListenerObject[] = [];\n  let childTippyInstances: Instance[] = [];\n  let disabled = false;\n\n  const {target} = props;\n\n  const nativeProps = removeProperties(props, ['target']);\n  const parentProps = {...nativeProps, trigger: 'manual', touch: false};\n  const childProps = {\n    touch: defaultProps.touch,\n    ...nativeProps,\n    showOnCreate: true,\n  };\n\n  const returnValue = tippy(targets, parentProps);\n  const normalizedReturnValue = normalizeToArray(returnValue);\n\n  function onTrigger(event: Event): void {\n    if (!event.target || disabled) {\n      return;\n    }\n\n    const targetNode = (event.target as Element).closest(target);\n\n    if (!targetNode) {\n      return;\n    }\n\n    // Get relevant trigger with fallbacks:\n    // 1. Check `data-tippy-trigger` attribute on target node\n    // 2. Fallback to `trigger` passed to `delegate()`\n    // 3. Fallback to `defaultProps.trigger`\n    const trigger =\n      targetNode.getAttribute('data-tippy-trigger') ||\n      props.trigger ||\n      defaultProps.trigger;\n\n    // @ts-ignore\n    if (targetNode._tippy) {\n      return;\n    }\n\n    if (event.type === 'touchstart' && typeof childProps.touch === 'boolean') {\n      return;\n    }\n\n    if (\n      event.type !== 'touchstart' &&\n      trigger.indexOf((BUBBLING_EVENTS_MAP as any)[event.type]) < 0\n    ) {\n      return;\n    }\n\n    const instance = tippy(targetNode, childProps);\n\n    if (instance) {\n      childTippyInstances = childTippyInstances.concat(instance);\n    }\n  }\n\n  function on(\n    node: Element,\n    eventType: string,\n    handler: EventListener,\n    options: boolean | Record<string, unknown> = false\n  ): void {\n    node.addEventListener(eventType, handler, options);\n    listeners.push({node, eventType, handler, options});\n  }\n\n  function addEventListeners(instance: Instance): void {\n    const {reference} = instance;\n\n    on(reference, 'touchstart', onTrigger, TOUCH_OPTIONS);\n    on(reference, 'mouseover', onTrigger);\n    on(reference, 'focusin', onTrigger);\n    on(reference, 'click', onTrigger);\n  }\n\n  function removeEventListeners(): void {\n    listeners.forEach(({node, eventType, handler, options}: ListenerObject) => {\n      node.removeEventListener(eventType, handler, options);\n    });\n    listeners = [];\n  }\n\n  function applyMutations(instance: Instance): void {\n    const originalDestroy = instance.destroy;\n    const originalEnable = instance.enable;\n    const originalDisable = instance.disable;\n\n    instance.destroy = (shouldDestroyChildInstances = true): void => {\n      if (shouldDestroyChildInstances) {\n        childTippyInstances.forEach((instance) => {\n          instance.destroy();\n        });\n      }\n\n      childTippyInstances = [];\n\n      removeEventListeners();\n      originalDestroy();\n    };\n\n    instance.enable = (): void => {\n      originalEnable();\n      childTippyInstances.forEach((instance) => instance.enable());\n      disabled = false;\n    };\n\n    instance.disable = (): void => {\n      originalDisable();\n      childTippyInstances.forEach((instance) => instance.disable());\n      disabled = true;\n    };\n\n    addEventListeners(instance);\n  }\n\n  normalizedReturnValue.forEach(applyMutations);\n\n  return returnValue;\n}\n\nexport default delegate;\n"
  },
  {
    "path": "src/bindGlobalEventListeners.ts",
    "content": "import {TOUCH_OPTIONS} from './constants';\nimport {isReferenceElement} from './dom-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\nexport default function bindGlobalEventListeners(): void {\n  document.addEventListener('touchstart', onDocumentTouchStart, TOUCH_OPTIONS);\n  window.addEventListener('blur', onWindowBlur);\n}\n"
  },
  {
    "path": "src/browser.ts",
    "content": "export const isBrowser =\n  typeof window !== 'undefined' && typeof document !== 'undefined';\n\nexport const isIE11 = isBrowser\n  ? // @ts-ignore\n    !!window.msCrypto\n  : false;\n"
  },
  {
    "path": "src/constants.ts",
    "content": "export const ROUND_ARROW =\n  '<svg width=\"16\" height=\"6\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M0 6s1.796-.013 4.67-3.615C5.851.9 6.93.006 8 0c1.07-.006 2.148.887 3.343 2.385C14.233 6.005 16 6 16 6H0z\"></svg>';\n\nexport const BOX_CLASS = `__NAMESPACE_PREFIX__-box`;\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 TOUCH_OPTIONS = {passive: true, capture: true};\n\nexport const TIPPY_DEFAULT_APPEND_TO = () => document.body;\n"
  },
  {
    "path": "src/createTippy.ts",
    "content": "import {createPopper, StrictModifiers, Modifier} from '@popperjs/core';\nimport {currentInput} from './bindGlobalEventListeners';\nimport {isIE11} from './browser';\nimport {TIPPY_DEFAULT_APPEND_TO, TOUCH_OPTIONS} from './constants';\nimport {\n  actualContains,\n  div,\n  getOwnerDocument,\n  isCursorOutsideInteractiveBorder,\n  isMouseEvent,\n  setTransitionDuration,\n  setVisibilityState,\n  updateTransitionEndListener,\n} from './dom-utils';\nimport {defaultProps, evaluateProps, getExtendedPassedProps} from './props';\nimport {getChildren} from './template';\nimport {\n  Content,\n  Instance,\n  LifecycleHooks,\n  PopperElement,\n  Props,\n  ReferenceElement,\n} from './types';\nimport {ListenerObject, PopperTreeData, PopperChildren} from './types-internal';\nimport {\n  arrayFrom,\n  debounce,\n  getValueAtIndexOrReturn,\n  invokeWithArgsOrReturn,\n  normalizeToArray,\n  pushIfUnique,\n  splitBySpaces,\n  unique,\n  removeUndefinedProps,\n} from './utils';\nimport {createMemoryLeakWarning, errorWhen, warnWhen} from './validation';\n\nlet idCounter = 1;\nlet mouseMoveListeners: ((event: MouseEvent) => void)[] = [];\n\n// Used by `hideAll()`\nexport let mountedInstances: Instance[] = [];\n\nexport default function createTippy(\n  reference: ReferenceElement,\n  passedProps: Partial<Props>\n): Instance {\n  const props = evaluateProps(reference, {\n    ...defaultProps,\n    ...getExtendedPassedProps(removeUndefinedProps(passedProps)),\n  });\n\n  // ===========================================================================\n  // 🔒 Private members\n  // ===========================================================================\n  let showTimeout: any;\n  let hideTimeout: any;\n  let scheduleHideAnimationFrame: number;\n  let isVisibleFromClick = false;\n  let didHideDueToDocumentMouseDown = false;\n  let didTouchMove = false;\n  let ignoreOnFirstUpdate = false;\n  let lastTriggerEvent: Event | undefined;\n  let currentTransitionEndListener: (event: TransitionEvent) => void;\n  let onFirstUpdate: () => void;\n  let listeners: ListenerObject[] = [];\n  let debouncedOnMouseMove = debounce(onMouseMove, props.interactiveDebounce);\n  let currentTarget: Element;\n\n  // ===========================================================================\n  // 🔑 Public members\n  // ===========================================================================\n  const id = idCounter++;\n  const popperInstance = null;\n  const plugins = unique(props.plugins);\n\n  const state = {\n    // Is the instance currently enabled?\n    isEnabled: true,\n    // Is the tippy currently showing and not transitioning out?\n    isVisible: false,\n    // Has the instance been destroyed?\n    isDestroyed: false,\n    // Is the tippy currently mounted to the DOM?\n    isMounted: false,\n    // Has the tippy finished transitioning in?\n    isShown: false,\n  };\n\n  const instance: Instance = {\n    // properties\n    id,\n    reference,\n    popper: div(),\n    popperInstance,\n    props,\n    state,\n    plugins,\n    // methods\n    clearDelayTimeouts,\n    setProps,\n    setContent,\n    show,\n    hide,\n    hideWithInteractivity,\n    enable,\n    disable,\n    unmount,\n    destroy,\n  };\n\n  // TODO: Investigate why this early return causes a TDZ error in the tests —\n  // it doesn't seem to happen in the browser\n  /* istanbul ignore if */\n  if (!props.render) {\n    if (__DEV__) {\n      errorWhen(true, 'render() function has not been supplied.');\n    }\n\n    return instance;\n  }\n\n  // ===========================================================================\n  // Initial mutations\n  // ===========================================================================\n  const {popper, onUpdate} = props.render(instance);\n\n  popper.setAttribute('data-__NAMESPACE_PREFIX__-root', '');\n  popper.id = `__NAMESPACE_PREFIX__-${instance.id}`;\n\n  instance.popper = popper;\n  reference._tippy = instance;\n  popper._tippy = instance;\n\n  const pluginsHooks = plugins.map((plugin) => plugin.fn(instance));\n  const hasAriaExpanded = reference.hasAttribute('aria-expanded');\n\n  addListeners();\n  handleAriaExpandedAttribute();\n  handleStyles();\n\n  invokeHook('onCreate', [instance]);\n\n  if (props.showOnCreate) {\n    scheduleShow();\n  }\n\n  // Prevent a tippy with a delay from hiding if the cursor left then returned\n  // before it started hiding\n  popper.addEventListener('mouseenter', () => {\n    if (instance.props.interactive && instance.state.isVisible) {\n      instance.clearDelayTimeouts();\n    }\n  });\n\n  popper.addEventListener('mouseleave', () => {\n    if (\n      instance.props.interactive &&\n      instance.props.trigger.indexOf('mouseenter') >= 0\n    ) {\n      getDocument().addEventListener('mousemove', debouncedOnMouseMove);\n    }\n  });\n\n  return instance;\n\n  // ===========================================================================\n  // 🔒 Private methods\n  // ===========================================================================\n  function getNormalizedTouchSettings(): [string | boolean, number] {\n    const {touch} = instance.props;\n    return Array.isArray(touch) ? touch : [touch, 0];\n  }\n\n  function getIsCustomTouchBehavior(): boolean {\n    return getNormalizedTouchSettings()[0] === 'hold';\n  }\n\n  function getIsDefaultRenderFn(): boolean {\n    // @ts-ignore\n    return !!instance.props.render?.$$tippy;\n  }\n\n  function getCurrentTarget(): Element {\n    return currentTarget || reference;\n  }\n\n  function getDocument(): Document {\n    const parent = getCurrentTarget().parentNode as Element;\n    return parent ? getOwnerDocument(parent) : document;\n  }\n\n  function getDefaultTemplateChildren(): PopperChildren {\n    return getChildren(popper);\n  }\n\n  function getDelay(isShow: boolean): number {\n    // For touch or keyboard input, force `0` delay for UX reasons\n    // Also if the instance is mounted but not visible (transitioning out),\n    // ignore delay\n    if (\n      (instance.state.isMounted && !instance.state.isVisible) ||\n      currentInput.isTouch ||\n      (lastTriggerEvent && lastTriggerEvent.type === 'focus')\n    ) {\n      return 0;\n    }\n\n    return getValueAtIndexOrReturn(\n      instance.props.delay,\n      isShow ? 0 : 1,\n      defaultProps.delay\n    );\n  }\n\n  function handleStyles(fromHide = false): void {\n    popper.style.pointerEvents =\n      instance.props.interactive && !fromHide ? '' : 'none';\n    popper.style.zIndex = `${instance.props.zIndex}`;\n  }\n\n  function invokeHook(\n    hook: keyof LifecycleHooks,\n    args: [Instance, any?],\n    shouldInvokePropsHook = true\n  ): void {\n    pluginsHooks.forEach((pluginHooks) => {\n      if (pluginHooks[hook]) {\n        pluginHooks[hook]!(...args);\n      }\n    });\n\n    if (shouldInvokePropsHook) {\n      instance.props[hook](...args);\n    }\n  }\n\n  function handleAriaContentAttribute(): void {\n    const {aria} = instance.props;\n\n    if (!aria.content) {\n      return;\n    }\n\n    const attr = `aria-${aria.content}`;\n    const id = popper.id;\n    const nodes = normalizeToArray(instance.props.triggerTarget || reference);\n\n    nodes.forEach((node) => {\n      const currentValue = node.getAttribute(attr);\n\n      if (instance.state.isVisible) {\n        node.setAttribute(attr, currentValue ? `${currentValue} ${id}` : id);\n      } else {\n        const nextValue = currentValue && currentValue.replace(id, '').trim();\n\n        if (nextValue) {\n          node.setAttribute(attr, nextValue);\n        } else {\n          node.removeAttribute(attr);\n        }\n      }\n    });\n  }\n\n  function handleAriaExpandedAttribute(): void {\n    if (hasAriaExpanded || !instance.props.aria.expanded) {\n      return;\n    }\n\n    const nodes = normalizeToArray(instance.props.triggerTarget || reference);\n\n    nodes.forEach((node) => {\n      if (instance.props.interactive) {\n        node.setAttribute(\n          'aria-expanded',\n          instance.state.isVisible && node === getCurrentTarget()\n            ? 'true'\n            : 'false'\n        );\n      } else {\n        node.removeAttribute('aria-expanded');\n      }\n    });\n  }\n\n  function cleanupInteractiveMouseListeners(): void {\n    getDocument().removeEventListener('mousemove', debouncedOnMouseMove);\n    mouseMoveListeners = mouseMoveListeners.filter(\n      (listener) => listener !== debouncedOnMouseMove\n    );\n  }\n\n  function onDocumentPress(event: MouseEvent | TouchEvent): void {\n    // Moved finger to scroll instead of an intentional tap outside\n    if (currentInput.isTouch) {\n      if (didTouchMove || event.type === 'mousedown') {\n        return;\n      }\n    }\n\n    const actualTarget =\n      (event.composedPath && event.composedPath()[0]) || event.target;\n\n    // Clicked on interactive popper\n    if (\n      instance.props.interactive &&\n      actualContains(popper, actualTarget as Element)\n    ) {\n      return;\n    }\n\n    // Clicked on the event listeners target\n    if (\n      normalizeToArray(instance.props.triggerTarget || reference).some((el) =>\n        actualContains(el, actualTarget as Element)\n      )\n    ) {\n      if (currentInput.isTouch) {\n        return;\n      }\n\n      if (\n        instance.state.isVisible &&\n        instance.props.trigger.indexOf('click') >= 0\n      ) {\n        return;\n      }\n    } else {\n      invokeHook('onClickOutside', [instance, event]);\n    }\n\n    if (instance.props.hideOnClick === true) {\n      instance.clearDelayTimeouts();\n      instance.hide();\n\n      // `mousedown` event is fired right before `focus` if pressing the\n      // currentTarget. This lets a tippy with `focus` trigger know that it\n      // should not show\n      didHideDueToDocumentMouseDown = true;\n      setTimeout(() => {\n        didHideDueToDocumentMouseDown = false;\n      });\n\n      // The listener gets added in `scheduleShow()`, but this may be hiding it\n      // before it shows, and hide()'s early bail-out behavior can prevent it\n      // from being cleaned up\n      if (!instance.state.isMounted) {\n        removeDocumentPress();\n      }\n    }\n  }\n\n  function onTouchMove(): void {\n    didTouchMove = true;\n  }\n\n  function onTouchStart(): void {\n    didTouchMove = false;\n  }\n\n  function addDocumentPress(): void {\n    const doc = getDocument();\n    doc.addEventListener('mousedown', onDocumentPress, true);\n    doc.addEventListener('touchend', onDocumentPress, TOUCH_OPTIONS);\n    doc.addEventListener('touchstart', onTouchStart, TOUCH_OPTIONS);\n    doc.addEventListener('touchmove', onTouchMove, TOUCH_OPTIONS);\n  }\n\n  function removeDocumentPress(): void {\n    const doc = getDocument();\n    doc.removeEventListener('mousedown', onDocumentPress, true);\n    doc.removeEventListener('touchend', onDocumentPress, TOUCH_OPTIONS);\n    doc.removeEventListener('touchstart', onTouchStart, TOUCH_OPTIONS);\n    doc.removeEventListener('touchmove', onTouchMove, TOUCH_OPTIONS);\n  }\n\n  function onTransitionedOut(duration: number, callback: () => void): void {\n    onTransitionEnd(duration, () => {\n      if (\n        !instance.state.isVisible &&\n        popper.parentNode &&\n        popper.parentNode.contains(popper)\n      ) {\n        callback();\n      }\n    });\n  }\n\n  function onTransitionedIn(duration: number, callback: () => void): void {\n    onTransitionEnd(duration, callback);\n  }\n\n  function onTransitionEnd(duration: number, callback: () => void): void {\n    const box = getDefaultTemplateChildren().box;\n\n    function listener(event: TransitionEvent): void {\n      if (event.target === box) {\n        updateTransitionEndListener(box, 'remove', listener);\n        callback();\n      }\n    }\n\n    // Make callback synchronous if duration is 0\n    // `transitionend` won't fire otherwise\n    if (duration === 0) {\n      return callback();\n    }\n\n    updateTransitionEndListener(box, 'remove', currentTransitionEndListener);\n    updateTransitionEndListener(box, 'add', listener);\n\n    currentTransitionEndListener = listener;\n  }\n\n  function on(\n    eventType: string,\n    handler: EventListener,\n    options: boolean | Record<string, unknown> = false\n  ): void {\n    const nodes = normalizeToArray(instance.props.triggerTarget || reference);\n    nodes.forEach((node) => {\n      node.addEventListener(eventType, handler, options);\n      listeners.push({node, eventType, handler, options});\n    });\n  }\n\n  function addListeners(): void {\n    if (getIsCustomTouchBehavior()) {\n      on('touchstart', onTrigger, {passive: true});\n      on('touchend', onMouseLeave as EventListener, {passive: true});\n    }\n\n    splitBySpaces(instance.props.trigger).forEach((eventType) => {\n      if (eventType === 'manual') {\n        return;\n      }\n\n      on(eventType, onTrigger);\n\n      switch (eventType) {\n        case 'mouseenter':\n          on('mouseleave', onMouseLeave as EventListener);\n          break;\n        case 'focus':\n          on(isIE11 ? 'focusout' : 'blur', onBlurOrFocusOut as EventListener);\n          break;\n        case 'focusin':\n          on('focusout', onBlurOrFocusOut as EventListener);\n          break;\n      }\n    });\n  }\n\n  function removeListeners(): void {\n    listeners.forEach(({node, eventType, handler, options}: ListenerObject) => {\n      node.removeEventListener(eventType, handler, options);\n    });\n    listeners = [];\n  }\n\n  function onTrigger(event: Event): void {\n    let shouldScheduleClickHide = false;\n\n    if (\n      !instance.state.isEnabled ||\n      isEventListenerStopped(event) ||\n      didHideDueToDocumentMouseDown\n    ) {\n      return;\n    }\n\n    const wasFocused = lastTriggerEvent?.type === 'focus';\n\n    lastTriggerEvent = event;\n    currentTarget = event.currentTarget as Element;\n\n    handleAriaExpandedAttribute();\n\n    if (!instance.state.isVisible && isMouseEvent(event)) {\n      // If scrolling, `mouseenter` events can be fired if the cursor lands\n      // over a new target, but `mousemove` events don't get fired. This\n      // causes interactive tooltips to get stuck open until the cursor is\n      // moved\n      mouseMoveListeners.forEach((listener) => listener(event));\n    }\n\n    // Toggle show/hide when clicking click-triggered tooltips\n    if (\n      event.type === 'click' &&\n      (instance.props.trigger.indexOf('mouseenter') < 0 ||\n        isVisibleFromClick) &&\n      instance.props.hideOnClick !== false &&\n      instance.state.isVisible\n    ) {\n      shouldScheduleClickHide = true;\n    } else {\n      scheduleShow(event);\n    }\n\n    if (event.type === 'click') {\n      isVisibleFromClick = !shouldScheduleClickHide;\n    }\n\n    if (shouldScheduleClickHide && !wasFocused) {\n      scheduleHide(event);\n    }\n  }\n\n  function onMouseMove(event: MouseEvent): void {\n    const target = event.target as Node;\n    const isCursorOverReferenceOrPopper =\n      getCurrentTarget().contains(target) || popper.contains(target);\n\n    if (event.type === 'mousemove' && isCursorOverReferenceOrPopper) {\n      return;\n    }\n\n    const popperTreeData = getNestedPopperTree()\n      .concat(popper)\n      .map((popper) => {\n        const instance = popper._tippy!;\n        const state = instance.popperInstance?.state;\n\n        if (state) {\n          return {\n            popperRect: popper.getBoundingClientRect(),\n            popperState: state,\n            props,\n          };\n        }\n\n        return null;\n      })\n      .filter(Boolean) as PopperTreeData[];\n\n    if (isCursorOutsideInteractiveBorder(popperTreeData, event)) {\n      cleanupInteractiveMouseListeners();\n      scheduleHide(event);\n    }\n  }\n\n  function onMouseLeave(event: MouseEvent): void {\n    const shouldBail =\n      isEventListenerStopped(event) ||\n      (instance.props.trigger.indexOf('click') >= 0 && isVisibleFromClick);\n\n    if (shouldBail) {\n      return;\n    }\n\n    if (instance.props.interactive) {\n      instance.hideWithInteractivity(event);\n      return;\n    }\n\n    scheduleHide(event);\n  }\n\n  function onBlurOrFocusOut(event: FocusEvent): void {\n    if (\n      instance.props.trigger.indexOf('focusin') < 0 &&\n      event.target !== getCurrentTarget()\n    ) {\n      return;\n    }\n\n    // If focus was moved to within the popper\n    if (\n      instance.props.interactive &&\n      event.relatedTarget &&\n      popper.contains(event.relatedTarget as Element)\n    ) {\n      return;\n    }\n\n    scheduleHide(event);\n  }\n\n  function isEventListenerStopped(event: Event): boolean {\n    return currentInput.isTouch\n      ? getIsCustomTouchBehavior() !== event.type.indexOf('touch') >= 0\n      : false;\n  }\n\n  function createPopperInstance(): void {\n    destroyPopperInstance();\n\n    const {\n      popperOptions,\n      placement,\n      offset,\n      getReferenceClientRect,\n      moveTransition,\n    } = instance.props;\n\n    const arrow = getIsDefaultRenderFn() ? getChildren(popper).arrow : null;\n\n    const computedReference = getReferenceClientRect\n      ? {\n          getBoundingClientRect: getReferenceClientRect,\n          contextElement:\n            getReferenceClientRect.contextElement || getCurrentTarget(),\n        }\n      : reference;\n\n    const tippyModifier: Modifier<'$$tippy', Record<string, unknown>> = {\n      name: '$$tippy',\n      enabled: true,\n      phase: 'beforeWrite',\n      requires: ['computeStyles'],\n      fn({state}) {\n        if (getIsDefaultRenderFn()) {\n          const {box} = getDefaultTemplateChildren();\n\n          ['placement', 'reference-hidden', 'escaped'].forEach((attr) => {\n            if (attr === 'placement') {\n              box.setAttribute('data-placement', state.placement);\n            } else {\n              if (state.attributes.popper[`data-popper-${attr}`]) {\n                box.setAttribute(`data-${attr}`, '');\n              } else {\n                box.removeAttribute(`data-${attr}`);\n              }\n            }\n          });\n\n          state.attributes.popper = {};\n        }\n      },\n    };\n\n    type TippyModifier = Modifier<'$$tippy', Record<string, unknown>>;\n    type ExtendedModifiers = StrictModifiers | Partial<TippyModifier>;\n\n    const modifiers: Array<ExtendedModifiers> = [\n      {\n        name: 'offset',\n        options: {\n          offset,\n        },\n      },\n      {\n        name: 'preventOverflow',\n        options: {\n          padding: {\n            top: 2,\n            bottom: 2,\n            left: 5,\n            right: 5,\n          },\n        },\n      },\n      {\n        name: 'flip',\n        options: {\n          padding: 5,\n        },\n      },\n      {\n        name: 'computeStyles',\n        options: {\n          adaptive: !moveTransition,\n        },\n      },\n      tippyModifier,\n    ];\n\n    if (getIsDefaultRenderFn() && arrow) {\n      modifiers.push({\n        name: 'arrow',\n        options: {\n          element: arrow,\n          padding: 3,\n        },\n      });\n    }\n\n    modifiers.push(...(popperOptions?.modifiers || []));\n\n    instance.popperInstance = createPopper<ExtendedModifiers>(\n      computedReference,\n      popper,\n      {\n        ...popperOptions,\n        placement,\n        onFirstUpdate,\n        modifiers,\n      }\n    );\n  }\n\n  function destroyPopperInstance(): void {\n    if (instance.popperInstance) {\n      instance.popperInstance.destroy();\n      instance.popperInstance = null;\n    }\n  }\n\n  function mount(): void {\n    const {appendTo} = instance.props;\n\n    let parentNode: any;\n\n    // By default, we'll append the popper to the triggerTargets's parentNode so\n    // it's directly after the reference element so the elements inside the\n    // tippy can be tabbed to\n    // If there are clipping issues, the user can specify a different appendTo\n    // and ensure focus management is handled correctly manually\n    const node = getCurrentTarget();\n\n    if (\n      (instance.props.interactive && appendTo === TIPPY_DEFAULT_APPEND_TO) ||\n      appendTo === 'parent'\n    ) {\n      parentNode = node.parentNode;\n    } else {\n      parentNode = invokeWithArgsOrReturn(appendTo, [node]);\n    }\n\n    // The popper element needs to exist on the DOM before its position can be\n    // updated as Popper needs to read its dimensions\n    if (!parentNode.contains(popper)) {\n      parentNode.appendChild(popper);\n    }\n\n    instance.state.isMounted = true;\n\n    createPopperInstance();\n\n    /* istanbul ignore else */\n    if (__DEV__) {\n      // Accessibility check\n      warnWhen(\n        instance.props.interactive &&\n          appendTo === defaultProps.appendTo &&\n          node.nextElementSibling !== popper,\n        [\n          'Interactive tippy element may not be accessible via keyboard',\n          'navigation because it is not directly after the reference element',\n          'in the DOM source order.',\n          '\\n\\n',\n          'Using a wrapper <div> or <span> tag around the reference element',\n          'solves this by creating a new parentNode context.',\n          '\\n\\n',\n          'Specifying `appendTo: document.body` silences this warning, but it',\n          'assumes you are using a focus management solution to handle',\n          'keyboard navigation.',\n          '\\n\\n',\n          'See: https://atomiks.github.io/tippyjs/v6/accessibility/#interactivity',\n        ].join(' ')\n      );\n    }\n  }\n\n  function getNestedPopperTree(): PopperElement[] {\n    return arrayFrom(\n      popper.querySelectorAll('[data-__NAMESPACE_PREFIX__-root]')\n    );\n  }\n\n  function scheduleShow(event?: Event): void {\n    instance.clearDelayTimeouts();\n\n    if (event) {\n      invokeHook('onTrigger', [instance, event]);\n    }\n\n    addDocumentPress();\n\n    let delay = getDelay(true);\n    const [touchValue, touchDelay] = getNormalizedTouchSettings();\n\n    if (currentInput.isTouch && touchValue === 'hold' && touchDelay) {\n      delay = touchDelay;\n    }\n\n    if (delay) {\n      showTimeout = setTimeout(() => {\n        instance.show();\n      }, delay);\n    } else {\n      instance.show();\n    }\n  }\n\n  function scheduleHide(event: Event): void {\n    instance.clearDelayTimeouts();\n\n    invokeHook('onUntrigger', [instance, event]);\n\n    if (!instance.state.isVisible) {\n      removeDocumentPress();\n\n      return;\n    }\n\n    // For interactive tippies, scheduleHide is added to a document.body handler\n    // from onMouseLeave so must intercept scheduled hides from mousemove/leave\n    // events when trigger contains mouseenter and click, and the tip is\n    // currently shown as a result of a click.\n    if (\n      instance.props.trigger.indexOf('mouseenter') >= 0 &&\n      instance.props.trigger.indexOf('click') >= 0 &&\n      ['mouseleave', 'mousemove'].indexOf(event.type) >= 0 &&\n      isVisibleFromClick\n    ) {\n      return;\n    }\n\n    const delay = getDelay(false);\n\n    if (delay) {\n      hideTimeout = setTimeout(() => {\n        if (instance.state.isVisible) {\n          instance.hide();\n        }\n      }, delay);\n    } else {\n      // Fixes a `transitionend` problem when it fires 1 frame too\n      // late sometimes, we don't want hide() to be called.\n      scheduleHideAnimationFrame = requestAnimationFrame(() => {\n        instance.hide();\n      });\n    }\n  }\n\n  // ===========================================================================\n  // 🔑 Public methods\n  // ===========================================================================\n  function enable(): void {\n    instance.state.isEnabled = true;\n  }\n\n  function disable(): void {\n    // Disabling the instance should also hide it\n    // https://github.com/atomiks/tippy.js-react/issues/106\n    instance.hide();\n    instance.state.isEnabled = false;\n  }\n\n  function clearDelayTimeouts(): void {\n    clearTimeout(showTimeout);\n    clearTimeout(hideTimeout);\n    cancelAnimationFrame(scheduleHideAnimationFrame);\n  }\n\n  function setProps(partialProps: Partial<Props>): void {\n    /* istanbul ignore else */\n    if (__DEV__) {\n      warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('setProps'));\n    }\n\n    if (instance.state.isDestroyed) {\n      return;\n    }\n\n    invokeHook('onBeforeUpdate', [instance, partialProps]);\n\n    removeListeners();\n\n    const prevProps = instance.props;\n    const nextProps = evaluateProps(reference, {\n      ...prevProps,\n      ...removeUndefinedProps(partialProps),\n      ignoreAttributes: true,\n    });\n\n    instance.props = nextProps;\n\n    addListeners();\n\n    if (prevProps.interactiveDebounce !== nextProps.interactiveDebounce) {\n      cleanupInteractiveMouseListeners();\n      debouncedOnMouseMove = debounce(\n        onMouseMove,\n        nextProps.interactiveDebounce\n      );\n    }\n\n    // Ensure stale aria-expanded attributes are removed\n    if (prevProps.triggerTarget && !nextProps.triggerTarget) {\n      normalizeToArray(prevProps.triggerTarget).forEach((node) => {\n        node.removeAttribute('aria-expanded');\n      });\n    } else if (nextProps.triggerTarget) {\n      reference.removeAttribute('aria-expanded');\n    }\n\n    handleAriaExpandedAttribute();\n    handleStyles();\n\n    if (onUpdate) {\n      onUpdate(prevProps, nextProps);\n    }\n\n    if (instance.popperInstance) {\n      createPopperInstance();\n\n      // Fixes an issue with nested tippies if they are all getting re-rendered,\n      // and the nested ones get re-rendered first.\n      // https://github.com/atomiks/tippyjs-react/issues/177\n      // TODO: find a cleaner / more efficient solution(!)\n      getNestedPopperTree().forEach((nestedPopper) => {\n        // React (and other UI libs likely) requires a rAF wrapper as it flushes\n        // its work in one\n        requestAnimationFrame(nestedPopper._tippy!.popperInstance!.forceUpdate);\n      });\n    }\n\n    invokeHook('onAfterUpdate', [instance, partialProps]);\n  }\n\n  function setContent(content: Content): void {\n    instance.setProps({content});\n  }\n\n  function show(): void {\n    /* istanbul ignore else */\n    if (__DEV__) {\n      warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('show'));\n    }\n\n    // Early bail-out\n    const isAlreadyVisible = instance.state.isVisible;\n    const isDestroyed = instance.state.isDestroyed;\n    const isDisabled = !instance.state.isEnabled;\n    const isTouchAndTouchDisabled =\n      currentInput.isTouch && !instance.props.touch;\n    const duration = getValueAtIndexOrReturn(\n      instance.props.duration,\n      0,\n      defaultProps.duration\n    );\n\n    if (\n      isAlreadyVisible ||\n      isDestroyed ||\n      isDisabled ||\n      isTouchAndTouchDisabled\n    ) {\n      return;\n    }\n\n    // Normalize `disabled` behavior across browsers.\n    // Firefox allows events on disabled elements, but Chrome doesn't.\n    // Using a wrapper element (i.e. <span>) is recommended.\n    if (getCurrentTarget().hasAttribute('disabled')) {\n      return;\n    }\n\n    invokeHook('onShow', [instance], false);\n    if (instance.props.onShow(instance) === false) {\n      return;\n    }\n\n    instance.state.isVisible = true;\n\n    if (getIsDefaultRenderFn()) {\n      popper.style.visibility = 'visible';\n    }\n\n    handleStyles();\n    addDocumentPress();\n\n    if (!instance.state.isMounted) {\n      popper.style.transition = 'none';\n    }\n\n    // If flipping to the opposite side after hiding at least once, the\n    // animation will use the wrong placement without resetting the duration\n    if (getIsDefaultRenderFn()) {\n      const {box, content} = getDefaultTemplateChildren();\n      setTransitionDuration([box, content], 0);\n    }\n\n    onFirstUpdate = (): void => {\n      if (!instance.state.isVisible || ignoreOnFirstUpdate) {\n        return;\n      }\n\n      ignoreOnFirstUpdate = true;\n\n      // reflow\n      void popper.offsetHeight;\n\n      popper.style.transition = instance.props.moveTransition;\n\n      if (getIsDefaultRenderFn() && instance.props.animation) {\n        const {box, content} = getDefaultTemplateChildren();\n        setTransitionDuration([box, content], duration);\n        setVisibilityState([box, content], 'visible');\n      }\n\n      handleAriaContentAttribute();\n      handleAriaExpandedAttribute();\n\n      pushIfUnique(mountedInstances, instance);\n\n      // certain modifiers (e.g. `maxSize`) require a second update after the\n      // popper has been positioned for the first time\n      instance.popperInstance?.forceUpdate();\n\n      invokeHook('onMount', [instance]);\n\n      if (instance.props.animation && getIsDefaultRenderFn()) {\n        onTransitionedIn(duration, () => {\n          instance.state.isShown = true;\n          invokeHook('onShown', [instance]);\n        });\n      }\n    };\n\n    mount();\n  }\n\n  function hide(): void {\n    /* istanbul ignore else */\n    if (__DEV__) {\n      warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('hide'));\n    }\n\n    // Early bail-out\n    const isAlreadyHidden = !instance.state.isVisible;\n    const isDestroyed = instance.state.isDestroyed;\n    const isDisabled = !instance.state.isEnabled;\n    const duration = getValueAtIndexOrReturn(\n      instance.props.duration,\n      1,\n      defaultProps.duration\n    );\n\n    if (isAlreadyHidden || isDestroyed || isDisabled) {\n      return;\n    }\n\n    invokeHook('onHide', [instance], false);\n    if (instance.props.onHide(instance) === false) {\n      return;\n    }\n\n    instance.state.isVisible = false;\n    instance.state.isShown = false;\n    ignoreOnFirstUpdate = false;\n    isVisibleFromClick = false;\n\n    if (getIsDefaultRenderFn()) {\n      popper.style.visibility = 'hidden';\n    }\n\n    cleanupInteractiveMouseListeners();\n    removeDocumentPress();\n    handleStyles(true);\n\n    if (getIsDefaultRenderFn()) {\n      const {box, content} = getDefaultTemplateChildren();\n\n      if (instance.props.animation) {\n        setTransitionDuration([box, content], duration);\n        setVisibilityState([box, content], 'hidden');\n      }\n    }\n\n    handleAriaContentAttribute();\n    handleAriaExpandedAttribute();\n\n    if (instance.props.animation) {\n      if (getIsDefaultRenderFn()) {\n        onTransitionedOut(duration, instance.unmount);\n      }\n    } else {\n      instance.unmount();\n    }\n  }\n\n  function hideWithInteractivity(event: MouseEvent): void {\n    /* istanbul ignore else */\n    if (__DEV__) {\n      warnWhen(\n        instance.state.isDestroyed,\n        createMemoryLeakWarning('hideWithInteractivity')\n      );\n    }\n\n    getDocument().addEventListener('mousemove', debouncedOnMouseMove);\n    pushIfUnique(mouseMoveListeners, debouncedOnMouseMove);\n    debouncedOnMouseMove(event);\n  }\n\n  function unmount(): void {\n    /* istanbul ignore else */\n    if (__DEV__) {\n      warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('unmount'));\n    }\n\n    if (instance.state.isVisible) {\n      instance.hide();\n    }\n\n    if (!instance.state.isMounted) {\n      return;\n    }\n\n    destroyPopperInstance();\n\n    // If a popper is not interactive, it will be appended outside the popper\n    // tree by default. This seems mainly for interactive tippies, but we should\n    // find a workaround if possible\n    getNestedPopperTree().forEach((nestedPopper) => {\n      nestedPopper._tippy!.unmount();\n    });\n\n    if (popper.parentNode) {\n      popper.parentNode.removeChild(popper);\n    }\n\n    mountedInstances = mountedInstances.filter((i) => i !== instance);\n\n    instance.state.isMounted = false;\n    invokeHook('onHidden', [instance]);\n  }\n\n  function destroy(): void {\n    /* istanbul ignore else */\n    if (__DEV__) {\n      warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('destroy'));\n    }\n\n    if (instance.state.isDestroyed) {\n      return;\n    }\n\n    instance.clearDelayTimeouts();\n    instance.unmount();\n\n    removeListeners();\n\n    delete reference._tippy;\n\n    instance.state.isDestroyed = true;\n\n    invokeHook('onDestroy', [instance]);\n  }\n}\n"
  },
  {
    "path": "src/css.ts",
    "content": "export function injectCSS(css: string): void {\n  const style = document.createElement('style');\n  style.textContent = css;\n  style.setAttribute('data-__NAMESPACE_PREFIX__-stylesheet', '');\n  const head = document.head;\n  const firstStyleOrLinkTag = document.querySelector('head>style,head>link');\n\n  if (firstStyleOrLinkTag) {\n    head.insertBefore(style, firstStyleOrLinkTag);\n  } else {\n    head.appendChild(style);\n  }\n}\n"
  },
  {
    "path": "src/dom-utils.ts",
    "content": "import {ReferenceElement, Targets} from './types';\nimport {PopperTreeData} from './types-internal';\nimport {arrayFrom, isType, normalizeToArray, getBasePlacement} from './utils';\n\nexport function div(): HTMLDivElement {\n  return document.createElement('div');\n}\n\nexport function isElement(value: unknown): value is Element | DocumentFragment {\n  return ['Element', 'Fragment'].some((type) => isType(value, type));\n}\n\nexport function isNodeList(value: unknown): value is NodeList {\n  return isType(value, 'NodeList');\n}\n\nexport function isMouseEvent(value: unknown): value is MouseEvent {\n  return isType(value, 'MouseEvent');\n}\n\nexport function isReferenceElement(value: any): value is ReferenceElement {\n  return !!(value && value._tippy && value._tippy.reference === value);\n}\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\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\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\nexport function getOwnerDocument(\n  elementOrElements: Element | Element[]\n): Document {\n  const [element] = normalizeToArray(elementOrElements);\n\n  // Elements created via a <template> have an ownerDocument with no reference to the body\n  return element?.ownerDocument?.body ? element.ownerDocument : document;\n}\n\nexport function isCursorOutsideInteractiveBorder(\n  popperTreeData: PopperTreeData[],\n  event: MouseEvent\n): boolean {\n  const {clientX, clientY} = event;\n\n  return popperTreeData.every(({popperRect, popperState, props}) => {\n    const {interactiveBorder} = props;\n    const basePlacement = getBasePlacement(popperState.placement);\n    const offsetData = popperState.modifiersData.offset;\n\n    if (!offsetData) {\n      return true;\n    }\n\n    const topDistance = basePlacement === 'bottom' ? offsetData.top!.y : 0;\n    const bottomDistance = basePlacement === 'top' ? offsetData.bottom!.y : 0;\n    const leftDistance = basePlacement === 'right' ? offsetData.left!.x : 0;\n    const rightDistance = basePlacement === 'left' ? offsetData.right!.x : 0;\n\n    const exceedsTop =\n      popperRect.top - clientY + topDistance > interactiveBorder;\n    const exceedsBottom =\n      clientY - popperRect.bottom - bottomDistance > interactiveBorder;\n    const exceedsLeft =\n      popperRect.left - clientX + leftDistance > interactiveBorder;\n    const exceedsRight =\n      clientX - popperRect.right - rightDistance > interactiveBorder;\n\n    return exceedsTop || exceedsBottom || exceedsLeft || exceedsRight;\n  });\n}\n\nexport function updateTransitionEndListener(\n  box: HTMLDivElement,\n  action: 'add' | 'remove',\n  listener: (event: TransitionEvent) => void\n): void {\n  if (listener) {\n    const method = `${action}EventListener` as\n      | 'addEventListener'\n      | 'removeEventListener';\n\n    // some browsers apparently support `transition` (unprefixed) but only fire\n    // `webkitTransitionEnd`...\n    ['transitionend', 'webkitTransitionEnd'].forEach((event) => {\n      box[method](event, listener as EventListener);\n    });\n  }\n}\n\n/**\n * Compared to xxx.contains, this function works for dom structures with shadow\n * dom\n */\nexport function actualContains(parent: Element, child: Element): boolean {\n  let target = child;\n  while (target) {\n    if (parent.contains(target)) {\n      return true;\n    }\n    target = (target.getRootNode?.() as any)?.host;\n  }\n  return false;\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "import bindGlobalEventListeners, {\n  currentInput,\n} from './bindGlobalEventListeners';\nimport createTippy, {mountedInstances} from './createTippy';\nimport {getArrayOfElements, isElement, isReferenceElement} from './dom-utils';\nimport {defaultProps, setDefaultProps, validateProps} from './props';\nimport {HideAll, HideAllOptions, Instance, Props, Targets} from './types';\nimport {validateTargets, warnWhen} from './validation';\n\nfunction tippy(\n  targets: Targets,\n  optionalProps: Partial<Props> = {}\n): Instance | Instance[] {\n  const plugins = defaultProps.plugins.concat(optionalProps.plugins || []);\n\n  /* istanbul ignore else */\n  if (__DEV__) {\n    validateTargets(targets);\n    validateProps(optionalProps, plugins);\n  }\n\n  bindGlobalEventListeners();\n\n  const passedProps: Partial<Props> = {...optionalProps, plugins};\n\n  const elements = getArrayOfElements(targets);\n\n  /* istanbul ignore else */\n  if (__DEV__) {\n    const isSingleContentElement = isElement(passedProps.content);\n    const isMoreThanOneReferenceElement = elements.length > 1;\n    warnWhen(\n      isSingleContentElement && isMoreThanOneReferenceElement,\n      [\n        'tippy() was passed an Element as the `content` prop, but more than',\n        'one tippy instance was created by this invocation. This means the',\n        'content element will only be appended to the last tippy instance.',\n        '\\n\\n',\n        'Instead, pass the .innerHTML of the element, or use a function that',\n        'returns a cloned version of the element instead.',\n        '\\n\\n',\n        '1) content: element.innerHTML\\n',\n        '2) content: () => element.cloneNode(true)',\n      ].join(' ')\n    );\n  }\n\n  const instances = elements.reduce<Instance[]>(\n    (acc, reference): Instance[] => {\n      const instance = reference && createTippy(reference, passedProps);\n\n      if (instance) {\n        acc.push(instance);\n      }\n\n      return acc;\n    },\n    []\n  );\n\n  return isElement(targets) ? instances[0] : instances;\n}\n\ntippy.defaultProps = defaultProps;\ntippy.setDefaultProps = setDefaultProps;\ntippy.currentInput = currentInput;\n\nexport default tippy;\n\nexport const hideAll: HideAll = ({\n  exclude: excludedReferenceOrInstance,\n  duration,\n}: HideAllOptions = {}) => {\n  mountedInstances.forEach((instance) => {\n    let isExcluded = false;\n\n    if (excludedReferenceOrInstance) {\n      isExcluded = isReferenceElement(excludedReferenceOrInstance)\n        ? instance.reference === excludedReferenceOrInstance\n        : instance.popper === (excludedReferenceOrInstance as Instance).popper;\n    }\n\n    if (!isExcluded) {\n      const originalDuration = instance.props.duration;\n\n      instance.setProps({duration});\n      instance.hide();\n\n      if (!instance.state.isDestroyed) {\n        instance.setProps({duration: originalDuration});\n      }\n    }\n  });\n};\n"
  },
  {
    "path": "src/plugins/animateFill.ts",
    "content": "import {BACKDROP_CLASS} from '../constants';\nimport {div, setVisibilityState} from '../dom-utils';\nimport {getChildren} from '../template';\nimport {AnimateFill} from '../types';\nimport {errorWhen} from '../validation';\n\nconst animateFill: AnimateFill = {\n  name: 'animateFill',\n  defaultValue: false,\n  fn(instance) {\n    // @ts-ignore\n    if (!instance.props.render?.$$tippy) {\n      if (__DEV__) {\n        errorWhen(\n          instance.props.animateFill,\n          'The `animateFill` plugin requires the default render function.'\n        );\n      }\n\n      return {};\n    }\n\n    const {box, content} = getChildren(instance.popper);\n\n    const backdrop = instance.props.animateFill\n      ? createBackdropElement()\n      : null;\n\n    return {\n      onCreate(): void {\n        if (backdrop) {\n          box.insertBefore(backdrop, box.firstElementChild!);\n          box.setAttribute('data-animatefill', '');\n          box.style.overflow = 'hidden';\n\n          instance.setProps({arrow: false, animation: 'shift-away'});\n        }\n      },\n      onMount(): void {\n        if (backdrop) {\n          const {transitionDuration} = box.style;\n          const duration = Number(transitionDuration.replace('ms', ''));\n\n          // The content should fade in after the backdrop has mostly filled the\n          // tooltip element. `clip-path` is the other alternative but is not\n          // well-supported and is buggy on some devices.\n          content.style.transitionDelay = `${Math.round(duration / 10)}ms`;\n\n          backdrop.style.transitionDuration = transitionDuration;\n          setVisibilityState([backdrop], 'visible');\n        }\n      },\n      onShow(): void {\n        if (backdrop) {\n          backdrop.style.transitionDuration = '0ms';\n        }\n      },\n      onHide(): void {\n        if (backdrop) {\n          setVisibilityState([backdrop], 'hidden');\n        }\n      },\n    };\n  },\n};\n\nexport default animateFill;\n\nfunction createBackdropElement(): HTMLDivElement {\n  const backdrop = div();\n  backdrop.className = BACKDROP_CLASS;\n  setVisibilityState([backdrop], 'hidden');\n  return backdrop;\n}\n"
  },
  {
    "path": "src/plugins/followCursor.ts",
    "content": "import {getOwnerDocument, isMouseEvent} from '../dom-utils';\nimport {FollowCursor, Instance} from '../types';\n\nlet mouseCoords = {clientX: 0, clientY: 0};\nlet activeInstances: Array<{instance: Instance; doc: Document}> = [];\n\nfunction storeMouseCoords({clientX, clientY}: MouseEvent): void {\n  mouseCoords = {clientX, clientY};\n}\n\nfunction addMouseCoordsListener(doc: Document): void {\n  doc.addEventListener('mousemove', storeMouseCoords);\n}\n\nfunction removeMouseCoordsListener(doc: Document): void {\n  doc.removeEventListener('mousemove', storeMouseCoords);\n}\n\nconst followCursor: FollowCursor = {\n  name: 'followCursor',\n  defaultValue: false,\n  fn(instance) {\n    const reference = instance.reference;\n    const doc = getOwnerDocument(instance.props.triggerTarget || reference);\n\n    let isInternalUpdate = false;\n    let wasFocusEvent = false;\n    let isUnmounted = true;\n    let prevProps = instance.props;\n\n    function getIsInitialBehavior(): boolean {\n      return (\n        instance.props.followCursor === 'initial' && instance.state.isVisible\n      );\n    }\n\n    function addListener(): void {\n      doc.addEventListener('mousemove', onMouseMove);\n    }\n\n    function removeListener(): void {\n      doc.removeEventListener('mousemove', onMouseMove);\n    }\n\n    function unsetGetReferenceClientRect(): void {\n      isInternalUpdate = true;\n      instance.setProps({getReferenceClientRect: null});\n      isInternalUpdate = false;\n    }\n\n    function onMouseMove(event: MouseEvent): void {\n      // If the instance is interactive, avoid updating the position unless it's\n      // over the reference element\n      const isCursorOverReference = event.target\n        ? reference.contains(event.target as Node)\n        : true;\n      const {followCursor} = instance.props;\n      const {clientX, clientY} = event;\n\n      const rect = reference.getBoundingClientRect();\n      const relativeX = clientX - rect.left;\n      const relativeY = clientY - rect.top;\n\n      if (isCursorOverReference || !instance.props.interactive) {\n        instance.setProps({\n          // @ts-ignore - unneeded DOMRect properties\n          getReferenceClientRect() {\n            const rect = reference.getBoundingClientRect();\n\n            let x = clientX;\n            let y = clientY;\n\n            if (followCursor === 'initial') {\n              x = rect.left + relativeX;\n              y = rect.top + relativeY;\n            }\n\n            const top = followCursor === 'horizontal' ? rect.top : y;\n            const right = followCursor === 'vertical' ? rect.right : x;\n            const bottom = followCursor === 'horizontal' ? rect.bottom : y;\n            const left = followCursor === 'vertical' ? rect.left : x;\n\n            return {\n              width: right - left,\n              height: bottom - top,\n              top,\n              right,\n              bottom,\n              left,\n            };\n          },\n        });\n      }\n    }\n\n    function create(): void {\n      if (instance.props.followCursor) {\n        activeInstances.push({instance, doc});\n        addMouseCoordsListener(doc);\n      }\n    }\n\n    function destroy(): void {\n      activeInstances = activeInstances.filter(\n        (data) => data.instance !== instance\n      );\n\n      if (activeInstances.filter((data) => data.doc === doc).length === 0) {\n        removeMouseCoordsListener(doc);\n      }\n    }\n\n    return {\n      onCreate: create,\n      onDestroy: destroy,\n      onBeforeUpdate(): void {\n        prevProps = instance.props;\n      },\n      onAfterUpdate(_, {followCursor}): void {\n        if (isInternalUpdate) {\n          return;\n        }\n\n        if (\n          followCursor !== undefined &&\n          prevProps.followCursor !== followCursor\n        ) {\n          destroy();\n\n          if (followCursor) {\n            create();\n\n            if (\n              instance.state.isMounted &&\n              !wasFocusEvent &&\n              !getIsInitialBehavior()\n            ) {\n              addListener();\n            }\n          } else {\n            removeListener();\n            unsetGetReferenceClientRect();\n          }\n        }\n      },\n      onMount(): void {\n        if (instance.props.followCursor && !wasFocusEvent) {\n          if (isUnmounted) {\n            onMouseMove(mouseCoords as MouseEvent);\n            isUnmounted = false;\n          }\n\n          if (!getIsInitialBehavior()) {\n            addListener();\n          }\n        }\n      },\n      onTrigger(_, event): void {\n        if (isMouseEvent(event)) {\n          mouseCoords = {clientX: event.clientX, clientY: event.clientY};\n        }\n        wasFocusEvent = event.type === 'focus';\n      },\n      onHidden(): void {\n        if (instance.props.followCursor) {\n          unsetGetReferenceClientRect();\n          removeListener();\n          isUnmounted = true;\n        }\n      },\n    };\n  },\n};\n\nexport default followCursor;\n"
  },
  {
    "path": "src/plugins/inlinePositioning.ts",
    "content": "import {Modifier, Placement} from '@popperjs/core';\nimport {isMouseEvent} from '../dom-utils';\nimport {BasePlacement, InlinePositioning, Props} from '../types';\nimport {arrayFrom, getBasePlacement} from '../utils';\n\nfunction getProps(props: Props, modifier: Modifier<any, any>): Partial<Props> {\n  return {\n    popperOptions: {\n      ...props.popperOptions,\n      modifiers: [\n        ...(props.popperOptions?.modifiers || []).filter(\n          ({name}) => name !== modifier.name\n        ),\n        modifier,\n      ],\n    },\n  };\n}\n\nconst inlinePositioning: InlinePositioning = {\n  name: 'inlinePositioning',\n  defaultValue: false,\n  fn(instance) {\n    const {reference} = instance;\n\n    function isEnabled(): boolean {\n      return !!instance.props.inlinePositioning;\n    }\n\n    let placement: Placement;\n    let cursorRectIndex = -1;\n    let isInternalUpdate = false;\n    let triedPlacements: Array<string> = [];\n\n    const modifier: Modifier<\n      'tippyInlinePositioning',\n      Record<string, unknown>\n    > = {\n      name: 'tippyInlinePositioning',\n      enabled: true,\n      phase: 'afterWrite',\n      fn({state}) {\n        if (isEnabled()) {\n          if (triedPlacements.indexOf(state.placement) !== -1) {\n            triedPlacements = [];\n          }\n\n          if (\n            placement !== state.placement &&\n            triedPlacements.indexOf(state.placement) === -1\n          ) {\n            triedPlacements.push(state.placement);\n            instance.setProps({\n              // @ts-ignore - unneeded DOMRect properties\n              getReferenceClientRect: () =>\n                getReferenceClientRect(state.placement),\n            });\n          }\n\n          placement = state.placement;\n        }\n      },\n    };\n\n    function getReferenceClientRect(placement: Placement): Partial<DOMRect> {\n      return getInlineBoundingClientRect(\n        getBasePlacement(placement),\n        reference.getBoundingClientRect(),\n        arrayFrom(reference.getClientRects()),\n        cursorRectIndex\n      );\n    }\n\n    function setInternalProps(partialProps: Partial<Props>): void {\n      isInternalUpdate = true;\n      instance.setProps(partialProps);\n      isInternalUpdate = false;\n    }\n\n    function addModifier(): void {\n      if (!isInternalUpdate) {\n        setInternalProps(getProps(instance.props, modifier));\n      }\n    }\n\n    return {\n      onCreate: addModifier,\n      onAfterUpdate: addModifier,\n      onTrigger(_, event): void {\n        if (isMouseEvent(event)) {\n          const rects = arrayFrom(instance.reference.getClientRects());\n          const cursorRect = rects.find(\n            (rect) =>\n              rect.left - 2 <= event.clientX &&\n              rect.right + 2 >= event.clientX &&\n              rect.top - 2 <= event.clientY &&\n              rect.bottom + 2 >= event.clientY\n          );\n          const index = rects.indexOf(cursorRect);\n          cursorRectIndex = index > -1 ? index : cursorRectIndex;\n        }\n      },\n      onHidden(): void {\n        cursorRectIndex = -1;\n      },\n    };\n  },\n};\n\nexport default inlinePositioning;\n\nexport function getInlineBoundingClientRect(\n  currentBasePlacement: BasePlacement | null,\n  boundingRect: DOMRect,\n  clientRects: DOMRect[],\n  cursorRectIndex: number\n): {\n  top: number;\n  bottom: number;\n  left: number;\n  right: number;\n  width: number;\n  height: number;\n} {\n  // Not an inline element, or placement is not yet known\n  if (clientRects.length < 2 || currentBasePlacement === null) {\n    return boundingRect;\n  }\n\n  // There are two rects and they are disjoined\n  if (\n    clientRects.length === 2 &&\n    cursorRectIndex >= 0 &&\n    clientRects[0].left > clientRects[1].right\n  ) {\n    return clientRects[cursorRectIndex] || boundingRect;\n  }\n\n  switch (currentBasePlacement) {\n    case 'top':\n    case 'bottom': {\n      const firstRect = clientRects[0];\n      const lastRect = clientRects[clientRects.length - 1];\n      const isTop = currentBasePlacement === 'top';\n\n      const top = firstRect.top;\n      const bottom = lastRect.bottom;\n      const left = isTop ? firstRect.left : lastRect.left;\n      const right = isTop ? firstRect.right : lastRect.right;\n      const width = right - left;\n      const height = bottom - top;\n\n      return {top, bottom, left, right, width, height};\n    }\n    case 'left':\n    case 'right': {\n      const minLeft = Math.min(...clientRects.map((rects) => rects.left));\n      const maxRight = Math.max(...clientRects.map((rects) => rects.right));\n      const measureRects = clientRects.filter((rect) =>\n        currentBasePlacement === 'left'\n          ? rect.left === minLeft\n          : rect.right === maxRight\n      );\n\n      const top = measureRects[0].top;\n      const bottom = measureRects[measureRects.length - 1].bottom;\n      const left = minLeft;\n      const right = maxRight;\n      const width = right - left;\n      const height = bottom - top;\n\n      return {top, bottom, left, right, width, height};\n    }\n    default: {\n      return boundingRect;\n    }\n  }\n}\n"
  },
  {
    "path": "src/plugins/sticky.ts",
    "content": "import {VirtualElement} from '@popperjs/core';\nimport {ReferenceElement, Sticky} from '../types';\n\nconst sticky: Sticky = {\n  name: 'sticky',\n  defaultValue: false,\n  fn(instance) {\n    const {reference, popper} = instance;\n\n    function getReference(): ReferenceElement | VirtualElement {\n      return instance.popperInstance\n        ? instance.popperInstance.state.elements.reference\n        : reference;\n    }\n\n    function shouldCheck(value: 'reference' | 'popper'): boolean {\n      return instance.props.sticky === true || instance.props.sticky === value;\n    }\n\n    let prevRefRect: ClientRect | null = null;\n    let prevPopRect: ClientRect | null = null;\n\n    function updatePosition(): void {\n      const currentRefRect = shouldCheck('reference')\n        ? getReference().getBoundingClientRect()\n        : null;\n      const currentPopRect = shouldCheck('popper')\n        ? popper.getBoundingClientRect()\n        : null;\n\n      if (\n        (currentRefRect && areRectsDifferent(prevRefRect, currentRefRect)) ||\n        (currentPopRect && areRectsDifferent(prevPopRect, currentPopRect))\n      ) {\n        if (instance.popperInstance) {\n          instance.popperInstance.update();\n        }\n      }\n\n      prevRefRect = currentRefRect;\n      prevPopRect = currentPopRect;\n\n      if (instance.state.isMounted) {\n        requestAnimationFrame(updatePosition);\n      }\n    }\n\n    return {\n      onMount(): void {\n        if (instance.props.sticky) {\n          updatePosition();\n        }\n      },\n    };\n  },\n};\n\nexport default sticky;\n\nfunction areRectsDifferent(\n  rectA: ClientRect | null,\n  rectB: ClientRect | null\n): boolean {\n  if (rectA && rectB) {\n    return (\n      rectA.top !== rectB.top ||\n      rectA.right !== rectB.right ||\n      rectA.bottom !== rectB.bottom ||\n      rectA.left !== rectB.left\n    );\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "src/props.ts",
    "content": "import {DefaultProps, Plugin, Props, ReferenceElement, Tippy} from './types';\nimport {\n  hasOwnProperty,\n  removeProperties,\n  invokeWithArgsOrReturn,\n} from './utils';\nimport {warnWhen} from './validation';\nimport {TIPPY_DEFAULT_APPEND_TO} from './constants';\n\nconst pluginProps = {\n  animateFill: false,\n  followCursor: false,\n  inlinePositioning: false,\n  sticky: false,\n};\n\nconst renderProps = {\n  allowHTML: false,\n  animation: 'fade',\n  arrow: true,\n  content: '',\n  inertia: false,\n  maxWidth: 350,\n  role: 'tooltip',\n  theme: '',\n  zIndex: 9999,\n};\n\nexport const defaultProps: DefaultProps = {\n  appendTo: TIPPY_DEFAULT_APPEND_TO,\n  aria: {\n    content: 'auto',\n    expanded: 'auto',\n  },\n  delay: 0,\n  duration: [300, 250],\n  getReferenceClientRect: null,\n  hideOnClick: true,\n  ignoreAttributes: false,\n  interactive: false,\n  interactiveBorder: 2,\n  interactiveDebounce: 0,\n  moveTransition: '',\n  offset: [0, 10],\n  onAfterUpdate() {},\n  onBeforeUpdate() {},\n  onCreate() {},\n  onDestroy() {},\n  onHidden() {},\n  onHide() {},\n  onMount() {},\n  onShow() {},\n  onShown() {},\n  onTrigger() {},\n  onUntrigger() {},\n  onClickOutside() {},\n  placement: 'top',\n  plugins: [],\n  popperOptions: {},\n  render: null,\n  showOnCreate: false,\n  touch: true,\n  trigger: 'mouseenter focus',\n  triggerTarget: null,\n  ...pluginProps,\n  ...renderProps,\n};\n\nconst defaultKeys = Object.keys(defaultProps);\n\nexport const setDefaultProps: Tippy['setDefaultProps'] = (partialProps) => {\n  /* istanbul ignore else */\n  if (__DEV__) {\n    const plugins = defaultProps.plugins.concat(partialProps.plugins || []);\n    validateProps(partialProps, plugins);\n  }\n\n  const keys = Object.keys(partialProps) as Array<keyof DefaultProps>;\n  keys.forEach((key) => {\n    (defaultProps as any)[key] = partialProps[key];\n  });\n};\n\nexport function getExtendedPassedProps(\n  passedProps: Partial<Props> & Record<string, unknown>\n): Partial<Props> {\n  const plugins = passedProps.plugins || [];\n  const pluginProps = plugins.reduce<Record<string, unknown>>((acc, plugin) => {\n    const {name, defaultValue} = plugin;\n\n    if (name) {\n      acc[name] =\n        passedProps[name] !== undefined\n          ? passedProps[name]\n          : (defaultProps as any)[name] ?? defaultValue;\n    }\n\n    return acc;\n  }, {});\n\n  return {\n    ...passedProps,\n    ...pluginProps,\n  };\n}\n\nexport function getDataAttributeProps(\n  reference: ReferenceElement,\n  plugins: Plugin[]\n): Record<string, unknown> {\n  const propKeys = plugins\n    ? Object.keys(getExtendedPassedProps({...defaultProps, plugins}))\n    : defaultKeys;\n\n  const props = propKeys.reduce(\n    (acc: Partial<Props> & Record<string, unknown>, 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\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  out.aria = {\n    ...defaultProps.aria,\n    ...out.aria,\n  };\n\n  out.aria = {\n    expanded:\n      out.aria.expanded === 'auto' ? props.interactive : out.aria.expanded,\n    content:\n      out.aria.content === 'auto'\n        ? props.interactive\n          ? null\n          : 'describedby'\n        : out.aria.content,\n  };\n\n  return out;\n}\n\nexport function validateProps(\n  partialProps: Partial<Props> = {},\n  plugins: Plugin[] = []\n): void {\n  const keys = Object.keys(partialProps) as Array<keyof Props>;\n  keys.forEach((prop) => {\n    const nonPluginProps = removeProperties(\n      defaultProps,\n      Object.keys(pluginProps)\n    );\n\n    let didPassUnknownProp = !hasOwnProperty(nonPluginProps, 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      didPassUnknownProp,\n      [\n        `\\`${prop}\\``,\n        \"is not a valid prop. You may have spelled it incorrectly, or if it's\",\n        'a plugin, forgot to pass it in an array as props.plugins.',\n        '\\n\\n',\n        'All props: https://atomiks.github.io/tippyjs/v6/all-props/\\n',\n        'Plugins: https://atomiks.github.io/tippyjs/v6/plugins/',\n      ].join(' ')\n    );\n  });\n}\n"
  },
  {
    "path": "src/scss/_mixins.scss",
    "content": "@mixin backdrop-transform-enter($placement) {\n  $scale: 1;\n  @if ($placement == 'top') {\n    transform: scale($scale) translate(-50%, -55%);\n  } @else if ($placement == 'bottom') {\n    transform: scale($scale) translate(-50%, -45%);\n  } @else if ($placement == 'left') {\n    transform: scale($scale) translate(-50%, -50%);\n  } @else if ($placement == 'right') {\n    transform: scale($scale) translate(-50%, -50%);\n  }\n}\n\n@mixin backdrop-transform-leave($placement) {\n  $scale: 0.2;\n  @if ($placement == 'top') {\n    transform: scale($scale) translate(-50%, -45%);\n  } @else if ($placement == 'bottom') {\n    transform: scale($scale) translate(-50%, 0);\n  } @else if ($placement == 'left') {\n    transform: scale($scale) translate(-75%, -50%);\n  } @else if ($placement == 'right') {\n    transform: scale($scale) translate(-25%, -50%);\n  }\n}\n"
  },
  {
    "path": "src/scss/_vars.scss",
    "content": "$namespace-prefix: '__NAMESPACE_PREFIX__' !default;\n$placements: 'top', 'bottom', 'left', 'right';\n$origins: bottom, top, right, left;\n$backdrop-origins: 0% 25%, 0% -50%, 50% 0%, -50% 0%;\n$backdrop-border-radii: 40% 40% 0 0, 0 0 30% 30%, 50% 0 0 50%, 0 50% 50% 0;\n$arrow-size: 16px;\n"
  },
  {
    "path": "src/scss/animations/fade.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n.#{$namespace-prefix}-box {\n  &[data-animation='fade'][data-state='hidden'] {\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/perspective-extreme.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin visible-transform($placement) {\n  @if ($placement == 'top') {\n    transform: perspective(700px);\n  } @else if ($placement == 'bottom') {\n    transform: perspective(700px);\n  } @else if ($placement == 'left') {\n    transform: perspective(700px);\n  } @else if ($placement == 'right') {\n    transform: perspective(700px);\n  }\n}\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: perspective(700px) translateY(10px) rotateX(90deg);\n  } @else if ($placement == 'bottom') {\n    transform: perspective(700px) translateY(-10px) rotateX(-90deg);\n  } @else if ($placement == 'left') {\n    transform: perspective(700px) translateX(10px) rotateY(-90deg);\n  } @else if ($placement == 'right') {\n    transform: perspective(700px) translateX(-10px) rotateY(90deg);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='perspective-extreme'] {\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        transform-origin: nth($origins, index($placements, $placement));\n\n        &[data-state='visible'] {\n          @include visible-transform($placement);\n        }\n\n        &[data-state='hidden'] {\n          @include hidden-transform($placement);\n        }\n      }\n    }\n\n    &[data-state='hidden'] {\n      opacity: 0.5;\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/perspective-subtle.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin visible-transform($placement) {\n  @if ($placement == 'top') {\n    transform: perspective(700px);\n  } @else if ($placement == 'bottom') {\n    transform: perspective(700px);\n  } @else if ($placement == 'left') {\n    transform: perspective(700px);\n  } @else if ($placement == 'right') {\n    transform: perspective(700px);\n  }\n}\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: perspective(700px) translateY(5px) rotateX(30deg);\n  } @else if ($placement == 'bottom') {\n    transform: perspective(700px) translateY(-5px) rotateX(-30deg);\n  } @else if ($placement == 'left') {\n    transform: perspective(700px) translateX(5px) rotateY(-30deg);\n  } @else if ($placement == 'right') {\n    transform: perspective(700px) translateX(-5px) rotateY(30deg);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='perspective-subtle'] {\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        transform-origin: nth($origins, index($placements, $placement));\n\n        &[data-state='visible'] {\n          @include visible-transform($placement);\n        }\n\n        &[data-state='hidden'] {\n          @include hidden-transform($placement);\n        }\n      }\n    }\n\n    &[data-state='hidden'] {\n      opacity: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/perspective.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin visible-transform($placement) {\n  @if ($placement == 'top') {\n    transform: perspective(700px);\n  } @else if ($placement == 'bottom') {\n    transform: perspective(700px);\n  } @else if ($placement == 'left') {\n    transform: perspective(700px);\n  } @else if ($placement == 'right') {\n    transform: perspective(700px);\n  }\n}\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: perspective(700px) translateY(8px) rotateX(60deg);\n  } @else if ($placement == 'bottom') {\n    transform: perspective(700px) translateY(-8px) rotateX(-60deg);\n  } @else if ($placement == 'left') {\n    transform: perspective(700px) translateX(8px) rotateY(-60deg);\n  } @else if ($placement == 'right') {\n    transform: perspective(700px) translateX(-8px) rotateY(60deg);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='perspective'] {\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        transform-origin: nth($origins, index($placements, $placement));\n\n        &[data-state='visible'] {\n          @include visible-transform($placement);\n        }\n\n        &[data-state='hidden'] {\n          @include hidden-transform($placement);\n        }\n      }\n    }\n\n    &[data-state='hidden'] {\n      opacity: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/scale-extreme.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n.#{$namespace-prefix}-box {\n  &[data-animation='scale-extreme'] {\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        transform-origin: nth($origins, index($placements, $placement));\n      }\n    }\n\n    &[data-state='hidden'] {\n      transform: scale(0);\n      opacity: 0.25;\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/scale-subtle.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n.#{$namespace-prefix}-box {\n  &[data-animation='scale-subtle'] {\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        transform-origin: nth($origins, index($placements, $placement));\n      }\n    }\n\n    &[data-state='hidden'] {\n      transform: scale(0.8);\n      opacity: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/scale.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n.#{$namespace-prefix}-box {\n  &[data-animation='scale'] {\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        transform-origin: nth($origins, index($placements, $placement));\n      }\n    }\n\n    &[data-state='hidden'] {\n      transform: scale(0.5);\n      opacity: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/shift-away-extreme.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: translateY(20px);\n  } @else if ($placement == 'bottom') {\n    transform: translateY(-20px);\n  } @else if ($placement == 'left') {\n    transform: translateX(20px);\n  } @else if ($placement == 'right') {\n    transform: translateX(-20px);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='shift-away-extreme'] {\n    &[data-state='hidden'] {\n      opacity: 0;\n\n      @each $placement in $placements {\n        &[data-placement^='#{$placement}'] {\n          @include hidden-transform($placement);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/shift-away-subtle.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: translateY(5px);\n  } @else if ($placement == 'bottom') {\n    transform: translateY(-5px);\n  } @else if ($placement == 'left') {\n    transform: translateX(5px);\n  } @else if ($placement == 'right') {\n    transform: translateX(-5px);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='shift-away-subtle'] {\n    &[data-state='hidden'] {\n      opacity: 0;\n\n      @each $placement in $placements {\n        &[data-placement^='#{$placement}'] {\n          @include hidden-transform($placement);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/shift-away.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: translateY(10px);\n  } @else if ($placement == 'bottom') {\n    transform: translateY(-10px);\n  } @else if ($placement == 'left') {\n    transform: translateX(10px);\n  } @else if ($placement == 'right') {\n    transform: translateX(-10px);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='shift-away'][data-state='hidden'] {\n    opacity: 0;\n\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        @include hidden-transform($placement);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/shift-toward-extreme.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: translateY(-20px);\n  } @else if ($placement == 'bottom') {\n    transform: translateY(20px);\n  } @else if ($placement == 'left') {\n    transform: translateX(-20px);\n  } @else if ($placement == 'right') {\n    transform: translateX(20px);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='shift-toward-extreme'][data-state='hidden'] {\n    opacity: 0;\n\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        @include hidden-transform($placement);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/shift-toward-subtle.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: translateY(-5px);\n  } @else if ($placement == 'bottom') {\n    transform: translateY(5px);\n  } @else if ($placement == 'left') {\n    transform: translateX(-5px);\n  } @else if ($placement == 'right') {\n    transform: translateX(5px);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='shift-toward-subtle'][data-state='hidden'] {\n    opacity: 0;\n\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        &[data-state='hidden'] {\n          @include hidden-transform($placement);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/animations/shift-toward.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n@mixin hidden-transform($placement) {\n  @if ($placement == 'top') {\n    transform: translateY(-10px);\n  } @else if ($placement == 'bottom') {\n    transform: translateY(10px);\n  } @else if ($placement == 'left') {\n    transform: translateX(-10px);\n  } @else if ($placement == 'right') {\n    transform: translateX(10px);\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animation='shift-toward'][data-state='hidden'] {\n    opacity: 0;\n\n    @each $placement in $placements {\n      &[data-placement^='#{$placement}'] {\n        @include hidden-transform($placement);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/backdrop.scss",
    "content": "@import './_mixins.scss';\n@import './_vars.scss';\n\n.#{$namespace-prefix}-box {\n  @each $placement in $placements {\n    &[data-placement^='#{$placement}'] {\n      > .#{$namespace-prefix}-backdrop {\n        transform-origin: nth(\n          $backdrop-origins,\n          index($placements, $placement)\n        );\n        border-radius: nth(\n          $backdrop-border-radii,\n          index($placements, $placement)\n        );\n\n        &[data-state='visible'] {\n          @include backdrop-transform-enter($placement);\n        }\n\n        &[data-state='hidden'] {\n          @include backdrop-transform-leave($placement);\n        }\n      }\n    }\n  }\n}\n\n.#{$namespace-prefix}-box {\n  &[data-animatefill] {\n    // Declared with !important so that custom themes don't need to specify\n    // this property.\n    background-color: transparent !important;\n  }\n}\n\n.#{$namespace-prefix}-backdrop {\n  position: absolute;\n  background-color: #333;\n  border-radius: 50%;\n  width: calc(110% + 32px);\n  left: 50%;\n  top: 50%;\n  z-index: -1;\n  transition: all cubic-bezier(0.46, 0.1, 0.52, 0.98);\n  backface-visibility: hidden;\n\n  &[data-state='hidden'] {\n    opacity: 0;\n  }\n\n  &::after {\n    content: '';\n    float: left;\n    padding-top: 100%;\n  }\n}\n\n.#{$namespace-prefix}-backdrop + .#{$namespace-prefix}-content {\n  transition-property: opacity;\n  will-change: opacity;\n\n  &[data-state='hidden'] {\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "src/scss/border.scss",
    "content": "@import './_vars.scss';\n\n.#{$namespace-prefix}-box {\n  border: 1px transparent;\n\n  &[data-placement^='top'] > .#{$namespace-prefix}-arrow {\n    &::after {\n      border-top-color: inherit;\n      border-width: 8px 8px 0;\n      bottom: -8px;\n      left: 0;\n    }\n  }\n\n  &[data-placement^='bottom'] > .#{$namespace-prefix}-arrow {\n    &::after {\n      border-bottom-color: inherit;\n      border-width: 0 8px 8px;\n      top: -8px;\n      left: 0;\n    }\n  }\n\n  &[data-placement^='left'] > .#{$namespace-prefix}-arrow {\n    &::after {\n      border-left-color: inherit;\n      border-width: 8px 0 8px 8px;\n      right: -8px;\n      top: 0;\n    }\n  }\n\n  &[data-placement^='right'] > .#{$namespace-prefix}-arrow {\n    &::after {\n      border-width: 8px 8px 8px 0;\n      left: -8px;\n      top: 0;\n      border-right-color: inherit;\n    }\n  }\n\n  &[data-placement^='top']\n    > .#{$namespace-prefix}-svg-arrow\n    > svg:first-child:not(:last-child) {\n    top: 17px;\n  }\n\n  &[data-placement^='bottom']\n    > .#{$namespace-prefix}-svg-arrow\n    > svg:first-child:not(:last-child) {\n    bottom: 17px;\n  }\n\n  &[data-placement^='left']\n    > .#{$namespace-prefix}-svg-arrow\n    > svg:first-child:not(:last-child) {\n    left: 12px;\n  }\n\n  &[data-placement^='right']\n    > .#{$namespace-prefix}-svg-arrow\n    > svg:first-child:not(:last-child) {\n    right: 12px;\n  }\n}\n\n.#{$namespace-prefix}-arrow {\n  & {\n    border-color: inherit;\n  }\n\n  &::after {\n    content: '';\n    z-index: -1;\n    position: absolute;\n    border-color: transparent;\n    border-style: solid;\n  }\n}\n"
  },
  {
    "path": "src/scss/index.scss",
    "content": "@import './_vars.scss';\n@import './animations/fade.scss';\n\n$color: #333;\n\n[data-#{$namespace-prefix}-root] {\n  max-width: calc(100vw - 10px);\n}\n\n.#{$namespace-prefix}-box {\n  position: relative;\n  background-color: $color;\n  color: white;\n  border-radius: 4px;\n  font-size: 14px;\n  line-height: 1.4;\n  white-space: initial;\n  outline: 0;\n  transition-property: transform, visibility, opacity;\n\n  &[data-placement^='top'] > .#{$namespace-prefix}-arrow {\n    bottom: 0;\n\n    &::before {\n      bottom: -7px;\n      left: 0;\n      border-width: 8px 8px 0;\n      border-top-color: initial;\n      transform-origin: center top;\n    }\n  }\n\n  &[data-placement^='bottom'] > .#{$namespace-prefix}-arrow {\n    top: 0;\n\n    &::before {\n      top: -7px;\n      left: 0;\n      border-width: 0 8px 8px;\n      border-bottom-color: initial;\n      transform-origin: center bottom;\n    }\n  }\n\n  &[data-placement^='left'] > .#{$namespace-prefix}-arrow {\n    right: 0;\n\n    &::before {\n      border-width: 8px 0 8px 8px;\n      border-left-color: initial;\n      right: -7px;\n      transform-origin: center left;\n    }\n  }\n\n  &[data-placement^='right'] > .#{$namespace-prefix}-arrow {\n    left: 0;\n\n    &::before {\n      left: -7px;\n      border-width: 8px 8px 8px 0;\n      border-right-color: initial;\n      transform-origin: center right;\n    }\n  }\n\n  &[data-inertia][data-state='visible'] {\n    transition-timing-function: cubic-bezier(0.54, 1.5, 0.38, 1.11);\n  }\n}\n\n.#{$namespace-prefix}-arrow {\n  & {\n    width: $arrow-size;\n    height: $arrow-size;\n    color: $color;\n  }\n\n  &::before {\n    content: '';\n    position: absolute;\n    border-color: transparent;\n    border-style: solid;\n  }\n}\n\n.#{$namespace-prefix}-content {\n  position: relative;\n  padding: 5px 9px;\n  z-index: 1;\n}\n"
  },
  {
    "path": "src/scss/svg-arrow.scss",
    "content": "@import './_vars.scss';\n\n.#{$namespace-prefix}-box {\n  &[data-placement^='top'] > .#{$namespace-prefix}-svg-arrow {\n    bottom: 0;\n\n    &::after,\n    > svg {\n      top: 16px;\n      transform: rotate(180deg);\n    }\n  }\n\n  &[data-placement^='bottom'] > .#{$namespace-prefix}-svg-arrow {\n    top: 0;\n\n    > svg {\n      bottom: 16px;\n    }\n  }\n\n  &[data-placement^='left'] > .#{$namespace-prefix}-svg-arrow {\n    right: 0;\n\n    &::after,\n    > svg {\n      transform: rotate(90deg);\n      top: calc(50% - 3px);\n      left: 11px;\n    }\n  }\n\n  &[data-placement^='right'] > .#{$namespace-prefix}-svg-arrow {\n    left: 0;\n\n    &::after,\n    > svg {\n      transform: rotate(-90deg);\n      top: calc(50% - 3px);\n      right: 11px;\n    }\n  }\n}\n\n.#{$namespace-prefix}-svg-arrow {\n  position: absolute;\n  width: $arrow-size;\n  height: $arrow-size;\n  fill: #333;\n  text-align: initial;\n\n  > svg {\n    position: absolute;\n  }\n}\n"
  },
  {
    "path": "src/scss/themes/light-border.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n$color: white;\n$transparent-light: rgba(0, 8, 16, 0.08);\n$transparent-dark: rgba(0, 8, 16, 0.15);\n$transparent-darker: rgba(0, 8, 16, 0.2);\n\n.#{$namespace-prefix}-box[data-theme~='light-border'] {\n  background-color: $color;\n  background-clip: padding-box;\n  border: 1px solid $transparent-dark;\n  color: #333;\n  box-shadow: 0 4px 14px -2px $transparent-light;\n\n  > .#{$namespace-prefix}-backdrop {\n    background-color: $color;\n  }\n\n  > .#{$namespace-prefix}-arrow,\n  > .#{$namespace-prefix}-svg-arrow {\n    &::after {\n      content: '';\n      position: absolute;\n      z-index: -1;\n    }\n  }\n\n  > .#{$namespace-prefix}-arrow::after {\n    border-color: transparent;\n    border-style: solid;\n  }\n\n  &[data-placement^='top'] {\n    > .#{$namespace-prefix}-arrow {\n      &::before {\n        border-top-color: $color;\n      }\n\n      &::after {\n        border-top-color: $transparent-darker;\n        border-width: 7px 7px 0;\n        top: $arrow-size + 1;\n        left: 1px;\n      }\n    }\n\n    > .#{$namespace-prefix}-svg-arrow {\n      > svg {\n        top: $arrow-size;\n      }\n\n      &::after {\n        top: $arrow-size + 1;\n      }\n    }\n  }\n\n  &[data-placement^='bottom'] {\n    > .#{$namespace-prefix}-arrow {\n      &::before {\n        border-bottom-color: $color;\n        bottom: $arrow-size;\n      }\n\n      &::after {\n        border-bottom-color: $transparent-darker;\n        border-width: 0 7px 7px;\n        bottom: $arrow-size + 1;\n        left: 1px;\n      }\n    }\n\n    > .#{$namespace-prefix}-svg-arrow {\n      > svg {\n        bottom: $arrow-size;\n      }\n\n      &::after {\n        bottom: $arrow-size + 1;\n      }\n    }\n  }\n\n  &[data-placement^='left'] {\n    > .#{$namespace-prefix}-arrow {\n      &::before {\n        border-left-color: $color;\n      }\n\n      &::after {\n        border-left-color: $transparent-darker;\n        border-width: 7px 0 7px 7px;\n        left: $arrow-size + 1;\n        top: 1px;\n      }\n    }\n\n    > .#{$namespace-prefix}-svg-arrow {\n      > svg {\n        left: 11px;\n      }\n\n      &::after {\n        left: 12px;\n      }\n    }\n  }\n\n  &[data-placement^='right'] {\n    > .#{$namespace-prefix}-arrow {\n      &::before {\n        border-right-color: $color;\n        right: $arrow-size;\n      }\n\n      &::after {\n        border-width: 7px 7px 7px 0;\n        right: $arrow-size + 1;\n        top: 1px;\n        border-right-color: $transparent-darker;\n      }\n    }\n\n    > .#{$namespace-prefix}-svg-arrow {\n      > svg {\n        right: 11px;\n      }\n\n      &::after {\n        right: 12px;\n      }\n    }\n  }\n\n  > .#{$namespace-prefix}-svg-arrow {\n    fill: white;\n\n    &::after {\n      background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiIC8+PC9zdmc+);\n      background-size: $arrow-size 6px;\n      width: $arrow-size;\n      height: 6px;\n    }\n  }\n}\n"
  },
  {
    "path": "src/scss/themes/light.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n$color: white;\n\n.#{$namespace-prefix}-box[data-theme~='light'] {\n  color: #26323d;\n  box-shadow: 0 0 20px 4px rgba(154, 161, 177, 0.15),\n    0 4px 80px -8px rgba(36, 40, 47, 0.25),\n    0 4px 4px -2px rgba(91, 94, 105, 0.15);\n  background-color: $color;\n\n  &[data-placement^='top'] > .#{$namespace-prefix}-arrow::before {\n    border-top-color: $color;\n  }\n\n  &[data-placement^='bottom'] > .#{$namespace-prefix}-arrow::before {\n    border-bottom-color: $color;\n  }\n\n  &[data-placement^='left'] > .#{$namespace-prefix}-arrow::before {\n    border-left-color: $color;\n  }\n\n  &[data-placement^='right'] > .#{$namespace-prefix}-arrow::before {\n    border-right-color: $color;\n  }\n\n  > .#{$namespace-prefix}-backdrop {\n    background-color: $color;\n  }\n\n  > .#{$namespace-prefix}-svg-arrow {\n    fill: $color;\n  }\n}\n"
  },
  {
    "path": "src/scss/themes/material.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n$color: #505355;\n\n.#{$namespace-prefix}-box[data-theme~='material'] {\n  background-color: $color;\n  font-weight: 600;\n\n  &[data-placement^='top'] > .#{$namespace-prefix}-arrow::before {\n    border-top-color: $color;\n  }\n\n  &[data-placement^='bottom'] > .#{$namespace-prefix}-arrow::before {\n    border-bottom-color: $color;\n  }\n\n  &[data-placement^='left'] > .#{$namespace-prefix}-arrow::before {\n    border-left-color: $color;\n  }\n\n  &[data-placement^='right'] > .#{$namespace-prefix}-arrow::before {\n    border-right-color: $color;\n  }\n\n  > .#{$namespace-prefix}-backdrop {\n    background-color: $color;\n  }\n\n  > .#{$namespace-prefix}-svg-arrow {\n    fill: $color;\n  }\n}\n"
  },
  {
    "path": "src/scss/themes/translucent.scss",
    "content": "@import '../_mixins.scss';\n@import '../_vars.scss';\n\n$color: rgba(0, 0, 0, 0.7);\n\n.#{$namespace-prefix}-box[data-theme~='translucent'] {\n  background-color: $color;\n\n  > .#{$namespace-prefix}-arrow {\n    width: 14px;\n    height: 14px;\n  }\n\n  /**\n  * We use an 8px arrow with 1px overlap by default, since some browsers (at\n  * least they used to) caused a 1px gap between the arrow and the popper.\n  * However, with the translucent theme, this causes darkening since it \n  * overlaps.\n  */\n  &[data-placement^='top'] > .#{$namespace-prefix}-arrow {\n    &::before {\n      border-width: 7px 7px 0;\n      border-top-color: $color;\n    }\n  }\n\n  &[data-placement^='bottom'] > .#{$namespace-prefix}-arrow {\n    &::before {\n      border-width: 0 7px 7px;\n      border-bottom-color: $color;\n    }\n  }\n\n  &[data-placement^='left'] > .#{$namespace-prefix}-arrow {\n    &::before {\n      border-width: 7px 0 7px 7px;\n      border-left-color: $color;\n    }\n  }\n\n  &[data-placement^='right'] > .#{$namespace-prefix}-arrow {\n    &::before {\n      border-width: 7px 7px 7px 0;\n      border-right-color: $color;\n    }\n  }\n\n  > .#{$namespace-prefix}-backdrop {\n    background-color: $color;\n  }\n\n  > .#{$namespace-prefix}-svg-arrow {\n    fill: $color;\n  }\n}\n"
  },
  {
    "path": "src/template.ts",
    "content": "import {\n  ARROW_CLASS,\n  BACKDROP_CLASS,\n  BOX_CLASS,\n  CONTENT_CLASS,\n  SVG_ARROW_CLASS,\n} from './constants';\nimport {div, isElement} from './dom-utils';\nimport {Instance, PopperElement, Props} from './types';\nimport {PopperChildren} from './types-internal';\nimport {arrayFrom} from './utils';\n\n// Firefox extensions don't allow .innerHTML = \"...\" property. This tricks it.\nconst innerHTML = (): 'innerHTML' => 'innerHTML';\n\nfunction dangerouslySetInnerHTML(element: Element, html: string): void {\n  element[innerHTML()] = html;\n}\n\nfunction createArrowElement(value: Props['arrow']): HTMLDivElement {\n  const arrow = div();\n\n  if (value === true) {\n    arrow.className = ARROW_CLASS;\n  } else {\n    arrow.className = SVG_ARROW_CLASS;\n\n    if (isElement(value)) {\n      arrow.appendChild(value);\n    } else {\n      dangerouslySetInnerHTML(arrow, value as string);\n    }\n  }\n\n  return arrow;\n}\n\nexport function setContent(content: HTMLDivElement, props: Props): void {\n  if (isElement(props.content)) {\n    dangerouslySetInnerHTML(content, '');\n    content.appendChild(props.content);\n  } else if (typeof props.content !== 'function') {\n    if (props.allowHTML) {\n      dangerouslySetInnerHTML(content, props.content);\n    } else {\n      content.textContent = props.content;\n    }\n  }\n}\n\nexport function getChildren(popper: PopperElement): PopperChildren {\n  const box = popper.firstElementChild as HTMLDivElement;\n  const boxChildren = arrayFrom(box.children);\n\n  return {\n    box,\n    content: boxChildren.find((node) => node.classList.contains(CONTENT_CLASS)),\n    arrow: boxChildren.find(\n      (node) =>\n        node.classList.contains(ARROW_CLASS) ||\n        node.classList.contains(SVG_ARROW_CLASS)\n    ),\n    backdrop: boxChildren.find((node) =>\n      node.classList.contains(BACKDROP_CLASS)\n    ),\n  };\n}\n\nexport function render(\n  instance: Instance\n): {\n  popper: PopperElement;\n  onUpdate?: (prevProps: Props, nextProps: Props) => void;\n} {\n  const popper = div();\n\n  const box = div();\n  box.className = BOX_CLASS;\n  box.setAttribute('data-state', 'hidden');\n  box.setAttribute('tabindex', '-1');\n\n  const content = div();\n  content.className = CONTENT_CLASS;\n  content.setAttribute('data-state', 'hidden');\n\n  setContent(content, instance.props);\n\n  popper.appendChild(box);\n  box.appendChild(content);\n\n  onUpdate(instance.props, instance.props);\n\n  function onUpdate(prevProps: Props, nextProps: Props): void {\n    const {box, content, arrow} = getChildren(popper);\n\n    if (nextProps.theme) {\n      box.setAttribute('data-theme', nextProps.theme);\n    } else {\n      box.removeAttribute('data-theme');\n    }\n\n    if (typeof nextProps.animation === 'string') {\n      box.setAttribute('data-animation', nextProps.animation);\n    } else {\n      box.removeAttribute('data-animation');\n    }\n\n    if (nextProps.inertia) {\n      box.setAttribute('data-inertia', '');\n    } else {\n      box.removeAttribute('data-inertia');\n    }\n\n    box.style.maxWidth =\n      typeof nextProps.maxWidth === 'number'\n        ? `${nextProps.maxWidth}px`\n        : nextProps.maxWidth;\n\n    if (nextProps.role) {\n      box.setAttribute('role', nextProps.role);\n    } else {\n      box.removeAttribute('role');\n    }\n\n    if (\n      prevProps.content !== nextProps.content ||\n      prevProps.allowHTML !== nextProps.allowHTML\n    ) {\n      setContent(content, instance.props);\n    }\n\n    if (nextProps.arrow) {\n      if (!arrow) {\n        box.appendChild(createArrowElement(nextProps.arrow));\n      } else if (prevProps.arrow !== nextProps.arrow) {\n        box.removeChild(arrow);\n        box.appendChild(createArrowElement(nextProps.arrow));\n      }\n    } else if (arrow) {\n      box.removeChild(arrow!);\n    }\n  }\n\n  return {\n    popper,\n    onUpdate,\n  };\n}\n\n// Runtime check to identify if the render function is the default one; this\n// way we can apply default CSS transitions logic and it can be tree-shaken away\nrender.$$tippy = true;\n"
  },
  {
    "path": "src/types-internal.ts",
    "content": "import {State} from '@popperjs/core';\nimport {Props} from './types';\n\nexport interface ListenerObject {\n  node: Element;\n  eventType: string;\n  handler: EventListenerOrEventListenerObject;\n  options: boolean | Record<string, unknown>;\n}\n\nexport interface PopperTreeData {\n  popperRect: ClientRect;\n  popperState: State;\n  props: Props;\n}\n\nexport interface PopperChildren {\n  box: HTMLDivElement;\n  content: HTMLDivElement;\n  arrow?: HTMLDivElement;\n  backdrop?: HTMLDivElement;\n}\n"
  },
  {
    "path": "src/types.ts",
    "content": "import * as Popper from '@popperjs/core';\n\nexport type BasePlacement = Popper.BasePlacement;\n\nexport type Placement = Popper.Placement;\n\nexport type Content =\n  | string\n  | Element\n  | DocumentFragment\n  | ((ref: Element) => string | Element | DocumentFragment);\n\nexport type SingleTarget = Element;\n\nexport type MultipleTargets = string | Element[] | NodeList;\n\nexport type Targets = SingleTarget | MultipleTargets;\n\nexport interface ReferenceElement<TProps = Props> extends Element {\n  _tippy?: Instance<TProps>;\n}\n\nexport interface PopperElement<TProps = Props> extends HTMLDivElement {\n  _tippy?: Instance<TProps>;\n}\n\nexport interface LifecycleHooks<TProps = Props> {\n  onAfterUpdate(\n    instance: Instance<TProps>,\n    partialProps: Partial<TProps>\n  ): void;\n  onBeforeUpdate(\n    instance: Instance<TProps>,\n    partialProps: Partial<TProps>\n  ): void;\n  onCreate(instance: Instance<TProps>): void;\n  onDestroy(instance: Instance<TProps>): void;\n  onHidden(instance: Instance<TProps>): void;\n  onHide(instance: Instance<TProps>): void | false;\n  onMount(instance: Instance<TProps>): void;\n  onShow(instance: Instance<TProps>): void | false;\n  onShown(instance: Instance<TProps>): void;\n  onTrigger(instance: Instance<TProps>, event: Event): void;\n  onUntrigger(instance: Instance<TProps>, event: Event): void;\n  onClickOutside(instance: Instance<TProps>, event: Event): void;\n}\n\nexport interface RenderProps {\n  allowHTML: boolean;\n  animation: string | boolean;\n  arrow: boolean | string | SVGElement | DocumentFragment;\n  content: Content;\n  inertia: boolean;\n  maxWidth: number | string;\n  role: string;\n  theme: string;\n  zIndex: number;\n}\n\nexport interface GetReferenceClientRect {\n  (): ClientRect | DOMRect;\n  contextElement?: Element;\n}\n\nexport interface Props extends LifecycleHooks, RenderProps {\n  animateFill: boolean;\n  appendTo: 'parent' | Element | ((ref: Element) => Element);\n  aria: {\n    content?: 'auto' | 'describedby' | 'labelledby' | null;\n    expanded?: 'auto' | boolean;\n  };\n  delay: number | [number | null, number | null];\n  duration: number | [number | null, number | null];\n  followCursor: boolean | 'horizontal' | 'vertical' | 'initial';\n  getReferenceClientRect: null | GetReferenceClientRect;\n  hideOnClick: boolean | 'toggle';\n  ignoreAttributes: boolean;\n  inlinePositioning: boolean;\n  interactive: boolean;\n  interactiveBorder: number;\n  interactiveDebounce: number;\n  moveTransition: string;\n  offset:\n    | [number, number]\n    | (({\n        placement,\n        popper,\n        reference,\n      }: {\n        placement: Placement;\n        popper: Popper.Rect;\n        reference: Popper.Rect;\n      }) => [number, number]);\n  placement: Placement;\n  plugins: Plugin<unknown>[];\n  popperOptions: Partial<Popper.Options>;\n  render:\n    | ((\n        instance: Instance\n      ) => {\n        popper: PopperElement;\n        onUpdate?: (prevProps: Props, nextProps: Props) => void;\n      })\n    | null;\n  showOnCreate: boolean;\n  sticky: boolean | 'reference' | 'popper';\n  touch: boolean | 'hold' | ['hold', number];\n  trigger: string;\n  triggerTarget: Element | Element[] | null;\n}\n\nexport interface DefaultProps extends Omit<Props, 'delay' | 'duration'> {\n  delay: number | [number, number];\n  duration: number | [number, number];\n}\n\nexport interface Instance<TProps = Props> {\n  clearDelayTimeouts(): void;\n  destroy(): void;\n  disable(): void;\n  enable(): void;\n  hide(): void;\n  hideWithInteractivity(event: MouseEvent): void;\n  id: number;\n  plugins: Plugin<TProps>[];\n  popper: PopperElement<TProps>;\n  popperInstance: Popper.Instance | null;\n  props: TProps;\n  reference: ReferenceElement<TProps>;\n  setContent(content: Content): void;\n  setProps(partialProps: Partial<TProps>): void;\n  show(): void;\n  state: {\n    isEnabled: boolean;\n    isVisible: boolean;\n    isDestroyed: boolean;\n    isMounted: boolean;\n    isShown: boolean;\n  };\n  unmount(): void;\n}\n\nexport interface TippyStatics {\n  readonly currentInput: {isTouch: boolean};\n  readonly defaultProps: DefaultProps;\n  setDefaultProps(partialProps: Partial<DefaultProps>): void;\n}\n\nexport interface Tippy<TProps = Props> extends TippyStatics {\n  (targets: SingleTarget, optionalProps?: Partial<TProps>): Instance<TProps>;\n}\n\nexport interface Tippy<TProps = Props> extends TippyStatics {\n  (targets: MultipleTargets, optionalProps?: Partial<TProps>): Instance<\n    TProps\n  >[];\n}\n\ndeclare const tippy: Tippy;\n\n// =============================================================================\n// Addon types\n// =============================================================================\nexport interface DelegateInstance<TProps = Props> extends Instance<TProps> {\n  destroy(shouldDestroyTargetInstances?: boolean): void;\n}\n\nexport interface Delegate<TProps = Props> {\n  (\n    targets: SingleTarget,\n    props: Partial<TProps> & {target: string}\n  ): DelegateInstance<TProps>;\n}\n\nexport interface Delegate<TProps = Props> {\n  (\n    targets: MultipleTargets,\n    props: Partial<TProps> & {target: string}\n  ): DelegateInstance<TProps>[];\n}\n\nexport type CreateSingletonProps<TProps = Props> = TProps & {\n  overrides: Array<keyof TProps>;\n};\n\nexport type CreateSingletonInstance<TProps = CreateSingletonProps> = Instance<\n  TProps\n> & {\n  setInstances(instances: Instance<any>[]): void;\n  show(target?: ReferenceElement | Instance | number): void;\n  showNext(): void;\n  showPrevious(): void;\n};\n\nexport type CreateSingleton<TProps = Props> = (\n  tippyInstances: Instance<any>[],\n  optionalProps?: Partial<CreateSingletonProps<TProps>>\n) => CreateSingletonInstance<CreateSingletonProps<TProps>>;\n\ndeclare const delegate: Delegate;\ndeclare const createSingleton: CreateSingleton;\n\n// =============================================================================\n// Plugin types\n// =============================================================================\nexport interface Plugin<TProps = Props> {\n  name?: string;\n  defaultValue?: any;\n  fn(instance: Instance<TProps>): Partial<LifecycleHooks<TProps>>;\n}\n\nexport interface AnimateFill extends Plugin {\n  name: 'animateFill';\n  defaultValue: false;\n}\n\nexport interface FollowCursor extends Plugin {\n  name: 'followCursor';\n  defaultValue: false;\n}\n\nexport interface InlinePositioning extends Plugin {\n  name: 'inlinePositioning';\n  defaultValue: false;\n}\n\nexport interface Sticky extends Plugin {\n  name: 'sticky';\n  defaultValue: false;\n}\n\ndeclare const animateFill: AnimateFill;\ndeclare const followCursor: FollowCursor;\ndeclare const inlinePositioning: InlinePositioning;\ndeclare const sticky: Sticky;\n\n// =============================================================================\n// Misc types\n// =============================================================================\nexport interface HideAllOptions {\n  duration?: number;\n  exclude?: Instance | ReferenceElement;\n}\n\nexport type HideAll = (options?: HideAllOptions) => void;\n\ndeclare const hideAll: HideAll;\ndeclare const roundArrow: string;\n\nexport default tippy;\nexport {\n  hideAll,\n  delegate,\n  createSingleton,\n  animateFill,\n  followCursor,\n  inlinePositioning,\n  sticky,\n  roundArrow,\n};\n"
  },
  {
    "path": "src/utils.ts",
    "content": "import {BasePlacement, Placement} from './types';\n\nexport function hasOwnProperty(\n  obj: Record<string, unknown>,\n  key: string\n): boolean {\n  return {}.hasOwnProperty.call(obj, key);\n}\n\nexport function getValueAtIndexOrReturn<T>(\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\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\nexport function invokeWithArgsOrReturn(value: any, args: any[]): any {\n  return typeof value === 'function' ? value(...args) : value;\n}\n\nexport function debounce<T>(\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\nexport function removeProperties<T>(obj: T, keys: string[]): Partial<T> {\n  const clone = {...obj};\n  keys.forEach((key) => {\n    delete (clone as any)[key];\n  });\n  return clone;\n}\n\nexport function splitBySpaces(value: string): string[] {\n  return value.split(/\\s+/).filter(Boolean);\n}\n\nexport function normalizeToArray<T>(value: T | T[]): T[] {\n  return ([] as T[]).concat(value);\n}\n\nexport function pushIfUnique<T>(arr: T[], value: T): void {\n  if (arr.indexOf(value) === -1) {\n    arr.push(value);\n  }\n}\n\nexport function appendPxIfNumber(value: string | number): string {\n  return typeof value === 'number' ? `${value}px` : value;\n}\n\nexport function unique<T>(arr: T[]): T[] {\n  return arr.filter((item, index) => arr.indexOf(item) === index);\n}\n\nexport function getNumber(value: string | number): number {\n  return typeof value === 'number' ? value : parseFloat(value);\n}\n\nexport function getBasePlacement(placement: Placement): BasePlacement {\n  return placement.split('-')[0] as BasePlacement;\n}\n\nexport function arrayFrom(value: ArrayLike<any>): any[] {\n  return [].slice.call(value);\n}\n\nexport function removeUndefinedProps(\n  obj: Record<string, unknown>\n): Partial<Record<string, unknown>> {\n  return Object.keys(obj).reduce((acc, key) => {\n    if (obj[key] !== undefined) {\n      (acc as any)[key] = obj[key];\n    }\n\n    return acc;\n  }, {});\n}\n"
  },
  {
    "path": "src/validation.ts",
    "content": "import {Targets} from './types';\n\nexport function createMemoryLeakWarning(method: string): string {\n  const txt = method === 'destroy' ? 'n already-' : ' ';\n\n  return [\n    `${method}() was called on a${txt}destroyed instance. This is a no-op but`,\n    'indicates a potential memory leak.',\n  ].join(' ');\n}\n\nexport function clean(value: string): string {\n  const spacesAndTabs = /[ \\t]{2,}/g;\n  const lineStartWithSpaces = /^[ \\t]*/gm;\n\n  return value\n    .replace(spacesAndTabs, ' ')\n    .replace(lineStartWithSpaces, '')\n    .trim();\n}\n\nfunction getDevMessage(message: string): string {\n  return clean(`\n  %ctippy.js\n\n  %c${clean(message)}\n\n  %c👷‍ This is a development-only message. It will be removed in production.\n  `);\n}\n\nexport function getFormattedMessage(message: string): string[] {\n  return [\n    getDevMessage(message),\n    // title\n    'color: #00C584; font-size: 1.3em; font-weight: bold;',\n    // message\n    'line-height: 1.5',\n    // footer\n    'color: #a6a095;',\n  ];\n}\n\n// Assume warnings and errors never have the same message\nlet visitedMessages: Set<string>;\nif (__DEV__) {\n  resetVisitedMessages();\n}\n\nexport function resetVisitedMessages(): void {\n  visitedMessages = new Set();\n}\n\nexport function warnWhen(condition: boolean, message: string): void {\n  if (condition && !visitedMessages.has(message)) {\n    visitedMessages.add(message);\n    console.warn(...getFormattedMessage(message));\n  }\n}\n\nexport function errorWhen(condition: boolean, message: string): void {\n  if (condition && !visitedMessages.has(message)) {\n    visitedMessages.add(message);\n    console.error(...getFormattedMessage(message));\n  }\n}\n\nexport function validateTargets(targets: Targets): void {\n  const didPassFalsyValue = !targets;\n  const didPassPlainObject =\n    Object.prototype.toString.call(targets) === '[object Object]' &&\n    !(targets as any).addEventListener;\n\n  errorWhen(\n    didPassFalsyValue,\n    [\n      'tippy() was passed',\n      '`' + String(targets) + '`',\n      'as its targets (first) argument. Valid types are: String, Element,',\n      'Element[], or NodeList.',\n    ].join(' ')\n  );\n\n  errorWhen(\n    didPassPlainObject,\n    [\n      'tippy() was passed a plain object which is not supported as an argument',\n      'for virtual positioning. Use props.getReferenceClientRect instead.',\n    ].join(' ')\n  );\n}\n"
  },
  {
    "path": "test/functional/border.test.js",
    "content": "/**\n * @jest-environment puppeteer\n */\nimport {navigateToTest, screenshotTest} from '../utils';\n\ndescribe('border', () => {\n  it('borders are correctly inherited and SVG styles are correct', async () => {\n    const page = await browser.newPage();\n    await page.setViewport({width: 1200, height: 800});\n\n    await page.goto('http://host.docker.internal:5000');\n    await navigateToTest(page, 'border');\n\n    expect(await screenshotTest(page, 'border')).toMatchImageSnapshot();\n  });\n});\n"
  },
  {
    "path": "test/functional/followCursor.test.js",
    "content": "/**\n * @jest-environment puppeteer\n */\nimport {navigateToTest, screenshotTest} from '../utils';\n\nfunction generateSelector(test) {\n  return `#followCursor [data-test=\"${test}\"]`;\n}\n\ndescribe('followCursor', () => {\n  describe('true', () => {\n    it('follows the cursor on both axes', async () => {\n      const selector = generateSelector(true);\n      const page = await browser.newPage();\n\n      await page.setViewport({width: 1200, height: 800});\n      await page.goto('http://host.docker.internal:5000');\n      await navigateToTest(page, 'followCursor');\n\n      const reference = await page.$(selector);\n      const rect = await page.evaluate((ref) => {\n        const {top, left} = ref.getBoundingClientRect();\n        return {top, left};\n      }, reference);\n\n      await page.hover(selector);\n      await page.waitFor(60);\n      await page.mouse.move(rect.left + 15, rect.top + 20);\n\n      expect(await screenshotTest(page, 'followCursor')).toMatchImageSnapshot();\n    });\n  });\n\n  it('stays at cursor when content changes', async () => {\n    const selector = generateSelector('contentChange');\n    const page = await browser.newPage();\n\n    await page.setViewport({width: 1200, height: 800});\n    await page.goto('http://host.docker.internal:5000');\n    await navigateToTest(page, 'followCursor');\n\n    await page.hover(selector);\n    await page.waitFor(150);\n\n    expect(await screenshotTest(page, 'followCursor')).toMatchImageSnapshot();\n  });\n\n  describe('false', () => {\n    it('does not follow the cursor at all', async () => {\n      const selector = generateSelector(false);\n      const page = await browser.newPage();\n\n      await page.setViewport({width: 1200, height: 800});\n      await page.goto('http://host.docker.internal:5000');\n      await navigateToTest(page, 'followCursor');\n\n      const reference = await page.$(selector);\n      const rect = await page.evaluate((ref) => {\n        const {top, left} = ref.getBoundingClientRect();\n        return {top, left};\n      }, reference);\n\n      await page.hover(selector);\n      await page.waitFor(60);\n      await page.mouse.move(rect.left + 15, rect.top + 20);\n\n      expect(await screenshotTest(page, 'followCursor')).toMatchImageSnapshot();\n    });\n  });\n\n  describe('horizontal', () => {\n    it('follows the cursor only on the horizontal axis', async () => {\n      const selector = generateSelector('horizontal');\n      const page = await browser.newPage();\n\n      await page.setViewport({width: 1200, height: 800});\n      await page.goto('http://host.docker.internal:5000');\n      await navigateToTest(page, 'followCursor');\n\n      const reference = await page.$(selector);\n      const rect = await page.evaluate((ref) => {\n        const {top, left} = ref.getBoundingClientRect();\n        return {top, left};\n      }, reference);\n\n      await page.hover(selector);\n      await page.waitFor(60);\n      await page.mouse.move(rect.left + 15, rect.top + 20);\n\n      expect(await screenshotTest(page, 'followCursor')).toMatchImageSnapshot();\n    });\n  });\n\n  describe('vertical', () => {\n    it('follows the cursor only on the vertical axis', async () => {\n      const selector = generateSelector('vertical');\n      const page = await browser.newPage();\n\n      await page.setViewport({width: 1200, height: 800});\n      await page.goto('http://host.docker.internal:5000');\n      await navigateToTest(page, 'followCursor');\n\n      const reference = await page.$(selector);\n      const rect = await page.evaluate((ref) => {\n        const {top, left} = ref.getBoundingClientRect();\n        return {top, left};\n      }, reference);\n\n      await page.hover(selector);\n      await page.waitFor(60);\n      await page.mouse.move(rect.left + 15, rect.top + 20);\n\n      expect(await screenshotTest(page, 'followCursor')).toMatchImageSnapshot();\n    });\n  });\n\n  describe('initial', () => {\n    it('follows the cursor only initially', async () => {\n      const selector = generateSelector('initial');\n      const page = await browser.newPage();\n\n      await page.setViewport({width: 1200, height: 800});\n      await page.goto('http://host.docker.internal:5000');\n      await navigateToTest(page, 'followCursor');\n\n      const reference = await page.$(selector);\n      const rect = await page.evaluate((ref) => {\n        const {top, left} = ref.getBoundingClientRect();\n        return {top, left};\n      }, reference);\n\n      await page.hover(selector);\n      await page.waitFor(60);\n      await page.mouse.move(rect.left, rect.top);\n\n      expect(await screenshotTest(page, 'followCursor')).toMatchImageSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "test/functional/inlinePositioning.test.js",
    "content": "/**\n * @jest-environment puppeteer\n */\nimport {navigateToTest, screenshotTest} from '../utils';\n\ndescribe('inlinePositioning', () => {\n  it('aligns correctly', async () => {\n    const page = await browser.newPage();\n    await page.setViewport({width: 1200, height: 800});\n\n    await page.goto('http://host.docker.internal:5000');\n    await navigateToTest(page, 'inlinePositioning');\n\n    expect(\n      await screenshotTest(page, 'inlinePositioning')\n    ).toMatchImageSnapshot();\n  });\n});\n"
  },
  {
    "path": "test/functional/sticky.test.js",
    "content": "/**\n * @jest-environment puppeteer\n */\nimport {navigateToTest, screenshotTest} from '../utils';\n\ndescribe('sticky', () => {\n  it('stays stuck to the reference element when it moves', async () => {\n    const page = await browser.newPage();\n    await page.setViewport({width: 1200, height: 800});\n\n    await page.goto('http://host.docker.internal:5000');\n    await navigateToTest(page, 'sticky');\n\n    expect(await screenshotTest(page, 'sticky')).toMatchImageSnapshot();\n  });\n});\n"
  },
  {
    "path": "test/functional/themes.test.js",
    "content": "/**\n * @jest-environment puppeteer\n */\nimport {navigateToTest, screenshotTest} from '../utils';\n\ndescribe('themes', () => {\n  it('all themes are correct', async () => {\n    const page = await browser.newPage();\n    await page.setViewport({width: 1200, height: 800});\n\n    await page.goto('http://host.docker.internal:5000');\n    await navigateToTest(page, 'themes');\n\n    expect(await screenshotTest(page, 'themes')).toMatchImageSnapshot();\n  });\n});\n"
  },
  {
    "path": "test/image-reporter.js",
    "content": "const {red, bold} = require('colorette');\nconst fs = require('fs');\nconst poster = require('poster');\n\n// https://api.anonymousfiles.io/\n\nclass ImageReporter {\n  constructor(globalConfig, options) {\n    this._globalConfig = globalConfig;\n    this._options = options;\n  }\n\n  onTestResult(test, testResult, aggregateResults) {\n    if (process.env.CI !== 'true') {\n      return;\n    }\n\n    if (\n      testResult.numFailingTests &&\n      testResult.failureMessage.match(/different from snapshot/)\n    ) {\n      const files = fs.readdirSync(\n        './test/functional/__image_snapshots__/__diff_output__/'\n      );\n      files.forEach(async (value) => {\n        const file = `./test/functional/__image_snapshots__/__diff_output__/${value}`;\n\n        poster.post(\n          file,\n          {\n            uploadUrl: 'https://api.anonymousfiles.io/',\n            fileId: 'file',\n            fileContentType: 'image/png',\n          },\n          (err, data) => {\n            if (err) {\n              throw err;\n            }\n\n            console.log(\n              red(bold(`Uploaded image diff file to ${JSON.parse(data).url}`))\n            );\n          }\n        );\n      });\n    }\n  }\n}\n\nmodule.exports = ImageReporter;\n"
  },
  {
    "path": "test/integration/__snapshots__/createTippy.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`createTippy returns the instance with expected properties 1`] = `\nObject {\n  \"clearDelayTimeouts\": [Function],\n  \"destroy\": [Function],\n  \"disable\": [Function],\n  \"enable\": [Function],\n  \"hide\": [Function],\n  \"hideWithInteractivity\": [Function],\n  \"id\": 1,\n  \"plugins\": Array [],\n  \"popper\": <div\n    data-__namespace_prefix__-root=\"\"\n    id=\"__NAMESPACE_PREFIX__-1\"\n    style=\"pointer-events: none; z-index: 9999;\"\n  >\n    <div\n      class=\"__NAMESPACE_PREFIX__-box\"\n      data-animation=\"fade\"\n      data-state=\"hidden\"\n      role=\"tooltip\"\n      style=\"max-width: 350px;\"\n      tabindex=\"-1\"\n    >\n      <div\n        class=\"__NAMESPACE_PREFIX__-content\"\n        data-state=\"hidden\"\n      >\n        __DEFAULT_TEST_CONTENT__\n      </div>\n      <div\n        class=\"__NAMESPACE_PREFIX__-arrow\"\n      />\n    </div>\n  </div>,\n  \"popperInstance\": null,\n  \"props\": Object {\n    \"allowHTML\": false,\n    \"animateFill\": false,\n    \"animation\": \"fade\",\n    \"appendTo\": [Function],\n    \"aria\": Object {\n      \"content\": \"describedby\",\n      \"expanded\": false,\n    },\n    \"arrow\": true,\n    \"content\": \"__DEFAULT_TEST_CONTENT__\",\n    \"delay\": 0,\n    \"duration\": 0,\n    \"followCursor\": false,\n    \"getReferenceClientRect\": null,\n    \"hideOnClick\": true,\n    \"ignoreAttributes\": false,\n    \"inertia\": false,\n    \"inlinePositioning\": false,\n    \"interactive\": false,\n    \"interactiveBorder\": 2,\n    \"interactiveDebounce\": 0,\n    \"maxWidth\": 350,\n    \"moveTransition\": \"\",\n    \"offset\": Array [\n      0,\n      10,\n    ],\n    \"onAfterUpdate\": [Function],\n    \"onBeforeUpdate\": [Function],\n    \"onClickOutside\": [Function],\n    \"onCreate\": [Function],\n    \"onDestroy\": [Function],\n    \"onHidden\": [Function],\n    \"onHide\": [Function],\n    \"onMount\": [Function],\n    \"onShow\": [Function],\n    \"onShown\": [Function],\n    \"onTrigger\": [Function],\n    \"onUntrigger\": [Function],\n    \"placement\": \"top\",\n    \"plugins\": Array [],\n    \"popperOptions\": Object {},\n    \"render\": [Function],\n    \"role\": \"tooltip\",\n    \"showOnCreate\": false,\n    \"sticky\": false,\n    \"theme\": \"\",\n    \"touch\": true,\n    \"trigger\": \"mouseenter focus\",\n    \"triggerTarget\": null,\n    \"zIndex\": 9999,\n  },\n  \"reference\": <button\n    class=\"__tippy\"\n  />,\n  \"setContent\": [Function],\n  \"setProps\": [Function],\n  \"show\": [Function],\n  \"state\": Object {\n    \"isDestroyed\": false,\n    \"isEnabled\": true,\n    \"isMounted\": false,\n    \"isShown\": false,\n    \"isVisible\": false,\n  },\n  \"unmount\": [Function],\n}\n`;\n"
  },
  {
    "path": "test/integration/__snapshots__/props.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`content DocumentFragment is injected into the tippy node 1`] = `\n<div\n  class=\"__NAMESPACE_PREFIX__-content\"\n  data-state=\"hidden\"\n>\n  <button\n    class=\"__tippy\"\n  />\n</div>\n`;\n\nexports[`content Element is injected into the tippy node 1`] = `\n<div\n  class=\"__NAMESPACE_PREFIX__-content\"\n  data-state=\"visible\"\n  style=\"transition-duration: 0ms;\"\n>\n  <button\n    class=\"__tippy\"\n  >\n    string\n  </button>\n</div>\n`;\n\nexports[`content Function is injected into the tippy node 1`] = `\n<div\n  class=\"__NAMESPACE_PREFIX__-content\"\n  data-state=\"visible\"\n  style=\"transition-duration: 0ms;\"\n>\n  string\n</div>\n`;\n\nexports[`content string is injected into the tippy node 1`] = `\n<div\n  class=\"__NAMESPACE_PREFIX__-content\"\n  data-state=\"visible\"\n  style=\"transition-duration: 0ms;\"\n>\n  string\n</div>\n`;\n\nexports[`popperOptions merges modifiers correctly 1`] = `\nArray [\n  Object {\n    \"data\": Object {},\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"popperOffsets\",\n    \"phase\": \"read\",\n  },\n  Object {\n    \"data\": Object {\n      \"_skip\": false,\n    },\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"flip\",\n    \"options\": Object {\n      \"fallbackPlacements\": Array [\n        \"right\",\n      ],\n      \"padding\": 5,\n    },\n    \"phase\": \"main\",\n    \"requiresIfExists\": Array [\n      \"offset\",\n    ],\n  },\n  Object {\n    \"data\": Object {},\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"preventOverflow\",\n    \"options\": Object {\n      \"padding\": Object {\n        \"bottom\": 2,\n        \"left\": 5,\n        \"right\": 5,\n        \"top\": 2,\n      },\n      \"rootBoundary\": \"document\",\n    },\n    \"phase\": \"main\",\n    \"requiresIfExists\": Array [\n      \"offset\",\n    ],\n  },\n  Object {\n    \"data\": Object {},\n    \"effect\": [Function],\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"arrow\",\n    \"options\": Object {\n      \"element\": <div\n        class=\"__NAMESPACE_PREFIX__-arrow\"\n        style=\"position: absolute; left: 0px; transform: translate(999px, 0px);\"\n      />,\n      \"padding\": 999,\n    },\n    \"phase\": \"main\",\n    \"requires\": Array [\n      \"popperOffsets\",\n    ],\n    \"requiresIfExists\": Array [\n      \"preventOverflow\",\n    ],\n  },\n  Object {\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"hide\",\n    \"phase\": \"main\",\n    \"requiresIfExists\": Array [\n      \"preventOverflow\",\n    ],\n  },\n  Object {\n    \"data\": Object {},\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"computeStyles\",\n    \"options\": Object {\n      \"adaptive\": true,\n    },\n    \"phase\": \"beforeWrite\",\n  },\n  Object {\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"$$tippy\",\n    \"phase\": \"beforeWrite\",\n    \"requires\": Array [\n      \"computeStyles\",\n    ],\n  },\n  Object {\n    \"data\": Object {},\n    \"effect\": [Function],\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"eventListeners\",\n    \"phase\": \"write\",\n  },\n  Object {\n    \"effect\": [Function],\n    \"enabled\": true,\n    \"fn\": [Function],\n    \"name\": \"applyStyles\",\n    \"phase\": \"write\",\n    \"requires\": Array [\n      \"computeStyles\",\n    ],\n  },\n]\n`;\n"
  },
  {
    "path": "test/integration/addons/createSingleton.test.js",
    "content": "import {fireEvent} from '@testing-library/dom';\nimport {h} from '../../utils';\n\nimport createSingleton from '../../../src/addons/createSingleton';\nimport tippy from '../../../src';\nimport {getFormattedMessage} from '../../../src/validation';\nimport {currentInput} from '../../../src/bindGlobalEventListeners';\n\ndescribe('createSingleton', () => {\n  it('shows when a tippy instance reference is triggered', () => {\n    const refs = [h(), h()];\n    const singletonInstance = createSingleton(tippy(refs));\n\n    fireEvent.mouseEnter(refs[0]);\n\n    jest.runAllTimers();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n  });\n\n  it('does not show the original tippy element', () => {\n    const refs = [h(), h()];\n    const firstRef = refs[0];\n\n    createSingleton(tippy(refs));\n\n    fireEvent.mouseEnter(firstRef);\n\n    jest.runAllTimers();\n\n    expect(firstRef._tippy.state.isVisible).toBe(false);\n  });\n\n  it('uses the relevant tippy instance content', () => {\n    const configs = [{content: 'hi'}, {content: 'bye'}];\n    const instances = configs.map((props) => tippy(h(), props));\n    const singletonInstance = createSingleton(instances);\n\n    fireEvent.mouseEnter(instances[0].reference);\n\n    expect(singletonInstance.props.content).toBe('hi');\n\n    fireEvent.mouseLeave(instances[0].reference);\n    fireEvent.mouseEnter(instances[1].reference);\n\n    expect(singletonInstance.props.content).toBe('bye');\n  });\n\n  it('uses `delay: number` correctly', () => {\n    const refs = [h(), h()];\n    const singletonInstance = createSingleton(tippy(refs), {delay: 1000});\n    const firstRef = refs[0];\n\n    fireEvent.mouseEnter(firstRef);\n    jest.advanceTimersByTime(999);\n\n    expect(singletonInstance.state.isVisible).toBe(false);\n\n    jest.advanceTimersByTime(1);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n\n    fireEvent.mouseLeave(firstRef);\n    jest.advanceTimersByTime(999);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n\n    jest.advanceTimersByTime(1);\n\n    expect(singletonInstance.state.isVisible).toBe(false);\n  });\n\n  it('uses `delay: [number, number]` correctly', () => {\n    const refs = [h(), h()];\n    const singletonInstance = createSingleton(tippy(refs), {\n      delay: [500, 1000],\n    });\n    const firstRef = refs[0];\n\n    fireEvent.mouseEnter(firstRef);\n    jest.advanceTimersByTime(499);\n\n    expect(singletonInstance.state.isVisible).toBe(false);\n\n    jest.advanceTimersByTime(1);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n\n    fireEvent.mouseLeave(firstRef);\n    jest.advanceTimersByTime(999);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n\n    jest.advanceTimersByTime(1);\n\n    expect(singletonInstance.state.isVisible).toBe(false);\n  });\n\n  it('throws if not passed an array', () => {\n    expect(() => {\n      createSingleton(null);\n    }).toThrow();\n\n    expect(console.error).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          'The first argument passed to createSingleton() must be an array of tippy',\n          'instances. The passed value was',\n          String(null),\n        ].join(' ')\n      )\n    );\n  });\n\n  it('does not throw if any passed instance is not part of an existing singleton', () => {\n    expect(() => {\n      const instances = tippy([h(), h()]);\n      const singleton = createSingleton(instances);\n      singleton.destroy();\n      createSingleton(instances);\n    }).not.toThrow();\n  });\n\n  it('allows updates to `onTrigger`, `onDestroy`, and `onAfterUpdate`', () => {\n    const instances = tippy([h()]);\n\n    const onTriggerSpy = jest.fn();\n    const onDestroySpy = jest.fn();\n    const onAfterUpdateSpy = jest.fn();\n\n    const singleton = createSingleton(instances);\n\n    singleton.setProps({\n      onTrigger: onTriggerSpy,\n      onDestroy: onDestroySpy,\n      onAfterUpdate: onAfterUpdateSpy,\n    });\n\n    fireEvent.mouseEnter(instances[0].reference);\n\n    expect(onTriggerSpy).toHaveBeenCalled();\n\n    singleton.setProps({});\n\n    expect(onAfterUpdateSpy).toHaveBeenCalled();\n\n    singleton.destroy();\n\n    expect(onDestroySpy).toHaveBeenCalled();\n  });\n\n  it('can update the `delay` option', () => {\n    const refs = [h(), h()];\n    const singletonInstance = createSingleton(tippy(refs), {delay: 1000});\n    const firstRef = refs[0];\n\n    singletonInstance.setProps({delay: 500});\n\n    fireEvent.mouseEnter(firstRef);\n    jest.advanceTimersByTime(499);\n\n    expect(singletonInstance.state.isVisible).toBe(false);\n\n    jest.advanceTimersByTime(1);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n\n    fireEvent.mouseLeave(firstRef);\n    jest.advanceTimersByTime(499);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n\n    jest.advanceTimersByTime(1);\n\n    expect(singletonInstance.state.isVisible).toBe(false);\n  });\n\n  it('does not destroy the passed instances if passed `false`', () => {\n    const tippyInstances = tippy([h(), h()]);\n    const singletonInstance = createSingleton(tippyInstances);\n    singletonInstance.destroy(false);\n    tippyInstances.forEach((instance) => {\n      expect(instance.state.isDestroyed).toBe(false);\n    });\n  });\n\n  it('restores original state when destroyed', () => {\n    const tippyInstances = tippy([h(), h()]);\n    const prevInstanceProps = tippyInstances.map((instance) => instance.props);\n    const singletonInstance = createSingleton(tippyInstances);\n\n    singletonInstance.destroy(false);\n    tippyInstances.forEach((instance, i) => {\n      const {props} = instance;\n      expect({...props, ...prevInstanceProps[i]}).toEqual(props);\n    });\n  });\n\n  it('handles aria attribute correctly', () => {\n    const tippyInstances = tippy([h(), h()]);\n    const singletonInstance = createSingleton(tippyInstances, {delay: 100});\n\n    const id = `__NAMESPACE_PREFIX__-${singletonInstance.id}`;\n    const {reference: firstRef} = tippyInstances[0];\n    const {reference: secondRef} = tippyInstances[1];\n\n    fireEvent.mouseEnter(firstRef);\n    jest.runAllTimers();\n\n    expect(firstRef.getAttribute('aria-describedby')).toBe(id);\n    expect(secondRef.getAttribute('aria-describedby')).toBe(id);\n\n    fireEvent.mouseLeave(firstRef);\n    fireEvent.mouseEnter(secondRef);\n\n    expect(firstRef.getAttribute('aria-describedby')).toBe(id);\n    expect(secondRef.getAttribute('aria-describedby')).toBe(id);\n\n    singletonInstance.setProps({aria: {content: 'labelledby'}});\n    singletonInstance.hide();\n\n    fireEvent.mouseEnter(firstRef);\n    jest.runAllTimers();\n\n    expect(firstRef.getAttribute('aria-labelledby')).toBe(id);\n    expect(secondRef.getAttribute('aria-labelledby')).toBe(id);\n\n    fireEvent.mouseLeave(firstRef);\n    jest.advanceTimersByTime(100);\n\n    expect(firstRef.getAttribute('aria-labelledby')).toBe(null);\n    expect(secondRef.getAttribute('aria-labelledby')).toBe(null);\n  });\n\n  it('does not use the placeholder element content with a function', () => {\n    const refs = [h(), h()];\n    const instances = tippy(refs, {content: () => 'hello'});\n    const singleton = createSingleton(instances);\n    const firstRef = refs[0];\n\n    expect(singleton.props.content).toBe('__DEFAULT_TEST_CONTENT__');\n\n    fireEvent.mouseEnter(firstRef);\n\n    expect(singleton.props.content).toBe('hello');\n  });\n});\n\ndescribe('overrides prop', () => {\n  it('individual tippy instance props override singleton instance props', () => {\n    const tippyInstances = tippy([h(), h()], {delay: 100});\n    const singletonInstance = createSingleton(tippyInstances, {\n      delay: 0,\n      overrides: ['delay'],\n    });\n\n    fireEvent.mouseEnter(tippyInstances[0].reference);\n\n    expect(singletonInstance.props.delay).toBe(100);\n  });\n\n  it('can be updated via .setProps()', () => {\n    const tippyInstances = tippy([h(), h()], {delay: 100});\n    const singletonInstance = createSingleton(tippyInstances, {\n      delay: 0,\n      overrides: ['delay'],\n    });\n\n    singletonInstance.setProps({overrides: []});\n\n    fireEvent.mouseEnter(tippyInstances[0].reference);\n\n    expect(singletonInstance.props.delay).toBe(0);\n  });\n});\n\ndescribe('.setInstances() method', () => {\n  it('updates the singleton instances', () => {\n    const initialRefs = [h(), h()];\n    const nextRefs = [initialRefs[0], h()];\n\n    const initialInstances = tippy(initialRefs);\n    const nextInstances = tippy(nextRefs);\n\n    const singleton = createSingleton(initialInstances);\n\n    singleton.setInstances(nextInstances);\n\n    expect(initialInstances[1].state.isEnabled).toBe(true);\n    expect(nextInstances[1].state.isEnabled).toBe(false);\n\n    fireEvent.mouseEnter(nextRefs[1]);\n\n    expect(singleton.state.isVisible).toBe(true);\n  });\n});\n\ndescribe('.show() method', () => {\n  const getInstances = () =>\n    [{content: 'first'}, {content: 'second'}, {content: 'last'}].map((props) =>\n      tippy(h(), props)\n    );\n\n  it('shows the first tippy instance when no parameters are passed', () => {\n    const singletonInstance = createSingleton(getInstances());\n\n    singletonInstance.show();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('first');\n  });\n\n  it('shows the tippy instance passed as an argument', () => {\n    const tippyInstances = getInstances();\n    const singletonInstance = createSingleton(tippyInstances);\n\n    singletonInstance.show(tippyInstances[1]);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('second');\n  });\n\n  it('shows the tippy instance related to the reference element passed as an argument', () => {\n    const tippyInstances = getInstances();\n    const singletonInstance = createSingleton(tippyInstances);\n\n    singletonInstance.show(tippyInstances[1].reference);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('second');\n  });\n\n  it('shows the tippy instance at the given index number', () => {\n    const singletonInstance = createSingleton(getInstances());\n\n    singletonInstance.show(1);\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('second');\n  });\n});\n\ndescribe('.showNext() method', () => {\n  const getInstances = () =>\n    [{content: 'first'}, {content: 'second'}, {content: 'last'}].map((props) =>\n      tippy(h(), props)\n    );\n\n  it('shows the first tippy instance if none is visible', () => {\n    const singletonInstance = createSingleton(getInstances());\n\n    singletonInstance.showNext();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('first');\n  });\n  it('shows the tippy instance after the currently visible one', () => {\n    const singletonInstance = createSingleton(getInstances());\n\n    singletonInstance.show();\n\n    expect(singletonInstance.props.content).toBe('first');\n    singletonInstance.showNext();\n    expect(singletonInstance.props.content).toBe('second');\n    singletonInstance.showNext();\n    expect(singletonInstance.props.content).toBe('last');\n  });\n  it('loops to the beginning if the last instance is visible', () => {\n    const singletonInstance = createSingleton(getInstances());\n\n    singletonInstance.show(2);\n\n    expect(singletonInstance.props.content).toBe('last');\n    singletonInstance.showNext();\n    expect(singletonInstance.props.content).toBe('first');\n  });\n});\n\ndescribe('.showPrevious() method', () => {\n  const getInstances = () =>\n    [{content: 'first'}, {content: 'second'}, {content: 'last'}].map((props) =>\n      tippy(h(), props)\n    );\n\n  it('shows the last tippy instance if none is visible', () => {\n    const singletonInstance = createSingleton(getInstances());\n\n    singletonInstance.showPrevious();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('last');\n  });\n  it('shows the tippy instance before the currently visible one', () => {\n    const singletonInstance = createSingleton(getInstances(), {\n      showOnCreate: true,\n    });\n\n    singletonInstance.hide();\n    singletonInstance.show(2);\n\n    expect(singletonInstance.props.content).toBe('last');\n    singletonInstance.showPrevious();\n    expect(singletonInstance.props.content).toBe('second');\n    singletonInstance.showPrevious();\n    expect(singletonInstance.props.content).toBe('first');\n  });\n  it('loops to the end if the first instance is visible', () => {\n    const singletonInstance = createSingleton(getInstances());\n\n    singletonInstance.show();\n\n    expect(singletonInstance.props.content).toBe('first');\n    singletonInstance.showPrevious();\n    expect(singletonInstance.props.content).toBe('last');\n  });\n});\n\ndescribe('showOnCreate prop', () => {\n  it('shows the first tippy instance on creation', () => {\n    const tippyInstances = [{content: 'first'}, {content: 'second'}].map(\n      (props) => tippy(h(), props)\n    );\n\n    const singletonInstance = createSingleton(tippyInstances, {\n      showOnCreate: true,\n    });\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('first');\n  });\n\n  it('resets correctly if showOnCreate is cancelled by a click outside', () => {\n    const tippyInstances = [{content: 'first'}, {content: 'second'}].map(\n      (props) => tippy(h(), props)\n    );\n\n    const singletonInstance = createSingleton(tippyInstances, {\n      showOnCreate: true,\n      delay: 500,\n    });\n\n    fireEvent.mouseDown(document.body);\n    jest.runAllTimers();\n    fireEvent.mouseEnter(tippyInstances[1].reference);\n    jest.runAllTimers();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('second');\n  });\n\n  it('does not hide tippy upon clicking next target', () => {\n    currentInput.isTouch = true;\n\n    const tippyInstances = [{content: 'first'}, {content: 'second'}].map(\n      (props) => tippy(h(), props)\n    );\n\n    const singletonInstance = createSingleton(tippyInstances);\n\n    fireEvent.mouseEnter(tippyInstances[0].reference);\n    fireEvent.mouseDown(document.body);\n    fireEvent.mouseEnter(tippyInstances[1].reference);\n\n    jest.runAllTimers();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('second');\n\n    currentInput.isTouch = false;\n  });\n\n  it('accepts custom `triggerTarget` in individual instances', () => {\n    const ref1 = h();\n    const ref2 = h();\n    const triggerTarget1 = h();\n    const triggerTarget2 = h();\n\n    const tippyInstances = [\n      {ref: ref1, content: 'first', triggerTarget: triggerTarget1},\n      {ref: ref2, content: 'second', triggerTarget: triggerTarget2},\n    ].map(({ref, ...props}) => tippy(ref, props));\n\n    const singletonInstance = createSingleton(tippyInstances);\n\n    fireEvent.mouseEnter(ref1);\n    jest.runAllTimers();\n    expect(singletonInstance.state.isVisible).toBe(false);\n\n    fireEvent.mouseEnter(triggerTarget1);\n    jest.runAllTimers();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('first');\n\n    fireEvent.mouseEnter(triggerTarget2);\n    jest.runAllTimers();\n\n    expect(singletonInstance.state.isVisible).toBe(true);\n    expect(singletonInstance.props.content).toBe('second');\n\n    fireEvent.mouseEnter(ref1);\n    jest.runAllTimers();\n\n    expect(singletonInstance.props.content).toBe('second');\n  });\n});\n"
  },
  {
    "path": "test/integration/addons/delegate.test.js",
    "content": "import {fireEvent} from '@testing-library/dom';\nimport {h} from '../../utils';\n\nimport delegate from '../../../src/addons/delegate';\nimport {getFormattedMessage} from '../../../src/validation';\nimport {normalizeToArray} from '../../../src/utils';\n\nlet instance;\nlet delegateElement = h();\n\nafterEach(() => {\n  if (instance) {\n    normalizeToArray(instance).forEach((i) => i.destroy());\n  }\n\n  delegateElement = h();\n});\n\ndescribe('delegate', () => {\n  it('creates an instance for the child target', () => {\n    const button = h('button', {}, delegateElement);\n    instance = delegate(delegateElement, {target: 'button'});\n\n    expect(button._tippy).toBeUndefined();\n\n    fireEvent.mouseOver(button);\n\n    expect(button._tippy).toBeDefined();\n\n    instance.destroy();\n  });\n\n  it('works with `trigger: click`', () => {\n    const button = h('button', {}, delegateElement);\n    instance = delegate(delegateElement, {\n      target: 'button',\n      trigger: 'click',\n    });\n\n    expect(button._tippy).toBeUndefined();\n\n    fireEvent.click(button);\n\n    expect(button._tippy).toBeDefined();\n\n    instance.destroy();\n  });\n\n  it('handles an array of delegate targets', () => {\n    const refs = [h(), h()];\n\n    refs.forEach((ref) => ref.append(document.createElement('button')));\n\n    instance = delegate(refs, {target: 'button'});\n    const button = refs[0].querySelector('button');\n\n    expect(button._tippy).toBeUndefined();\n\n    fireEvent.mouseOver(button);\n\n    expect(button._tippy).toBeDefined();\n\n    instance.forEach((instance) => instance.destroy());\n  });\n\n  it('does not show its own tippy', () => {\n    instance = delegate(delegateElement, {target: 'button'});\n\n    fireEvent.mouseOver(delegateElement);\n    fireEvent.mouseEnter(delegateElement);\n\n    jest.runAllTimers();\n\n    expect(instance.state.isVisible).toBe(false);\n\n    instance.destroy();\n  });\n\n  it('throws if delegate target is falsy', () => {\n    delegate(null, {target: 'button'});\n\n    expect(console.error).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          'tippy() was passed',\n          '`' + String(null) + '`',\n          'as its targets (first) argument. Valid types are: String, Element, Element[],',\n          'or NodeList.',\n        ].join(' ')\n      )\n    );\n  });\n\n  it('errors if passed missing props object', () => {\n    expect(() => delegate(delegateElement)).toThrow();\n\n    expect(console.error).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          'You must specity a `target` prop indicating a CSS selector string matching',\n          'the target elements that should receive a tippy.',\n        ].join(' ')\n      )\n    );\n  });\n\n  it('errors if passed falsy or missing `target` prop', () => {\n    delegate(delegateElement, {target: ''});\n\n    expect(console.error).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          'You must specity a `target` prop indicating a CSS selector string matching',\n          'the target elements that should receive a tippy.',\n        ].join(' ')\n      )\n    );\n  });\n\n  it('can be destroyed', () => {\n    const button = h('button', {}, delegateElement);\n    instance = delegate(delegateElement, {target: 'button'});\n\n    instance.destroy();\n    fireEvent.mouseOver(button);\n\n    expect(button._tippy).toBeUndefined();\n  });\n\n  it('destroys child instance by default too', () => {\n    const button = h('button', {}, delegateElement);\n    instance = delegate(delegateElement, {target: 'button'});\n\n    fireEvent.mouseOver(button);\n    instance.destroy();\n\n    expect(button._tippy).toBeUndefined();\n  });\n\n  it('does not destroy child instance if passed `false`', () => {\n    const button = h('button', {}, delegateElement);\n    instance = delegate(delegateElement, {target: 'button'});\n\n    fireEvent.mouseOver(button);\n    instance.destroy(false);\n\n    expect(button._tippy).toBeDefined();\n  });\n\n  it('handles `data-tippy-trigger` attribute', () => {\n    const clickButton = h(\n      'button',\n      {'data-tippy-trigger': 'click'},\n      delegateElement\n    );\n    const focusButton = h(\n      'button',\n      {'data-tippy-trigger': 'focus'},\n      delegateElement\n    );\n\n    instance = delegate(delegateElement, {\n      target: 'button',\n      trigger: 'mouseenter',\n    });\n\n    fireEvent.mouseOver(clickButton);\n    expect(clickButton._tippy).toBeUndefined();\n\n    fireEvent.click(clickButton);\n    expect(clickButton._tippy).toBeDefined();\n\n    fireEvent.mouseOver(focusButton);\n    expect(focusButton._tippy).toBeUndefined();\n\n    fireEvent.focusIn(focusButton);\n    expect(focusButton._tippy).toBeDefined();\n  });\n\n  it('respects `delay` on first show', () => {\n    const button = h('button', {}, delegateElement);\n    instance = delegate(delegateElement, {target: 'button', delay: 100});\n\n    fireEvent.mouseOver(button);\n\n    jest.advanceTimersByTime(99);\n\n    expect(button._tippy.state.isVisible).toBe(false);\n\n    jest.advanceTimersByTime(1);\n\n    expect(button._tippy.state.isVisible).toBe(true);\n  });\n\n  it('does not hide tippy with touch input using click trigger', () => {\n    const button = h('button', {}, delegateElement);\n    instance = delegate(delegateElement, {target: 'button', trigger: 'click'});\n\n    fireEvent.touchStart(button, {bubbles: true});\n    fireEvent.click(button, {bubbles: true});\n\n    jest.runAllTimers();\n\n    expect(button._tippy.state.isVisible).toBe(true);\n  });\n});\n"
  },
  {
    "path": "test/integration/bindGlobalEventListeners.test.js",
    "content": "import {h} from '../utils';\n\nimport tippy from '../../src';\nimport * as Listeners from '../../src/bindGlobalEventListeners';\n\ndescribe('onDocumentTouchStart', () => {\n  it('sets currentInput.isTouch to `true`', () => {\n    Listeners.onDocumentTouchStart();\n    Listeners.onDocumentTouchStart();\n\n    expect(Listeners.currentInput.isTouch).toBe(true);\n  });\n\n  it('is undone if two consecutive mousemove events are fired', () => {\n    // NOTE: this is dependent on the previous test\n    Listeners.onDocumentMouseMove();\n    Listeners.onDocumentMouseMove();\n\n    expect(Listeners.currentInput.isTouch).toBe(false);\n  });\n});\n\ndescribe('onWindowBlur', () => {\n  it('does not blur reference element if the tippy is visible', () => {\n    const instance = tippy(h(), {trigger: 'manual'});\n    const spy = jest.fn();\n\n    instance.reference.addEventListener('blur', spy);\n    instance.reference.focus();\n    instance.show();\n\n    Listeners.onWindowBlur();\n\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('does blur reference element if the tippy is not visible', () => {\n    const instance = tippy(h(), {trigger: 'manual'});\n    const spy = jest.fn();\n\n    instance.reference.addEventListener('blur', spy);\n    instance.reference.focus();\n\n    Listeners.onWindowBlur();\n\n    expect(spy).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "test/integration/createTippy.test.js",
    "content": "import {fireEvent} from '@testing-library/dom';\nimport {h, enableTouchEnvironment, disableTouchEnvironment} from '../utils';\n\nimport {defaultProps} from '../../src/props';\nimport createTippy, {mountedInstances} from '../../src/createTippy';\nimport {IOS_CLASS} from '../../src/constants';\nimport animateFill from '../../src/plugins/animateFill';\nimport {getChildren} from '../../src/template';\nimport {getFormattedMessage} from '../../src/validation';\n\nlet instance;\n\nafterEach(() => {\n  if (instance) {\n    instance.destroy();\n  }\n});\n\ndescribe('createTippy', () => {\n  it('returns the instance with expected properties', () => {\n    instance = createTippy(h(), defaultProps);\n\n    expect(instance).toMatchSnapshot();\n  });\n\n  it('sets `undefined` prop to the default', () => {\n    instance = createTippy(h(), {\n      theme: undefined,\n    });\n\n    expect(instance.props.theme).not.toBe(undefined);\n  });\n\n  it('increments the `id` on each call with valid arguments', () => {\n    const instances = [\n      createTippy(h(), defaultProps),\n      createTippy(h(), defaultProps),\n      createTippy(h(), defaultProps),\n    ];\n\n    expect(instances[0].id).toBe(instances[1].id - 1);\n    expect(instances[1].id).toBe(instances[2].id - 1);\n  });\n\n  it('adds correct listeners to the reference element based on `trigger` (`interactive`: false)', () => {\n    instance = createTippy(h(), {\n      ...defaultProps,\n      trigger: 'mouseenter focus click focusin',\n    });\n\n    fireEvent.mouseEnter(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.mouseLeave(instance.reference);\n    expect(instance.state.isVisible).toBe(false);\n\n    fireEvent.focus(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.blur(instance.reference);\n    expect(instance.state.isVisible).toBe(false);\n\n    fireEvent.click(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.mouseLeave(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.click(instance.reference);\n    expect(instance.state.isVisible).toBe(false);\n\n    fireEvent.focusIn(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.focusOut(instance.reference);\n    expect(instance.state.isVisible).toBe(false);\n\n    // For completeness, it would seem to make sense to test that the tippy *is*\n    // hidden on clicking it's content (as this is a non-interactive instance);\n    // however, we use CSS pointer-events: none for non-interaction, so firing a\n    // click event on the tippy content won't test this scenario. Neither can we\n    // test for that style with window.getComputedStyle in the testing\n    // environment.\n  });\n\n  it('adds correct listeners to the reference element based on `trigger` (`interactive`: true)', () => {\n    instance = createTippy(h(), {\n      ...defaultProps,\n      interactive: true,\n      trigger: 'mouseenter focus click focusin',\n    });\n\n    fireEvent.mouseEnter(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    // For interactive tippies, the reference onMouseLeave adds a document.body\n    // listener to scheduleHide, but doesn't scheduleHide itself (hence event\n    // bubbling being required here for the tip to hide).\n    fireEvent.mouseLeave(instance.reference, {bubbles: true});\n    expect(instance.state.isVisible).toBe(false);\n\n    fireEvent.focus(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.blur(instance.reference);\n    expect(instance.state.isVisible).toBe(false);\n\n    fireEvent.click(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.mouseLeave(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.click(instance.reference);\n    expect(instance.state.isVisible).toBe(false);\n\n    fireEvent.click(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.click(getChildren(instance.popper).content);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.focusIn(instance.reference);\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.focusOut(instance.reference);\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('extends `instance.props` with plugin props', () => {\n    instance = createTippy(h(), {...defaultProps, plugins: [animateFill]});\n\n    expect(instance.props.animateFill).toBe(animateFill.defaultValue);\n  });\n\n  it('`instance.plugins` does not contain duplicate plugins', () => {\n    instance = createTippy(h(), {\n      ...defaultProps,\n      plugins: [animateFill, animateFill],\n    });\n\n    expect(instance.plugins).toEqual([animateFill]);\n  });\n\n  it('does not remove an existing `aria-expanded` attribute', () => {\n    const ref = h('div', {'aria-expanded': 'true'});\n    instance = createTippy(ref, {interactive: false});\n\n    expect(ref.hasAttribute('aria-expanded')).toBe(true);\n  });\n\n  // I don't know why a TDZ error occurs due to this, it doesn't happen in the\n  // browser\n  it.skip('bails if props.render is not supplied', () => {\n    const spy = jest.spyOn(console, 'error');\n    instance = createTippy(h(), {render: null});\n\n    expect(spy).toHaveBeenCalledWith(\n      ...getFormattedMessage('render() function has not been supplied.')\n    );\n  });\n\n  // I don't know why a TDZ error occurs due to this, it doesn't happen in the\n  // browser\n  it.skip('bails if props.content is not supplied', () => {\n    const spy = jest.spyOn(console, 'error');\n    instance = createTippy(h(), {content: null});\n\n    expect(spy).toHaveBeenCalledWith(\n      ...getFormattedMessage('content has not been supplied.')\n    );\n  });\n\n  it('does not pass props that are `undefined`', () => {\n    instance = createTippy(h(), {placement: undefined});\n\n    expect(instance.props.placement).toBe('top');\n\n    instance.setProps({placement: undefined});\n\n    expect(instance.props.placement).toBe('top');\n  });\n});\n\ndescribe('instance.destroy()', () => {\n  it('sets state.isDestroyed to `true`', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.destroy();\n\n    expect(instance.state.isDestroyed).toBe(true);\n  });\n\n  it('deletes the `_tippy` property from the reference', () => {\n    const ref = h();\n    instance = createTippy(ref, defaultProps);\n\n    expect('_tippy' in ref).toBe(true);\n\n    instance.destroy();\n\n    expect('_tippy' in ref).toBe(false);\n  });\n\n  it('removes listeners from the reference', () => {\n    const ref = h();\n\n    instance = createTippy(ref, {\n      ...defaultProps,\n      trigger: 'mouseenter',\n    });\n\n    instance.destroy();\n    fireEvent.mouseEnter(ref);\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('does nothing if the instance is already destroyed', () => {\n    const ref = h();\n\n    instance = createTippy(ref, defaultProps);\n    instance.state.isDestroyed = true;\n    instance.destroy();\n\n    expect(ref._tippy).toBeDefined();\n  });\n\n  it('still unmounts the tippy if the instance is disabled', () => {\n    instance = createTippy(h(), defaultProps);\n\n    instance.show();\n    instance.disable();\n    instance.destroy();\n\n    expect(instance.state.isMounted).toBe(false);\n  });\n\n  it('still unmounts the tippy if the instance is disabled', () => {\n    instance = createTippy(h(), defaultProps);\n\n    instance.show();\n\n    jest.runAllTimers();\n\n    instance.disable();\n    instance.destroy();\n\n    expect(instance.state.isMounted).toBe(false);\n  });\n\n  it('clears pending timeouts', () => {\n    instance = createTippy(h(), {...defaultProps, delay: 500});\n\n    const spy = jest.spyOn(instance, 'clearDelayTimeouts');\n\n    fireEvent.mouseEnter(instance.reference);\n\n    instance.destroy();\n\n    jest.advanceTimersByTime(500);\n\n    expect(spy).toHaveBeenCalled();\n  });\n\n  it('destroys popperInstance if it was created', () => {\n    const spy = jest.fn();\n    instance = createTippy(h(), {\n      ...defaultProps,\n      delay: 500,\n      popperOptions: {\n        modifiers: [\n          {\n            name: 'x',\n            enabled: true,\n            phase: 'afterWrite',\n            fn() {},\n            effect() {\n              return spy;\n            },\n          },\n        ],\n      },\n    });\n\n    instance.show();\n    jest.runAllTimers();\n    instance.destroy();\n\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('does not cause a circular call loop if called within onHidden()', () => {\n    instance = createTippy(h(), {\n      ...defaultProps,\n      onHidden() {\n        instance.destroy();\n      },\n    });\n\n    instance.show();\n    jest.runAllTimers();\n\n    instance.hide();\n\n    expect(instance.state.isDestroyed).toBe(true);\n    expect(instance.state.isMounted).toBe(false);\n  });\n});\n\ndescribe('instance.show()', () => {\n  it('changes state.isVisible to `true`', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.show();\n\n    expect(instance.state.isVisible).toBe(true);\n  });\n\n  it('mounts the popper to the DOM', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.show();\n    jest.runAllTimers();\n\n    expect(document.body.contains(instance.popper)).toBe(true);\n  });\n\n  it('does not show tooltip if the reference has a `disabled` attribute', () => {\n    const ref = h();\n\n    ref.setAttribute('disabled', 'disabled');\n    instance = createTippy(ref, defaultProps);\n    instance.show();\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('bails out if already visible', () => {\n    const spy = jest.fn();\n\n    instance = createTippy(h(), {...defaultProps, onShow: spy});\n    instance.show();\n    instance.show();\n\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n});\n\ndescribe('instance.hide()', () => {\n  it('changes state.isVisible to false', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.hide();\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('removes the popper element from the DOM after hiding', () => {\n    instance = createTippy(h(), {\n      ...defaultProps,\n    });\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(document.body.contains(instance.popper)).toBe(true);\n\n    instance.hide();\n    jest.runAllTimers();\n\n    expect(document.body.contains(instance.popper)).toBe(false);\n  });\n\n  it('bails out if already hidden', () => {\n    const spy = jest.fn();\n\n    instance = createTippy(h(), {...defaultProps, onHide: spy});\n    instance.hide();\n    instance.hide();\n\n    expect(spy).toHaveBeenCalledTimes(0);\n\n    instance.show();\n    instance.hide();\n    instance.hide();\n\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n});\n\ndescribe('instance.enable()', () => {\n  it('sets state.isEnabled to `true`', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.enable();\n\n    expect(instance.state.isEnabled).toBe(true);\n  });\n\n  it('allows a tippy to be shown', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.enable();\n    instance.show();\n\n    expect(instance.state.isVisible).toBe(true);\n  });\n});\n\ndescribe('instance.disable()', () => {\n  it('sets state.isEnabled to `false`', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.disable();\n\n    expect(instance.state.isEnabled).toBe(false);\n  });\n\n  it('disallows a tippy to be shown', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.disable();\n    instance.show();\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('hides the instance if visible', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.show();\n    instance.disable();\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n});\n\ndescribe('instance.setProps()', () => {\n  it('sets the new props by merging them with the current instance', () => {\n    instance = createTippy(h(), defaultProps);\n\n    expect(instance.props.arrow).toBe(defaultProps.arrow);\n    expect(instance.props.duration).toBe(defaultProps.duration);\n\n    instance.setProps({arrow: !defaultProps.arrow, duration: 82});\n\n    expect(instance.props.arrow).toBe(!defaultProps.arrow);\n    expect(instance.props.duration).toBe(82);\n  });\n\n  it('redraws the tooltip by creating a new popper element', () => {\n    instance = createTippy(h(), defaultProps);\n\n    expect(\n      instance.popper.querySelector('.__NAMESPACE_PREFIX__-arrow')\n    ).not.toBeNull();\n\n    instance.setProps({arrow: false});\n\n    expect(\n      instance.popper.querySelector('.__NAMESPACE_PREFIX__-arrow')\n    ).toBeNull();\n  });\n\n  it('popper._tippy is defined with the correct instance', () => {\n    instance = createTippy(h(), defaultProps);\n\n    instance.setProps({arrow: true});\n\n    expect(instance.popper._tippy).toBe(instance);\n  });\n\n  it('changing `trigger` or `touchHold` changes listeners', () => {\n    const ref = h();\n    instance = createTippy(ref, defaultProps);\n\n    instance.setProps({trigger: 'click'});\n    fireEvent.mouseEnter(ref);\n\n    expect(instance.state.isVisible).toBe(false);\n\n    fireEvent.click(ref);\n    expect(instance.state.isVisible).toBe(true);\n  });\n\n  it('does nothing if the instance is destroyed', () => {\n    instance = createTippy(h(), defaultProps);\n\n    instance.destroy();\n    instance.setProps({content: 'hello'});\n\n    expect(instance.props.content).not.toBe('hello');\n  });\n\n  it('correctly removes stale `aria-expanded` attributes', () => {\n    instance = createTippy(h(), {...defaultProps, interactive: true});\n    const triggerTarget = h();\n\n    expect(instance.reference.getAttribute('aria-expanded')).toBe('false');\n\n    instance.setProps({interactive: false});\n\n    expect(instance.reference.getAttribute('aria-expanded')).toBe(null);\n\n    instance.setProps({triggerTarget, interactive: true});\n\n    expect(instance.reference.getAttribute('aria-expanded')).toBe(null);\n    expect(triggerTarget.getAttribute('aria-expanded')).toBe('false');\n\n    instance.setProps({triggerTarget: null});\n\n    expect(instance.reference.getAttribute('aria-expanded')).toBe('false');\n  });\n});\n\ndescribe('instance.setContent()', () => {\n  it('works like set({ content: newContent })', () => {\n    instance = createTippy(h(), defaultProps);\n\n    const content = 'Hello!';\n    instance.setContent(content);\n\n    expect(instance.props.content).toBe(content);\n    expect(getChildren(instance.popper).content.textContent).toBe(content);\n\n    const div = document.createElement('div');\n    instance.setContent(div);\n\n    expect(instance.props.content).toBe(div);\n    expect(getChildren(instance.popper).content.firstElementChild).toBe(div);\n  });\n});\n\ndescribe('instance.state', () => {\n  it('isEnabled', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.show();\n\n    expect(instance.state.isVisible).toBe(true);\n\n    instance.state.isEnabled = false;\n    instance.hide();\n\n    expect(instance.state.isVisible).toBe(true);\n\n    instance.state.isEnabled = true;\n    instance.hide();\n\n    expect(instance.state.isVisible).toBe(false);\n\n    instance.state.isEnabled = false;\n    instance.show();\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('isVisible', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.show();\n\n    expect(instance.state.isVisible).toBe(true);\n\n    instance.hide();\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('isShown', () => {\n    instance = createTippy(h(), defaultProps);\n    instance.show();\n\n    expect(instance.state.isShown).toBe(false);\n\n    jest.runAllTimers();\n\n    expect(instance.state.isShown).toBe(true);\n\n    instance.hide();\n\n    expect(instance.state.isShown).toBe(false);\n  });\n});\n\ndescribe('mountedInstances', () => {\n  it('should correctly add and clear instances', () => {\n    instance = createTippy(h(), defaultProps);\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(mountedInstances[0]).toBe(instance);\n\n    const instance2 = createTippy(h(), defaultProps);\n\n    instance2.show();\n    jest.runAllTimers();\n\n    expect(mountedInstances[0]).toBe(instance);\n    expect(mountedInstances[1]).toBe(instance2);\n\n    instance.destroy();\n\n    expect(mountedInstances[0]).toBe(instance2);\n\n    instance2.hide();\n\n    expect(mountedInstances.length).toBe(0);\n\n    instance2.destroy();\n  });\n});\n\ndescribe('updateIOSClass', () => {\n  beforeEach(enableTouchEnvironment);\n  afterEach(disableTouchEnvironment);\n\n  // TODO: figure out why this no longer works. The `platform` property is empty\n  it.skip('should add on mount and remove on unmount', () => {\n    instance = createTippy(h(), defaultProps);\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(document.body.classList.contains(IOS_CLASS)).toBe(true);\n\n    instance.hide();\n\n    expect(document.body.classList.contains(IOS_CLASS)).toBe(false);\n  });\n\n  // TODO: figure out why this no longer works. The `platform` property is empty\n  it.skip('should only remove if mountedInstances.length is 0', () => {\n    instance = createTippy(h(), defaultProps);\n    const instance2 = createTippy(h(), defaultProps);\n\n    instance.show();\n    instance2.show();\n    jest.runAllTimers();\n\n    expect(document.body.classList.contains(IOS_CLASS)).toBe(true);\n\n    instance.hide();\n\n    expect(document.body.classList.contains(IOS_CLASS)).toBe(true);\n\n    instance2.destroy();\n\n    expect(document.body.classList.contains(IOS_CLASS)).toBe(false);\n  });\n});\n\ndescribe('instance.unmount()', () => {\n  it('unmounts the tippy from the DOM', () => {\n    instance = createTippy(h(), defaultProps);\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(document.body.contains(instance.popper)).toBe(true);\n\n    instance.unmount();\n\n    expect(document.body.contains(instance.popper)).toBe(false);\n  });\n\n  it('unmounts subtree poppers', () => {\n    const content = h();\n    const subNode = h();\n\n    content.appendChild(subNode);\n\n    const subInstance = createTippy(subNode, {\n      ...defaultProps,\n      interactive: true,\n    });\n\n    subInstance.show();\n    jest.runAllTimers();\n\n    instance = createTippy(h(), {...defaultProps, content});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(document.body.contains(instance.popper)).toBe(true);\n    expect(document.body.contains(subInstance.popper)).toBe(true);\n\n    instance.unmount();\n\n    expect(document.body.contains(instance.popper)).toBe(false);\n    expect(instance.popper.contains(subInstance.popper)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "test/integration/plugins/__snapshots__/inlinePositioning.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`inlinePositioning does not have its popper modifier removed when updating popperOptions 1`] = `\nObject {\n  \"modifiers\": Array [\n    Object {\n      \"enabled\": true,\n      \"fn\": [Function],\n      \"name\": \"tippyInlinePositioning\",\n      \"phase\": \"afterWrite\",\n    },\n  ],\n}\n`;\n"
  },
  {
    "path": "test/integration/plugins/animateFill.test.js",
    "content": "import {h} from '../../utils';\n\nimport tippy from '../../../src';\nimport animateFill from '../../../src/plugins/animateFill';\nimport {getChildren} from '../../../src/template';\nimport {getFormattedMessage} from '../../../src/validation';\n\ntippy.setDefaultProps({plugins: [animateFill]});\n\ndescribe('animateFill', () => {\n  it('true: sets `data-animatefill` attribute on tooltip', () => {\n    const ref = h();\n    const instance = tippy(ref, {animateFill: true});\n\n    expect(\n      getChildren(instance.popper).box.hasAttribute('data-animatefill')\n    ).toBe(true);\n  });\n\n  it('false: does not set `data-animatefill` attribute on tooltip', () => {\n    const ref = h();\n    const instance = tippy(ref, {animateFill: false});\n\n    expect(\n      getChildren(instance.popper).box.hasAttribute('data-animatefill')\n    ).toBe(false);\n  });\n\n  it('true: sets `transitionDelay` style on content element', () => {\n    const instance = tippy(h(), {animateFill: true, duration: 120});\n    const {content} = getChildren(instance.popper);\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(content.style.transitionDelay).toBe(`${120 / 10}ms`);\n  });\n\n  it('false: does not set `transitionDelay` style on content element', () => {\n    const instance = tippy(h(), {\n      animateFill: false,\n      duration: 120,\n    });\n    const {content} = getChildren(instance.popper);\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(content.style.transitionDelay).toBe('');\n  });\n\n  it('true: sets `animation: \"shift-away\"', () => {\n    const instance = tippy(h(), {animateFill: true});\n    expect(instance.props.animation).toBe('shift-away');\n  });\n\n  it('false: does not set `animation: \"shift-away\"', () => {\n    const instance = tippy(h(), {animateFill: false});\n    expect(instance.props.animation).not.toBe('shift-away');\n  });\n\n  it('sets `data-state` correctly', () => {\n    const instance = tippy(h(), {animateFill: true});\n    const {backdrop} = getChildren(instance.popper);\n\n    expect(backdrop.getAttribute('data-state')).toBe('hidden');\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(backdrop.getAttribute('data-state')).toBe('visible');\n\n    instance.hide();\n\n    expect(backdrop.getAttribute('data-state')).toBe('hidden');\n  });\n\n  it('true: should error when render function is not default', () => {\n    const spy = jest.spyOn(console, 'error');\n\n    tippy(h(), {\n      animateFill: true,\n      render() {\n        return {\n          popper: document.createElement('div'),\n        };\n      },\n    });\n\n    expect(spy).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        'The `animateFill` plugin requires the default render function.'\n      )\n    );\n  });\n\n  it('false: should not error when render function is not default', () => {\n    const spy = jest.spyOn(console, 'error');\n\n    tippy(h(), {\n      animateFill: false,\n      render() {\n        return {\n          popper: document.createElement('div'),\n        };\n      },\n    });\n\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should not error if render fn is not default', () => {\n    const spy = jest.spyOn(console, 'error');\n\n    tippy(h(), {\n      animateFill: false,\n      render() {\n        return {\n          popper: document.createElement('div'),\n        };\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "test/integration/plugins/followCursor.test.js",
    "content": "import {fireEvent} from '@testing-library/dom';\nimport {h, enableTouchEnvironment, disableTouchEnvironment} from '../../utils';\n\nimport tippy from '../../../src';\nimport followCursor from '../../../src/plugins/followCursor';\nimport {getBasePlacement} from '../../../src/utils';\n\ntippy.setDefaultProps({\n  plugins: [followCursor],\n});\n\ndescribe('followCursor', () => {\n  // NOTE: Jest's simulated window dimensions are 1024 x 768. These values\n  // should be within that\n  const defaultPosition = {clientX: 1, clientY: 1};\n\n  const first = {clientX: 317, clientY: 119};\n  const second = {clientX: 240, clientY: 500};\n\n  const placements = ['top', 'bottom', 'left', 'right'];\n\n  let rect;\n  let instance;\n\n  afterEach(() => {\n    instance.destroy();\n  });\n\n  function matches(receivedRect) {\n    const isVerticalPlacement = ['top', 'bottom'].includes(\n      getBasePlacement(instance.popperInstance.state.placement)\n    );\n\n    expect(rect.left).toBe(receivedRect.left);\n    expect(rect.right).toBe(receivedRect.right);\n    expect(rect.top).toBe(receivedRect.top);\n    expect(rect.bottom).toBe(receivedRect.bottom);\n  }\n\n  it('true: follows both axes', () => {\n    placements.forEach((placement) => {\n      instance = tippy(h(), {followCursor: true, placement});\n\n      fireEvent.mouseEnter(instance.reference, defaultPosition);\n\n      jest.runAllTimers();\n\n      fireEvent.mouseMove(instance.reference, first);\n      rect = instance.props.getReferenceClientRect();\n      matches({\n        top: first.clientY,\n        bottom: first.clientY,\n        left: first.clientX,\n        right: first.clientX,\n      });\n\n      fireEvent.mouseMove(instance.reference, second);\n      rect = instance.props.getReferenceClientRect();\n      matches({\n        top: second.clientY,\n        bottom: second.clientY,\n        left: second.clientX,\n        right: second.clientX,\n      });\n    });\n  });\n\n  it('\"horizontal\": follows x-axis', () => {\n    placements.forEach((placement) => {\n      instance = tippy(h(), {\n        followCursor: 'horizontal',\n        placement,\n      });\n      const referenceRect = instance.reference.getBoundingClientRect();\n\n      fireEvent.mouseEnter(instance.reference, defaultPosition);\n\n      jest.runAllTimers();\n\n      fireEvent.mouseMove(instance.reference, first);\n      rect = instance.props.getReferenceClientRect();\n\n      matches({\n        top: referenceRect.top,\n        bottom: referenceRect.bottom,\n        left: first.clientX,\n        right: first.clientX,\n      });\n\n      fireEvent.mouseMove(instance.reference, second);\n      rect = instance.props.getReferenceClientRect();\n\n      matches({\n        top: referenceRect.top,\n        bottom: referenceRect.bottom,\n        left: second.clientX,\n        right: second.clientX,\n      });\n    });\n  });\n\n  it('\"vertical\": follows y-axis', () => {\n    placements.forEach((placement) => {\n      instance = tippy(h(), {followCursor: 'vertical', placement});\n      const referenceRect = instance.reference.getBoundingClientRect();\n\n      fireEvent.mouseEnter(instance.reference, defaultPosition);\n\n      jest.runAllTimers();\n\n      fireEvent.mouseMove(instance.reference, first);\n      rect = instance.props.getReferenceClientRect();\n\n      matches({\n        top: first.clientY,\n        bottom: first.clientY,\n        left: referenceRect.left,\n        right: referenceRect.right,\n      });\n\n      fireEvent.mouseMove(instance.reference, second);\n      rect = instance.props.getReferenceClientRect();\n\n      matches({\n        top: second.clientY,\n        bottom: second.clientY,\n        left: referenceRect.left,\n        right: referenceRect.right,\n      });\n    });\n  });\n\n  it('\"initial\": only follows once', () => {\n    placements.forEach((placement) => {\n      instance = tippy(h(), {followCursor: 'initial', placement});\n\n      fireEvent.mouseMove(instance.reference, first);\n\n      instance.show();\n      jest.runAllTimers();\n\n      fireEvent.mouseMove(instance.reference, first);\n      rect = instance.props.getReferenceClientRect();\n\n      matches({\n        top: first.clientY,\n        bottom: first.clientY,\n        left: first.clientX,\n        right: first.clientX,\n      });\n\n      fireEvent.mouseMove(instance.reference, second);\n      rect = instance.props.getReferenceClientRect();\n\n      matches({\n        top: first.clientY,\n        bottom: first.clientY,\n        left: first.clientX,\n        right: first.clientX,\n      });\n    });\n  });\n\n  it('is at correct position after a delay', () => {\n    instance = tippy(h(), {followCursor: true, delay: 100});\n\n    fireEvent.mouseEnter(instance.reference, defaultPosition);\n\n    jest.runAllTimers();\n\n    fireEvent.mouseMove(instance.reference, first);\n\n    jest.advanceTimersByTime(100);\n\n    rect = instance.props.getReferenceClientRect();\n\n    matches({\n      top: first.clientY,\n      bottom: first.clientY,\n      left: first.clientX,\n      right: first.clientX,\n    });\n  });\n\n  it('is at correct position after a content update', () => {\n    instance = tippy(h(), {followCursor: true});\n\n    fireEvent.mouseEnter(instance.reference, defaultPosition);\n\n    jest.runAllTimers();\n\n    fireEvent.mouseMove(instance.reference, first);\n\n    rect = instance.props.getReferenceClientRect();\n\n    matches({\n      top: first.clientY,\n      bottom: first.clientY,\n      left: first.clientX,\n      right: first.clientX,\n    });\n\n    instance.setContent('x');\n\n    jest.runAllTimers();\n\n    rect = instance.props.getReferenceClientRect();\n\n    matches({\n      top: first.clientY,\n      bottom: first.clientY,\n      left: first.clientX,\n      right: first.clientX,\n    });\n  });\n\n  it('does not continue to follow if interactive: true and cursor is over popper', () => {\n    instance = tippy(h(), {\n      followCursor: 'horizontal',\n      interactive: true,\n    });\n\n    fireEvent.mouseEnter(instance.reference, defaultPosition);\n\n    jest.runAllTimers();\n\n    fireEvent.mouseMove(instance.reference, first);\n\n    const referenceRect = instance.reference.getBoundingClientRect();\n    rect = instance.props.getReferenceClientRect();\n\n    fireEvent.mouseMove(instance.reference, second);\n\n    matches({\n      top: referenceRect.top,\n      bottom: referenceRect.bottom,\n      left: first.clientX,\n      right: first.clientX,\n    });\n  });\n\n  it('should reset popperInstance.reference if triggered by `focus`', () => {\n    instance = tippy(h(), {\n      followCursor: true,\n      flip: false,\n      delay: 1000,\n    });\n\n    fireEvent.mouseEnter(instance.reference, defaultPosition);\n\n    jest.runAllTimers();\n\n    fireEvent.mouseMove(instance.reference, first);\n    fireEvent.mouseLeave(instance.reference);\n\n    fireEvent.mouseMove(instance.reference, second);\n\n    instance.hide();\n\n    fireEvent.focus(instance.reference);\n\n    expect(instance.props.getReferenceClientRect).toBe(null);\n  });\n\n  it('\"initial\": does not update if triggered again while still visible', () => {\n    instance = tippy(h(), {\n      followCursor: 'initial',\n    });\n\n    fireEvent.mouseMove(instance.reference, first);\n\n    instance.show();\n    jest.runAllTimers();\n\n    fireEvent.mouseMove(instance.reference, second);\n\n    rect = instance.props.getReferenceClientRect();\n\n    matches({\n      top: first.clientY,\n      bottom: first.clientY,\n      left: first.clientX,\n      right: first.clientX,\n    });\n  });\n\n  it('works with manual trigger and .show()', () => {\n    instance = tippy(h(), {\n      followCursor: true,\n      trigger: 'manual',\n    });\n\n    instance.show();\n    jest.runAllTimers();\n\n    fireEvent.mouseMove(document, first);\n\n    rect = instance.props.getReferenceClientRect();\n\n    matches({\n      top: first.clientY,\n      bottom: first.clientY,\n      left: first.clientX,\n      right: first.clientX,\n    });\n  });\n\n  it('is cleaned up if untriggered before showing', () => {\n    instance = tippy(h(), {followCursor: true, delay: 100});\n\n    fireEvent.mouseEnter(instance.reference, first);\n    fireEvent.mouseLeave(instance.reference);\n    fireEvent.mouseMove(instance.reference, second);\n\n    expect(instance.props.getReferenceClientRect).toBe(null);\n  });\n});\n"
  },
  {
    "path": "test/integration/plugins/inlinePositioning.test.js",
    "content": "import {h} from '../../utils';\n\nimport tippy from '../../../src';\nimport inlinePositioning from '../../../src/plugins/inlinePositioning';\n\ntippy.setDefaultProps({plugins: [inlinePositioning]});\n\ndescribe('inlinePositioning', () => {\n  it('does not have its popper modifier removed when updating popperOptions', () => {\n    const instance = tippy(h());\n\n    instance.setProps({\n      popperOptions: {},\n    });\n\n    expect(instance.props.popperOptions).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "test/integration/props.test.js",
    "content": "import {fireEvent, createEvent} from '@testing-library/dom';\nimport {h, enableTouchEnvironment, disableTouchEnvironment} from '../utils';\n\nimport tippy from '../../src';\nimport {getChildren} from '../../src/template';\nimport {getFormattedMessage} from '../../src/validation';\n\n// =============================================================================\n// Key props\n// =============================================================================\ndescribe('appendTo', () => {\n  describe('Element', () => {\n    it('appends the tippy to the node', () => {\n      const node = h();\n      const instance = tippy(h(), {appendTo: node});\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(node.contains(instance.popper)).toBe(true);\n    });\n  });\n\n  describe('Function', () => {\n    it('appends the tippy to the node', () => {\n      const node = h();\n      const instance = tippy(h(), {appendTo: () => node});\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(node.contains(instance.popper)).toBe(true);\n    });\n  });\n\n  describe('\"parent\"', () => {\n    it('appends the tippy to the node', () => {\n      const node = h();\n      const instance = tippy(h('div', {}, node), {appendTo: 'parent'});\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(node.parentNode.contains(instance.popper)).toBe(true);\n    });\n  });\n});\n\ndescribe('aria', () => {\n  describe('content', () => {\n    it('works correctly with \"describedby\"', () => {\n      const instance = tippy(h(), {\n        aria: {content: 'describedby'},\n      });\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.getAttribute('aria-describedby')).toBe(\n        `__NAMESPACE_PREFIX__-${instance.id}`\n      );\n    });\n\n    it('works correctly with \"labelledby\"', () => {\n      const instance = tippy(h(), {\n        aria: {content: 'labelledby'},\n      });\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.getAttribute('aria-labelledby')).toBe(\n        `__NAMESPACE_PREFIX__-${instance.id}`\n      );\n    });\n\n    it('does not add `aria-expanded` attribute by default', () => {\n      const instance = tippy(h());\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.hasAttribute('aria-expanded')).toBe(false);\n    });\n  });\n\n  describe('expanded', () => {\n    it('does not set any attribute if `null` by default', () => {\n      const instance = tippy(h());\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.hasAttribute('aria-expanded')).toBe(false);\n    });\n\n    it('sets the attribute if interactive by default', () => {\n      const instance = tippy(h(), {interactive: true});\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe('false');\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe('true');\n    });\n\n    it('does not set attribute if interactive and explicitly set to false', () => {\n      const instance = tippy(h(), {\n        interactive: true,\n        aria: {expanded: false},\n      });\n\n      expect(instance.reference.hasAttribute('aria-expanded')).toBe(false);\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.hasAttribute('aria-expanded')).toBe(false);\n    });\n  });\n});\n\ndescribe('content', () => {\n  describe('string', () => {\n    it('is injected into the tippy node', () => {\n      const instance = tippy(h(), {content: 'string'});\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(getChildren(instance.popper).content).toMatchSnapshot();\n    });\n  });\n\n  describe('Element', () => {\n    it('is injected into the tippy node', () => {\n      const node = h();\n      node.textContent = 'string';\n      const instance = tippy(h(), {content: node});\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(getChildren(instance.popper).content).toMatchSnapshot();\n    });\n  });\n\n  describe('DocumentFragment', () => {\n    it('is injected into the tippy node', () => {\n      const fragment = document.createDocumentFragment();\n      const node = h();\n      fragment.appendChild(node);\n      const instance = tippy(h(), {content: fragment});\n\n      expect(getChildren(instance.popper).content).toMatchSnapshot();\n    });\n  });\n\n  describe('Function', () => {\n    it('is injected into the tippy node', () => {\n      const instance = tippy(h(), {content: () => 'string'});\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(getChildren(instance.popper).content).toMatchSnapshot();\n    });\n  });\n});\n\ndescribe('delay', () => {\n  describe('number', () => {\n    it('delays after a trigger', () => {\n      const instance = tippy(h(), {delay: 128});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.advanceTimersByTime(127);\n\n      expect(instance.state.isVisible).toBe(false);\n\n      jest.advanceTimersByTime(1);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseLeave(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      jest.advanceTimersByTime(127);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      jest.advanceTimersByTime(1);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('tuple', () => {\n    it('delays after a trigger', () => {\n      const instance = tippy(h(), {delay: [242, 199]});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.advanceTimersByTime(241);\n\n      expect(instance.state.isVisible).toBe(false);\n\n      jest.advanceTimersByTime(1);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseLeave(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      jest.advanceTimersByTime(198);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      jest.advanceTimersByTime(1);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  it('is cleared if untriggered before timeout finishes', () => {\n    const instance = tippy(h(), {delay: 128});\n\n    fireEvent.mouseEnter(instance.reference);\n    jest.advanceTimersByTime(100);\n\n    fireEvent.mouseLeave(instance.reference);\n    jest.advanceTimersByTime(28);\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n\n  it('is cleared if the cursor leaves the popper then re-enters', () => {\n    const instance = tippy(h(), {delay: [0, 100], interactive: true});\n\n    fireEvent.mouseEnter(instance.reference);\n    jest.runAllTimers();\n\n    fireEvent.mouseEnter(instance.popper);\n    fireEvent.mouseLeave(instance.popper);\n    jest.advanceTimersByTime(99);\n\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.mouseEnter(instance.popper);\n    jest.advanceTimersByTime(1);\n\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.mouseLeave(instance.popper);\n    fireEvent.mouseMove(document.body, {clientX: 1000, clientY: 1000});\n    jest.advanceTimersByTime(100);\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n});\n\ndescribe('duration', () => {\n  describe('number', () => {\n    it('sets the CSS transition duration', () => {\n      const instance = tippy(h(), {duration: 59});\n      const box = getChildren(instance.popper).box;\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(box.style.transitionDuration).toBe('59ms');\n\n      instance.hide();\n\n      expect(box.style.transitionDuration).toBe('59ms');\n    });\n  });\n\n  describe('tuple', () => {\n    it('sets the CSS transition duration', () => {\n      const instance = tippy(h(), {duration: [1, 218]});\n      const box = getChildren(instance.popper).box;\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(box.style.transitionDuration).toBe('1ms');\n\n      instance.hide();\n\n      expect(box.style.transitionDuration).toBe('218ms');\n    });\n  });\n});\n\ndescribe('getReferenceClientRect', () => {\n  it('sets a virtual element as the popperInstance reference', () => {\n    const getBoundingClientRect = () => ({\n      width: 0,\n      height: 0,\n      top: 0,\n      right: 0,\n      bottom: 0,\n      left: 0,\n    });\n\n    const instance = tippy(h(), {\n      getReferenceClientRect: getBoundingClientRect,\n    });\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(\n      instance.popperInstance.state.elements.reference.getBoundingClientRect\n    ).toBe(getBoundingClientRect);\n  });\n\n  it('leaves the popperInstance reference as default when null', () => {\n    const instance = tippy(h());\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(instance.popperInstance.state.elements.reference).toBe(\n      instance.reference\n    );\n  });\n});\n\ndescribe('onClickOutside', () => {\n  it('should be called on document mousedown if provided', () => {\n    const onClickOutside = jest.fn();\n    const instance = tippy(h(), {onClickOutside});\n\n    instance.show();\n    jest.runAllTimers();\n    const outsideClickEvent = createEvent.mouseDown(document.body);\n    fireEvent(document.body, outsideClickEvent);\n    // fire events multiple times to be sure its called once\n    fireEvent(document.body, outsideClickEvent);\n    fireEvent(document.body, outsideClickEvent);\n\n    expect(onClickOutside).toHaveBeenCalledTimes(1);\n    expect(onClickOutside).toHaveBeenCalledWith(instance, outsideClickEvent);\n  });\n\n  it('should not be called if instance not shown', () => {\n    const onClickOutside = jest.fn();\n    tippy(h(), {onClickOutside});\n\n    fireEvent.mouseDown(document.body);\n\n    expect(onClickOutside).toHaveBeenCalledTimes(0);\n  });\n\n  it('should not be called if instance already hidden', () => {\n    const onClickOutside = jest.fn();\n    const instance = tippy(h(), {onClickOutside});\n\n    instance.show();\n    jest.runAllTimers();\n    instance.hide();\n    jest.runAllTimers();\n    fireEvent.mouseDown(document.body);\n\n    expect(onClickOutside).toHaveBeenCalledTimes(0);\n  });\n});\n\ndescribe('hideOnClick', () => {\n  describe('true', () => {\n    it('hides the tippy on outside mousedown', () => {\n      const instance = tippy(h(), {hideOnClick: true});\n\n      instance.show();\n      jest.runAllTimers();\n      fireEvent.mouseDown(document.body);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n\n    it('hides the tippy on inside mousedown', () => {\n      const instance = tippy(h(), {hideOnClick: true});\n\n      instance.show();\n      jest.runAllTimers();\n      fireEvent.mouseDown(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n\n    it('does not hide tippy upon clicking popper', () => {\n      const instance = tippy(h(), {hideOnClick: true, interactive: true});\n\n      instance.show();\n      jest.runAllTimers();\n      fireEvent.mouseDown(instance.popper);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n\n    it('does not hide on unintentional tap outside', () => {\n      const instance = tippy(h(), {hideOnClick: true});\n\n      instance.show();\n      jest.runAllTimers();\n\n      fireEvent.touchStart(instance.popper);\n      fireEvent.touchMove(instance.popper);\n      fireEvent.touchEnd(instance.popper);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n\n    it('hides on intentional tap outside', () => {\n      const instance = tippy(h(), {hideOnClick: true});\n\n      instance.show();\n      jest.runAllTimers();\n\n      fireEvent.touchStart(instance.popper);\n      fireEvent.touchEnd(instance.popper);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('false', () => {\n    it('does not hide the tippy on outside mousedown', () => {\n      const instance = tippy(h(), {hideOnClick: false});\n\n      instance.show();\n      jest.runAllTimers();\n      fireEvent.mouseDown(document.body);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n\n    it('does not hide the tippy on inside mousedown', () => {\n      const instance = tippy(h(), {hideOnClick: false});\n\n      instance.show();\n      jest.runAllTimers();\n      fireEvent.mouseDown(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n  });\n\n  describe('\"toggle\"', () => {\n    it('does not hide the tippy on outside mousedown', () => {\n      const instance = tippy(h(), {hideOnClick: 'toggle'});\n\n      instance.show();\n      jest.runAllTimers();\n      fireEvent.mouseDown(document.body);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n\n    it('hides the tippy on inside click', () => {\n      const instance = tippy(h(), {\n        hideOnClick: 'toggle',\n        trigger: 'click',\n      });\n\n      instance.show();\n      jest.runAllTimers();\n      fireEvent.click(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n});\n\ndescribe('ignoreAttributes', () => {\n  describe('true', () => {\n    it('ignores data-tippy-* attributes on the reference', () => {\n      const instance = tippy(h('div', {'data-tippy-animation': 'x'}), {\n        animation: 'y',\n        ignoreAttributes: true,\n      });\n\n      expect(instance.props.animation).toBe('y');\n    });\n  });\n\n  describe('false', () => {\n    it('does not ignore data-tippy-* attributes on the reference', () => {\n      const instance = tippy(h('div', {'data-tippy-animation': 'x'}), {\n        animation: 'y',\n        ignoreAttributes: false,\n      });\n\n      expect(instance.props.animation).toBe('x');\n    });\n  });\n});\n\ndescribe('interactive', () => {\n  describe('false', () => {\n    it('sets pointer-events: none styles on show', () => {\n      const instance = tippy(h(), {interactive: false});\n\n      instance.show();\n\n      expect(instance.popper.style.pointerEvents).toBe('none');\n    });\n\n    it('does not add `aria-expanded` attribute', () => {\n      const instance = tippy(h(), {interactive: false});\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe(null);\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe(null);\n    });\n  });\n\n  describe('true', () => {\n    it('sets no pointer-events styles on show', () => {\n      const instance = tippy(h(), {interactive: true});\n\n      instance.show();\n\n      expect(instance.popper.style.pointerEvents).toBe('');\n    });\n\n    it('sets pointer-events styles to none on hide', () => {\n      const instance = tippy(h(), {interactive: true});\n\n      instance.show();\n      jest.runAllTimers();\n      instance.hide();\n\n      expect(instance.popper.style.pointerEvents).toBe('none');\n    });\n\n    it('appends the tippy to the reference parent', () => {\n      const parentNode = h();\n      const instance = tippy(h('div', {}, parentNode), {interactive: true});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.runAllTimers();\n\n      expect(parentNode.contains(instance.popper)).toBe(true);\n    });\n\n    it('does not cause the tippy to hide when clicked inside', () => {\n      const instance = tippy(h(), {interactive: true});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.runAllTimers();\n\n      fireEvent.click(instance.popper);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n\n    it('tippy does not hide as cursor moves over it or the reference', () => {\n      const instance = tippy(h(), {interactive: true});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.runAllTimers();\n\n      fireEvent.mouseLeave(instance.reference);\n      fireEvent.mouseMove(instance.popper);\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseMove(getChildren(instance.popper).box);\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseMove(instance.reference);\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseMove(document.body, {clientX: 1000, clientY: 1000});\n      expect(instance.state.isVisible).toBe(false);\n    });\n\n    it('handles the `aria-expanded` attribute', () => {\n      const instance = tippy(h(), {interactive: true});\n      const triggerTarget = h();\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe('false');\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe('true');\n\n      instance.hide();\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe('false');\n\n      instance.setProps({triggerTarget});\n\n      fireEvent.mouseEnter(triggerTarget);\n      jest.runAllTimers();\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe(null);\n      expect(triggerTarget.getAttribute('aria-expanded')).toBe('true');\n\n      instance.hide();\n\n      expect(triggerTarget.getAttribute('aria-expanded')).toBe('false');\n    });\n\n    it('true: warns if tippy is not accessible', () => {\n      const instance = tippy(h(), {interactive: true});\n\n      const inbetweenNode = h();\n      instance.reference.parentNode.appendChild(inbetweenNode);\n\n      instance.show();\n      jest.runAllTimers();\n\n      expect(console.warn).toHaveBeenCalledWith(\n        ...getFormattedMessage(\n          [\n            'Interactive tippy element may not be accessible via keyboard',\n            'navigation because it is not directly after the reference element',\n            'in the DOM source order.',\n            '\\n\\n',\n            'Using a wrapper <div> or <span> tag around the reference element',\n            'solves this by creating a new parentNode context.',\n            '\\n\\n',\n            'Specifying `appendTo: document.body` silences this warning, but it',\n            'assumes you are using a focus management solution to handle',\n            'keyboard navigation.',\n            '\\n\\n',\n            'See: https://atomiks.github.io/tippyjs/v6/accessibility/#interactivity',\n          ].join(' ')\n        )\n      );\n\n      instance.reference.parentNode.removeChild(inbetweenNode);\n    });\n\n    it('it cleans up correctly if cursor entered and left before show with `delay`', () => {\n      const instance = tippy(h(), {interactive: true, delay: 100});\n\n      fireEvent.mouseEnter(instance.reference);\n      fireEvent.mouseLeave(instance.reference);\n\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n\n    it('handles `aria-expanded` attribute correctly with .setProps()', () => {\n      const instance = tippy(h(), {interactive: true});\n\n      expect(instance.reference.getAttribute('aria-expanded')).not.toBe(null);\n\n      instance.setProps({interactive: false});\n\n      expect(instance.reference.getAttribute('aria-expanded')).toBe(null);\n    });\n  });\n});\n\ndescribe('interactiveBorder', () => {\n  // TODO\n});\n\ndescribe('interactiveDebounce', () => {\n  it('debounces the internal mousemove listener', () => {\n    const instance = tippy(h(), {interactive: true, interactiveDebounce: 500});\n\n    fireEvent.mouseEnter(instance.reference);\n    jest.runAllTimers();\n\n    fireEvent.mouseLeave(instance.reference);\n    fireEvent.mouseMove(document.body, {clientX: 1000, clientY: 1000});\n    jest.advanceTimersByTime(499);\n\n    expect(instance.state.isVisible).toBe(true);\n\n    fireEvent.mouseMove(document.body, {clientX: 1000, clientY: 1000});\n    jest.advanceTimersByTime(1);\n\n    expect(instance.state.isVisible).toBe(true);\n\n    jest.advanceTimersByTime(498);\n\n    expect(instance.state.isVisible).toBe(true);\n\n    jest.advanceTimersByTime(1);\n\n    expect(instance.state.isVisible).toBe(false);\n  });\n});\n\ndescribe('moveTransition', () => {\n  it('sets the transition on the popper element', () => {\n    const instance = tippy(h(), {moveTransition: 'transform 0.5s ease'});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(instance.popper.style.transition).toBe('transform 0.5s ease');\n  });\n\n  it('disables the \"computeStyles\" modifier\\'s `adaptive` option', () => {\n    const instance = tippy(h(), {moveTransition: 'transform 0.5s ease'});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(\n      instance.popperInstance.state.options.modifiers.find(\n        (modifier) => modifier.name === 'computeStyles'\n      ).options.adaptive\n    ).toBe(false);\n  });\n});\n\ndescribe('offset', () => {\n  it('is placed in the offset modifier', () => {\n    const instance = tippy(h(), {offset: [5, 20]});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(\n      instance.popperInstance.state.options.modifiers.find(\n        (modifier) => modifier.name === 'offset'\n      ).options.offset\n    ).toEqual([5, 20]);\n  });\n});\n\ndescribe('onAfterUpdate', () => {\n  it('is called after the instance props change', () => {\n    const onAfterUpdate = jest.fn(() => {\n      expect(instance.props.content).toBe('next');\n    });\n    const instance = tippy(h(), {\n      content: 'prev',\n      onAfterUpdate,\n    });\n\n    const props = {content: 'next'};\n    instance.setProps(props);\n\n    expect(onAfterUpdate).toHaveBeenCalledTimes(1);\n    expect(onAfterUpdate).toHaveBeenCalledWith(instance, props);\n  });\n});\n\ndescribe('onBeforeUpdate', () => {\n  it('is called before the instance props change', () => {\n    const onBeforeUpdate = jest.fn(() => {\n      expect(instance.props.content).toBe('prev');\n    });\n    const instance = tippy(h(), {\n      content: 'prev',\n      onBeforeUpdate,\n    });\n\n    const props = {content: 'next'};\n    instance.setProps(props);\n\n    expect(onBeforeUpdate).toHaveBeenCalledTimes(1);\n    expect(onBeforeUpdate).toHaveBeenCalledWith(instance, props);\n  });\n});\n\ndescribe('onCreate', () => {\n  it('is called once the instance has been created', () => {\n    const onCreate = jest.fn();\n    const instance = tippy(h(), {onCreate});\n\n    expect(onCreate).toHaveBeenCalledTimes(1);\n    expect(onCreate).toHaveBeenCalledWith(instance);\n  });\n});\n\ndescribe('onDestroy', () => {\n  it('is called once the instance has been destroyed', () => {\n    const onDestroy = jest.fn();\n    const instance = tippy(h(), {onDestroy});\n\n    expect(onDestroy).toHaveBeenCalledTimes(0);\n\n    instance.destroy();\n\n    expect(onDestroy).toHaveBeenCalledTimes(1);\n    expect(onDestroy).toHaveBeenCalledWith(instance);\n  });\n});\n\ndescribe('onHidden', () => {\n  it('is called once the instance is unmounted', () => {\n    const onHidden = jest.fn();\n    const instance = tippy(h(), {onHidden});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(onHidden).toHaveBeenCalledTimes(0);\n\n    instance.hide();\n\n    expect(onHidden).toHaveBeenCalledTimes(1);\n    expect(onHidden).toHaveBeenCalledWith(instance);\n  });\n\n  it('is called once the instance is hidden', () => {\n    const onHidden = jest.fn();\n    const instance = tippy(h(), {onHidden});\n\n    expect(onHidden).toHaveBeenCalledTimes(0);\n\n    instance.show();\n    jest.runAllTimers();\n    instance.hide();\n\n    expect(onHidden).toHaveBeenCalledTimes(1);\n    expect(onHidden).toHaveBeenCalledWith(instance);\n  });\n});\n\ndescribe('onHide', () => {\n  it('is called once the instance starts to hide', () => {\n    const onHide = jest.fn();\n    const instance = tippy(h(), {onHide});\n\n    expect(onHide).toHaveBeenCalledTimes(0);\n\n    instance.show();\n    jest.runAllTimers();\n    instance.hide();\n\n    expect(onHide).toHaveBeenCalledTimes(1);\n    expect(onHide).toHaveBeenCalledWith(instance);\n  });\n\n  // TODO: this may be a bad idea so remove it maybe; it doesn't work with\n  // plugins (not composable)\n  it('can cancel hiding by returning false', () => {\n    const onHide = jest.fn(() => false);\n    const instance = tippy(h(), {onHide});\n\n    expect(onHide).toHaveBeenCalledTimes(0);\n\n    instance.show();\n    jest.runAllTimers();\n    instance.hide();\n\n    expect(onHide).toHaveBeenCalledTimes(1);\n    expect(onHide).toHaveBeenCalledWith(instance);\n    expect(instance.state.isVisible).toBe(true);\n  });\n});\n\ndescribe('onShow', () => {\n  it('is called once the instance starts to hide', () => {\n    const onShow = jest.fn();\n    const instance = tippy(h(), {onShow});\n\n    expect(onShow).toHaveBeenCalledTimes(0);\n\n    instance.show();\n\n    expect(onShow).toHaveBeenCalledTimes(1);\n    expect(onShow).toHaveBeenCalledWith(instance);\n  });\n\n  // TODO: this may be a bad idea so remove it maybe; it doesn't work with\n  // plugins (not composable)\n  it('can cancel showing by returning false', () => {\n    const onShow = jest.fn(() => false);\n    const instance = tippy(h(), {onShow});\n\n    expect(onShow).toHaveBeenCalledTimes(0);\n\n    instance.show();\n\n    expect(onShow).toHaveBeenCalledTimes(1);\n    expect(onShow).toHaveBeenCalledWith(instance);\n    expect(instance.state.isVisible).toBe(false);\n  });\n});\n\ndescribe('onShown', () => {\n  it('is called once the CSS transitions finish', () => {\n    const onShown = jest.fn();\n    const instance = tippy(h(), {onShown, duration: 100});\n\n    expect(onShown).toHaveBeenCalledTimes(0);\n\n    instance.show();\n    jest.runAllTimers();\n    fireEvent.transitionEnd(getChildren(instance.popper).box);\n\n    expect(onShown).toHaveBeenCalledTimes(1);\n    expect(onShown).toHaveBeenCalledWith(instance);\n  });\n});\n\ndescribe('onTrigger', () => {\n  it('is called due to a trigger event', () => {\n    const onTrigger = jest.fn();\n    const instance = tippy(h(), {onTrigger});\n\n    expect(onTrigger).toHaveBeenCalledTimes(0);\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(onTrigger).toHaveBeenCalledTimes(0);\n\n    instance.hide();\n\n    fireEvent.mouseEnter(instance.reference);\n\n    expect(onTrigger).toHaveBeenCalledTimes(1);\n    expect(onTrigger).toHaveBeenCalledWith(\n      instance,\n      new MouseEvent('mouseenter')\n    );\n  });\n});\n\ndescribe('onTrigger', () => {\n  it('is called due to an untrigger event', () => {\n    const onUntrigger = jest.fn();\n    const instance = tippy(h(), {onUntrigger});\n\n    expect(onUntrigger).toHaveBeenCalledTimes(0);\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(onUntrigger).toHaveBeenCalledTimes(0);\n\n    instance.hide();\n\n    fireEvent.mouseLeave(instance.reference);\n\n    expect(onUntrigger).toHaveBeenCalledTimes(1);\n    expect(onUntrigger).toHaveBeenCalledWith(\n      instance,\n      new MouseEvent('mouseleave')\n    );\n  });\n});\n\ndescribe('placement', () => {\n  it('is placed in popper options', () => {\n    const instance = tippy(h(), {placement: 'right'});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(instance.popperInstance.state.options.placement).toBe('right');\n  });\n});\n\ndescribe('plugins', () => {\n  it('is placed in instance.plugins uniquely', () => {\n    const pluginA = {fn: () => ({})};\n    const pluginB = {fn: () => ({})};\n    const plugins = [pluginA, pluginB, pluginA];\n\n    const instance = tippy(h(), {plugins});\n\n    expect(instance.plugins).toEqual([pluginA, pluginB]);\n  });\n\n  it('invokes plugin fn', () => {\n    const fn = jest.fn(() => ({}));\n    const instance = tippy(h(), {\n      plugins: [{fn}],\n    });\n\n    expect(fn).toHaveBeenCalledTimes(1);\n    expect(fn).toHaveBeenCalledWith(instance);\n  });\n});\n\ndescribe('popperOptions', () => {\n  it('merges modifiers correctly', () => {\n    const instance = tippy(h(), {\n      popperOptions: {\n        strategy: 'fixed',\n        modifiers: [\n          {\n            name: 'flip',\n            options: {\n              fallbackPlacements: ['right'],\n            },\n          },\n          {\n            name: 'preventOverflow',\n            options: {\n              rootBoundary: 'document',\n            },\n          },\n          {\n            name: 'offset',\n            enabled: false,\n          },\n          {\n            name: 'arrow',\n            options: {\n              padding: 999,\n            },\n          },\n        ],\n      },\n    });\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(instance.popperInstance.state.orderedModifiers).toMatchSnapshot();\n  });\n});\n\ndescribe('render', () => {\n  it('is used as the template creator', () => {\n    const popper = h();\n\n    const instance = tippy(h(), {\n      render() {\n        return {\n          popper,\n          update() {},\n        };\n      },\n    });\n\n    expect(instance.popper).toBe(popper);\n  });\n\n  it('calls the update function with (prevProps, nextProps) args', () => {\n    const spy = jest.fn();\n\n    const instance = tippy(h(), {\n      render() {\n        return {\n          popper: h(),\n          onUpdate: spy,\n        };\n      },\n    });\n\n    const prevProps = instance.props;\n    instance.setProps({});\n    const nextProps = instance.props;\n\n    expect(spy).toHaveBeenCalledTimes(1);\n    expect(spy).toHaveBeenCalledWith(prevProps, nextProps);\n  });\n});\n\ndescribe('showOnCreate', () => {\n  describe('true', () => {\n    it('is called onCreate', () => {\n      const instance = tippy(h(), {showOnCreate: true});\n\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n\n    it('respects delays', () => {\n      const instance = tippy(h(), {showOnCreate: true, delay: 100});\n\n      jest.advanceTimersByTime(99);\n\n      expect(instance.state.isVisible).toBe(false);\n\n      jest.advanceTimersByTime(1);\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n  });\n});\n\ndescribe('touch', () => {\n  beforeEach(enableTouchEnvironment);\n  afterEach(disableTouchEnvironment);\n\n  describe('true', () => {\n    it('does not prevent the instance from showing', () => {\n      const instance = tippy(h(), {touch: true});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n  });\n\n  describe('false', () => {\n    it('prevents instance from showing', () => {\n      const instance = tippy(h(), {touch: false});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('hold', () => {\n    it('only shows while holding the press', () => {\n      const instance = tippy(h(), {touch: 'hold'});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(false);\n\n      fireEvent.touchStart(instance.reference);\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.touchEnd(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('[\"hold\", delay]', () => {\n    it('only shows after a delay', () => {\n      const instance = tippy(h(), {touch: ['hold', 500]});\n\n      fireEvent.mouseEnter(instance.reference);\n      jest.runAllTimers();\n\n      expect(instance.state.isVisible).toBe(false);\n\n      fireEvent.touchStart(instance.reference);\n      jest.advanceTimersByTime(499);\n\n      expect(instance.state.isVisible).toBe(false);\n\n      jest.advanceTimersByTime(1);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.touchEnd(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n});\n\ndescribe('trigger', () => {\n  describe('mouseenter', () => {\n    it('is triggered and untriggered correctly', () => {\n      const instance = tippy(h(), {trigger: 'mouseenter'});\n\n      fireEvent.mouseEnter(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseLeave(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('mouseenter focus', () => {\n    it('is triggered and untriggered correctly', () => {\n      const instance = tippy(h(), {trigger: 'mouseenter focus'});\n\n      fireEvent.mouseEnter(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseLeave(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n\n      fireEvent.focus(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.blur(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('focus', () => {\n    it('is triggered and untriggered correctly', () => {\n      const instance = tippy(h(), {trigger: 'mouseenter focus'});\n\n      fireEvent.focus(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.blur(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('click', () => {\n    it('is triggered and untriggered correctly', () => {\n      const instance = tippy(h(), {trigger: 'click'});\n\n      fireEvent.click(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.click(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n\n    it('toggles on repeated clicks with inner element target', () => {\n      const inner = h();\n      const outer = h();\n      outer.appendChild(inner);\n\n      const instance = tippy(outer, {trigger: 'click'});\n\n      fireEvent.mouseDown(inner, {bubbles: true});\n      fireEvent.click(inner, {bubbles: true});\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.mouseDown(inner, {bubbles: true});\n      fireEvent.click(inner, {bubbles: true});\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  describe('click focus', () => {\n    it('does not hide immediately and can be toggled', () => {\n      const instance = tippy(h(), {trigger: 'click focus'});\n\n      fireEvent.focus(instance.reference);\n\n      fireEvent.click(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      fireEvent.click(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n});\n\ndescribe('triggerTarget', () => {\n  describe('null', () => {\n    it('uses the reference as the trigger target', () => {\n      const instance = tippy(h(), {triggerTarget: null});\n\n      fireEvent.mouseEnter(instance.reference);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n  });\n\n  describe('Element', () => {\n    it('is used as the trigger target', () => {\n      const triggerTarget = h();\n      const instance = tippy(h(), {triggerTarget});\n\n      fireEvent.mouseEnter(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n\n      fireEvent.mouseEnter(triggerTarget);\n\n      expect(instance.state.isVisible).toBe(true);\n    });\n  });\n\n  describe('Element[]', () => {\n    it('is used as the trigger target', () => {\n      const triggerTarget = [h(), h(), h()];\n      const instance = tippy(h(), {triggerTarget});\n\n      fireEvent.mouseEnter(instance.reference);\n\n      expect(instance.state.isVisible).toBe(false);\n\n      fireEvent.mouseEnter(triggerTarget[0]);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      instance.hide();\n\n      fireEvent.mouseEnter(triggerTarget[1]);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      instance.hide();\n\n      fireEvent.mouseEnter(triggerTarget[2]);\n\n      expect(instance.state.isVisible).toBe(true);\n\n      instance.hide();\n    });\n  });\n});\n\n// =============================================================================\n// Render props\n// =============================================================================\ndescribe('animation', () => {\n  it('is set correctly on .tippy-box', () => {\n    const instance = tippy(h(), {animation: 'anything'});\n\n    expect(\n      getChildren(instance.popper).box.getAttribute('data-animation')\n    ).toBe('anything');\n  });\n});\n\ndescribe('allowHTML', () => {\n  describe('true', () => {\n    it('renders content as HTML', () => {\n      const instance = tippy(h(), {content: '<b>hello</b>', allowHTML: true});\n\n      expect(getChildren(instance.popper).content.querySelector('b')).not.toBe(\n        null\n      );\n    });\n  });\n\n  describe('false', () => {\n    it('renders content as HTML', () => {\n      const instance = tippy(h(), {content: '<b>hello</b>', allowHTML: false});\n\n      expect(getChildren(instance.popper).content.querySelector('b')).toBe(\n        null\n      );\n    });\n  });\n\n  it('should update even if content does not change', () => {\n    const instance = tippy(h(), {content: '<b>hello</b>', allowHTML: true});\n\n    expect(getChildren(instance.popper).content.querySelector('b')).not.toBe(\n      null\n    );\n\n    instance.setProps({allowHTML: false});\n\n    expect(getChildren(instance.popper).content.querySelector('b')).toBe(null);\n  });\n});\n\ndescribe('inertia', () => {\n  it('sets attribute correctly on .tippy-box', () => {\n    const instance = tippy(h(), {inertia: true});\n\n    expect(getChildren(instance.popper).box.hasAttribute('data-inertia')).toBe(\n      true\n    );\n  });\n\n  it('is updated correctly with .setProps()', () => {\n    const instance = tippy(h(), {inertia: false});\n\n    expect(getChildren(instance.popper).box.hasAttribute('data-inertia')).toBe(\n      false\n    );\n\n    instance.setProps({inertia: true});\n\n    expect(getChildren(instance.popper).box.hasAttribute('data-inertia')).toBe(\n      true\n    );\n  });\n});\n\ndescribe('arrow', () => {\n  describe('true', () => {\n    it('creates an arrow', () => {\n      const instance = tippy(h(), {arrow: true});\n\n      expect(getChildren(instance.popper).arrow).not.toBe(undefined);\n    });\n  });\n\n  describe('false', () => {\n    it('does not create an arrow', () => {\n      const instance = tippy(h(), {arrow: false});\n\n      expect(getChildren(instance.popper).arrow).toBe(undefined);\n    });\n  });\n\n  describe('string', () => {\n    it('creates an svg', () => {\n      const instance = tippy(h(), {arrow: '<svg></svg>'});\n\n      expect(getChildren(instance.popper).arrow.className).toBe(\n        '__NAMESPACE_PREFIX__-svg-arrow'\n      );\n      expect(getChildren(instance.popper).arrow.querySelector('svg')).not.toBe(\n        null\n      );\n    });\n  });\n\n  describe('Element', () => {\n    it('uses an svg', () => {\n      const instance = tippy(h(), {\n        arrow: document.createElementNS('http://www.w3.org/2000/svg', 'svg'),\n      });\n\n      expect(getChildren(instance.popper).arrow.className).toBe(\n        '__NAMESPACE_PREFIX__-svg-arrow'\n      );\n      expect(getChildren(instance.popper).arrow.querySelector('svg')).not.toBe(\n        null\n      );\n    });\n  });\n\n  describe('Fragment', () => {\n    it('uses an svg', () => {\n      const fragment = document.createDocumentFragment();\n      const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n\n      fragment.appendChild(svg);\n\n      const instance = tippy(h(), {\n        arrow: fragment,\n      });\n\n      expect(getChildren(instance.popper).arrow.querySelector('svg')).not.toBe(\n        null\n      );\n    });\n  });\n\n  it('is updated correctly by .setProps()', () => {\n    const instance = tippy(h(), {arrow: true});\n\n    instance.setProps({arrow: false});\n\n    expect(getChildren(instance.popper).arrow).toBe(undefined);\n\n    instance.setProps({arrow: '<svg></svg>'});\n\n    expect(getChildren(instance.popper).arrow).not.toBe(undefined);\n\n    instance.setProps({arrow: '<svg><path d=\"\" /></svg>'});\n\n    expect(getChildren(instance.popper).arrow.querySelector('path')).not.toBe(\n      undefined\n    );\n  });\n});\n\ndescribe('content', () => {\n  describe('string', () => {\n    it('is injected into .tippy-content correctly', () => {\n      const instance = tippy(h(), {content: 'hello'});\n\n      expect(getChildren(instance.popper).content.textContent).toBe('hello');\n    });\n\n    it('does not render HTML by default', () => {\n      const instance = tippy(h(), {content: '<b>hello</b>'});\n\n      expect(getChildren(instance.popper).content.innerHTML).not.toBe(\n        '<b>hello</b>'\n      );\n    });\n  });\n\n  describe('Element', () => {\n    it('is injected into .tippy-content correctly', () => {\n      const content = h();\n      const instance = tippy(h(), {content});\n\n      expect(getChildren(instance.popper).content.firstElementChild).toBe(\n        content\n      );\n    });\n  });\n\n  describe('Function', () => {\n    it('is called with the reference as an argument', () => {\n      const node = h();\n      const content = jest.fn(() => node);\n      const instance = tippy(h(), {content});\n\n      expect(getChildren(instance.popper).content.firstElementChild).toBe(node);\n      expect(content).toHaveBeenCalledWith(instance.reference);\n    });\n  });\n});\n\ndescribe('maxWidth', () => {\n  describe('number', () => {\n    it('appends px', () => {\n      const instance = tippy(h(), {maxWidth: 200});\n\n      expect(getChildren(instance.popper).box.style.maxWidth).toBe('200px');\n    });\n  });\n\n  describe('string', () => {\n    it('appends directly (\"none\")', () => {\n      const instance = tippy(h(), {maxWidth: 'none'});\n\n      expect(getChildren(instance.popper).box.style.maxWidth).toBe('none');\n    });\n\n    it('appends directly (\"10rem\")', () => {\n      const instance = tippy(h(), {maxWidth: '10rem'});\n\n      expect(getChildren(instance.popper).box.style.maxWidth).toBe('10rem');\n    });\n  });\n\n  it('is updated correctly by .setProps()', () => {\n    const instance = tippy(h(), {maxWidth: 'none'});\n\n    instance.setProps({maxWidth: 100});\n\n    expect(getChildren(instance.popper).box.style.maxWidth).toBe('100px');\n  });\n});\n\ndescribe('moveTransition', () => {\n  it('is set correctly', () => {\n    const instance = tippy(h(), {moveTransition: 'transform 1s ease-in'});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(instance.popper.style.transition).toBe('transform 1s ease-in');\n  });\n\n  it('is updated correctly by .setProps()', () => {\n    const instance = tippy(h(), {moveTransition: 'transform 1s ease-in'});\n\n    instance.setProps({moveTransition: 'none'});\n\n    instance.show();\n    jest.runAllTimers();\n\n    expect(instance.popper.style.transition).toBe('none');\n  });\n});\n\ndescribe('role', () => {\n  it('sets role attribute', () => {\n    const instance = tippy(h(), {role: 'menu'});\n\n    expect(getChildren(instance.popper).box.getAttribute('role')).toBe('menu');\n  });\n\n  it('does not add an attribute if `null`', () => {\n    const instance = tippy(h(), {role: null});\n\n    expect(getChildren(instance.popper).box.hasAttribute('role')).toBe(false);\n  });\n});\n\ndescribe('theme', () => {\n  it('sets `data-theme` attribute correctly', () => {\n    const instance = tippy(h(), {theme: 'a bunch of themes'});\n\n    expect(getChildren(instance.popper).box.getAttribute('data-theme')).toBe(\n      'a bunch of themes'\n    );\n  });\n\n  it('does not add `data-theme` attribute if `null`', () => {\n    const instance = tippy(h(), {theme: null});\n\n    expect(getChildren(instance.popper).box.hasAttribute('data-theme')).toBe(\n      false\n    );\n  });\n});\n\ndescribe('zIndex', () => {\n  it('sets zIndex style property correctly', () => {\n    const instance = tippy(h(), {zIndex: 927});\n\n    expect(instance.popper.style.zIndex).toBe('927');\n  });\n});\n"
  },
  {
    "path": "test/setup.js",
    "content": "import 'expect-puppeteer';\n\nimport tippy from '../src';\nimport {render} from '../src/template';\nimport {cleanDocumentBody} from './utils';\nimport {toMatchImageSnapshot} from 'jest-image-snapshot';\nimport {resetVisitedMessages} from '../src/validation';\n\nexpect.extend({toMatchImageSnapshot});\n\ntippy.setDefaultProps({\n  render,\n  content: '__DEFAULT_TEST_CONTENT__',\n  duration: 0,\n  delay: 0,\n});\n\njest.useFakeTimers();\n\n// We want to use macrotask timers that can be mocked by Jest\nglobal.Promise = require('promise');\n\nglobal.requestAnimationFrame = (cb) => cb();\n\n// Prevents console from spamming test output while still allowing for debugging\n// while writing tests\nglobal.console = {\n  log: console.log,\n  warn: jest.fn(),\n  error: jest.fn(),\n};\n\nafterEach(() => {\n  global.console.warn.mockReset();\n  global.console.error.mockReset();\n\n  resetVisitedMessages();\n\n  if (typeof document !== 'undefined') {\n    cleanDocumentBody();\n  }\n});\n"
  },
  {
    "path": "test/unit/__snapshots__/props.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`evaluateProps considers plugin props 1`] = `\nObject {\n  \"aria\": Object {\n    \"content\": \"describedby\",\n    \"expanded\": undefined,\n  },\n  \"content\": undefined,\n  \"plugin\": \"y\",\n  \"plugins\": Array [\n    Object {\n      \"fn\": [Function],\n      \"name\": \"plugin\",\n    },\n  ],\n}\n`;\n\nexports[`evaluateProps does not ignore attributes if \\`ignoreAttributes: false\\` 1`] = `\nObject {\n  \"animation\": \"fade\",\n  \"aria\": Object {\n    \"content\": \"describedby\",\n    \"expanded\": undefined,\n  },\n  \"content\": undefined,\n  \"ignoreAttributes\": false,\n}\n`;\n\nexports[`evaluateProps ignores attributes if \\`ignoreAttributes: true\\` 1`] = `\nObject {\n  \"animation\": \"scale\",\n  \"aria\": Object {\n    \"content\": \"describedby\",\n    \"expanded\": undefined,\n  },\n  \"content\": undefined,\n  \"ignoreAttributes\": true,\n}\n`;\n"
  },
  {
    "path": "test/unit/__snapshots__/tippy.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`tippy merges the default props with the supplied props 1`] = `\nObject {\n  \"allowHTML\": false,\n  \"animateFill\": false,\n  \"animation\": \"fade\",\n  \"appendTo\": [Function],\n  \"aria\": Object {\n    \"content\": \"describedby\",\n    \"expanded\": false,\n  },\n  \"arrow\": true,\n  \"content\": \"__DEFAULT_TEST_CONTENT__\",\n  \"delay\": 0,\n  \"duration\": 0,\n  \"followCursor\": false,\n  \"getReferenceClientRect\": null,\n  \"hideOnClick\": true,\n  \"ignoreAttributes\": false,\n  \"inertia\": false,\n  \"inlinePositioning\": false,\n  \"interactive\": false,\n  \"interactiveBorder\": 2,\n  \"interactiveDebounce\": 0,\n  \"maxWidth\": 350,\n  \"moveTransition\": \"\",\n  \"offset\": Array [\n    0,\n    10,\n  ],\n  \"onAfterUpdate\": [Function],\n  \"onBeforeUpdate\": [Function],\n  \"onClickOutside\": [Function],\n  \"onCreate\": [Function],\n  \"onDestroy\": [Function],\n  \"onHidden\": [Function],\n  \"onHide\": [Function],\n  \"onMount\": [Function],\n  \"onShow\": [Function],\n  \"onShown\": [Function],\n  \"onTrigger\": [Function],\n  \"onUntrigger\": [Function],\n  \"placement\": \"bottom-end\",\n  \"plugins\": Array [],\n  \"popperOptions\": Object {},\n  \"render\": [Function],\n  \"role\": \"tooltip\",\n  \"showOnCreate\": false,\n  \"sticky\": false,\n  \"theme\": \"\",\n  \"touch\": true,\n  \"trigger\": \"mouseenter focus\",\n  \"triggerTarget\": null,\n  \"zIndex\": 9999,\n}\n`;\n"
  },
  {
    "path": "test/unit/css.test.js",
    "content": "import {injectCSS} from '../../src/css';\n\nafterEach(() => {\n  document.head.innerHTML = '';\n});\n\ndescribe('injectCSS', () => {\n  const styles = 'body { color: red; }';\n\n  it('injects a string of css styles into the document `head`', () => {\n    expect(document.head.querySelector('style')).toBe(null);\n\n    injectCSS(styles);\n\n    const stylesheet = document.head.querySelector(\n      '[data-__NAMESPACE_PREFIX__-stylesheet]'\n    );\n\n    expect(stylesheet).not.toBe(null);\n    expect(stylesheet.textContent).toBe(styles);\n  });\n\n  it('places the node before the first style or link node (link before style)', () => {\n    document.head.append(document.createElement('title'));\n    document.head.append(document.createElement('link'));\n    document.head.append(document.createElement('style'));\n\n    injectCSS(styles);\n\n    const stylesheet = document.head.querySelector(\n      '[data-__NAMESPACE_PREFIX__-stylesheet]'\n    );\n\n    expect(document.head.children[1]).toBe(stylesheet);\n  });\n\n  it('places the node before the first style or link node (link after style)', () => {\n    document.head.append(document.createElement('title'));\n    document.head.append(document.createElement('style'));\n    document.head.append(document.createElement('link'));\n\n    injectCSS(styles);\n\n    const stylesheet = document.head.querySelector(\n      '[data-__NAMESPACE_PREFIX__-stylesheet]'\n    );\n\n    expect(document.head.children[1]).toBe(stylesheet);\n  });\n});\n"
  },
  {
    "path": "test/unit/dom-utils.test.js",
    "content": "import {h, IDENTIFIER} from '../utils';\n\nimport * as DomUtils from '../../src/dom-utils';\nimport tippy from '../../src';\n\ndescribe('getArrayOfElements', () => {\n  it('returns an empty array with no arguments', () => {\n    expect(Array.isArray(DomUtils.getArrayOfElements())).toBe(true);\n  });\n\n  it('returns the same array if given an array', () => {\n    const arr = [];\n    expect(DomUtils.getArrayOfElements(arr)).toBe(arr);\n  });\n\n  it('returns an array of elements when given a valid selector string', () => {\n    [...Array(10)].map(() => h());\n    const allAreElements = DomUtils.getArrayOfElements(IDENTIFIER).every(\n      (value) => value instanceof Element\n    );\n    expect(allAreElements).toBe(true);\n  });\n\n  it('returns an empty array when given an invalid selector string', () => {\n    const arr = DomUtils.getArrayOfElements('😎');\n\n    expect(Array.isArray(arr)).toBe(true);\n    expect(arr.length).toBe(0);\n  });\n\n  it('returns an array of length 1 if the value is a DOM element', () => {\n    const ref = h();\n    const arr = DomUtils.getArrayOfElements(ref);\n\n    expect(arr[0]).toBe(ref);\n    expect(arr.length).toBe(1);\n  });\n\n  it('returns an array if given a NodeList', () => {\n    const ref = h();\n    const arr = DomUtils.getArrayOfElements(\n      document.querySelectorAll(`.${IDENTIFIER}`)\n    );\n\n    expect(arr[0]).toBe(ref);\n    expect(Array.isArray(arr)).toBe(true);\n  });\n});\n\ndescribe('div', () => {\n  it('creates and returns a div element', () => {\n    const d = DomUtils.div();\n    expect(d.nodeName).toBe('DIV');\n  });\n});\n\ndescribe('setTransitionDuration', () => {\n  it('sets the `transition-duration` property on a list of elements with the value specified', () => {\n    const els = [h(), h(), null, h()];\n    DomUtils.setTransitionDuration(els, 1298);\n\n    expect(els[0].style.transitionDuration).toBe('1298ms');\n    expect(els[1].style.transitionDuration).toBe('1298ms');\n    expect(els[3].style.transitionDuration).toBe('1298ms');\n  });\n});\n\ndescribe('setVisibilityState', () => {\n  it('sets the `data-state` attribute on a list of elements with the value specified', () => {\n    const els = [h(), h(), null, h()];\n\n    DomUtils.setVisibilityState(els, 'visible');\n\n    expect(els[0].getAttribute('data-state')).toBe('visible');\n    expect(els[1].getAttribute('data-state')).toBe('visible');\n    expect(els[3].getAttribute('data-state')).toBe('visible');\n\n    DomUtils.setVisibilityState(els, 'hidden');\n\n    expect(els[0].getAttribute('data-state')).toBe('hidden');\n    expect(els[1].getAttribute('data-state')).toBe('hidden');\n    expect(els[3].getAttribute('data-state')).toBe('hidden');\n  });\n});\n\ndescribe('isReferenceElement', () => {\n  it('correctly determines if a value is a reference element', () => {\n    const instance = tippy(h());\n\n    expect(DomUtils.isReferenceElement(document.createElement('div'))).toBe(\n      false\n    );\n    expect(DomUtils.isReferenceElement(instance.reference)).toBe(true);\n    expect(DomUtils.isReferenceElement(instance.popper)).toBe(false);\n\n    instance.popper.classList.add('other');\n\n    expect(DomUtils.isReferenceElement(instance.popper)).toBe(false);\n  });\n});\n\ndescribe('getOwnerDocument', () => {\n  it('finds the ownerDocument of an element', () => {\n    expect(DomUtils.getOwnerDocument(document.createElement('div'))).toBe(document);\n  });\n\n  it('uses the default document if the element was created from a template', () => {\n    const template = document.createElement('template');\n\n    template.innerHTML = '<div></div>';\n\n    const div = template.content.firstChild;\n\n    expect(DomUtils.getOwnerDocument(div)).toBe(document);\n  });\n});\n"
  },
  {
    "path": "test/unit/props.test.js",
    "content": "import {h} from '../utils';\n\nimport {\n  getDataAttributeProps,\n  evaluateProps,\n  validateProps,\n  setDefaultProps,\n} from '../../src/props';\nimport {getFormattedMessage} from '../../src/validation';\nimport tippy from '../../src';\n\ndescribe('getDataAttributeProps', () => {\n  it('uses data-tippy-content', () => {\n    const ref = h();\n    ref.setAttribute('data-tippy-content', 'test');\n\n    expect(getDataAttributeProps(ref).content).toBe('test');\n  });\n\n  it('does not parse data-tippy-content', () => {\n    const ref = h();\n\n    ref.setAttribute('data-tippy-content', '[Hello');\n    expect(getDataAttributeProps(ref).content).toBe('[Hello');\n\n    ref.setAttribute('data-tippy-content', '3333333333333333333333333');\n    expect(getDataAttributeProps(ref).content).toBe(\n      '3333333333333333333333333'\n    );\n  });\n\n  it('returns the attribute props', () => {\n    const ref = h();\n\n    ref.setAttribute('data-tippy-arrow', 'round');\n\n    expect(getDataAttributeProps(ref)).toEqual({arrow: 'round'});\n  });\n\n  it('correctly parses true & false strings', () => {\n    const ref = h();\n\n    ref.setAttribute('data-tippy-interactive', 'true');\n    ref.setAttribute('data-tippy-arrow', 'false');\n\n    expect(getDataAttributeProps(ref)).toEqual({\n      interactive: true,\n      arrow: false,\n    });\n  });\n\n  it('correctly parses number strings', () => {\n    const ref = h();\n\n    ref.setAttribute('data-tippy-delay', '129');\n    ref.setAttribute('data-tippy-duration', '111');\n\n    expect(getDataAttributeProps(ref)).toEqual({delay: 129, duration: 111});\n  });\n\n  it('correctly parses JSON-serializable props', () => {\n    const ref = h();\n\n    ref.setAttribute('data-tippy-delay', '[100, 255]');\n    ref.setAttribute('data-tippy-duration', '[0, 999]');\n    ref.setAttribute('data-tippy-popperOptions', '{ \"placement\": \"right\" }');\n\n    expect(getDataAttributeProps(ref)).toEqual({\n      delay: [100, 255],\n      duration: [0, 999],\n      popperOptions: {placement: 'right'},\n    });\n  });\n\n  it('does not break if content begins with [ or {', () => {\n    const ref = h();\n\n    ref.setAttribute('data-tippy-content', '[');\n    expect(() => getDataAttributeProps(ref)).not.toThrow();\n\n    ref.setAttribute('data-tippy-content', '{');\n    expect(() => getDataAttributeProps(ref)).not.toThrow();\n  });\n});\n\ndescribe('evaluateProps', () => {\n  it('ignores attributes if `ignoreAttributes: true`', () => {\n    const props = {animation: 'scale', ignoreAttributes: true};\n    const reference = h();\n\n    reference.setAttribute('data-tippy-animation', 'fade');\n\n    expect(evaluateProps(reference, props)).toMatchSnapshot();\n  });\n\n  it('does not ignore attributes if `ignoreAttributes: false`', () => {\n    const props = {animation: 'scale', ignoreAttributes: false};\n    const reference = h();\n\n    reference.setAttribute('data-tippy-animation', 'fade');\n\n    expect(evaluateProps(reference, props)).toMatchSnapshot();\n  });\n\n  it('considers plugin props', () => {\n    const plugins = [{name: 'plugin', fn: () => ({})}];\n    const props = {plugin: 'x', plugins};\n    const reference = h();\n\n    reference.setAttribute('data-tippy-plugin', 'y');\n\n    expect(evaluateProps(reference, props)).toMatchSnapshot();\n  });\n});\n\ndescribe('validateProps', () => {\n  it('recognizes an unknown prop', () => {\n    const prop = '__x';\n    validateProps({[prop]: true});\n    expect(console.warn).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          `\\`${prop}\\``,\n          \"is not a valid prop. You may have spelled it incorrectly, or if it's\",\n          'a plugin, forgot to pass it in an array as props.plugins.',\n          '\\n\\n',\n          'All props: https://atomiks.github.io/tippyjs/v6/all-props/\\n',\n          'Plugins: https://atomiks.github.io/tippyjs/v6/plugins/',\n        ].join(' ')\n      )\n    );\n  });\n\n  it('handles included plugin props', () => {\n    const prop = 'followCursor';\n    const plugins = [{name: prop, fn: () => ({})}];\n\n    validateProps({[prop]: true});\n    expect(console.warn).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          `\\`${prop}\\``,\n          \"is not a valid prop. You may have spelled it incorrectly, or if it's\",\n          'a plugin, forgot to pass it in an array as props.plugins.',\n          '\\n\\n',\n          'All props: https://atomiks.github.io/tippyjs/v6/all-props/\\n',\n          'Plugins: https://atomiks.github.io/tippyjs/v6/plugins/',\n        ].join(' ')\n      )\n    );\n\n    console.warn.mockClear();\n\n    validateProps({[prop]: true}, plugins);\n    expect(console.warn).not.toHaveBeenCalled();\n  });\n\n  it('handles custom plugin props', () => {\n    const prop = '__custom';\n    const plugins = [{name: prop, fn: () => ({})}];\n\n    validateProps({[prop]: true});\n    expect(console.warn).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          `\\`${prop}\\``,\n          \"is not a valid prop. You may have spelled it incorrectly, or if it's\",\n          'a plugin, forgot to pass it in an array as props.plugins.',\n          '\\n\\n',\n          'All props: https://atomiks.github.io/tippyjs/v6/all-props/\\n',\n          'Plugins: https://atomiks.github.io/tippyjs/v6/plugins/',\n        ].join(' ')\n      )\n    );\n\n    console.warn.mockClear();\n\n    validateProps({[prop]: true}, plugins);\n    expect(console.warn).not.toHaveBeenCalled();\n  });\n});\n\ndescribe('setDefaultProps', () => {\n  it('is preferred over .defaultValue on Plugin objects', () => {\n    const instance1 = tippy(h());\n    expect(instance1.props.followCursor).toBe(false);\n    setDefaultProps({followCursor: 'initial'});\n    const instance2 = tippy(h());\n    expect(instance2.props.followCursor).toBe('initial');\n    const instance3 = tippy(h(), {followCursor: true});\n    expect(instance3.props.followCursor).toBe(true);\n  });\n\n  it('works as expected with non-default plugins', () => {\n    const instance1 = tippy(h(), {\n      plugins: [{name: 'testPlugin', defaultValue: 'new', fn: () => ({})}],\n    });\n    expect(instance1.props.testPlugin).toBe('new');\n    setDefaultProps({testPlugin: false});\n    const instance2 = tippy(h(), {\n      plugins: [{name: 'testPlugin', defaultValue: 'new', fn: () => ({})}],\n    });\n    expect(instance2.props.testPlugin).toBe(false);\n  });\n});\n"
  },
  {
    "path": "test/unit/tippy.test.js",
    "content": "import {h} from '../utils';\n\nimport {defaultProps, extraProps} from '../../src/props';\nimport {POPPER_SELECTOR} from '../../src/constants';\nimport tippy, {hideAll} from '../../src';\nimport {getFormattedMessage} from '../../src/validation';\n\ndescribe('tippy', () => {\n  it('returns the expected object', () => {\n    expect(typeof tippy(h())).toBe('object');\n    expect(Array.isArray(tippy([h(), h()]))).toBe(true);\n  });\n\n  it('merges the default props with the supplied props', () => {\n    expect(tippy(h(), {placement: 'bottom-end'}).props).toMatchSnapshot();\n  });\n\n  it('warns if invalid props(s) are supplied', () => {\n    tippy(h(), {placement: 'top', _someInvalidProp: true});\n\n    expect(console.warn).toHaveBeenCalledTimes(1);\n  });\n\n  it('handles falsy reference in an array', () => {\n    tippy([null, false, 0, undefined]);\n  });\n\n  it('errors if passed falsy Target type', () => {\n    tippy(null);\n\n    expect(console.error).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          'tippy() was passed',\n          '`' + String(null) + '`',\n          'as its targets (first) argument. Valid types are: String, Element, Element[],',\n          'or NodeList.',\n        ].join(' ')\n      )\n    );\n  });\n\n  it('warns if passed a single content element for many different references', () => {\n    const targets = [h(), h()];\n\n    tippy(targets, {content: document.createElement('div')});\n\n    expect(console.warn).toHaveBeenCalledWith(\n      ...getFormattedMessage(\n        [\n          'tippy() was passed an Element as the `content` prop, but more than',\n          'one tippy instance was created by this invocation. This means the',\n          'content element will only be appended to the last tippy instance.',\n          '\\n\\n',\n          'Instead, pass the .innerHTML of the element, or use a function that',\n          'returns a cloned version of the element instead.',\n          '\\n\\n',\n          '1) content: element.innerHTML\\n',\n          '2) content: () => element.cloneNode(true)',\n        ].join(' ')\n      )\n    );\n  });\n});\n\ndescribe('tippy.setDefaultProps()', () => {\n  it('changes the default props applied to instances', () => {\n    const newPlacement = 'bottom-end';\n\n    tippy.setDefaultProps({placement: newPlacement});\n\n    expect(defaultProps.placement).toBe(newPlacement);\n  });\n});\n\ndescribe('hideAll()', () => {\n  it('hides all tippys on the document, ignoring `hideOnClick`', () => {\n    const props = {showOnCreate: true, hideOnClick: false};\n    const instances = [...Array(3)].map(() => tippy(h(), props));\n\n    jest.runAllTimers();\n    hideAll();\n\n    instances.forEach((instance) => {\n      expect(instance.state.isVisible).toBe(false);\n    });\n  });\n\n  it('respects `duration` option', () => {\n    const props = {showOnCreate: true, duration: 100};\n    const instances = [...Array(3)].map(() => tippy(h(), props));\n\n    jest.runAllTimers();\n    hideAll({duration: 0});\n\n    instances.forEach((instance) => {\n      expect(instance.state.isMounted).toBe(false);\n    });\n  });\n\n  it('respects `exclude` option', () => {\n    const props = {showOnCreate: true};\n    const instances = [...Array(3)].map(() => tippy(h(), props));\n\n    jest.runAllTimers();\n    hideAll({exclude: instances[0]});\n\n    instances.forEach((instance) => {\n      expect(instance.state.isVisible).toBe(\n        instance === instances[0] ? true : false\n      );\n    });\n  });\n\n  it('respects `exclude` option as type ReferenceElement for multiple tippys', () => {\n    const props = {showOnCreate: true, multiple: true};\n    const ref = h();\n\n    tippy(ref, props);\n    tippy(ref, props);\n    hideAll({exclude: ref});\n\n    const instances = [...document.querySelectorAll(POPPER_SELECTOR)].map(\n      (popper) => popper._tippy\n    );\n\n    instances.forEach((instance) => {\n      expect(instance.state.isVisible).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/utils.test.js",
    "content": "import * as Utils from '../../src/utils';\n\ndescribe('hasOwnProperty', () => {\n  it('works for plain objects', () => {\n    expect(Utils.hasOwnProperty({prop: true}, 'prop')).toBe(true);\n    expect(Utils.hasOwnProperty({}, 'toString')).toBe(false);\n  });\n\n  it('works for prototypeless objects', () => {\n    const o = Object.create(null);\n    o.prop = true;\n    expect(Utils.hasOwnProperty(o, 'prop')).toBe(true);\n  });\n});\n\ndescribe('getValueAtIndexOrReturn', () => {\n  it('returns the value if not an array', () => {\n    expect(Utils.getValueAtIndexOrReturn('unique', 0)).toBe('unique');\n    expect(Utils.getValueAtIndexOrReturn('unique', 1)).toBe('unique');\n    expect(Utils.getValueAtIndexOrReturn(true, 1)).toBe(true);\n  });\n\n  it('returns the value at the specified index if an array', () => {\n    expect(Utils.getValueAtIndexOrReturn([-100, -200], 0)).toBe(-100);\n    expect(Utils.getValueAtIndexOrReturn([-100, -200], 1)).toBe(-200);\n    expect(Utils.getValueAtIndexOrReturn(['x', 'y'], 0)).toBe('x');\n    expect(Utils.getValueAtIndexOrReturn(['x', 'y'], 1)).toBe('y');\n  });\n\n  it('uses the default duration if the value is null', () => {\n    expect(Utils.getValueAtIndexOrReturn([null, 5], 0, -1)).toBe(-1);\n    expect(Utils.getValueAtIndexOrReturn([5, null], 1, 1000)).toBe(1000);\n    expect(Utils.getValueAtIndexOrReturn([null, 5], 0, [8, 9])).toBe(8);\n    expect(Utils.getValueAtIndexOrReturn([5, null], 1, [1, 2])).toBe(2);\n  });\n\n  it('uses the default duration if the value is undefined', () => {\n    expect(Utils.getValueAtIndexOrReturn([undefined, 5], 0, -1)).toBe(-1);\n    expect(Utils.getValueAtIndexOrReturn([5, undefined], 1, 1000)).toBe(1000);\n    expect(Utils.getValueAtIndexOrReturn([undefined, 5], 0, [8, 9])).toBe(8);\n    expect(Utils.getValueAtIndexOrReturn([5, undefined], 1, [1, 2])).toBe(2);\n  });\n});\n\ndescribe('debounce', () => {\n  it('works as expected', () => {\n    const fn = jest.fn();\n    const debouncedFn = Utils.debounce(fn, 50);\n    debouncedFn();\n    expect(fn).toHaveBeenCalledTimes(0);\n    jest.advanceTimersByTime(40);\n    expect(fn).toHaveBeenCalledTimes(0);\n    debouncedFn();\n    jest.advanceTimersByTime(40);\n    expect(fn).toHaveBeenCalledTimes(0);\n    jest.advanceTimersByTime(10);\n    expect(fn).toHaveBeenCalledTimes(1);\n  });\n\n  it('is called with arguments', () => {\n    const fn = jest.fn();\n    const ms = 50;\n    const debouncedFn = Utils.debounce(fn, ms);\n    debouncedFn('string');\n    jest.advanceTimersByTime(ms);\n    expect(fn).toHaveBeenCalledWith('string');\n  });\n\n  it('does not wrap with new function if ms = 0', () => {\n    const fn = jest.fn();\n    const debouncedFn = Utils.debounce(fn, 0);\n    expect(debouncedFn).toBe(fn);\n  });\n});\n\ndescribe('removeProperties', () => {\n  it('deletes unwanted properties', () => {\n    expect(Utils.removeProperties({a: 1, b: 2}, ['b'])).toEqual({a: 1});\n  });\n});\n\ndescribe('splitBySpaces', () => {\n  it('returns an array parsed from the specified string', () => {\n    expect(Utils.splitBySpaces('')).toMatchObject([]);\n    expect(Utils.splitBySpaces('one')).toMatchObject(['one']);\n    expect(Utils.splitBySpaces('one two')).toMatchObject(['one', 'two']);\n    expect(Utils.splitBySpaces('one  two    three')).toMatchObject([\n      'one',\n      'two',\n      'three',\n    ]);\n  });\n\n  it('ignores surrounding whitespace', () => {\n    expect(Utils.splitBySpaces('  one  ')).toMatchObject(['one']);\n    expect(Utils.splitBySpaces(' one  two ')).toMatchObject(['one', 'two']);\n  });\n});\n\ndescribe('isType', () => {\n  it('correctly determines types of Elements', () => {\n    expect(Utils.isType(document.createElement('div'), 'Element')).toBe(true);\n    expect(\n      Utils.isType(\n        document.createElementNS('http://www.w3.org/2000/svg', 'svg'),\n        'Element'\n      )\n    ).toBe(true);\n    expect(Utils.isType({}, 'Element')).toBe(false);\n    expect(Utils.isType('button', 'Element')).toBe(false);\n    expect(Utils.isType(document.querySelectorAll('a'), 'Element')).toBe(false);\n  });\n\n  it('correctly determines type of MouseEvents', () => {\n    expect(Utils.isType(new MouseEvent('mouseenter'), 'MouseEvent')).toBe(true);\n    expect(Utils.isType(new FocusEvent('focus'), 'MouseEvent')).toBe(false);\n  });\n\n  it('correctly determines type of NodeLists', () => {\n    expect(Utils.isType(document.querySelectorAll('a'), 'NodeList')).toBe(true);\n    expect(Utils.isType(document.createElement('div'), 'NodeList')).toBe(false);\n    expect(Utils.isType({}, 'NodeList')).toBe(false);\n  });\n});\n\ndescribe('pushIfUnique', () => {\n  it('adds item only if unique', () => {\n    const item = {};\n    const arr = [];\n\n    Utils.pushIfUnique(arr, item);\n    Utils.pushIfUnique(arr, item);\n    Utils.pushIfUnique(arr, 2);\n\n    expect(arr).toEqual([item, 2]);\n  });\n});\n\ndescribe('appendPxIfNumber', () => {\n  it('should append `px` if number', () => {\n    expect(Utils.appendPxIfNumber(200)).toBe('200px');\n    expect(Utils.appendPxIfNumber(0)).toBe('0px');\n  });\n\n  it('should not append `px` if string', () => {\n    expect(Utils.appendPxIfNumber('200rem')).toBe('200rem');\n    expect(Utils.appendPxIfNumber('10px')).toBe('10px');\n  });\n});\n\ndescribe('unique', () => {\n  it('filters out duplicate elements', () => {\n    const ref1 = {};\n    const ref2 = {};\n    expect(Utils.unique([0, 1, 0, 2, 3, 2, 3, 3, 4])).toEqual([0, 1, 2, 3, 4]);\n    expect(Utils.unique([ref1, ref1, ref2])).toEqual([ref1, ref2]);\n  });\n});\n\ndescribe('getNumber', () => {\n  it('number: returns number', () => {\n    expect(Utils.getNumber(0)).toBe(0);\n    expect(Utils.getNumber(100)).toBe(100);\n    expect(Utils.getNumber(-1.13812)).toBe(-1.13812);\n  });\n\n  it('string: returns number from CSS string', () => {\n    expect(Utils.getNumber('0px')).toBe(0);\n    expect(Utils.getNumber('100rem')).toBe(100);\n    expect(Utils.getNumber('-21.35em')).toBe(-21.35);\n  });\n});\n\ndescribe('removeUndefinedProps', () => {\n  it('removes properties that are set to `undefined`', () => {\n    expect(\n      Utils.removeUndefinedProps({\n        a: undefined,\n        b: null,\n        c: 0,\n        d: true,\n        e: undefined,\n      })\n    ).toEqual({\n      b: null,\n      c: 0,\n      d: true,\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/validation.test.js",
    "content": "import {\n  validateTargets,\n  getFormattedMessage,\n  warnWhen,\n  errorWhen,\n} from '../../src/validation';\n\ndescribe('validateTargets', () => {\n  it('recognizes a falsy target', () => {\n    const falsys = [null, undefined, false, NaN, 0, ''];\n    falsys.forEach((falsy) => {\n      validateTargets(falsy);\n\n      expect(console.error).toHaveBeenCalledWith(\n        ...getFormattedMessage(\n          [\n            'tippy() was passed',\n            '`' + String(falsy) + '`',\n            'as its targets (first) argument. Valid types are: String, Element, Element[],',\n            'or NodeList.',\n          ].join(' ')\n        )\n      );\n    });\n  });\n});\n\ndescribe('warnWhen', () => {\n  it('should only ever emit a warning of the same message once', () => {\n    warnWhen(true, 'warning');\n    warnWhen(true, 'warning');\n\n    expect(console.warn).toHaveBeenCalledTimes(1);\n  });\n});\n\ndescribe('errorWhen', () => {\n  it('should only ever emit an error of the same message once', () => {\n    errorWhen(true, 'error');\n    errorWhen(true, 'error');\n\n    expect(console.error).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "test/utils.js",
    "content": "import {\n  onDocumentMouseMove,\n  onDocumentTouchStart,\n} from '../src/bindGlobalEventListeners';\nimport tippy from '../src';\n\nexport const IDENTIFIER = '__tippy';\n\nexport function cleanDocumentBody() {\n  document.body.innerHTML = '';\n}\n\nexport function h(nodeName = 'button', attributes = {}, to = document.body) {\n  const el = document.createElement(nodeName);\n  el.className = IDENTIFIER;\n\n  for (const attr in attributes) {\n    el.setAttribute(attr, attributes[attr]);\n  }\n\n  to.appendChild(el);\n\n  return el;\n}\n\nexport function enableTouchEnvironment() {\n  window.ontouchstart = true;\n  onDocumentTouchStart();\n}\n\nexport function disableTouchEnvironment() {\n  delete window.ontouchstart;\n  onDocumentMouseMove();\n  onDocumentMouseMove();\n}\n\nexport async function screenshotTest(page, name) {\n  // Remove container border so the image is clean\n  await page.addStyleTag({\n    content: `\n    * { \n      color: transparent; \n    }\n\n    .container {\n      border: none !important;\n    }\n    `,\n  });\n\n  const rect = await page.evaluate((selector) => {\n    const element = document.querySelector(selector);\n    const {x, y, width, height} = element.getBoundingClientRect();\n    return {left: x, top: y, width, height, id: element.id};\n  }, `#${name}`);\n\n  return page.screenshot({\n    path: null,\n    clip: {\n      x: rect.left,\n      y: rect.top,\n      width: rect.width,\n      height: rect.height,\n    },\n  });\n}\n\nexport async function navigateToTest(page, name) {\n  return page.$eval(`button[data-id=\"${name}\"]`, (el) => el.click());\n}\n"
  },
  {
    "path": "test/visual/index.css",
    "content": "*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: Arial !important;\n}\n\n#controls {\n  position: fixed;\n  top: 0;\n  right: 0;\n  overflow-y: auto;\n  width: calc(100vw - 816px);\n  height: 100vh;\n  padding: 15px 25px;\n  background: #eee;\n}\n\n.link {\n  position: relative;\n  display: block;\n  color: #333;\n  text-decoration: underline;\n  background: none;\n  border: none;\n  font-size: 100%;\n  cursor: pointer;\n  margin: 5px 0;\n  outline: 0;\n}\n\n.link:focus {\n  box-shadow: 0 0 0 1px purple;\n}\n\n.link[data-current] {\n  font-weight: bold;\n  color: purple;\n}\n\n.link[data-current]::before {\n  content: '•';\n  color: purple;\n  position: absolute;\n  left: -10px;\n}\n\nbutton:not(.link) {\n  all: unset;\n  font-size: 16px;\n  border: none;\n  background: #eee;\n  padding: 8px 16px;\n}\n\nbutton:not(.link):focus {\n  outline: 1px solid;\n}\n\n.container {\n  position: relative;\n  display: none;\n  overflow: hidden;\n  border: 2px dashed red;\n  height: 500px;\n  width: 800px;\n  padding: 25px;\n  place-items: center;\n}\n\n.__NAMESPACE_PREFIX__-box[data-theme~='border'] {\n  border: 1px solid blue;\n  background-color: white;\n  color: blue;\n}\n\n.__NAMESPACE_PREFIX__-box[data-placement^='top'][data-theme~='border']\n  > .__NAMESPACE_PREFIX__-arrow::before {\n  border-top-color: white;\n}\n.__NAMESPACE_PREFIX__-box[data-placement^='bottom'][data-theme~='border']\n  > .__NAMESPACE_PREFIX__-arrow::before {\n  border-bottom-color: white;\n}\n.__NAMESPACE_PREFIX__-box[data-placement^='left'][data-theme~='border']\n  > .__NAMESPACE_PREFIX__-arrow::before {\n  border-left-color: white;\n}\n.__NAMESPACE_PREFIX__-box[data-placement^='right'][data-theme~='border']\n  > .__NAMESPACE_PREFIX__-arrow::before {\n  border-right-color: white;\n}\n\n.__NAMESPACE_PREFIX__-box[data-theme~='border']\n  > .__NAMESPACE_PREFIX__-svg-arrow\n  > svg:first-child {\n  fill: blue;\n}\n\n.__NAMESPACE_PREFIX__-box[data-theme~='border']\n  > .__NAMESPACE_PREFIX__-svg-arrow\n  > svg:last-child {\n  fill: white;\n}\n"
  },
  {
    "path": "test/visual/index.html",
    "content": "<!DOCTYPE html> <title>test</title>\n\n<meta charset=\"utf8\" />\n<link rel=\"stylesheet\" href=\"dist/bundle.css\" />\n<link rel=\"stylesheet\" href=\"index.css\" />\n\n<div id=\"controls\">\n  <h1>Tippy Development</h1>\n</div>\n\n<div class=\"container\" id=\"default\">\n  <div class=\"wrapper\">\n    <button class=\"reference\">Reference</button>\n  </div>\n</div>\n\n<div class=\"container\" id=\"sticky\">\n  <style>\n    @keyframes sticky-shift {\n      to {\n        transform: translate(0, -150px);\n      }\n    }\n\n    #sticky .animate {\n      animation: sticky-shift 2s ease-in-out infinite alternate;\n    }\n  </style>\n  <div class=\"wrapper\">\n    <button class=\"reference\">Reference</button>\n    <button class=\"animation\">Enable animation</button>\n  </div>\n</div>\n\n<div class=\"container\" id=\"inlinePositioning\">\n  <style>\n    #inlinePositioning .wrapper {\n      max-width: 300px;\n    }\n\n    #inlinePositioning [class^='reference'] {\n      color: white;\n      outline: 1px solid black;\n    }\n  </style>\n  <div class=\"wrapper\">\n    This is\n    <span class=\"reference-connected\"\n      >some text and an inline element that spans over many lines to demonstrate\n      this inline positioning solution</span\n    >, and some more text.\n  </div>\n\n  <div class=\"wrapper\">\n    This is some text and an\n    <span class=\"reference-disconnected\">inline element that</span>\n    spans over many lines to demonstrate this inline positioning solution , and\n    some more text.\n  </div>\n</div>\n\n<div class=\"container\" id=\"followCursor\">\n  <div class=\"wrapper\">\n    <button class=\"reference\" data-test=\"true\">true</button>\n    <button class=\"reference\" data-test=\"false\">false</button>\n    <button class=\"reference\" data-test=\"horizontal\">horizontal</button>\n    <button class=\"reference\" data-test=\"vertical\">vertical</button>\n    <button class=\"reference\" data-test=\"initial\">initial</button>\n    <button class=\"reference\" data-test=\"contentChange\">contentChange</button>\n  </div>\n</div>\n\n<div class=\"container\" id=\"themes\">\n  <style>\n    #themes button {\n      font-size: 12px;\n      padding: 2px 4px;\n    }\n  </style>\n  <div class=\"wrapper\" style=\"text-align: right;\"></div>\n</div>\n\n<div class=\"container\" id=\"animations\">\n  <style>\n    #animations button {\n      margin: 5px;\n      font-size: 12px;\n    }\n  </style>\n  <div class=\"wrapper\"></div>\n</div>\n\n<div class=\"container\" id=\"createSingleton\">\n  <div class=\"wrapper\">\n    <button class=\"reference\" data-tippy-content=\"Tippy A\">Reference</button>\n    <button class=\"reference\" data-tippy-content=\"Tippy B\">Reference</button>\n    <button class=\"reference\" data-tippy-content=\"Tippy C\">Reference</button>\n  </div>\n</div>\n\n<div class=\"container\" id=\"delegate\">\n  <div class=\"wrapper\">\n    <button class=\"reference\" data-tippy-content=\"Tippy A\">Reference</button>\n    <button class=\"reference\" data-tippy-content=\"Tippy B\">Reference</button>\n    <button class=\"reference\" data-tippy-content=\"Tippy C\">Reference</button>\n  </div>\n</div>\n\n<div class=\"container\" id=\"animateFill\">\n  <div class=\"wrapper\">\n    <button class=\"reference\">Reference</button>\n  </div>\n</div>\n\n<div class=\"container\" id=\"border\">\n  <div class=\"wrapper\">\n    <button class=\"reference\">Reference</button>\n    <button class=\"reference\">Reference</button>\n  </div>\n</div>\n\n<script src=\"dist/bundle.js\"></script>\n<script src=\"index.js\"></script>\n"
  },
  {
    "path": "test/visual/index.js",
    "content": "const containers = document.querySelectorAll('.container');\n\ncontainers.forEach((container) => {\n  const button = document.createElement('button');\n\n  button.textContent = container.id;\n  button.className = 'link';\n  button.setAttribute('data-id', container.id);\n\n  document.querySelector('#controls').appendChild(button);\n\n  button.onclick = () => {\n    hide();\n\n    state.currentTest = container.id;\n\n    show();\n    run();\n\n    window.location.hash = container.id;\n  };\n});\n\nfunction hide() {\n  const container = document.getElementById(state.currentTest);\n  const button = document.querySelector(\n    `button[data-id=\"${state.currentTest}\"]`\n  );\n\n  if (container) {\n    container.style.display = 'none';\n    button.removeAttribute('data-current');\n  }\n}\n\nfunction show() {\n  const container = document.getElementById(state.currentTest);\n  const button = document.querySelector(\n    `button[data-id=\"${state.currentTest}\"]`\n  );\n\n  if (container) {\n    container.style.display = 'grid';\n    button.setAttribute('data-current', '');\n  }\n}\n\nfunction run() {\n  if (window.cleanup) {\n    window.cleanup();\n  }\n\n  window.cleanup = state.tests[state.currentTest]();\n}\n\nconst initialTestId = window.location.hash\n  ? window.location.hash.split('#')[1]\n  : 'default';\n\ndocument.querySelector(`button[data-id=\"${initialTestId}\"]`).click();\n"
  },
  {
    "path": "test/visual/tests.js",
    "content": "import tippy from '../../src';\nimport {render} from '../../src/template';\nimport {ROUND_ARROW as roundArrow} from '../../src/constants';\nimport sticky from '../../src/plugins/sticky';\nimport inlinePositioning from '../../src/plugins/inlinePositioning';\nimport followCursor from '../../src/plugins/followCursor';\nimport animateFill from '../../src/plugins/animateFill';\nimport createSingleton from '../../src/addons/createSingleton';\nimport delegate from '../../src/addons/delegate';\n\nimport '../../src/scss/index.scss';\nimport '../../src/scss/border.scss';\nimport '../../src/scss/svg-arrow.scss';\nimport '../../src/scss/backdrop.scss';\n\nimport '../../src/scss/themes/light.scss';\nimport '../../src/scss/themes/light-border.scss';\nimport '../../src/scss/themes/material.scss';\nimport '../../src/scss/themes/translucent.scss';\n\nimport '../../src/scss/animations/shift-away.scss';\nimport '../../src/scss/animations/shift-away-subtle.scss';\nimport '../../src/scss/animations/shift-away-extreme.scss';\nimport '../../src/scss/animations/shift-toward.scss';\nimport '../../src/scss/animations/shift-toward-extreme.scss';\nimport '../../src/scss/animations/shift-toward-subtle.scss';\nimport '../../src/scss/animations/perspective.scss';\nimport '../../src/scss/animations/perspective-extreme.scss';\nimport '../../src/scss/animations/perspective-subtle.scss';\nimport '../../src/scss/animations/scale.scss';\nimport '../../src/scss/animations/scale-subtle.scss';\nimport '../../src/scss/animations/scale-extreme.scss';\n\ntippy.setDefaultProps({render, appendTo: document.body});\n\nwindow.state = {\n  currentTest: '',\n  tests: {},\n};\n\nconst tests = window.state.tests;\n\ntests.default = () => {\n  const content = document.createDocumentFragment();\n  const svgA = document.createElement('svg');\n  const svgB = document.createElement('svg');\n\n  content.appendChild(svgA);\n  content.appendChild(svgB);\n\n  const [instance] = tippy('#default .reference', {\n    content: 'hello',\n    arrow: content,\n    interactive: true,\n    trigger: 'click focus',\n  });\n\n  console.log(instance.props.appendTo);\n\n  return instance.destroy;\n};\n\ntests.sticky = () => {\n  const reference = document.querySelector('#sticky .reference');\n\n  const instance = tippy(reference, {\n    content: 'tippy',\n    sticky: true,\n    plugins: [sticky],\n    showOnCreate: true,\n    duration: 0,\n    hideOnClick: false,\n    trigger: 'manual',\n    onMount() {\n      reference.style.transform = 'translateY(150px)';\n    },\n  });\n\n  document.querySelector('#sticky .animation').onclick = () => {\n    reference.classList.add('animate');\n  };\n\n  return instance.destroy;\n};\n\ntests.inlinePositioning = () => {\n  const instances = [];\n\n  ['top', 'right', 'bottom', 'left'].forEach((placement) => {\n    const [instance] = tippy('#inlinePositioning .reference-connected', {\n      placement,\n      content: 'tippy',\n      trigger: 'manual',\n      inlinePositioning: true,\n      plugins: [inlinePositioning],\n      hideOnClick: false,\n      showOnCreate: true,\n      duration: 0,\n    });\n\n    instances.push(instance);\n  });\n\n  for (let i = 0; i < 2; i++) {\n    ['top', 'right', 'bottom', 'left'].forEach((placement) => {\n      const [instance] = tippy('#inlinePositioning .reference-disconnected', {\n        placement,\n        content: 'tippy',\n        inlinePositioning: true,\n        plugins: [inlinePositioning],\n        hideOnClick: false,\n        showOnCreate: true,\n        duration: 0,\n      });\n\n      const rects = instance.reference.getClientRects();\n\n      instance.reference.dispatchEvent(\n        new MouseEvent('mouseenter', {\n          clientX: rects[i].left,\n          clientY: rects[i].top,\n        })\n      );\n\n      instance.setProps({trigger: 'manual'});\n\n      instances.push(instance);\n    });\n  }\n\n  return () => {\n    instances.forEach((instance) => instance.destroy());\n  };\n};\n\ntests.followCursor = () => {\n  const instances = [];\n\n  [true, false, 'vertical', 'horizontal', 'initial', 'contentChange'].forEach(\n    (test) => {\n      let interval;\n\n      const [instance] = tippy(`#followCursor [data-test=\"${test}\"]`, {\n        content: 'tippy',\n        followCursor: test === 'contentChange' ? true : test,\n        plugins: [followCursor],\n        delay: [50, 0],\n        duration: 0,\n        appendTo: 'parent',\n        ...(test === 'contentChange' && {\n          onCreate({setContent}) {\n            const contentLoop = ['.', '....', '..........'];\n            let index = 0;\n\n            interval = setInterval(() => {\n              setContent(contentLoop[index++]);\n\n              if (index === 3) {\n                clearInterval(interval);\n              }\n            }, 50);\n          },\n          onDestroy() {\n            clearInterval(interval);\n          },\n        }),\n      });\n\n      instances.push(instance);\n    }\n  );\n\n  return () => {\n    instances.forEach((instance) => instance.destroy());\n  };\n};\n\ntests.themes = () => {\n  const instances = [];\n\n  const themes = ['dark', 'light', 'light-border', 'material', 'translucent'];\n  const placements = ['top', 'bottom', 'left', 'right'];\n  const arrows = [false, true, roundArrow];\n\n  const container = document.querySelector('#themes .wrapper');\n\n  themes.forEach((theme) => {\n    const heading = document.createElement('h3');\n    heading.textContent = theme;\n    container.appendChild(heading);\n\n    placements.forEach((placement) => {\n      arrows.forEach((arrow) => {\n        const button = document.createElement('button');\n        button.textContent = 'ref';\n        button.style.margin = '0 5px';\n        container.appendChild(button);\n\n        const instance = tippy(button, {\n          content: '.',\n          showOnCreate: true,\n          duration: 0,\n          trigger: 'manual',\n          hideOnClick: false,\n          arrow,\n          theme,\n          placement,\n        });\n\n        instances.push(instance);\n      });\n    });\n  });\n\n  return () => {\n    instances.forEach((instance) => instance.destroy());\n    container.innerHTML = '';\n  };\n};\n\ntests.animations = () => {\n  const instances = [];\n\n  const animations = ['fade'].concat(\n    ['shift-away', 'shift-toward', 'scale', 'perspective'].reduce(\n      (acc, animation) =>\n        acc.concat(animation, `${animation}-subtle`, `${animation}-extreme`),\n      []\n    )\n  );\n  const placements = ['top', 'bottom', 'left', 'right'];\n  const container = document.querySelector('#animations .wrapper');\n\n  animations.forEach((animation) => {\n    placements.forEach((placement) => {\n      const button = document.createElement('button');\n      button.textContent = animation;\n      container.appendChild(button);\n\n      const instance = tippy(button, {\n        content: 'Tippy',\n        animation,\n        placement,\n      });\n\n      instances.push(instance);\n    });\n  });\n\n  return () => {\n    instances.forEach((instance) => instance.destroy());\n    container.innerHTML = '';\n  };\n};\n\ntests.createSingleton = () => {\n  const wrapper = document.querySelector('#createSingleton .wrapper');\n  const newReference = document.createElement('button');\n\n  newReference.textContent = 'Reference';\n  wrapper.append(newReference);\n\n  let instances = tippy('#createSingleton .reference', {\n    placement: 'bottom',\n    duration: 0,\n  });\n\n  const singleton = createSingleton(instances, {\n    delay: 500,\n    overrides: ['placement', 'duration'],\n    showOnCreate: true,\n  });\n\n  instances = instances.concat(\n    tippy(newReference, {\n      content: 'hello',\n    })\n  );\n\n  singleton.setInstances(instances);\n  singleton.setProps({overrides: ['duration']});\n\n  return () => {\n    instances.forEach((instance) => instance.destroy());\n    singleton.destroy();\n  };\n};\n\ntests.delegate = () => {\n  const refs = Array.from(document.querySelectorAll('#delegate button'));\n\n  refs.forEach((ref) => {\n    ref.oncontextmenu = (e) => e.preventDefault();\n  });\n\n  const instances = delegate('#delegate', {\n    target: 'button',\n    trigger: 'click',\n  });\n\n  return () => instances.forEach((instance) => instance.destroy());\n};\n\ntests.animateFill = () => {\n  const instances = [];\n\n  ['top', 'right', 'bottom', 'left'].forEach((placement) => {\n    const [instance] = tippy('#animateFill .reference', {\n      placement,\n      content: 'Tippy',\n      animateFill: true,\n      plugins: [animateFill],\n    });\n\n    instances.push(instance);\n  });\n\n  return () => {\n    instances.forEach((instance) => instance.destroy());\n  };\n};\n\ntests.border = () => {\n  const props = {\n    content: 'Tippy',\n    theme: 'border',\n    duration: 0,\n    showOnCreate: true,\n  };\n\n  const instances = [\n    tippy('#border .reference:first-child', props),\n    tippy('#border .reference:first-child', {\n      ...props,\n      placement: 'bottom',\n    }),\n    tippy('#border .reference:first-child', {\n      ...props,\n      placement: 'right',\n    }),\n    tippy('#border .reference:first-child', {\n      ...props,\n      placement: 'left',\n    }),\n    tippy('#border .reference:last-child', {\n      arrow: roundArrow + roundArrow,\n      ...props,\n    }),\n    tippy('#border .reference:last-child', {\n      arrow: roundArrow + roundArrow,\n      placement: 'bottom',\n      ...props,\n    }),\n    tippy('#border .reference:last-child', {\n      arrow: roundArrow + roundArrow,\n      placement: 'right',\n      ...props,\n    }),\n    tippy('#border .reference:last-child', {\n      arrow: roundArrow + roundArrow,\n      placement: 'left',\n      ...props,\n    }),\n  ].flat();\n\n  return () => {\n    instances.forEach((instance) => instance.destroy());\n  };\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"es2015\"],\n    \"moduleResolution\": \"node\",\n    \"noEmit\": true,\n    \"resolveJsonModule\": true,\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"types\": [\"node\"],\n    \"allowJs\": true\n  },\n  \"include\": [\"src/**/*\", \"index.d.ts\", \"index.test-d.ts\"]\n}\n"
  },
  {
    "path": "website/.eslintignore",
    "content": "../dist"
  },
  {
    "path": "website/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Typescript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# dotenv environment variables file\n.env\n\n# gatsby files\n.cache/\npublic\n\n# Mac files\n.DS_Store\n\n# Yarn\nyarn-error.log\n.pnp/\n.pnp.js\n# Yarn Integrity file\n.yarn-integrity\n"
  },
  {
    "path": "website/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 gatsbyjs\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "website/README.md",
    "content": "<!-- AUTO-GENERATED-CONTENT:START (STARTER) -->\n<p align=\"center\">\n  <a href=\"https://www.gatsbyjs.org\">\n    <img alt=\"Gatsby\" src=\"https://www.gatsbyjs.org/monogram.svg\" width=\"60\" />\n  </a>\n</p>\n<h1 align=\"center\">\n  Gatsby's default starter\n</h1>\n\nKick off your project with this default boilerplate. This starter ships with the\nmain Gatsby configuration files you might need to get up and running blazing\nfast with the blazing fast app generator for React.\n\n_Have another more specific idea? You may want to check out our vibrant\ncollection of\n[official and community-created starters](https://www.gatsbyjs.org/docs/gatsby-starters/)._\n\n## 🚀 Quick start\n\n1.  **Create a Gatsby site.**\n\n    Use the Gatsby CLI to create a new site, specifying the default starter.\n\n    ```sh\n    # create a new Gatsby site using the default starter\n    npx gatsby new my-default-starter https://github.com/gatsbyjs/gatsby-starter-default\n    ```\n\n1.  **Start developing.**\n\n    Navigate into your new site’s directory and start it up.\n\n    ```sh\n    cd my-default-starter/\n    gatsby develop\n    ```\n\n1.  **Open the source code and start editing!**\n\n    Your site is now running at `http://localhost:8000`!\n\n    \\_Note: You'll also see a second link: `http://localhost:8000/___graphql`.\n    This is a tool you can use to experiment with querying your data. Learn more\n    about using this tool in the\n    [Gatsby tutorial](https://www.gatsbyjs.org/tutorial/part-five/#introducing-graphiql).\\_\n\n    Open the `my-default-starter` directory in your code editor of choice and\n    edit `src/pages/index.js`. Save your changes and the browser will update in\n    real time!\n\n## 🧐 What's inside?\n\nA quick look at the top-level files and directories you'll see in a Gatsby\nproject.\n\n    .\n    ├── node_modules\n    ├── src\n    ├── .gitignore\n    ├── .prettierrc\n    ├── gatsby-browser.js\n    ├── gatsby-config.js\n    ├── gatsby-node.js\n    ├── gatsby-ssr.js\n    ├── LICENSE\n    ├── package-lock.json\n    ├── package.json\n    └── README.md\n\n1.  **`/node_modules`**: This directory contains all of the modules of code that\n    your project depends on (npm packages) are automatically installed.\n\n2.  **`/src`**: This directory will contain all of the code related to what you\n    will see on the front-end of your site (what you see in the browser) such as\n    your site header or a page template. `src` is a convention for “source\n    code”.\n\n3.  **`.gitignore`**: This file tells git which files it should not track / not\n    maintain a version history for.\n\n4.  **`.prettierrc`**: This is a configuration file for\n    [Prettier](https://prettier.io/). Prettier is a tool to help keep the\n    formatting of your code consistent.\n\n5.  **`gatsby-browser.js`**: This file is where Gatsby expects to find any usage\n    of the [Gatsby browser APIs](https://www.gatsbyjs.org/docs/browser-apis/)\n    (if any). These allow customization/extension of default Gatsby settings\n    affecting the browser.\n\n6.  **`gatsby-config.js`**: This is the main configuration file for a Gatsby\n    site. This is where you can specify information about your site (metadata)\n    like the site title and description, which Gatsby plugins you’d like to\n    include, etc. (Check out the\n    [config docs](https://www.gatsbyjs.org/docs/gatsby-config/) for more\n    detail).\n\n7.  **`gatsby-node.js`**: This file is where Gatsby expects to find any usage of\n    the [Gatsby Node APIs](https://www.gatsbyjs.org/docs/node-apis/) (if any).\n    These allow customization/extension of default Gatsby settings affecting\n    pieces of the site build process.\n\n8.  **`gatsby-ssr.js`**: This file is where Gatsby expects to find any usage of\n    the\n    [Gatsby server-side rendering APIs](https://www.gatsbyjs.org/docs/ssr-apis/)\n    (if any). These allow customization of default Gatsby settings affecting\n    server-side rendering.\n\n9.  **`LICENSE`**: Gatsby is licensed under the MIT license.\n\n10. **`package-lock.json`** (See `package.json` below, first). This is an\n    automatically generated file based on the exact versions of your npm\n    dependencies that were installed for your project. **(You won’t change this\n    file directly).**\n\n11. **`package.json`**: A manifest file for Node.js projects, which includes\n    things like metadata (the project’s name, author, etc). This manifest is how\n    npm knows which packages to install for your project.\n\n12. **`README.md`**: A text file containing useful reference information about\n    your project.\n\n## 🎓 Learning Gatsby\n\nLooking for more guidance? Full documentation for Gatsby lives\n[on the website](https://www.gatsbyjs.org/). Here are some places to start:\n\n- **For most developers, we recommend starting with our\n  [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.org/tutorial/).**\n  It starts with zero assumptions about your level of ability and walks through\n  every step of the process.\n\n- **To dive straight into code samples, head\n  [to our documentation](https://www.gatsbyjs.org/docs/).** In particular, check\n  out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the\n  sidebar.\n\n## 💫 Deploy\n\n[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-default)\n\n<!-- AUTO-GENERATED-CONTENT:END -->\n"
  },
  {
    "path": "website/gatsby-config.js",
    "content": "module.exports = {\n  pathPrefix: '/tippyjs',\n  siteMetadata: {\n    title: `Tippy.js`,\n    description: `The complete tooltip, popover, dropdown, and menu solution for the web`,\n    author: `@atomiks`,\n  },\n  plugins: [\n    `gatsby-plugin-react-helmet`,\n    {\n      resolve: `gatsby-source-filesystem`,\n      options: {\n        name: `images`,\n        path: `${__dirname}/src/images`,\n      },\n    },\n    {\n      resolve: `gatsby-source-filesystem`,\n      options: {\n        name: `pages`,\n        path: `${__dirname}/src/pages`,\n      },\n    },\n    `gatsby-transformer-sharp`,\n    `gatsby-plugin-sharp`,\n    {\n      resolve: `gatsby-plugin-manifest`,\n      options: {\n        name: `gatsby-starter-default`,\n        short_name: `starter`,\n        start_url: `/`,\n        background_color: `#663399`,\n        theme_color: `#663399`,\n        display: `minimal-ui`,\n        icon: `src/favicon.png`,\n      },\n    },\n    {\n      resolve: `gatsby-plugin-google-analytics`,\n      options: {\n        trackingId: 'UA-61550002-7',\n        head: false,\n      },\n    },\n    `gatsby-plugin-catch-links`,\n    // this (optional) plugin enables Progressive Web App + Offline functionality\n    // To learn more, visit: https://gatsby.app/offline\n    // 'gatsby-plugin-offline',\n    `gatsby-plugin-emotion`,\n    {\n      resolve: `gatsby-plugin-mdx`,\n      options: {\n        defaultLayouts: {\n          default: require.resolve('./src/components/Layout.js'),\n        },\n        gatsbyRemarkPlugins: [\n          {\n            resolve: `gatsby-remark-vscode`,\n            options: {\n              theme: `Moonlight II`,\n              extensions: ['moonlight'],\n            },\n          },\n        ],\n      },\n    },\n    `gatsby-plugin-client-side-redirect`, // keep it in last in list\n  ],\n};\n"
  },
  {
    "path": "website/gatsby-node.js",
    "content": "exports.createPages = ({graphql, actions}) => {\n  const {createRedirect} = actions;\n\n  const paths = [\n    'creating-tooltips',\n    'customizing-tooltips',\n    'all-props',\n    'html-content',\n    'themes',\n    'animations',\n    'tippy-instance',\n    'methods',\n    'lifecycle-hooks',\n    'ajax',\n    'accessibility',\n    'addons',\n    'plugins',\n    'misc',\n    'faq',\n    'motivation',\n  ];\n\n  paths.forEach((path) => {\n    createRedirect({\n      fromPath: `/${path}/`,\n      toPath: `/v5/${path}/`,\n      isPermanent: true,\n    });\n  });\n};\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"gatsby-starter-default\",\n  \"private\": true,\n  \"description\": \"A simple starter to get up and developing quickly with Gatsby\",\n  \"version\": \"0.1.0\",\n  \"author\": \"Kyle Mathews <mathews.kyle@gmail.com>\",\n  \"browserslist\": [\n    \">5%\",\n    \"not dead\"\n  ],\n  \"dependencies\": {\n    \"@emotion/core\": \"^10.0.27\",\n    \"@emotion/styled\": \"^10.0.27\",\n    \"@mdx-js/mdx\": \"^1.5.5\",\n    \"@mdx-js/react\": \"^1.5.5\",\n    \"@reach/skip-nav\": \"^0.1.3\",\n    \"@tippyjs/react\": \"^4.2.6\",\n    \"animate.css\": \"^3.7.2\",\n    \"elastic-scroll-polyfill\": \"^2.1.0\",\n    \"focus-visible\": \"^5.0.2\",\n    \"gatsby\": \"^2.32.13\",\n    \"gatsby-image\": \"^2.2.19\",\n    \"gatsby-plugin-catch-links\": \"^2.1.9\",\n    \"gatsby-plugin-client-side-redirect\": \"0.0.2\",\n    \"gatsby-plugin-emotion\": \"^4.1.18\",\n    \"gatsby-plugin-google-analytics\": \"^2.1.16\",\n    \"gatsby-plugin-manifest\": \"^2.2.16\",\n    \"gatsby-plugin-mdx\": \"^1.1.5\",\n    \"gatsby-plugin-offline\": \"^3.0.7\",\n    \"gatsby-plugin-react-helmet\": \"^3.1.7\",\n    \"gatsby-plugin-sharp\": \"^2.2.22\",\n    \"gatsby-redirect-from\": \"^0.2.1\",\n    \"gatsby-remark-autolink-headers\": \"^2.1.10\",\n    \"gatsby-remark-vscode\": \"^2.0.3\",\n    \"gatsby-source-filesystem\": \"^2.1.22\",\n    \"gatsby-transformer-remark\": \"^2.6.22\",\n    \"gatsby-transformer-sharp\": \"^2.2.14\",\n    \"moonlight\": \"github:atomiks/moonlight-vscode-theme\",\n    \"normalize.css\": \"^8.0.1\",\n    \"prop-types\": \"^15.7.2\",\n    \"react\": \"^16.9.0\",\n    \"react-dom\": \"^16.9.0\",\n    \"react-feather\": \"^2.0.3\",\n    \"react-flip-toolkit\": \"^6.6.3\",\n    \"react-helmet\": \"^5.2.1\",\n    \"rehype-react\": \"^3.1.0\"\n  },\n  \"keywords\": [\n    \"gatsby\"\n  ],\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"build\": \"gatsby build\",\n    \"build:ci\": \"gatsby build --prefix-paths\",\n    \"start\": \"gatsby develop\",\n    \"clean\": \"rimraf .cache/\",\n    \"dev\": \"yarn clean && yarn start\",\n    \"format\": \"prettier --write \\\"src/**/*.js\\\"\",\n    \"deploy\": \"yarn clean && gatsby build --prefix-paths && gh-pages -d public\",\n    \"test\": \"echo \\\"Write tests! -> https://gatsby.app/unit-testing\\\"\",\n    \"postinstall\": \"cd node_modules/moonlight && node build\"\n  },\n  \"devDependencies\": {\n    \"@mdx-js/loader\": \"^1.5.5\",\n    \"eslint-config-react-app\": \"^5.0.2\",\n    \"gh-pages\": \"^2.1.1\",\n    \"loader-utils\": \"^1.2.3\",\n    \"prettier\": \"github:prettier/prettier\",\n    \"rimraf\": \"^3.0.2\"\n  },\n  \"resolutions\": {\n    \"tippy.js\": \"^6.2.5\",\n    \"@popperjs/core\": \"^2.4.4\",\n    \"sharp\": \"^0.29.0\",\n    \"oniguruma\": \"^7.2.3\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/gatsbyjs/gatsby-starter-default\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/gatsbyjs/gatsby/issues\"\n  }\n}\n"
  },
  {
    "path": "website/scripts/should-deploy-docs.js",
    "content": "#!/usr/bin/env node\n\nconst {execSync} = require('child_process');\n\nconst {TRAVIS_COMMIT_RANGE = '', TRAVIS_COMMIT_MESSAGE = ''} = process.env;\n\nconsole.log(`TRAVIS_COMMIT_RANGE=${TRAVIS_COMMIT_RANGE}`);\nconsole.log(`TRAVIS_COMMIT_MESSAGE=${TRAVIS_COMMIT_MESSAGE}`);\n\nlet commitMessages;\n\nif (TRAVIS_COMMIT_RANGE) {\n  // see https://github.com/travis-ci/travis-ci/issues/4596\n  const COMMIT_RANGE = TRAVIS_COMMIT_RANGE.replace('...', '..');\n  const BASE_COMMIT = COMMIT_RANGE.split('..')[0];\n\n  // make sure that the command doesn't error out,\n  // the output is being validated below\n  const baseCommitType = execSync(`git cat-file -t ${BASE_COMMIT} || true`)\n    .toString()\n    .trim();\n\n  if (baseCommitType !== 'commit') {\n    // commit not found -> history was rewritten\n    console.log(`Commit ${BASE_COMMIT} not found, exiting...`);\n    process.exit(0);\n  }\n\n  const commitList = execSync(\n    `git rev-list ${COMMIT_RANGE} --oneline`\n  ).toString();\n\n  console.log(`Commits included in this build:\\n${commitList}`);\n\n  commitMessages = commitList\n    .split('\\n')\n    // filter out empty lines\n    .filter((line) => line)\n    // extract commit message, line should be something like: `dbede8c message`\n    .map((line) => line.slice(8));\n} else {\n  commitMessages = [TRAVIS_COMMIT_MESSAGE];\n}\n\nconst DOCS_PREFIXES = ['docs', 'release'];\n\nconst shouldDeployDocs = commitMessages.some((message) => {\n  return DOCS_PREFIXES.some((prefix) => message.startsWith(`${prefix}: `));\n});\n\nconsole.log(`SHOULD_DEPLOY_DOCS=${shouldDeployDocs}`);\n"
  },
  {
    "path": "website/scripts/should-deploy-docs.sh",
    "content": "#!/bin/bash\n\nset -e\n\nlocal NODE_OUPUT=$(node ./scripts/should-deploy-docs.js)\n\necho \"$NODE_OUPUT\"\n\n# match anything except newline, source: https://stackoverflow.com/a/12619967\nlocal get_value_regex='SHOULD_DEPLOY_DOCS=([^\\\n]*)'\n\nif [[ $NODE_OUPUT =~ $get_value_regex ]]; then\n  export SHOULD_DEPLOY_DOCS=\"${BASH_REMATCH[1]}\"\n\n  if [[ $SHOULD_DEPLOY_DOCS != 'true' ]]; then\n    echo 'Exiting early, docs deploy is skipped...'\n    travis_terminate 0\n  else\n    echo 'Proceeding to deploy docs...'\n  fi\nfi\n"
  },
  {
    "path": "website/src/components/ElasticScroll.js",
    "content": "import React, {useEffect, useRef, cloneElement} from 'react';\nimport elasticScroll from 'elastic-scroll-polyfill';\n\nfunction ElasticScroll({children, ...props}) {\n  const targetRef = useRef();\n\n  useEffect(() => {\n    const instance = elasticScroll({\n      targets: targetRef.current,\n      ...props,\n    });\n\n    return () => {\n      instance.disable();\n    };\n  });\n\n  return cloneElement(children, {\n    children: (\n      <div\n        style={{display: 'inline-block', minWidth: '100%'}}\n        data-elastic-wrapper\n      >\n        {children.props.children}\n      </div>\n    ),\n    ref: (node) => {\n      targetRef.current = node;\n      const {ref} = children;\n      if (ref) {\n        if (typeof ref === 'function') {\n          ref(node);\n        } else if (ref.hasOwnProperty('current')) {\n          ref.current = node;\n        }\n      }\n    },\n  });\n}\n\nexport default ElasticScroll;\n"
  },
  {
    "path": "website/src/components/Footer.js",
    "content": "import styled from '@emotion/styled';\nimport Theme from '../css/theme';\n\nconst Footer = styled.footer`\n  text-align: center;\n  padding: 25px 0;\n  border-top: 1px solid ${Theme.border};\n  font-size: 85%;\n`;\n\nexport default Footer;\n"
  },
  {
    "path": "website/src/components/Framework.js",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport {css} from '@emotion/core';\nimport {Link as GatsbyLink} from 'gatsby';\n\nexport const MEDIA_SIZES = {\n  xs: 360,\n  sm: 576,\n  md: 768,\n  lg: 992,\n  xl: 1200,\n};\n\nexport const MEDIA = Object.keys(MEDIA_SIZES).reduce((acc, mediaSize) => {\n  acc[mediaSize] = `@media (min-width: ${MEDIA_SIZES[mediaSize]}px)`;\n  return acc;\n}, {});\n\nexport const Center = styled.div`\n  text-align: center;\n`;\n\nexport const Container = styled.div`\n  position: relative;\n  max-width: 875px;\n  padding: 0 ${(props) => props.mobilePadding || '16'}px;\n  margin: 0 auto;\n\n  ${MEDIA.sm} {\n    padding: 0 25px;\n  }\n  ${MEDIA.md} {\n    padding: 0 60px;\n  }\n  ${MEDIA.lg} {\n    padding: 0 75px;\n  }\n`;\n\nexport const Row = styled(({spacing, ...rest}) => <div {...rest} />)`\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: space-between;\n  margin: 0 -${(props) => props.spacing || '8'}px;\n`;\n\nexport const Col = (props) => {\n  const {spacing = 8, base, xs, sm, md, lg, xl, ...rest} = props;\n\n  const mediaCss = ['xs', 'sm', 'md', 'lg', 'xl']\n    .filter((size) => props[size])\n    .map(\n      (size) => css`\n        ${MEDIA[size]} {\n          flex-basis: calc(${(100 * props[size]) / 12}% - ${2 * spacing}px);\n        }\n      `\n    );\n\n  return (\n    <div\n      css={css`\n        flex: 1;\n        padding: 0 ${spacing}px;\n        flex-basis: ${(100 * base) / 12}%;\n        ${mediaCss}\n      `}\n      {...rest}\n    />\n  );\n};\n\nexport const Link = (props) => (\n  <GatsbyLink\n    css={css`\n      color: inherit;\n      text-decoration: none;\n      transition: color 0.15s;\n    `}\n    activeStyle={\n      props.children.startsWith('v')\n        ? {fontWeight: '600'}\n        : {\n            fontWeight: '600',\n            background: 'linear-gradient(to right, #424557, transparent)',\n            color: '#fff',\n            borderWidth: '0',\n          }\n    }\n    {...props}\n  />\n);\n\nexport const ExternalLink = (props) => (\n  <a\n    target=\"_blank\"\n    rel=\"noopener noreferrer\"\n    css={css`\n      color: inherit;\n      text-decoration: none;\n      transition: color 0.15s;\n\n      &:hover {\n        color: #2263e5;\n      }\n    `}\n    {...props}\n  >\n    {/* jsx a11y rule */}\n    {props.children}\n  </a>\n);\n\nexport const Flex = styled.div`\n  display: flex;\n  justify-content: ${(props) => props.justify || 'space-between'};\n  align-items: ${(props) => props.align || 'center'};\n\n  > div {\n    margin-right: 15px;\n    margin-bottom: 15px;\n    flex: ${(props) => props.type === 'even' && 1};\n  }\n`;\n\nexport const Button = styled.button`\n  border: none;\n  color: #fff;\n  background: #424557;\n  will-change: opacity;\n  font-size: 16px;\n  font-weight: 600;\n  padding: 10px 16px;\n  border-radius: 4px;\n  transition: background 0.2s, color 0.2s;\n  box-shadow: 0 1px 4px -2px black,\n    inset 0 2px 1px -1px rgba(255, 255, 255, 0.1);\n\n  &:hover {\n    color: #81edff;\n  }\n`;\n\nexport const Demo = styled.div`\n  background-color: #272935;\n  margin: 15px -16px 25px;\n  padding: 25px 10px;\n\n  ${MEDIA.sm} {\n    padding-left: 25px;\n    padding-right: 25px;\n    margin-left: -25px;\n    margin-right: -25px;\n  }\n\n  ${MEDIA.md} {\n    border-radius: 8px;\n  }\n\n  > ${Button} {\n    margin: 5px;\n  }\n`;\n"
  },
  {
    "path": "website/src/components/Header.js",
    "content": "import React, {Component} from 'react';\nimport styled from '@emotion/styled';\nimport {css, keyframes} from '@emotion/core';\nimport {Location} from '@reach/router';\nimport TippyLogo from '../images/logo.svg';\nimport {MEDIA, Container, Flex, ExternalLink} from './Framework';\nimport GitHub from 'react-feather/dist/icons/github';\nimport Menu from 'react-feather/dist/icons/menu';\nimport {version} from '../../../package.json';\nimport {Link} from 'gatsby';\nimport {getVersionFromPath, CURRENT_MAJOR} from '../utils';\nimport bubbles from '../images/bubbles.svg';\n\n// Firefox needs `rotate()` for it to be smooth...\nconst hover = keyframes`\n  from {\n    transform: translate3d(0, 4px, 0) rotate(0);\n  }\n\n  to {\n    transform: translate3d(0, 10px, 0) rotate(0.01deg);\n  }\n`;\n\nconst HeaderRoot = styled.header`\n  position: relative;\n  background-image: linear-gradient(45deg, #0058ff, #df72a1, #f7ffbb);\n  background-repeat: no-repeat;\n  background-size: cover;\n  padding: 25px 0;\n  text-align: center;\n  margin-bottom: 50px;\n  color: white;\n  left: -250px;\n  padding-left: 250px;\n  width: 100%;\n\n  &::before {\n    content: '';\n    position: absolute;\n    top: -50px;\n    display: block;\n    background-image: url(${bubbles});\n    background-size: cover;\n    width: 100%;\n    height: calc(100vh + 50px);\n    left: 0;\n  }\n`;\n\nconst Logo = styled.img`\n  display: block;\n  height: 100px;\n  margin: 0 auto 10px;\n  animation: ${hover} 2s ease-in-out infinite alternate;\n`;\n\nconst Title = styled.h1`\n  display: inline-block;\n  font-size: 56px;\n  font-weight: bold;\n  color: white;\n  margin-top: 0;\n  margin-bottom: 25px;\n  text-shadow: 0px 2px 6px #00000047, -1px 2px 1px #0000003b;\n`;\n\nconst ButtonLink = styled(ExternalLink)`\n  background: rgba(255, 255, 255, 0.4);\n  padding: 12px 24px;\n  border-radius: 4px;\n  transition: all 0.25s;\n  color: #000;\n  margin: 0 8px 8px;\n  font-weight: bold;\n  font-size: 18px;\n  font-weight: 500;\n  will-change: opacity;\n\n  &:hover {\n    background: white;\n    border-bottom-color: white;\n    box-shadow: 0 8px 16px -2px rgba(0, 32, 128, 0.25);\n    text-decoration: none;\n  }\n`;\n\nexport const MenuButton = styled.button`\n  position: absolute;\n  top: -10px;\n  left: 25px;\n  color: rgb(36, 58, 89);\n  font-weight: bold;\n  border: none;\n  background: none;\n  text-transform: uppercase;\n  border-radius: 4px;\n  padding: 0;\n\n  ${MEDIA.lg} {\n    display: none;\n  }\n`;\n\nconst Version = styled.a`\n  display: inline-block;\n  color: #fff;\n  font-weight: bold;\n  margin: 16px 0;\n  font-size: 14px;\n\n  ${MEDIA.md} {\n    margin: 16px 0;\n  }\n`;\n\nconst OldVersionWarning = styled.div`\n  position: relative;\n  background: #fff5c5;\n  color: #333;\n  z-index: 2;\n  text-align: center;\n  padding: 25px 0;\n  font-size: 16px;\n  font-weight: bold;\n`;\n\nconst svgStyles = css`\n  margin: -16px 0 -32px;\n\n  ${MEDIA.md} {\n    margin: -10% 0 -32px;\n    margin-left: -250px;\n  }\n`;\n\nconst iconStyles = {\n  verticalAlign: '-7px',\n  marginRight: '8px',\n};\n\nconst githubStyles = {\n  ...iconStyles,\n  width: '24px',\n  height: '24px',\n  color: '#333',\n};\n\nconst menuStyles = {\n  width: '40px',\n  height: '40px',\n};\n\nclass Header extends Component {\n  render() {\n    const {isNavOpen, openNav} = this.props;\n\n    return (\n      <>\n        <Location>\n          {({location}) =>\n            getVersionFromPath(location.pathname) !== CURRENT_MAJOR && (\n              <OldVersionWarning>\n                <Container>\n                  <span role=\"img\" aria-label=\"alert\">\n                    ❗\n                  </span>{' '}\n                  You're viewing the previous major version's docs.{' '}\n                  <Link to=\"/\">Click here</Link> to view the latest version.\n                </Container>\n              </OldVersionWarning>\n            )\n          }\n        </Location>\n\n        <HeaderRoot>\n          <Container>\n            <Logo src={TippyLogo} draggable=\"false\" alt=\"Tippy Logo\" />\n            <Title>Tippy.js</Title>\n            <Flex justify=\"center\">\n              <ButtonLink href=\"https://github.com/atomiks/tippyjs\">\n                <GitHub style={githubStyles} />\n                View on GitHub\n              </ButtonLink>\n            </Flex>\n            <Version href=\"https://github.com/atomiks/tippyjs/releases\">\n              v{version}\n            </Version>\n            <MenuButton\n              aria-label=\"Menu\"\n              aria-expanded={isNavOpen ? 'true' : 'false'}\n              onClick={openNav}\n            >\n              <Menu style={menuStyles} />\n            </MenuButton>\n          </Container>\n          <svg\n            css={svgStyles}\n            xmlns=\"http://www.w3.org/2000/svg\"\n            viewBox=\"0 0 1920 240\"\n            fill=\"#1f2028\"\n          >\n            <g>\n              <path d=\"M1920,144.5l0,95.5l-1920,0l0,-65.5c196,-36 452.146,-15.726 657.5,8.5c229.698,27.098 870,57 1262.5,-38.5Z\" />\n            </g>\n          </svg>\n        </HeaderRoot>\n      </>\n    );\n  }\n}\n\nexport default Header;\n"
  },
  {
    "path": "website/src/components/Icon.js",
    "content": "import React, {forwardRef} from 'react';\nimport {css} from '@emotion/core';\n\nconst Icon = forwardRef(({src, alt, float, size = 32}, ref) => {\n  return (\n    <img\n      src={src}\n      alt={alt}\n      ref={ref}\n      draggable=\"false\"\n      css={css`\n        position: relative;\n        width: ${size}px;\n        vertical-align: middle;\n        top: -2px;\n        margin-right: 10px;\n        user-select: none;\n        float: ${float ? 'left' : 'none'};\n        overflow: hidden;\n      `}\n    />\n  );\n});\n\nexport default Icon;\n"
  },
  {
    "path": "website/src/components/Image.js",
    "content": "import React from 'react';\nimport {StaticQuery, graphql} from 'gatsby';\nimport Img from 'gatsby-image';\nimport styled from '@emotion/styled';\nimport {MEDIA} from '../components/Framework';\n\nconst ImgWrapper = styled.div`\n  margin-left: -16px;\n  margin-right: -16px;\n  margin-bottom: 16px;\n\n  ${MEDIA.sm} {\n    margin-left: -25px;\n    margin-right: -25px;\n  }\n\n  ${MEDIA.md} {\n    img {\n      border-radius: 8px;\n    }\n  }\n`;\n\nconst Image = ({name}) => (\n  <StaticQuery\n    query={graphql`\n      query {\n        allImageSharp {\n          edges {\n            node {\n              fluid(maxWidth: 840, quality: 95) {\n                ...GatsbyImageSharpFluid\n                originalName\n              }\n            }\n          }\n        }\n      }\n    `}\n    render={(data) => {\n      const image = data.allImageSharp.edges.find(\n        (edge) => edge.node.fluid.originalName === name\n      );\n\n      return image ? (\n        <ImgWrapper>\n          <Img fluid={image.node.fluid} />\n        </ImgWrapper>\n      ) : null;\n    }}\n  />\n);\n\nexport default Image;\n"
  },
  {
    "path": "website/src/components/Layout.js",
    "content": "import React, {Component} from 'react';\nimport {SkipNavLink, SkipNavContent} from '@reach/skip-nav';\nimport {MDXProvider} from '@mdx-js/react';\nimport styled from '@emotion/styled';\nimport {\n  Container,\n  Demo,\n  Button,\n  Row,\n  Col,\n  Flex,\n  MEDIA,\n  ExternalLink,\n} from './Framework';\nimport Tippy from './Tippy';\nimport Nav from './Nav';\nimport NavButtons from './NavButtons';\nimport Header from './Header';\nimport Main from './Main';\nimport Footer from './Footer';\nimport SEO from './SEO';\nimport Image from './Image';\nimport Icon from './Icon';\nimport ElasticScroll from './ElasticScroll';\nimport CSS from '../css';\n\nimport 'normalize.css';\nimport 'animate.css/source/_base.css';\nimport 'animate.css/source/attention_seekers/rubberBand.css';\nimport 'animate.css/source/attention_seekers/tada.css';\nimport 'animate.css/source/attention_seekers/wobble.css';\nimport 'focus-visible';\n\nconst LinkIcon = styled.a`\n  display: inline-block;\n  position: absolute;\n  padding: 10px 0;\n  opacity: 0;\n  transition: opacity 0.2s;\n  width: 32px;\n  top: -10px;\n  right: -16px;\n  color: #81edff;\n\n  &:hover,\n  &:focus {\n    opacity: 1;\n    text-decoration: none;\n  }\n\n  ${MEDIA.md} {\n    right: initial;\n    text-align: center;\n    width: 30px;\n    left: -30px;\n  }\n`;\n\nconst A = styled.a`\n  font-weight: bold;\n  border-bottom: 2px solid #425991;\n  transition: color 0.25s, border-color 0.2s;\n\n  &:hover {\n    color: #fff;\n    border-bottom: 2px solid rgba(255, 255, 255, 0.6);\n    text-decoration: none;\n  }\n\n  &:active {\n    border-bottom-style: dashed;\n  }\n`;\n\nlet hrefs = new Set();\n\nclass Heading extends React.Component {\n  constructor(props) {\n    super(props);\n\n    let href = []\n      .concat(this.props.children)\n      .filter((child) => typeof child === 'string')\n      .join(' ')\n      .replace(/[^a-zA-Z0-9]/g, '-')\n      .replace(/-+/g, '-')\n      .replace(/-$/g, '')\n      .toLowerCase();\n\n    // Check for duplicate #s\n    if (hrefs.has(href)) {\n      let counter = 1;\n\n      while (hrefs.has(href + counter)) {\n        counter++;\n      }\n\n      href = `${href}-${counter}`;\n    }\n\n    hrefs.add(href);\n\n    this.state = {href};\n  }\n\n  render() {\n    const {level, ...props} = this.props;\n    const Tag = `h${level}`;\n\n    return (\n      <Tag {...props}>\n        <LinkIcon\n          className=\"link-icon\"\n          id={this.state.href}\n          href={`#${this.state.href}`}\n        >\n          #\n        </LinkIcon>\n        {props.children}\n      </Tag>\n    );\n  }\n}\n\nconst components = {\n  Tippy,\n  Demo,\n  Button,\n  Row,\n  Col,\n  Flex,\n  Image,\n  Icon,\n  a: (props) => {\n    const extendedProps = {...props};\n    const re = /^(\\.\\.)?[/#]/.test(props.href);\n\n    if (props.href && !re) {\n      extendedProps.rel = 'nofollow noreferrer';\n      extendedProps.target = '_blank';\n    }\n\n    return <A {...extendedProps} />;\n  },\n  h3: (props) => <Heading {...props} level={3} />,\n  h4: (props) => <Heading {...props} level={4} />,\n  h5: (props) => <Heading {...props} level={5} />,\n  h6: (props) => <Heading {...props} level={6} />,\n  pre: (props) => (\n    <ElasticScroll>\n      <pre {...props} />\n    </ElasticScroll>\n  ),\n};\n\nclass Layout extends Component {\n  constructor() {\n    super();\n    hrefs = new Set();\n  }\n\n  state = {\n    isNavOpen: false,\n  };\n\n  openNav = () => {\n    this.setState({isNavOpen: true});\n  };\n\n  closeNav = () => {\n    this.setState({isNavOpen: false});\n  };\n\n  render() {\n    const {isNavOpen} = this.state;\n    const {children, pageContext} = this.props;\n\n    const HeaderToUse = Header;\n\n    return (\n      <MDXProvider components={components}>\n        <CSS />\n        <SEO pageContext={pageContext} />\n        <SkipNavLink />\n        <Main>\n          <HeaderToUse\n            openNav={this.openNav}\n            isNavOpen={isNavOpen}\n            pageIndex={pageContext.frontmatter.index}\n          />\n          <Nav isOpen={isNavOpen} close={this.closeNav} />\n          <SkipNavContent>\n            <Container>\n              {pageContext.frontmatter.title !== 'Demo' && (\n                <h2>{pageContext.frontmatter.title}</h2>\n              )}\n              {children}\n            </Container>\n            <NavButtons next={pageContext.frontmatter.index + 1} />\n          </SkipNavContent>\n          <Footer>\n            <p>© {new Date().getFullYear()} — MIT License</p>\n            <small>\n              Icons made by Freepik from{' '}\n              <ExternalLink href=\"https://flaticon.com\">\n                www.flaticon.com\n              </ExternalLink>\n            </small>\n          </Footer>\n        </Main>\n      </MDXProvider>\n    );\n  }\n}\n\nexport default Layout;\n"
  },
  {
    "path": "website/src/components/Main.js",
    "content": "import styled from '@emotion/styled';\nimport {MEDIA} from './Framework';\n\nconst Main = styled.main`\n  ${MEDIA.lg} {\n    margin-left: 250px;\n  }\n`;\n\nexport default Main;\n"
  },
  {
    "path": "website/src/components/MiniHeader.js",
    "content": "import React, {Component} from 'react';\nimport styled from '@emotion/styled';\nimport TippyLogo from '../images/logo.svg';\nimport {Container, Flex, Link} from './Framework';\nimport Menu from 'react-feather/dist/icons/menu';\nimport theme from '../css/theme';\nimport {MenuButton} from './Header';\n\nconst HeaderRoot = styled.header`\n  position: relative;\n  background-repeat: no-repeat;\n  background-size: cover;\n  text-align: center;\n  margin-left: -250px;\n  padding-left: 250px;\n  padding-top: 12px;\n  padding-bottom: 12px;\n  margin-bottom: 32px;\n  border-bottom: 1px solid ${theme.border};\n`;\n\nconst Logo = styled.img`\n  display: block;\n  height: 60px;\n`;\n\nconst MenuButtonDark = styled(MenuButton)`\n  color: #7761d1;\n  margin-top: 18px;\n`;\n\nconst menuStyles = {\n  width: 40,\n  height: 40,\n};\n\nclass MiniHeader extends Component {\n  render() {\n    const {isNavOpen, openNav} = this.props;\n    return (\n      <HeaderRoot>\n        <Container>\n          <Flex justify=\"center\">\n            <Link to=\"/\">\n              <Logo src={TippyLogo} draggable=\"false\" alt=\"Tippy Logo\" />\n            </Link>\n            <MenuButtonDark\n              aria-label=\"Menu\"\n              aria-expanded={isNavOpen ? 'true' : 'false'}\n              onClick={openNav}\n            >\n              <Menu style={menuStyles} />\n            </MenuButtonDark>\n          </Flex>\n        </Container>\n      </HeaderRoot>\n    );\n  }\n}\n\nexport default MiniHeader;\n"
  },
  {
    "path": "website/src/components/Nav.js",
    "content": "import React, {Component, createRef} from 'react';\nimport styled from '@emotion/styled';\nimport {StaticQuery, graphql} from 'gatsby';\nimport {css} from '@emotion/core';\nimport {ChevronDown} from 'react-feather';\nimport {Location} from '@reach/router';\nimport {MEDIA, Link, Button} from './Framework';\nimport {sortActivePages, getVersionFromPath} from '../utils';\nimport X from 'react-feather/dist/icons/x';\nimport ElasticScroll from './ElasticScroll';\nimport Tippy from './Tippy';\n\nconst Navbar = styled.nav`\n  display: ${(props) => (props.isMounted ? 'block' : 'none')};\n  position: fixed;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 250px;\n  background: #1f202899;\n  overflow-y: auto;\n  z-index: 2;\n  transform: ${(props) =>\n    props.isOpen ? 'translate3d(0, 0, 0)' : 'translate3d(-100%, 0, 0)'};\n  transition: ${(props) =>\n      props.isOpen ? 'transform 0.5s' : 'transform 0.5s 0.15s'},\n    visibility 0.15s, opacity 0.15s;\n  transition-timing-function: ${(props) =>\n    props.isOpen ? 'cubic-bezier(0.22, 1, 0.36, 1)' : 'ease'};\n  visibility: ${(props) => (props.isOpen ? 'visible' : 'hidden')};\n  box-shadow: 4px 0 32px 0 rgba(0, 32, 64, 0.25);\n  backdrop-filter: blur(15px) saturate(180%);\n  opacity: ${(props) => (props.isOpen ? '1' : '0')};\n\n  ${MEDIA.lg} {\n    padding-top: 0;\n    display: block;\n    visibility: visible;\n    transform: none;\n    box-shadow: none;\n    opacity: 1;\n    will-change: transform, opacity;\n    backdrop-filter: blur(30px) saturate(100%);\n  }\n`;\n\nconst List = styled.ul`\n  list-style: none;\n  padding-left: 0;\n  margin: 0;\n`;\n\nconst ListItem = styled.li`\n  margin: 0;\n\n  &:last-of-type {\n    padding-bottom: 32px;\n  }\n\n  > a {\n    display: block;\n    padding: 4px 25px;\n    font-size: 17px;\n    padding-left: 40px;\n\n    ${MEDIA.lg} {\n    }\n\n    &:hover {\n      border-bottom-color: transparent;\n      text-decoration: none;\n      color: white;\n    }\n  }\n`;\n\nconst XButton = styled.button`\n  position: absolute;\n  border: none;\n  padding: 0;\n  top: 8px;\n  right: 16px;\n  border-radius: 32px;\n  height: 40px;\n  width: 40px;\n  cursor: pointer;\n  background: transparent;\n  color: #fff;\n\n  &:active {\n    box-shadow: 0 2px 0 rgba(0, 32, 64, 0.2);\n  }\n\n  ${MEDIA.lg} {\n    display: none;\n  }\n`;\n\nconst XIcon = styled(X)`\n  margin-top: 4px;\n  height: 32px;\n  width: 32px;\n`;\n\nconst VersionButton = styled(Button)`\n  background: #424557;\n  color: #81edff;\n  border: none;\n  margin: 15px 25px;\n  margin-left: 40px;\n\n  &:hover {\n    background-color: white;\n    color: #000;\n  }\n`;\n\nconst Li = styled.li`\n  list-style: none;\n\n  &:not(:last-of-type) {\n    margin-bottom: 5px;\n    margin-top: 0;\n  }\n`;\n\nclass Nav extends Component {\n  state = {\n    isMounted: false,\n    transitions: true,\n  };\n\n  ref = createRef();\n\n  handleResize = () => {\n    this.setState({transitions: false});\n    clearTimeout(this.timeout);\n    this.timeout = setTimeout(() => {\n      this.setState({transitions: true});\n    }, 100);\n  };\n\n  handleClose = () => {\n    this.props.close();\n  };\n\n  handleBlur = (e) => {\n    if (!this.ref.current.contains(e.relatedTarget)) {\n      this.props.close();\n    }\n  };\n\n  handleOutsideClick = (e) => {\n    if (this.props.isOpen && !this.ref.current.contains(e.target)) {\n      this.props.close();\n    }\n  };\n\n  componentDidMount() {\n    this.setState({isMounted: true});\n    window.addEventListener('resize', this.handleResize);\n    window.addEventListener('mousedown', this.handleOutsideClick, true);\n    this.handleResize();\n\n    // TODO: Scroll the container so the currently active link is visible\n    // this.ref.current.scrollTop = document\n    //   .querySelector('[aria-current]')\n    //   .getBoundingClientRect().top\n  }\n\n  componentWillUnmount() {\n    window.removeEventListener('resize', this.handleResize);\n    window.removeEventListener('mousedown', this.handleOutsideClick, true);\n    clearTimeout(this.timeout);\n  }\n\n  render() {\n    const {isOpen} = this.props;\n    const {isMounted, transitions} = this.state;\n\n    return (\n      <Location>\n        {({location}) => (\n          <ElasticScroll>\n            <Navbar\n              id=\"main-nav\"\n              ref={this.ref}\n              style={{transition: transitions ? '' : 'none'}}\n              isOpen={isOpen}\n              isMounted={isMounted}\n              onBlur={this.handleBlur}\n              tabIndex=\"-1\"\n            >\n              <XButton aria-label=\"Close Menu\" onClick={this.handleClose}>\n                <XIcon />\n              </XButton>\n              <List>\n                <div>\n                  <Tippy\n                    theme=\"light\"\n                    placement=\"bottom-start\"\n                    trigger=\"mouseenter click\"\n                    interactive={true}\n                    arrow={false}\n                    offset={[0, 5]}\n                    duration={[200, 100]}\n                    css={css`\n                      font-size: 16px;\n                      padding: 8px;\n                    `}\n                    sticky={true}\n                    content={\n                      <ul\n                        css={css`\n                          padding-left: 0;\n                        `}\n                      >\n                        <Li>\n                          <Link to=\"/v6/getting-started/\">\n                            v6.x docs (latest)\n                          </Link>\n                        </Li>\n                        <Li>\n                          <Link to=\"/v5/getting-started/\">v5.x docs</Link>\n                        </Li>\n                      </ul>\n                    }\n                  >\n                    <VersionButton>\n                      {getVersionFromPath(location.pathname)}.x{' '}\n                      <ChevronDown\n                        size={20}\n                        style={{\n                          position: 'relative',\n                          verticalAlign: -5,\n                          top: 1,\n                        }}\n                      />\n                    </VersionButton>\n                  </Tippy>\n                </div>\n                <StaticQuery\n                  query={allMdxQuery}\n                  render={(data) => {\n                    return sortActivePages(data.allMdx.edges, location).map(\n                      ({node}) => (\n                        <ListItem key={node.frontmatter.path}>\n                          <Link to={node.frontmatter.path}>\n                            {node.frontmatter.title}\n                          </Link>\n                        </ListItem>\n                      )\n                    );\n                  }}\n                />\n              </List>\n            </Navbar>\n          </ElasticScroll>\n        )}\n      </Location>\n    );\n  }\n}\n\nexport default Nav;\n\nconst allMdxQuery = graphql`\n  query {\n    allMdx {\n      edges {\n        node {\n          frontmatter {\n            title\n            path\n            index\n          }\n        }\n      }\n    }\n  }\n`;\n"
  },
  {
    "path": "website/src/components/NavButtons.js",
    "content": "import React from 'react';\nimport {Link, graphql, StaticQuery} from 'gatsby';\nimport styled from '@emotion/styled';\nimport {MEDIA, Flex, Container} from './Framework';\nimport {sortActivePages} from '../utils';\nimport ArrowRight from 'react-feather/dist/icons/arrow-right';\nimport ArrowLeft from 'react-feather/dist/icons/arrow-left';\nimport theme from '../css/theme';\nimport {css} from '@emotion/core';\nimport {Location} from '@reach/router';\n\nconst NavButtonsContainer = styled.div`\n  margin-top: 64px;\n  border-top: 1px solid ${theme.border};\n`;\n\nconst NavButtonFlex = styled(Flex)`\n  margin: 0 -15px;\n\n  ${MEDIA.md} {\n    margin: 0 -25px;\n  }\n`;\n\nconst NavButton = styled(Link)`\n  position: relative;\n  display: block;\n  font-weight: bold;\n  border-bottom: 2px solid transparent;\n  padding: 48px 16px;\n  flex: 1 1 auto;\n  font-size: 18px;\n\n  ${MEDIA.xs} {\n    font-size: 22px;\n  }\n\n  ${MEDIA.sm} {\n    font-size: 24px;\n  }\n\n  ${MEDIA.md} {\n    width: 50%;\n    padding: 64px 16px;\n  }\n\n  ${MEDIA.xl} {\n    font-size: 26px;\n  }\n\n  &:hover {\n    color: #7cbbff;\n    background: rgba(0, 0, 0, 0.1);\n    border-bottom: 2px solid #425991;\n    text-decoration: none;\n  }\n\n  &:active {\n    border-bottom-style: dashed;\n  }\n\n  &[data-next] {\n    text-align: right;\n    padding-right: 45px;\n\n    ${MEDIA.xs} {\n      padding-right: 50px;\n    }\n\n    ${MEDIA.md} {\n      padding-right: 65px;\n\n      &:first-of-type {\n        margin-left: 50%;\n      }\n\n      &:not(:first-of-type) {\n        border-left: 1px solid ${theme.border};\n      }\n    }\n  }\n\n  &[data-prev] {\n    padding-left: 45px;\n\n    ${MEDIA.xs} {\n      padding-left: 50px;\n    }\n\n    ${MEDIA.md} {\n      padding-left: 65px;\n\n      &:last-of-type {\n        margin-right: 50%;\n      }\n    }\n  }\n`;\n\nconst arrowCss = css`\n  position: absolute;\n  top: 50%;\n  vertical-align: -6px;\n  width: 24px;\n  height: 24px;\n  margin-top: -12px;\n\n  ${MEDIA.xs} {\n    width: 28px;\n    height: 28px;\n    margin-top: -14px;\n  }\n\n  &[data-prev] {\n    left: 16px;\n\n    ${MEDIA.md} {\n      left: 25px;\n    }\n  }\n\n  &[data-next] {\n    right: 16px;\n\n    ${MEDIA.md} {\n      right: 25px;\n    }\n  }\n\n  ${MEDIA.md} {\n    margin-top: -16px;\n    width: 32px;\n    height: 32px;\n  }\n`;\n\nfunction NavButtons({next}) {\n  return (\n    <NavButtonsContainer>\n      <Container>\n        <Location>\n          {({location}) => (\n            <StaticQuery\n              query={allMdxQuery}\n              render={(data) => {\n                const links = sortActivePages(data.allMdx.edges, location).map(\n                  ({node}) => node\n                );\n                const nextLink = links[next];\n                const prevLink = next > 1 ? links[next - 2] : null;\n\n                return (\n                  <NavButtonFlex>\n                    {prevLink && (\n                      <NavButton to={prevLink.frontmatter.path} data-prev>\n                        <ArrowLeft\n                          aria-label=\"Previous\"\n                          css={arrowCss}\n                          data-prev\n                        />{' '}\n                        {prevLink.frontmatter.title}\n                      </NavButton>\n                    )}\n                    {nextLink && (\n                      <NavButton to={nextLink.frontmatter.path} data-next>\n                        {nextLink.frontmatter.title}{' '}\n                        <ArrowRight\n                          aria-label=\"Next\"\n                          css={arrowCss}\n                          data-next\n                        />\n                      </NavButton>\n                    )}\n                  </NavButtonFlex>\n                );\n              }}\n            />\n          )}\n        </Location>\n      </Container>\n    </NavButtonsContainer>\n  );\n}\n\nexport default NavButtons;\n\nconst allMdxQuery = graphql`\n  query {\n    allMdx {\n      edges {\n        node {\n          frontmatter {\n            title\n            path\n            index\n          }\n        }\n      }\n    }\n  }\n`;\n"
  },
  {
    "path": "website/src/components/PluginIcon.js",
    "content": "import React from 'react';\nimport Icon from './Icon';\nimport Tippy from './Tippy';\n\nimport plugin from '../images/plugin.svg';\n\nconst description = 'Requires importing its plugin when using modules';\n\nfunction RenderIcon({large}) {\n  return (\n    <Tippy\n      content={\n        <>\n          <strong>Plugin:</strong> {description}\n        </>\n      }\n      placement=\"right\"\n      maxWidth=\"none\"\n      popperOptions={{\n        modifiers: [\n          {\n            name: 'flip',\n            options: {\n              fallbackPlacements: ['auto'],\n            },\n          },\n        ],\n      }}\n    >\n      <Icon src={plugin} alt={description} size={large ? 38 : 20} />\n    </Tippy>\n  );\n}\n\nexport default RenderIcon;\n"
  },
  {
    "path": "website/src/components/RenderIcon.js",
    "content": "import React from 'react';\nimport Icon from './Icon';\nimport Tippy from './Tippy';\n\nimport render from '../images/render.svg';\n\nconst description = 'Configured by the render() function';\n\nfunction RenderIcon({large}) {\n  return (\n    <Tippy\n      content={\n        <>\n          <strong>Render:</strong> {description}\n        </>\n      }\n      placement=\"right\"\n      maxWidth=\"none\"\n      popperOptions={{\n        modifiers: [\n          {\n            name: 'flip',\n            options: {\n              fallbackPlacements: ['auto'],\n            },\n          },\n        ],\n      }}\n    >\n      <Icon src={render} alt={description} size={large ? 38 : 20} />\n    </Tippy>\n  );\n}\n\nexport default RenderIcon;\n"
  },
  {
    "path": "website/src/components/SEO.js",
    "content": "import React from 'react';\nimport Helmet from 'react-helmet';\nimport {StaticQuery, graphql} from 'gatsby';\n\nfunction SEO({title, description, lang, meta, keywords, pageContext}) {\n  return (\n    <StaticQuery\n      query={detailsQuery}\n      render={(data) => {\n        const metaDescription =\n          description || data.site.siteMetadata.description;\n        const isIndex = pageContext.frontmatter.title === 'Demo';\n        const computedTitle =\n          title ||\n          (isIndex\n            ? 'Tippy.js - Tooltip, Popover, Dropdown, and Menu Library'\n            : pageContext.frontmatter.title);\n        return (\n          <Helmet\n            htmlAttributes={{\n              lang,\n            }}\n            title={computedTitle}\n            titleTemplate={\n              isIndex ? null : `%s | ${data.site.siteMetadata.title}`\n            }\n            meta={[\n              {\n                name: `description`,\n                content: metaDescription,\n              },\n              {\n                property: `og:title`,\n                content: computedTitle,\n              },\n              {\n                property: `og:description`,\n                content: metaDescription,\n              },\n              {\n                property: `og:type`,\n                content: `website`,\n              },\n              {\n                name: `twitter:card`,\n                content: `summary`,\n              },\n              {\n                name: `twitter:creator`,\n                content: data.site.siteMetadata.author,\n              },\n              {\n                name: `twitter:title`,\n                content: computedTitle,\n              },\n              {\n                name: `twitter:description`,\n                content: metaDescription,\n              },\n            ]\n              .concat(\n                keywords.length > 0\n                  ? {\n                      name: `keywords`,\n                      content: keywords.join(`, `),\n                    }\n                  : []\n              )\n              .concat(meta)}\n          />\n        );\n      }}\n    />\n  );\n}\n\nSEO.defaultProps = {\n  lang: `en`,\n  meta: [],\n  keywords: [],\n};\n\nexport default SEO;\n\nconst detailsQuery = graphql`\n  query DefaultSEOQuery {\n    site {\n      siteMetadata {\n        title\n        description\n        author\n      }\n    }\n  }\n`;\n"
  },
  {
    "path": "website/src/components/TextGradient.js",
    "content": "import styled from '@emotion/styled';\n\nconst TextGradient = styled.span`\n  background: linear-gradient(45deg, #fff2df, #99ffec, #faa7ff);\n  -webkit-text-fill-color: transparent;\n  -webkit-background-clip: text;\n  background-clip: text;\n`;\n\nexport default TextGradient;\n"
  },
  {
    "path": "website/src/components/Tippy.js",
    "content": "import React, {forwardRef} from 'react';\nimport Tippy, {useSingleton, tippy} from '@tippyjs/react';\nimport {\n  roundArrow,\n  followCursor,\n  animateFill,\n  inlinePositioning,\n  sticky,\n} from 'tippy.js';\n\nimport 'tippy.js/dist/tippy.css';\nimport 'tippy.js/dist/backdrop.css';\nimport 'tippy.js/dist/svg-arrow.css';\n\nimport 'tippy.js/themes/light.css';\nimport 'tippy.js/themes/light-border.css';\nimport 'tippy.js/themes/material.css';\nimport 'tippy.js/themes/translucent.css';\n\nimport 'tippy.js/animations/perspective.css';\nimport 'tippy.js/animations/perspective-subtle.css';\nimport 'tippy.js/animations/perspective-extreme.css';\nimport 'tippy.js/animations/scale.css';\nimport 'tippy.js/animations/scale-subtle.css';\nimport 'tippy.js/animations/scale-extreme.css';\nimport 'tippy.js/animations/shift-away.css';\nimport 'tippy.js/animations/shift-away-subtle.css';\nimport 'tippy.js/animations/shift-away-extreme.css';\nimport 'tippy.js/animations/shift-toward.css';\nimport 'tippy.js/animations/shift-toward-subtle.css';\nimport 'tippy.js/animations/shift-toward-extreme.css';\n\nconst hideOnPopperBlur = {\n  name: 'hideOnPopperBlur',\n  defaultValue: true,\n  fn(instance) {\n    return {\n      onCreate() {\n        instance.popper.addEventListener('focusout', (event) => {\n          if (\n            instance.props.hideOnPopperBlur &&\n            event.relatedTarget &&\n            !instance.popper.contains(event.relatedTarget)\n          ) {\n            instance.hide();\n          }\n        });\n      },\n    };\n  },\n};\n\nconst hideOnEsc = {\n  name: 'hideOnEsc',\n  defaultValue: false,\n  fn({hide}) {\n    function onKeyDown(event) {\n      if (event.keyCode === 27) {\n        hide();\n      }\n    }\n\n    return {\n      onShow() {\n        document.addEventListener('keydown', onKeyDown);\n      },\n      onHide() {\n        document.removeEventListener('keydown', onKeyDown);\n      },\n    };\n  },\n};\n\nexport default forwardRef(({...props}, ref) => {\n  if (props.arrow === 'round') {\n    props.arrow = roundArrow;\n  }\n\n  return (\n    <Tippy\n      content=\"I'm a Tippy tooltip!\"\n      plugins={[\n        followCursor,\n        animateFill,\n        inlinePositioning,\n        sticky,\n        hideOnPopperBlur,\n        hideOnEsc,\n        ...(props.plugins || []),\n      ]}\n      {...props}\n      ref={ref}\n    />\n  );\n});\n\nexport {useSingleton, tippy};\n"
  },
  {
    "path": "website/src/components/TippyTransition.js",
    "content": "import {cloneElement, Children} from 'react';\nimport Flipper from 'react-flip-toolkit/es/core';\nimport {useInstance} from '../hooks';\n\nfunction parseTranslate3d(string) {\n  const match = string.match(/translate3d\\((.+?),\\s*(.+?),/);\n  return {x: parseFloat(match[1]), y: parseFloat(match[2])};\n}\n\nfunction preserveInvocation(fn, args) {\n  if (fn) {\n    fn.apply(null, args);\n  }\n}\n\nfunction useStableMemo(fn, deps) {\n  const component = useInstance();\n  let areDepsEqual = component.prevDeps ? true : false;\n\n  if (Array.isArray(deps) && areDepsEqual) {\n    for (let i = 0; i < deps.length; i++) {\n      if (deps[i] !== component.prevDeps[i]) {\n        areDepsEqual = false;\n        break;\n      }\n    }\n  }\n\n  component.prevDeps = deps;\n\n  if (!areDepsEqual) {\n    component.result = fn();\n  }\n\n  return component.result;\n}\n\nfunction TippyTransition({children, onChange}) {\n  const child = Children.only(children);\n\n  const component = useInstance({\n    offsets: {},\n  });\n\n  function onCreate(instance) {\n    const {popper} = instance;\n    const {tooltip, content, arrow} = instance.popperChildren;\n\n    // Very first transition is jerky otherwise.\n    content.style.willChange = 'transform';\n    tooltip.style.textAlign = 'left';\n\n    const flipper = new Flipper({element: popper});\n\n    flipper.addFlipped({\n      element: tooltip,\n      // TODO: Make this unique if this component is used more than once\n      flipId: 'tooltip',\n      spring: 'veryGentle',\n      onComplete() {\n        popper.style.transitionDuration = `${child.props.updateDuration}ms`;\n        popper.style.transitionProperty = '';\n        component.instance.popperInstance.enableEventListeners();\n        component.wasManuallyUpdated = false;\n      },\n      onSpringUpdate(springValue) {\n        if (component.wasInterrupted) {\n          // Since the FLIP animation was interrupted, the popper's translation\n          // begins at the tweened offset\n          component.offsets.prev = component.offsets.tween;\n          component.wasInterrupted = false;\n        }\n\n        const {x: prevX, y: prevY} = component.offsets.prev;\n        const {x: currentX, y: currentY} = component.offsets.current;\n\n        // Calculate tweened offset\n        const tweenedX = prevX - springValue * (prevX - currentX);\n        const tweenedY = prevY - springValue * (prevY - currentY);\n\n        // Write the current tweened offsets due to the FLIP animation\n        component.offsets.tween = {x: tweenedX, y: tweenedY};\n\n        // Set tweened transform\n        const tweenedTransform = `translate3d(${tweenedX}px, ${tweenedY}px, 0)`;\n        component.instance.popper.style.transform = tweenedTransform;\n      },\n    });\n\n    flipper.addInverted({\n      element: content,\n      parent: tooltip,\n    });\n\n    if (arrow) {\n      flipper.addInverted({\n        element: arrow,\n        parent: tooltip,\n      });\n    }\n\n    component.instance = instance;\n    component.flipper = flipper;\n  }\n\n  function onBeforeUpdate(instance) {\n    if (!instance.state.isVisible) {\n      return;\n    }\n\n    component.wasManuallyUpdated = true;\n    component.flipper.recordBeforeUpdate();\n\n    const {tooltip} = instance.popperChildren;\n    const prevDimensions = component.dimensions;\n\n    tooltip.style.width = '';\n    tooltip.style.height = '';\n\n    component.dimensions = {\n      width: tooltip.offsetWidth,\n      height: tooltip.offsetHeight,\n    };\n\n    if (prevDimensions) {\n      tooltip.style.width = `${prevDimensions.width}px`;\n      tooltip.style.height = `${prevDimensions.height}px`;\n    }\n\n    Object.keys(instance.popperChildren).forEach((key) => {\n      if (instance.popperChildren[key]) {\n        instance.popperChildren[key].style.transitionDuration = '0ms';\n        instance.popperChildren[key].style.transitionProperty =\n          'opacity, visibility';\n      }\n    });\n\n    if (component.dimensions.width) {\n      tooltip.style.width = `${component.dimensions.width + 1}px`;\n      tooltip.style.height = `${component.dimensions.height}px`;\n    }\n  }\n\n  function onAfterUpdate(instance) {\n    if (!instance.state.isVisible) {\n      return;\n    }\n\n    // Allow `padding` to be transitioned if the popper switches placements\n    component.instance.popper.style.transitionProperty = 'padding';\n    component.instance.popper.style.transitionDuration = '500ms';\n    component.instance.popperInstance.disableEventListeners();\n\n    component.flipper.onUpdate();\n\n    if (onChange) {\n      onChange(instance);\n    }\n  }\n\n  function onMount(instance) {\n    if (!component.dimensions) {\n      onBeforeUpdate(instance);\n    }\n  }\n\n  function onHidden(instance) {\n    const {content, tooltip, arrow} = instance.popperChildren;\n\n    content.style.transform = '';\n    tooltip.style.transform = '';\n    tooltip.style.top = '';\n\n    if (arrow) {\n      arrow.style.transform = '';\n    }\n\n    component.wasManuallyUpdated = false;\n  }\n\n  function popperOnCreate(data) {\n    const currentOffsets = parseTranslate3d(data.styles.transform);\n    component.offsets.prev = currentOffsets;\n    component.offsets.current = currentOffsets;\n    component.offsets.tween = currentOffsets;\n  }\n\n  function popperOnUpdate(data) {\n    const {arrow} = component.instance.popperChildren;\n\n    // `react-flip-toolkit` adds this\n    if (arrow) {\n      arrow.style.transformOrigin = '';\n    }\n\n    component.wasInterrupted = true;\n    component.offsets.prev = component.offsets.current;\n\n    // We need to parse it because Popper rounds the values but doesn't expose\n    // the rounded values for us...\n    const currentOffsets = parseTranslate3d(data.styles.transform);\n\n    component.offsets.current = currentOffsets;\n\n    // Runs AFTER first `onSpringUpdate` frame\n    requestAnimationFrame(() => {\n      component.offsets.tween = currentOffsets;\n    });\n\n    // onSpringUpdate and popper's .update() run in different frames, leading to\n    // 1 frame glitch\n    if (component.wasManuallyUpdated) {\n      const {x, y} = component.offsets.tween || component.offsets.prev;\n      component.instance.popper.style.transform = `translate3d(${x}px, ${y}px, 0)`;\n    }\n  }\n\n  const popperOptions = useStableMemo(\n    () => ({\n      ...child.props.popperOptions,\n      onCreate(data) {\n        preserveInvocation(\n          child.props.popperOptions && child.props.popperOptions.onCreate,\n          [data]\n        );\n        popperOnCreate(data);\n      },\n      onUpdate(data) {\n        preserveInvocation(\n          child.props.popperOptions && child.props.popperOptions.onUpdate,\n          [data]\n        );\n        popperOnUpdate(data);\n      },\n    }),\n    [child.props.popperOptions]\n  );\n\n  return cloneElement(child, {\n    popperOptions,\n    onBeforeUpdate(...args) {\n      preserveInvocation(child.props.onBeforeUpdate, args);\n      onBeforeUpdate(...args);\n    },\n    onAfterUpdate(...args) {\n      preserveInvocation(child.props.onAfterUpdate, args);\n      onAfterUpdate(...args);\n    },\n    onCreate(...args) {\n      preserveInvocation(child.props.onCreate, args);\n      onCreate(...args);\n    },\n    onMount(...args) {\n      preserveInvocation(child.props.onMount, args);\n      onMount(...args);\n    },\n    onHidden(...args) {\n      preserveInvocation(child.props.onHidden, args);\n      onHidden(...args);\n    },\n  });\n}\n\nexport default TippyTransition;\n"
  },
  {
    "path": "website/src/components/examples/Ajax.js",
    "content": "import React, {useState} from 'react';\nimport Tippy from '../Tippy';\nimport {Button} from '../Framework';\n\nfunction Img({src}) {\n  return (\n    <img\n      style={{\n        width: 200,\n        height: 200,\n        display: 'block',\n      }}\n      alt=\"Unsplash\"\n      src={src}\n    />\n  );\n}\n\nfunction Ajax({children}) {\n  const [fetching, setFetching] = useState(false);\n  const [src, setSrc] = useState(null);\n  const [error, setError] = useState(null);\n\n  const content = error || src ? <Img src={src} /> : 'Loading...';\n\n  return (\n    <Tippy\n      content={content}\n      onShow={async () => {\n        if (fetching || src || error) {\n          return;\n        }\n\n        setFetching(true);\n\n        try {\n          const response = await fetch('https://unsplash.it/200/?random');\n          const blob = await response.blob();\n          setSrc(URL.createObjectURL(blob));\n        } catch (e) {\n          setError(`Fetch failed. ${e}`);\n        } finally {\n          setFetching(false);\n        }\n      }}\n      onHidden={() => {\n        setSrc(null);\n        setError(null);\n      }}\n    >\n      <Button>{children}</Button>\n    </Tippy>\n  );\n}\n\nexport default Ajax;\n"
  },
  {
    "path": "website/src/components/examples/ContextMenu.js",
    "content": "import React, {useEffect, useRef} from 'react';\nimport {tippy} from '../Tippy';\nimport {css} from '@emotion/core';\n\nfunction ContextMenu() {\n  const containerRef = useRef();\n\n  useEffect(() => {\n    function handleContextMenu(event) {\n      event.preventDefault();\n\n      instance.setProps({\n        getReferenceClientRect: () => ({\n          width: 0,\n          height: 0,\n          top: event.clientY,\n          bottom: event.clientY,\n          left: event.clientX,\n          right: event.clientX,\n        }),\n      });\n\n      instance.show();\n    }\n\n    function handleScroll() {\n      instance.hide();\n      instance.unmount();\n    }\n\n    const container = containerRef.current;\n\n    const instance = tippy(container, {\n      content: 'Context menu',\n      offset: [0, 0],\n      arrow: false,\n      placement: 'right-start',\n      interactive: true,\n      theme: 'light',\n      trigger: 'manual',\n    });\n\n    container.addEventListener('contextmenu', handleContextMenu);\n    window.addEventListener('scroll', handleScroll);\n\n    return () => {\n      container.removeEventListener('contextmenu', handleContextMenu);\n      window.removeEventListener('scroll', handleScroll);\n      instance.destroy();\n    };\n  });\n\n  return (\n    <div\n      ref={containerRef}\n      css={css`\n        position: relative;\n        overflow: hidden;\n        margin-bottom: 8px;\n        border: 2px dashed red;\n        position: relative;\n        height: 250px;\n        display: grid;\n        place-items: center;\n      `}\n    >\n      Right click inside\n    </div>\n  );\n}\n\nexport default ContextMenu;\n"
  },
  {
    "path": "website/src/components/examples/Dropdown.js",
    "content": "import React, {forwardRef} from 'react';\nimport styled from '@emotion/styled';\nimport {css} from '@emotion/core';\nimport Tippy from '../Tippy';\nimport {Button} from '../Framework';\n\nconst List = styled.div`\n  margin: 0;\n  padding-left: 0;\n  list-style: none;\n  text-align: left;\n`;\n\nconst Reaction = styled.button`\n  background: none;\n  border: none;\n  font-size: 22px;\n  color: inherit;\n  transition: transform 0.1s ease-out;\n  transform: scale(1.0001);\n  cursor: pointer;\n\n  &:hover,\n  &:focus {\n    transform: scale(1.25);\n  }\n`;\n\nconst Text = styled.p`\n  margin: 6px 0;\n  color: #777;\n`;\n\nconst DropdownTippy = forwardRef((props, ref) => (\n  <Tippy\n    css={css`\n      hr {\n        margin: 6px 0 10px;\n      }\n    `}\n    ref={ref}\n    {...props}\n  />\n));\n\nfunction Dropdown({text = 'Dropdown'}) {\n  return (\n    <DropdownTippy\n      content={\n        <>\n          <Text>Pick your reaction</Text>\n          <hr />\n          <List>\n            <Reaction aria-label=\"React with thumbs up emoji\">\n              <span role=\"img\" aria-label=\"Thumbs up\">\n                👍\n              </span>\n            </Reaction>\n            <Reaction aria-label=\"React with thumbs down emoji\">\n              <span role=\"img\" aria-label=\"Thumbs down\">\n                👎\n              </span>\n            </Reaction>\n            <Reaction aria-label=\"React with heart emoji\">\n              <span role=\"img\" aria-label=\"Heart\">\n                ❤️\n              </span>\n            </Reaction>\n            <Reaction aria-label=\"React with crying with laughter emoji\">\n              <span role=\"img\" aria-label=\"Crying with laughter\">\n                😂\n              </span>\n            </Reaction>\n            <Reaction aria-label=\"React with party emoji\">\n              <span role=\"img\" aria-label=\"Party\">\n                🎉\n              </span>\n            </Reaction>\n          </List>\n        </>\n      }\n      interactive={true}\n      arrow={true}\n      animateFill={false}\n      offset={[0, 7]}\n      placement=\"bottom\"\n      animation=\"fade\"\n      theme=\"light-border\"\n      trigger=\"click\"\n    >\n      <Button>{text}</Button>\n    </DropdownTippy>\n  );\n}\n\nexport default Dropdown;\n"
  },
  {
    "path": "website/src/components/examples/EventDelegation.js",
    "content": "import React from 'react';\nimport Tippy from '../Tippy';\nimport {Button} from '../Framework';\n\nfunction EventDelegation() {\n  return (\n    <Tippy target=\".child\" ignoreAttributes={false}>\n      <div id=\"parent\">\n        <Button className=\"child\" data-tippy-content=\"Tooltip 1\">\n          One\n        </Button>\n        <Button\n          className=\"child\"\n          data-tippy-content=\"Tooltip 2\"\n          data-tippy-arrow=\"true\"\n        >\n          Two\n        </Button>\n        <Button\n          className=\"child\"\n          data-tippy-content=\"Tooltip 3\"\n          data-tippy-theme=\"light\"\n        >\n          Three\n        </Button>\n      </div>\n    </Tippy>\n  );\n}\n\nexport default EventDelegation;\n"
  },
  {
    "path": "website/src/components/examples/ImageTransition.js",
    "content": "import React, {useState, useRef} from 'react';\nimport styled from '@emotion/styled';\nimport Tippy from '../Tippy';\nimport {Button} from '../Framework';\nimport TippyTransition from '../TippyTransition';\n\nconst StyledTippy = styled(Tippy)`\n  overflow: hidden;\n`;\n\nfunction DimensionsTransition() {\n  const [display, setDisplay] = useState('none');\n  const [expanded, setExpanded] = useState(false);\n  const imageContainerRef = useRef();\n\n  function onClick() {\n    setExpanded((expanded) => !expanded);\n    setDisplay((display) => (display === 'none' ? 'block' : 'none'));\n  }\n\n  function onChange(instance) {\n    if (!instance.state.isVisible) {\n      return;\n    }\n\n    imageContainerRef.current.style.display = 'block';\n  }\n\n  return (\n    <TippyTransition onChange={onChange}>\n      <StyledTippy\n        content={\n          <>\n            <Button onClick={onClick} style={{margin: 10, width: 140}}>\n              {expanded ? 'Close' : 'Open'} Image\n            </Button>\n            <div\n              className=\"TippyTransition-image\"\n              style={{display}}\n              ref={imageContainerRef}\n            >\n              <img\n                style={{\n                  width: 300,\n                  marginTop: 5,\n                  transform: 'scale(1.1)',\n                  transformOrigin: 'top',\n                }}\n                src=\"https://images.unsplash.com/photo-1519681393784-d120267933ba?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60\"\n                alt=\"Starry mountain landscape\"\n              />\n            </div>\n          </>\n        }\n        interactive={true}\n        arrow={false}\n        trigger=\"click\"\n      >\n        <Button>Image transition (click)</Button>\n      </StyledTippy>\n    </TippyTransition>\n  );\n}\n\nexport default DimensionsTransition;\n"
  },
  {
    "path": "website/src/components/examples/Nesting.js",
    "content": "import React from 'react';\nimport {css} from '@emotion/core';\nimport Tippy from '../Tippy';\nimport {Button} from '../Framework';\n\nconst padding = css`\n  padding: 10px;\n`;\n\nconst commonProps = {\n  onCreate({popper}) {\n    popper.style.width = 'max-content';\n  },\n  interactive: true,\n  theme: 'light-border',\n  css: padding,\n};\n\nfunction Nesting() {\n  return (\n    <Tippy\n      {...commonProps}\n      content={\n        <Tippy\n          {...commonProps}\n          content={\n            <Tippy\n              {...commonProps}\n              placement=\"right\"\n              content={\n                <Tippy\n                  {...commonProps}\n                  placement=\"bottom\"\n                  content=\"Level 4 (final)\"\n                >\n                  <Button>Level 3</Button>\n                </Tippy>\n              }\n            >\n              <Button>Level 2</Button>\n            </Tippy>\n          }\n        >\n          <Button>Level 1</Button>\n        </Tippy>\n      }\n    >\n      <Button>Level 0</Button>\n    </Tippy>\n  );\n}\n\nexport default Nesting;\n"
  },
  {
    "path": "website/src/components/examples/Singleton.js",
    "content": "import React, {cloneElement} from 'react';\nimport Tippy, {useSingleton} from '../Tippy';\nimport {Button} from '../Framework';\nimport {Children} from 'react';\n\nconst array = Array(4).fill();\n\nfunction Singleton({group, transition}) {\n  const [source, target] = useSingleton();\n  const delay = transition ? [100, 500] : 500;\n\n  const children = array.map((_, i) => (\n    <Tippy key={i} content={`Tooltip ${i + 1}`} delay={delay}>\n      <Button>Text</Button>\n    </Tippy>\n  ));\n\n  const sourceElement = (\n    <Tippy\n      singleton={source}\n      delay={delay}\n      moveTransition={\n        transition ? 'transform 0.4s cubic-bezier(0.22, 1, 0.36, 1)' : ''\n      }\n    />\n  );\n\n  if (group) {\n    return (\n      <>\n        {sourceElement}\n        {Children.map(children, (child) =>\n          cloneElement(child, {singleton: target})\n        )}\n      </>\n    );\n  }\n\n  return (\n    <>\n      {sourceElement}\n      {children}\n    </>\n  );\n}\n\nexport default Singleton;\n"
  },
  {
    "path": "website/src/components/examples/TextTransition.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport styled from '@emotion/styled';\nimport Tippy from '../Tippy';\nimport {Button} from '../Framework';\nimport TippyTransition from '../TippyTransition';\nimport {useInstance} from '../../hooks';\n\nconst StyledTippy = styled(Tippy)`\n  overflow: hidden;\n`;\n\nconst contents = [\n  'Hello there!',\n  'This is an example of a simple text transition.',\n  'We are using a FLIP library called `react-flip-toolkit`, which allows 60 FPS transitions of element dimensions.',\n  \"The text itself does not transition, just the tippy element's dimensions.\",\n  'You might want to use an opacity transition for the text itself.',\n  'Thanks for reading! (restarting...)',\n];\n\nfunction DimensionsTransition() {\n  const [content, setContent] = useState(contents[0]);\n  const component = useInstance({currentIndex: 0});\n\n  function scheduleNextContent() {\n    const currentIndex = contents.findIndex((c) => c === content);\n    const nextIndex =\n      currentIndex === contents.length - 1 ? 0 : currentIndex + 1;\n    const nextContent = contents[nextIndex];\n\n    clearTimeout(component.timeout);\n    component.timeout = setTimeout(() => {\n      setContent(nextContent);\n      scheduleNextContent();\n    }, 1000 + contents[currentIndex].length * 50);\n  }\n\n  useEffect(() => {\n    if (component.instance.state.isVisible) {\n      scheduleNextContent();\n    }\n  });\n\n  function onCreate(instance) {\n    component.instance = instance;\n  }\n\n  function onMount() {\n    scheduleNextContent();\n  }\n\n  function onHidden() {\n    clearTimeout(component.timeout);\n  }\n\n  return (\n    <TippyTransition>\n      <StyledTippy\n        content={content}\n        onCreate={onCreate}\n        onHidden={onHidden}\n        onMount={onMount}\n        arrow={false}\n        animation=\"fade\"\n        trigger=\"click\"\n      >\n        <Button>Text transition (click)</Button>\n      </StyledTippy>\n    </TippyTransition>\n  );\n}\n\nexport default DimensionsTransition;\n"
  },
  {
    "path": "website/src/components/examples/TriggerTarget.js",
    "content": "import React, {useState, useEffect, useRef} from 'react';\nimport Tippy from '../Tippy';\nimport styled from '@emotion/styled';\n\nconst PositioningTarget = styled.span`\n  background: tomato;\n  color: white;\n  padding: 4px 8px;\n`;\n\nfunction TriggerTarget() {\n  const [mounted, setMounted] = useState(false);\n  const ref = useRef();\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  return (\n    <div style={{marginBottom: 8}}>\n      <span ref={ref}>Trigger target</span> vs{' '}\n      {mounted && (\n        <Tippy triggerTarget={ref.current}>\n          <PositioningTarget>positioning target</PositioningTarget>\n        </Tippy>\n      )}\n    </div>\n  );\n}\n\nexport default TriggerTarget;\n"
  },
  {
    "path": "website/src/components/examples/mouseRestPlugin.js",
    "content": "export default {\n  name: 'mouseRest',\n  defaultValue: false,\n  fn(instance) {\n    const {reference} = instance;\n    const DEBOUNCE_MS = 80;\n\n    let timeout;\n\n    // If the `trigger` isn't `\"mouseenter\"`, then this plugin doesn't apply.\n    function getIsEnabled() {\n      return (\n        instance.props.mouseRest &&\n        instance.props.trigger.indexOf('mouseenter') !== -1\n      );\n    }\n\n    return {\n      onCreate() {\n        if (!getIsEnabled()) {\n          return;\n        }\n\n        const triggerWithoutMouseEnter = instance.props.trigger\n          .replace('mouseenter', '')\n          .trim();\n\n        instance.setProps({trigger: triggerWithoutMouseEnter});\n\n        reference.addEventListener('mousemove', () => {\n          clearTimeout(timeout);\n          timeout = setTimeout(() => instance.show(), DEBOUNCE_MS);\n        });\n\n        reference.addEventListener('mouseleave', () => {\n          clearTimeout(timeout);\n          instance.hide();\n        });\n      },\n      onDestroy() {\n        clearTimeout(timeout);\n      },\n    };\n  },\n};\n"
  },
  {
    "path": "website/src/css/index.js",
    "content": "import React from 'react';\nimport {MEDIA} from '../components/Framework';\nimport {Global, css} from '@emotion/core';\n\nconst MONOSPACE_FONT_STACK = `Menlo, \"Dank Mono\", Inconsolata, \"Operator Mono\", Consolas, \"Andale Mono WT\", \"Andale Mono\", \"Lucida Console\", \"Lucida Sans Typewriter\", \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\", \"Liberation Mono\", \"Nimbus Mono L\", \"Courier New\", Courier, monospace`;\n\nconst core = css`\n  html {\n    height: 100%;\n  }\n\n  body {\n    font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI',\n      Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif;\n    margin: 0;\n    background-color: #1f2028;\n    color: #bfc3d9;\n    height: 100%;\n    font-size: 17px;\n    -webkit-tap-highlight-color: transparent;\n\n    ${MEDIA.md} {\n      font-size: 18px;\n    }\n  }\n\n  :focus:not(.focus-visible) {\n    outline: 0;\n  }\n\n  pre code::-moz-selection,\n  pre span::-moz-selection {\n    background-color: rgba(200, 210, 255, 0.25);\n    color: inherit;\n  }\n  pre code::selection,\n  pre span::selection {\n    background-color: rgba(200, 210, 255, 0.25);\n    color: inherit;\n  }\n\n  a {\n    color: #7cbbff;\n    text-decoration: none;\n\n    &:hover {\n      text-decoration: underline;\n    }\n  }\n\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6 {\n    position: relative;\n    margin-top: 0;\n    margin-bottom: 16px;\n    color: #fff;\n    word-break: break-word;\n\n    &:hover .link-icon {\n      opacity: 1;\n    }\n\n    .link-icon.focus-visible {\n      outline: 0;\n      box-shadow: 0 0 0 1px;\n    }\n  }\n\n  h1 {\n    font-size: 40px;\n    margin-top: 40px;\n  }\n\n  h2 {\n    font-size: 48px;\n    display: inline-block;\n    color: inherit;\n    text-shadow: -2px 2px 0px #000, -4px 3px 0px #000;\n    color: #fff;\n    padding: 10px 0;\n    transition: color 0.3s;\n\n    &::-moz-selection {\n      background: rgba(0, 160, 255, 0.5);\n      text-shadow: none;\n    }\n\n    &::selection {\n      background: rgba(0, 160, 255, 0.5);\n      text-shadow: none;\n    }\n\n    &::before {\n      content: '';\n      position: absolute;\n      left: 0;\n      top: 0;\n      bottom: 0;\n      width: calc(15% + 40px);\n      margin-left: -25px;\n      background: linear-gradient(45deg, #0058ff, #df72a1, #f7ffbb);\n      z-index: -1;\n      transition: width 0.4s cubic-bezier(0.23, 1, 0.32, 1);\n      border-radius: 3px;\n    }\n\n    ${MEDIA.md} {\n      font-size: 64px;\n    }\n  }\n\n  h3 {\n    font-size: 28px;\n    margin-top: 60px;\n    margin-bottom: 24px;\n    padding-right: 30px;\n\n    ${MEDIA.sm} {\n      font-size: 32px;\n    }\n\n    ${MEDIA.md} {\n      font-size: 36px;\n    }\n  }\n\n  h4 {\n    font-size: 24px;\n    margin-top: 35px;\n\n    ${MEDIA.md} {\n      font-size: 28px;\n    }\n  }\n\n  h5 {\n    font-size: 22px;\n    margin-top: 32px;\n    color: #666c80;\n    font-weight: 500;\n  }\n\n  p,\n  li {\n    line-height: 1.6;\n    margin-top: 12px;\n  }\n\n  ul {\n    padding-left: 18px;\n  }\n\n  table {\n    box-shadow: 0 0 0 1px rgba(0, 32, 128, 0.1);\n    border-collapse: collapse;\n    margin: 0;\n    padding: 0;\n    line-height: 1.4;\n    border-radius: 0 0 10px 10px;\n    font-size: 16px;\n\n    ${MEDIA.xl} {\n      width: calc(100% + 50px);\n      margin-left: -25px;\n    }\n  }\n\n  table tr {\n    padding: 5px;\n\n    &:not(:last-of-type) {\n      border-bottom: 2px dashed rgba(0, 32, 128, 0.1);\n    }\n\n    &:nth-of-type(even) {\n      background-color: #272935;\n    }\n  }\n\n  td:first-of-type code {\n    background: none;\n    border: none;\n    font-size: 18px;\n    padding: 0;\n  }\n\n  th:last-of-type,\n  td:last-of-type {\n    padding-left: 25px;\n  }\n\n  table th,\n  table td {\n    text-align: left;\n    padding: 15px;\n\n    ${MEDIA.xl} {\n      padding: 15px 25px;\n    }\n  }\n\n  table th {\n    position: relative;\n    z-index: 1;\n    font-size: 14px;\n    text-transform: uppercase;\n    background: rgba(119, 97, 209, 0.8);\n    backdrop-filter: blur(5px);\n    color: white;\n    position: sticky;\n    top: 0;\n  }\n\n  @media (max-width: 1150px) {\n    table {\n      border: 0;\n      box-shadow: none;\n    }\n\n    table thead {\n      display: none;\n    }\n\n    table tr {\n      border: 1px solid rgba(0, 32, 128, 0.1);\n      display: block;\n      margin-bottom: 10px;\n      border-radius: 10px;\n    }\n\n    table td {\n      display: block;\n\n      &:not(:last-of-type) {\n        border-bottom: 1px dotted rgba(0, 32, 128, 0.1);\n      }\n    }\n\n    table td:last-of-type {\n      border-bottom: 0;\n    }\n\n    th:last-of-type,\n    td:last-of-type {\n      padding-left: 15px;\n    }\n\n    table td::before {\n      content: attr(data-label);\n      display: block;\n      font-weight: bold;\n      text-transform: uppercase;\n      opacity: 0.7;\n      font-size: 13px;\n      margin-bottom: 5px;\n    }\n\n    td:first-of-type code {\n      font-size: 100%;\n    }\n  }\n\n  hr {\n    border: none;\n    border-top: 1px solid rgba(0, 16, 64, 0.15);\n    margin: 50px 0;\n  }\n\n  table tr.plugin-prop {\n    background-color: rgba(180, 255, 210, 0.5);\n  }\n\n  [data-reach-skip-link] {\n    position: fixed;\n    z-index: 3;\n    padding: 10px;\n    left: -9999px;\n    background: white;\n    border-radius: 4px;\n    font-weight: bold;\n    font-size: 15px;\n\n    &:focus {\n      left: 5px;\n      top: 5px;\n    }\n  }\n\n  button,\n  a {\n    &.focus-visible:not(.link-icon) {\n      outline: 0;\n      box-shadow: 0 0 0 2px rgb(0, 0, 0), 0 0 0 4px rgb(100, 150, 255);\n    }\n  }\n\n  blockquote {\n    border-left: 5px solid #6db4ff;\n    background: #323b57;\n    color: #fff;\n    margin: 0;\n    padding: 5px 15px;\n    margin-left: -15px;\n    margin-right: -15px;\n    border-radius: 0 8px 8px 0;\n    font-size: 95%;\n    margin-bottom: 15px;\n\n    ${MEDIA.md} {\n      padding: 5px 20px;\n      margin-left: -25px;\n      margin-right: -25px;\n    }\n\n    p {\n      margin-bottom: 10px;\n    }\n  }\n`;\n\nconst tippy = css`\n  .tippy-backdrop {\n    background: #3e55e1;\n  }\n\n  .tippy-svg-arrow {\n    fill: #3e55e1;\n  }\n\n  .tippy-backdrop ~ .tippy-box {\n    box-shadow: none;\n  }\n\n  .tippy-box {\n    background: #3e55e1;\n    box-shadow: 0 0 4px rgba(0, 0, 0, 0.3),\n      inset 0 1px 0 rgba(255, 255, 255, 0.05);\n\n    &[data-placement^='top'] {\n      > .tippy-arrow::before {\n        border-top-color: #3e55e1;\n      }\n    }\n\n    &[data-placement^='bottom'] {\n      > .tippy-arrow::before {\n        border-bottom-color: #3e55e1;\n      }\n    }\n\n    &[data-placement^='left'] {\n      > .tippy-arrow::before {\n        border-left-color: #3e55e1;\n      }\n    }\n\n    &[data-placement^='right'] {\n      > .tippy-arrow::before {\n        border-right-color: #3e55e1;\n      }\n    }\n  }\n\n  .tippy-box[data-theme~='default'] {\n    background: #424557;\n    box-shadow: 0 0 4px rgba(0, 0, 0, 0.3),\n      inset 0 1px 0 rgba(255, 255, 255, 0.05);\n\n    &[data-placement^='top'] {\n      > .tippy-arrow::before {\n        border-top-color: #424557;\n      }\n    }\n\n    &[data-placement^='bottom'] {\n      > .tippy-arrow::before {\n        border-bottom-color: #424557;\n      }\n    }\n\n    &[data-placement^='left'] {\n      > .tippy-arrow::before {\n        border-left-color: #424557;\n      }\n    }\n\n    &[data-placement^='right'] {\n      > .tippy-arrow::before {\n        border-right-color: #424557;\n      }\n    }\n  }\n\n  .tippy-box[data-theme~='ajax'] {\n    position: absolute;\n    width: 200px;\n    padding: 0;\n    overflow: hidden;\n\n    img {\n      display: block;\n      max-width: 100%;\n    }\n  }\n\n  .tippy-box[data-theme~='tomato'] {\n    font-weight: bold;\n    color: yellow;\n    background: tomato;\n\n    &[data-placement^='top'] {\n      > .tippy-arrow::before {\n        border-top-color: tomato;\n      }\n    }\n\n    &[data-placement^='bottom'] {\n      > .tippy-arrow::before {\n        border-bottom-color: tomato;\n      }\n    }\n\n    .tippy-backdrop {\n      background: tomato;\n    }\n\n    .tippy-svg-arrow {\n      fill: tomato;\n      transform: scale(2);\n    }\n  }\n\n  .tippy-box[data-theme~='scaled-arrow'] > .tippy-arrow::before {\n    transform: scale(1.25);\n  }\n\n  .tippy-box[data-theme~='large-arrow'] > .tippy-arrow::before {\n    transform: scale(1.75);\n  }\n\n  .tippy-box[data-theme~='small-arrow'] > .tippy-arrow::before {\n    transform: scale(0.75);\n  }\n\n  .tippy-box[data-theme~='wide-arrow'] > .tippy-arrow::before {\n    transform: scaleX(1.5);\n  }\n\n  .tippy-box[data-theme~='narrow-arrow'] > .tippy-arrow::before {\n    transform: scale(0.6, 1.2);\n  }\n\n  .tippy-box[data-theme~='gradient'] {\n    background: linear-gradient(130deg, #507bf4, #ff8bcb);\n    box-shadow: 0 8px 12px #402860;\n    font-weight: bold;\n  }\n\n  .tippy-box[data-theme~='retro'] {\n    background: beige;\n    border: 2px solid tomato;\n    color: tomato;\n    font-weight: bold;\n  }\n\n  .tippy-box[data-theme~='forest'] {\n    background: linear-gradient(90deg, #9fe597, #cce581);\n    color: #683b33;\n    font-weight: bold;\n  }\n`;\n\nconst code = css`\n  code:not(.grvsc-code) {\n    color: #81edff;\n    font-family: ${MONOSPACE_FONT_STACK};\n    padding: 0.15em 0.25em;\n    border-radius: 0.25em;\n    line-height: inherit;\n    font-size: 90%;\n    background: none;\n  }\n\n  .grvsc-container {\n    border-radius: 0 !important;\n    overflow-x: none !important;\n\n    ${MEDIA.sm} {\n      border-radius: 10px !important;\n    }\n  }\n\n  .moonlight-ii {\n    background-color: #272935 !important;\n    margin-left: -16px;\n    margin-right: -16px;\n\n    ${MEDIA.md} {\n      margin-left: -25px;\n      margin-right: -25px;\n    }\n  }\n\n  .grvsc-line {\n    padding: 0 15px !important;\n\n    ${MEDIA.sm} {\n      padding: 0 25px !important;\n    }\n  }\n\n  .grvsc-code {\n    font-family: ${MONOSPACE_FONT_STACK};\n    line-height: 2;\n    font-size: 15px;\n\n    ${MEDIA.sm} {\n      font-size: 16px;\n    }\n  }\n`;\n\nfunction CSS() {\n  return (\n    <>\n      <Global styles={core} />\n      <Global styles={tippy} />\n      <Global styles={code} />\n    </>\n  );\n}\n\nexport default CSS;\n"
  },
  {
    "path": "website/src/css/theme.js",
    "content": "export default {\n  border: 'rgba(0, 32, 128, 0.12)',\n  gradient: 'linear-gradient(135deg, #00acff, #6f99fc) no-repeat',\n};\n"
  },
  {
    "path": "website/src/hooks/index.js",
    "content": "import {useState} from 'react';\n\nexport function useInstance(initialValue = {}) {\n  return useState(initialValue)[0];\n}\n"
  },
  {
    "path": "website/src/pages/.prettierrc.json",
    "content": "{\n  \"singleQuote\": true,\n  \"bracketSpacing\": false,\n  \"proseWrap\": \"always\"\n}\n"
  },
  {
    "path": "website/src/pages/404.js",
    "content": "import React from 'react';\nimport Layout from '../components/Layout';\nimport SEO from '../components/SEO';\n\nfunction NotFoundPage({pageContext}) {\n  const context = {...pageContext, frontmatter: {title: '404: Not Found'}};\n  return (\n    <Layout pageContext={context}>\n      <SEO title=\"404: Not found\" pageContext={context} />\n      <p>Unfortunately, the page you were looking for does not exist.</p>\n    </Layout>\n  );\n}\n\nexport default NotFoundPage;\n"
  },
  {
    "path": "website/src/pages/index.mdx",
    "content": "---\ntitle: Demo\npath: /\nindex: 0\n---\n\nimport {ALL_PLACEMENTS, EXTRA_ANIMATIONS} from '../utils';\nimport Dropdown from '../components/examples/Dropdown';\nimport Singleton from '../components/examples/Singleton';\nimport Nesting from '../components/examples/Nesting';\nimport {css} from '@emotion/core';\n\nimport brain from '../images/brain.svg';\nimport lightning from '../images/lightning.svg';\nimport pointer from '../images/pointer.svg';\nimport wheelchair from '../images/wheelchair.svg';\nimport paintbrush from '../images/paintbrush.svg';\nimport typescript from '../images/typescript.svg';\nimport browser from '../images/browser.svg';\n\nTippy.js is the complete tooltip, popover, dropdown, and menu solution for the\nweb, powered by [Popper](https://popper.js.org).\n\nIt provides the logic and optional styling of elements that \"pop out\" from the\nflow of the document and float next to a target element.\n\n- <Icon src={brain} alt=\"brain\" float /> <strong>Smart:</strong> will always float\n  optimally in view\n- <Icon src={pointer} alt=\"mobile\" float /> <strong>Universal:</strong> compatible\n  with mouse, keyboard, and touch inputs\n- <Icon src={paintbrush} alt=\"paintbrush\" float /> <strong>\n    Customizable:\n  </strong> fine-tunable functionality and fully stylable with CSS\n- <Icon src={typescript} alt=\"typescript\" float /> <strong>Typed:</strong> TypeScript\n  support\n\nReady to start? Visit [Getting Started](/v6/getting-started/), or view a demo of\nTippy's features below.\n\n---\n\n### Default\n\nThe default tippy tooltip looks like this:\n\n<Demo>\n  <Tippy theme=\"default\">\n    <Button>My Button</Button>\n  </Tippy>\n</Demo>\n\nIt is triggered by either `mouseenter` or `focus` events so it appears when\nhovered, focused via keyboard navigation, or tapped when using a touch device.\n\nWith a button element on the document like this:\n\n```html\n<button id=\"myButton\">My Button</button>\n```\n\nYou can initialize it like so:\n\n```js\ntippy('#myButton', {\n  content: \"I'm a Tippy tooltip!\",\n});\n```\n\n---\n\n### Placements\n\nYour tippy can be placed in four base ways in relation to the reference element.\nAdditionally, the tooltip can be shifted along the axis.\n\n<Demo>\n  <Row>\n    {ALL_PLACEMENTS.map((placement, i) => (\n      <Col\n        key={placement}\n        base={12}\n        xs={6}\n        md={4}\n        lg={6}\n        xl={4}\n        style={{margin: '8px 0'}}\n      >\n        <Tippy\n          key={placement}\n          content=\"Tooltip\"\n          placement={placement}\n          arrow={false}\n          popperOptions={{\n            modifiers: [\n              {\n                name: 'flip',\n                enabled: false,\n              },\n              {\n                name: 'preventOverflow',\n                options: {\n                  altAxis: true,\n                  tether: false,\n                },\n              },\n            ],\n          }}\n        >\n          <Button\n            style={{\n              display: 'inline-block',\n              width: '100%',\n              height: '60px',\n            }}\n          >\n            {placement}\n          </Button>\n        </Tippy>\n      </Col>\n    ))}\n  </Row>\n</Demo>\n\n```js\ntippy(button, {\n  // default\n  placement: 'top',\n});\n```\n\nIf a tippy cannot fit within its desired placement, it will flip to the opposite\nplacement if there is not enough space. In the above examples, flipping has been\ndisabled to demonstrate each placement properly.\n\n---\n\n### Arrows\n\nThe arrow that points toward the element can have its proportion or shape\nmodified, or be disabled completely.\n\n<Demo>\n  <Tippy arrow animation=\"fade\">\n    <Button>Default</Button>\n  </Tippy>\n  <Tippy arrow=\"round\" animation=\"fade\" animation=\"fade\">\n    <Button>Round</Button>\n  </Tippy>\n  <Tippy animation=\"fade\" theme=\"large-arrow\" offset={[0, 16]}>\n    <Button>Large</Button>\n  </Tippy>\n  <Tippy animation=\"fade\" theme=\"small-arrow\" offset={[0, 8]}>\n    <Button>Small</Button>\n  </Tippy>\n  <Tippy animation=\"fade\" theme=\"wide-arrow\">\n    <Button>Wide</Button>\n  </Tippy>\n  <Tippy animation=\"fade\" theme=\"narrow-arrow\">\n    <Button>Narrow</Button>\n  </Tippy>\n</Demo>\n\n```js\ntippy(button, {\n  // default\n  arrow: true,\n});\n```\n\n---\n\n### Animations\n\nYour tippy can have any type of transition animations. By default, it's a simple\n`fade` (opacity transition).\n\n```js\ntippy(button, {\n  // default\n  animation: 'fade',\n});\n```\n\n#### Extra included animations\n\nThese animations are included in the package and can be imported separately.\n\n<Demo>\n  <Row>\n    {EXTRA_ANIMATIONS.map((animation) => (\n      <Col\n        key={animation}\n        base={12}\n        md={4}\n        lg={6}\n        xl={4}\n        style={{margin: '8px 0'}}\n      >\n        <Tippy animation={animation} animateFill={false}>\n          <Button\n            style={{\n              width: '100%',\n              height: '100%',\n            }}\n          >\n            {animation}\n          </Button>\n        </Tippy>\n      </Col>\n    ))}\n  </Row>\n</Demo>\n\n#### Material filling effect\n\n<Demo>\n  <Tippy\n    animateFill={true}\n    css={css`\n      box-shadow: none;\n    `}\n    animation=\"shift-away\"\n    duration={250}\n  >\n    <Button>Text</Button>\n  </Tippy>\n</Demo>\n\n#### Inertia / slingshot elastic effect\n\nAdd CSS spring physics to the animation using `transition-timing-function`.\n\n<Demo>\n  {EXTRA_ANIMATIONS.filter((animation) => animation.includes('scale')).map(\n    (animation) => (\n      <Tippy\n        key={animation}\n        animation={animation}\n        animateFill={false}\n        inertia={true}\n        duration={[450, 175]}\n      >\n        <Button>{animation}</Button>\n      </Tippy>\n    )\n  )}\n</Demo>\n\n#### CSS keyframe animations\n\nGetting more advanced, you can use actual CSS animations (`@keyframes` rules),\nfor example using the `animate.css` package:\n\n<Demo>\n  <Tippy\n    animation=\"fade\"\n    animateFill={false}\n    duration={[500, 200]}\n    onMount={(instance) => {\n      requestAnimationFrame(() => {\n        instance.popper.firstElementChild.classList.add(\n          'rubberBand',\n          'animated'\n        );\n      });\n    }}\n    onHidden={(instance) => {\n      instance.popper.firstElementChild.classList.remove(\n        'rubberBand',\n        'animated'\n      );\n    }}\n  >\n    <Button>rubberBand</Button>\n  </Tippy>\n  <Tippy\n    animation=\"fade\"\n    animateFill={false}\n    duration={[500, 200]}\n    onMount={(instance) => {\n      requestAnimationFrame(() => {\n        instance.popper.firstElementChild.classList.add('tada', 'animated');\n      });\n    }}\n    onHidden={(instance) => {\n      instance.popper.firstElementChild.classList.remove('tada', 'animated');\n    }}\n  >\n    <Button>tada</Button>\n  </Tippy>\n</Demo>\n\n#### Duration\n\n<Demo>\n  <Tippy duration={0}>\n    <Button>0</Button>\n  </Tippy>\n  <Tippy duration={1000}>\n    <Button>1000</Button>\n  </Tippy>\n  <Tippy duration={[0, 500]}>\n    <Button>[0, 500]</Button>\n  </Tippy>\n  <Tippy duration={[500, 0]}>\n    <Button>[500, 0]</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### Themes\n\nYour tippy can have custom styling.\n\n```js\ntippy(button, {\n  theme: 'light',\n});\n```\n\n#### Included themes\n\nThese themes are included in the package and can be imported separately.\n\n<Demo>\n  {['light', 'light-border', 'material', 'translucent'].map((theme) => (\n    <Tippy key={theme} theme={theme} animateFill={false}>\n      <Button>{theme}</Button>\n    </Tippy>\n  ))}\n</Demo>\n\n#### Custom themes\n\nYou can apply any CSS to a tippy via a theme.\n\n<Demo>\n  {['gradient', 'retro', 'forest'].map((theme) => (\n    <Tippy key={theme} theme={theme} animateFill={false} arrow={false}>\n      <Button>{theme}</Button>\n    </Tippy>\n  ))}\n</Demo>\n\n---\n\n### Triggers\n\nYour tippy can be triggered by a variety of different events, including `click`,\n`focus`, or any other event:\n\n<Demo>\n  <Tippy trigger=\"click\">\n    <Button>Click</Button>\n  </Tippy>\n  <Tippy trigger=\"focus\" hideOnClick={false}>\n    <Button>Focus</Button>\n  </Tippy>\n</Demo>\n\n```js\ntippy(button, {\n  // default\n  trigger: 'click',\n});\n```\n\n---\n\n### Interactivity\n\nYour tippy can be interactive, allowing you to hover over and click inside it.\n\n<Demo>\n  <Tippy interactive content=\"You can select the text inside here.\">\n    <Button>Interactive</Button>\n  </Tippy>\n</Demo>\n\n```js\ntippy(button, {\n  interactive: true,\n});\n```\n\n---\n\n### HTML Content\n\nYour tippy can contain HTML.\n\n<Demo>\n  <Tippy\n    content={\n      <strong>\n        Bolded <span style={{color: 'aqua'}}>content</span>\n      </strong>\n    }\n  >\n    <Button>HTML Content</Button>\n  </Tippy>\n  <Dropdown />\n</Demo>\n\n```js\ntippy(button, {\n  content: '<strong>Bolded <span style=\"color: aqua;\">content</span></strong>',\n  allowHTML: true,\n});\n```\n\n---\n\n### Delay\n\nYour tippy can delay hiding or showing after a trigger.\n\n<Demo>\n  <Tippy delay={500}>\n    <Button>500</Button>\n  </Tippy>\n  <Tippy delay={[800, 0]}>\n    <Button>[800, 0]</Button>\n  </Tippy>\n  <Tippy delay={[0, 800]}>\n    <Button>[0, 800]</Button>\n  </Tippy>\n</Demo>\n\n```js\ntippy(button, {\n  delay: 500, // ms\n});\n```\n\n---\n\n### Follow Cursor\n\nYour tippy can follow the mouse cursor and abide by a certain axis.\nAdditionally, the tooltip can follow the cursor until it shows, at which point\nit will stop following (initial).\n\n<Demo>\n  <Tippy followCursor animateFill={false} duration={200} animation=\"fade\">\n    <Button>Default</Button>\n  </Tippy>\n  <Tippy\n    followCursor=\"horizontal\"\n    animateFill={false}\n    duration={200}\n    animation=\"fade\"\n  >\n    <Button>Horizontal</Button>\n  </Tippy>\n  <Tippy\n    followCursor=\"vertical\"\n    animateFill={false}\n    duration={200}\n    animation=\"fade\"\n  >\n    <Button>Vertical</Button>\n  </Tippy>\n  <Tippy\n    followCursor=\"initial\"\n    animateFill={false}\n    delay={200}\n    duration={200}\n    animation=\"fade\"\n  >\n    <Button>Initial</Button>\n  </Tippy>\n</Demo>\n\n```js\ntippy(button, {\n  followCursor: true,\n});\n```\n\n---\n\n### SVGs\n\nYour tippy can be placed on SVG nodes, where `followCursor: 'initial'` becomes\nvery useful, since it can be placed directly on the line.\n\n<svg height=\"150\" width=\"150\">\n  <Tippy followCursor=\"initial\" animation=\"fade\" delay={100}>\n    <line\n      x1=\"0\"\n      y1=\"0\"\n      x2=\"150\"\n      y2=\"150\"\n      style={{stroke: 'tomato', strokeWidth: 5}}\n    />\n  </Tippy>\n</svg>\n\n---\n\n### Singleton\n\nUse a single tippy for many different reference elements. This allows you to\n\"group\" tooltips with a shared timer to improve UX when elements near each other\nhave tooltips with a `delay` prop.\n\nNon-singleton tippy with `delay: 500`:\n\n<Demo>\n  <Singleton />\n</Demo>\n\nSingleton tippy to group each tippy's `delay: 500`:\n\n<Demo>\n  <Singleton group />\n</Demo>\n\nSingleton tippy with a transition:\n\n<Demo>\n  <Singleton group transition />\n</Demo>\n\n```js\ntippy.createSingleton(tippy(buttons), {\n  delay: 500,\n});\n```\n\nView [singletons in detail](/v6/addons/#singleton).\n\n---\n\n### Nesting\n\nA tippy can be nested within another one.\n\n<Demo>\n  <Nesting />\n</Demo>\n\nThis allows you to create a hover menu system.\n\n### Plenty more...\n\nThe above is not a complete list of features. Tippy is capable of many more\nthings.\n"
  },
  {
    "path": "website/src/pages/v5/accessibility.mdx",
    "content": "---\ntitle: Accessibility\npath: /v5/accessibility/\nindex: 12\n---\n\nTooltip and popovers are usually not mouse-only UI elements. If vital\nfunctionality or information is contained within them, they should be accessible\nto keyboard and touch inputs so that users who navigate interfaces without using\na mouse are not locked out. This is especially true for people with disabilities\nsuch as low vision who rely on screen reader technology to assist them with\nusing an application.\n\nTo ensure these users get the best possible experience, Tippy already employs\nbaked-in defaults to ensure accessibility. However, some special consideration\nshould be taken into account when using the library so you can be aware of\npotential accessibility problems that may arise.\n\n### Use natively focusable elements\n\nTooltips should only be applied to natively focusable elements like `<button>`\nor `<input>`. If you are using a `<div>` or `<span>` element, ensure you add\n`tabindex=\"0\"` so that it can receive focus.\n\n### Mouse, keyboard, and touch input\n\nThe default trigger for tooltips is `\"mouseenter focus\"` This means both a hover\nvia mouse and focus via keyboard navigation will trigger a tooltip. Both of\nthese events also cover touch devices via a tap, with some mobile browsers\nfiring `mouseenter` and others `focus` (or both).\n\n### Announcing tooltip content\n\nNon-interactive tooltips give the reference element an `aria-describedby`\nattribute once they show:\n\n```html\n<button aria-describedby=\"tippy-1\">Text</button>\n<div id=\"tippy-1\" role=\"tooltip\" class=\"tippy-popper\">\n  <!-- inner elements -->\n</div>\n```\n\nThis allows screen reader software to announce the tooltip content describing\nthe reference element once it's in focus.\n\n### Interactivity\n\nTippy uses two techniques to ensure interactive popovers are accessible:\n\n- `aria-expanded` attribute\n- `appendTo: \"parent\"`\n\nThis means once the reference element has focus, the assistive technology will\nlet the user know it has an expandable popover attached to it.\n\nOnce they open it, elements within the tippy can be tabbed to immediately once\nfocus has left the reference element. This relies on there being no more\nfocusable sibling elements after the reference element itself.\n\nBefore opening the popover:\n\n```html\n<div id=\"parent\">\n  <button aria-expanded=\"false\">Text</button>\n</div>\n```\n\nAfter opening the popover:\n\n```html\n<div id=\"parent\">\n  <button aria-expanded=\"true\">Text</button>\n  <div id=\"tippy-1\" role=\"tooltip\" class=\"tippy-popper\">\n    <!-- inner elements, with focusable content -->\n  </div>\n</div>\n```\n\nYou should wrap the reference element in its own parent element (`<div>` or\n`<span>`) if it's not the only focusable sibling element.\n\n#### Clipping issues\n\nSometimes, this behavior won't work for your app due to clipping issues. In this\ncase, you need to specify a custom `appendTo` element outside of the parent node\ncontext and use a focus management solution to handle keyboard navigation.\n[More details here](../faq/#my-tooltip-appears-cut-off-or-is-not-showing-at-all).\n"
  },
  {
    "path": "website/src/pages/v5/addons.mdx",
    "content": "---\ntitle: Addons\npath: /v5/addons/\nindex: 13\n---\n\nAddons are external functions that control or create many different Tippy\ninstances, and can be tree-shaken away by bundlers.\n\n### Event delegation\n\nEvent delegation allows you to let a common parent element handle the creation\nof tippy instances for child elements.\n\nThis allows two things:\n\n- It prevents the need to create new instances for new child elements appended\n  to the parent.\n- It improves performance as the creation of the tippy instances is deferred\n  until they are triggered for the first time.\n\n#### Usage\n\nYour markup should have a structure like this example:\n\n```html\n<div class=\"parent\">\n  <button class=\"child\">Text</button>\n  <button class=\"child\">Text</button>\n  <button class=\"child\">Text</button>\n</div>\n```\n\nPass a `targets` argument to the `delegate()` addon function (the same type the\n`tippy()` function can accept) which represents the parent element(s) that\nshould act as a delegate, and a `target` prop representing a CSS selector that\nshould match the child elements which should receive a tippy.\n\n```js\nimport {delegate} from 'tippy.js';\n\ndelegate('#parent', {\n  target: '.child',\n});\n```\n\nIn the CDN (`iife`) version, it's available as `tippy.delegate()`\n\n#### Return type\n\nBecause `delegate()` can create many different instances, it returns an opaque\nvalue depending on the type supplied, just like `tippy()`.\n\n```js\nconst delegateInstances = delegate('.parent', {\n  target: '.child',\n}); // Instance[]\n\nconst delegateInstance = delegate(parentElement, {\n  target: '.child',\n}); // Instance\n```\n\n#### Cleanup\n\nBy default, when you destroy a delegate instance, it also destroys any child\ninstances that may have been created by it. If you want to prevent this\nbehavior, pass `false` as an argument:\n\n```js\nconst delegateInstance = delegate(parentElement, {\n  target: '.child',\n});\n\n// Prevents further creation and destroys any created child tippy instances\ndelegateInstance.destroy();\n// Prevents further creation only\ndelegateInstance.destroy(false);\n```\n\n#### Polyfill\n\nThis addon uses `Element.prototype.closest()`, which is not supported in older\nbrowsers. You will need to polyfill this method to get full support.\n\n---\n\n### Singleton\n\nA singleton is a single tippy element that takes the place of an array of\nregular tippy instances.\n\nThis allows two things:\n\n- Smooth transitions of the tippy between many different reference element\n  targets\n- Elements with tooltips next to each other that have a `delay` can be \"grouped\"\n  so they appear to share a timeout, which greatly improves UX\n\nSee the [demo](/#singleton) for it in action.\n\n#### Usage\n\nPass an **array** of tippy instances to the `createSingleton` addon function,\nand a `delay` prop:\n\n```js\nimport tippy, {createSingleton} from 'tippy.js';\n\nconst tippyInstances = tippy('button');\nconst singleton = createSingleton(tippyInstances, {delay: 1000});\n```\n\nIn the CDN (`iife`) version, it's available as `tippy.createSingleton()`\n\n#### Smooth transitions\n\nUtilize the `updateDuration` prop, which is the transition duration between\nposition updates of the tippy element:\n\n```js\nconst singleton = createSingleton(tippyInstances, {\n  delay: 1000,\n  updateDuration: 500,\n});\n```\n\n> **Note**\n>\n> Enabling transitions may cause overflow issues if the tippy content is near\n> the right/bottom edge of a boundary (e.g. window) and the tippy content\n> changes from small to large. This is because of the transition causing the\n> tippy to expand the boundary, making Popper.js think it will fit.\n\nTo solve this, constrain the tippy to the viewport:\n\n```js\ncreateSingleton(instances, {\n  boundary: 'viewport',\n});\n```\n\n#### Timing function\n\nThe `transition-timing-function` by default is `easeOutQuint`. Usually this\nlooks nice, but you can change this (to add an inertial slingshot effect for\nexample) like so:\n\n```js\nconst singleton = createSingleton(tippyInstances, {\n  updateDuration: 500,\n  onCreate({popper}) {\n    // Any easing function you want.\n    popper.style.transitionTimingFunction = 'cubic-bezier(...)';\n  },\n});\n```\n"
  },
  {
    "path": "website/src/pages/v5/ajax.mdx",
    "content": "---\ntitle: AJAX\npath: /v5/ajax/\nindex: 11\n---\n\nimport Ajax from '../../components/examples/Ajax';\n\nInitiating AJAX requests is facilitated by lifecycle hooks. This allows you to\ndo very powerful things. For example, let's say you wanted to show a new image\ninside a tooltip each time it gets shown:\n\n<Demo>\n  <Ajax>Hover for a new image</Ajax>\n</Demo>\n\nLet's walk through a little tutorial to learn how to do this.\n\nFirst, let's setup our HTML:\n\n```html\n<button id=\"ajax-tippy\">Hover for a new image</button>\n```\n\nNow, let's add some JavaScript:\n\n```js\ntippy('#ajax-tippy', {\n  content: 'Loading...',\n  // This prop is recommended if your tooltip changes size while showing\n  flipOnUpdate: true,\n});\n```\n\nHere's the result so far (nothing happens yet!):\n\n<Demo>\n  <Tippy content=\"Loading...\" animation=\"fade\" animateFill={false}>\n    <Button>Hover for a new image</Button>\n  </Tippy>\n</Demo>\n\nTo initiate the AJAX request every time the tippy shows, use the `onShow`\nlifecycle:\n\n```js\ntippy('#ajax-tippy', {\n  content: 'Loading...',\n  flipOnUpdate: true,\n  onShow(instance) {\n    // Code here is executed every time the tippy shows\n  },\n});\n```\n\nUsing `fetch`, we can fetch a random image from an Unsplash API:\n\n```js\ntippy('#ajax-tippy', {\n  // ...\n  onShow(instance) {\n    fetch('https://unsplash.it/200/?random')\n      .then((response) => response.blob())\n      .then((blob) => {\n        // Convert the blob into a URL\n        const url = URL.createObjectURL(blob);\n        // Create an image\n        const image = new Image();\n        image.width = 200;\n        image.height = 200;\n        image.style.display = 'block';\n        image.src = url;\n        // Update the tippy content with the image\n        instance.setContent(image);\n      })\n      .catch((error) => {\n        // Fallback if the network request failed\n        instance.setContent(`Request failed. ${error}`);\n      });\n  },\n});\n```\n\nThere are currently two problems with this:\n\n- When the tippy is hidden, it doesn't reset back to `Loading...`\n- If you quickly hover in and out of the tippy, it initiates many different\n  requests and each image rapidly replaces the old one as each request finishes\n\nThe first one can be solved by using the `onHidden` lifecycle, which is executed\nonce the tippy fully transitions out and is unmounted from the DOM:\n\n```js\ntippy('#ajax-tippy', {\n  // ...\n  onHidden(instance) {\n    instance.setContent('Loading...');\n  },\n});\n```\n\nThe second one requires some state:\n\n```js\ntippy('#ajax-tippy', {\n  // ...\n  onCreate(instance) {\n    // Setup our own custom state properties\n    instance._isFetching = false;\n    instance._src = null;\n    instance._error = null;\n  },\n  onShow(instance) {\n    if (instance._isFetching || instance._src || instance._error) {\n      return;\n    }\n\n    instance._isFetching = true;\n\n    fetch('https://unsplash.it/200/?random')\n      .then((response) => response.blob())\n      .then((blob) => {\n        const src = URL.createObjectURL(blob);\n        instance._src = src;\n        // ...\n      })\n      .catch((error) => {\n        instance._error = error;\n        instance.setContent(`Request failed. ${error}`);\n      })\n      .finally(() => {\n        instance._isFetching = false;\n      });\n  },\n  onHidden(instance) {\n    instance.setContent('Loading...');\n    // Unset these properties so new network requests can be initiated\n    instance._src = null;\n    instance._error = null;\n  },\n});\n```\n\nCurrently, the image instantly replaces the `Loading...` text without any smooth\ntransition. How do we make it so the tooltip smoothly transitions in height?\n\n[See the Animations page for details](../animations/#dimensions-transition).\n"
  },
  {
    "path": "website/src/pages/v5/all-props.mdx",
    "content": "---\ntitle: All Props\npath: /v5/all-props/\nindex: 4\n---\n\n| Prop                                                           |       Default        | Description                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| -------------------------------------------------------------- | :------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `allowHTML`                                                    |        `true`        | **Determines if `content` strings are parsed as HTML instead of text.** <br /><br /> Make sure you are sanitizing any user data if rendering HTML to prevent XSS attacks.                                                                                                                                                                                                                                                   |\n| **`animateFill`** (available as a [plugin](../plugins/))       |       `false`        | **Determines if the background fill color of the tippy should be animated.** <br /><br /> You must import the `dist/backdrop.css` & `animations/shift-away.css` stylesheets for styling to work.                                                                                                                                                                                                                            |\n| `animation`                                                    |       `\"fade\"`       | **The type of transition animation.** <br /><br /> See [Animations](../animations/) for details.                                                                                                                                                                                                                                                                                                                            |\n| `appendTo`                                                     |   `document.body`    | **The element to append the tippy to.** <br /><br /> Possible values: `\"parent\"` (the reference's parentNode), `Element`, `(reference) => Element`. <br /><br /> If `interactive: true`, the default behavior is `appendTo: \"parent\"` instead of `document.body`. <br /><br /> See [Accessibility](../accessibility/#interactivity) for more information.                                                                   |\n| `aria`                                                         |   `\"describedby\"`    | **The `aria-*` attribute applied to the reference element.** This allows screen reader software to announce the tippy content once the reference element is in focus. <br /><br /> Possible values: `\"describedby\"`, `\"labelledby\"`. Use `null` to prevent the attribute from being added.                                                                                                                                  |\n| `arrow`                                                        |        `true`        | **Determines if the tippy has an arrow.** <br /><br /> Possible values: `boolean`, `string` (of SVG), or `SVGElement`. <br /><br /> To use the default round arrow, import `roundArrow` from the package (`tippy.roundArrow` in `iife` version) and pass it as the value. <br /><br /> You must also import `dist/svg-arrow.css` when using SVG arrows for styling to work.                                                 |\n| `boundary`                                                     |   `\"scrollParent\"`   | **The boundary that Popper.js' `preventOverflow` modifier adheres to.** <br /><br /> Possible values: `\"scrollParent\"`, `\"window\"`, `\"viewport\"`, or an `HTMLElement`.                                                                                                                                                                                                                                                      |\n| `content`                                                      |         `\"\"`         | **The content of the tippy.** <br /><br /> Possible values: `string`, `Element`, or `(reference) => Element`. <br /><br /> Set `allowHTML: false` to render strings as text instead of HTML.                                                                                                                                                                                                                                |\n| `delay`                                                        |         `0`          | **Delay in ms once a trigger event is fired before a tippy shows or hides.** <br /><br /> Possibles values: `number`, `[number, number]` = [show, hide]. <br /><br /> Specifying a number means both the show and hide delays are the same. Use `null` in the array to use the default value.                                                                                                                               |\n| `distance`                                                     |         `10`         | **How far in pixels the tippy element is from the reference element.** <br /><br /> Possible values: `number` (px), `string` (with units `\"rem\"` only). <br /><br /> Only applies to a single axis and not to the parent popper element, see the `offset` prop.                                                                                                                                                             |\n| `duration`                                                     |     `[275, 250]`     | **Duration of the CSS transition animation in ms.** <br /><br /> Possibles values: `number`, `[number, number]` = [show, hide]. <br /><br /> Specifying a number means both the show and hide delays are the same. Use `null` in the array to use the default value.                                                                                                                                                        |\n| `flip`                                                         |        `true`        | **Determines if the tippy flips so that it is placed within the viewport as best it can be if there is not enough space.**                                                                                                                                                                                                                                                                                                  |\n| `flipBehavior`                                                 |       `\"flip\"`       | **Determines the order of flipping, i.e. which placements to prefer if a certain placement cannot be used.** <br /><br /> Possible values: `\"flip\"`, `Placement[]`. <br /><br /> Use an array such as `[\"bottom\", \"left\"]` to prefer the `\"left\"` placement if `\"bottom\"` is unavailable, instead of `\"top\"`, if using the `\"bottom\"` placement.                                                                            |\n| `flipOnUpdate`                                                 |       `false`        | **Determines if the tippy should flip when necessary if its position updates while showing (for example, while scrolling, resize, or if the size of the tooltip changed).**                                                                                                                                                                                                                                                 |\n| **`followCursor`** (available as a [plugin](../plugins/))      |       `false`        | **Determines if the tippy follows the user's mouse cursor.** <br /><br /> Use the strings `\"vertical\"` or `\"horizontal\"` to only follow the cursor on a single axis. <br /><br /> Use `\"initial\"` to place the tippy at the initial cursor position upon show, but prevent following it. <br /><br /> On touch devices, `\"initial\"` is the behavior for all truthy values.                                                  |\n| `hideOnClick`                                                  |        `true`        | **Determines if the tippy should hide if a mousedown event was fired outside of it (i.e. clicking on the reference element or the body of the page).** <br /><br /> For click-triggered tippies, using `false` will prevent the tippy from ever hiding once it is showing. <br /><br /> To prevent clicks outside of the tippy from hiding it but still allow it to be toggled, use the string `\"toggle\"`.                  |\n| `ignoreAttributes`                                             |       `false`        | **Determines if `data-tippy-*` attributes on the reference element should be ignored.** <br /><br /> Increases performance if you enable it.                                                                                                                                                                                                                                                                                |\n| `inertia`                                                      |       `false`        | **Determines if an inertial slingshot effect is applied to the CSS animation.**                                                                                                                                                                                                                                                                                                                                             |\n| **`inlinePositioning`** (available as a [plugin](../plugins/)) |       `false`        | **Adds enhanced support for inline element positioning (`display: inline`).** <br /><br /> Automatically detects inline elements and positions the tippy correctly.                                                                                                                                                                                                                                                         |\n| `interactive`                                                  |       `false`        | **Determines if the tippy is interactive, i.e. it can be hovered over or clicked without hiding.** <br /><br /> If your tippy appears cut off or invisible, [see the FAQ](../faq/#my-tooltip-appears-cut-off-or-is-not-showing-at-all) for solutions.                                                                                                                                                                       |\n| `interactiveBorder`                                            |         `2`          | **Determines the size in pixels of the invisible border around a tippy which will prevent it from hiding if the cursor left it.**                                                                                                                                                                                                                                                                                           |\n| `interactiveDebounce`                                          |         `0`          | **Number in ms to debounce the internal `onMouseMove` handler which determines when an interactive tippy should hide.**                                                                                                                                                                                                                                                                                                     |\n| `lazy`                                                         |        `true`        | **Determines if the positioning engine (powered by Popper.js) is created lazily. That is, it's only created when necessary upon showing the tippy for the first time.** <br /><br /> If you need to access the `popperInstance` synchronously after creation, set this to `false`. Note that disabling this decreases performance considerably.                                                                             |\n| `maxWidth`                                                     |        `350`         | **Determines the maximum width of the tippy.** <br /><br /> Use a `number` for pixels, or a `string` to add units such as `rem`, or `\"none\"`.                                                                                                                                                                                                                                                                               |\n| `multiple`                                                     |       `false`        | **Determines if the reference element can have multiple tippies applied to it.**                                                                                                                                                                                                                                                                                                                                            |\n| `offset`                                                       |         `0`          | **Determines the offset of the tippy element.** <br /> <br /> Unlike `distance`, it can work on both axes by using a string in the form `\"x, y\"`, such as `\"50, 20\"`. <br /><br /> Avoid using an `offset` along the same axis as the `placement` prop if using `interactive: true`. If using a `number`, there won't be any problems.                                                                                      |\n| `onAfterUpdate`                                                |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onafterupdate) invoked after the tippy's props have been updated.**                                                                                                                                                                                                                                                                                                                    |\n| `onBeforeUpdate`                                               |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onbeforeupdate) invoked before the tippy's props have been updated.**                                                                                                                                                                                                                                                                                                                  |\n| `onCreate`                                                     |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#oncreate) invoked when the tippy has has been created.**                                                                                                                                                                                                                                                                                                                               |\n| `onDestroy`                                                    |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#ondestroy) invoked when the tippy has has been destroyed.**                                                                                                                                                                                                                                                                                                                            |\n| `onHidden`                                                     |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onhidden) invoked when the tippy has fully transitioned out and is unmounted from the DOM.**                                                                                                                                                                                                                                                                                           |\n| `onHide`                                                       |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onhide) invoked when the tippy begins to transition out.** <br /><br /> You can cancel hiding by returning `false` from this lifecycle.                                                                                                                                                                                                                                                |\n| `onMount`                                                      |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onmount) invoked when the tippy has been mounted to the DOM (called after `onShow`).**                                                                                                                                                                                                                                                                                                 |\n| `onShow`                                                       |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onshow) invoked when the tippy begins to transition in.** <br /><br /> You can cancel showing by returning `false` from this lifecycle.                                                                                                                                                                                                                                                |\n| `onShown`                                                      |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onshown) invoked when the tippy has fully transitioned in.**                                                                                                                                                                                                                                                                                                                           |\n| `onTrigger`                                                    |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#ontrigger) invoked when the tippy was triggered by a real DOM event (called before `onShow`) to show the tippy.**                                                                                                                                                                                                                                                                      |\n| `onUntrigger`                                                  |        `noop`        | **[Lifecycle hook](/lifecycle-hooks/#onuntrigger) invoked when the tippy was triggered by a real DOM event (called before `onHide`) to hide the tippy.**                                                                                                                                                                                                                                                                    |\n| `placement`                                                    |       `\"top\"`        | **Positions the tippy relative to its reference element.** <br /><br /> Use the suffix `-start` or `-end` to shift the tippy to the start or end of the reference element, instead of centering it. For example, `\"top-start\"` or `\"left-end\"`.                                                                                                                                                                             |\n| `plugins`                                                      |         `[]`         | **Specify plugins to use.** <br /><br /> See [Plugins](../plugins/) for details.                                                                                                                                                                                                                                                                                                                                            |\n| `popperOptions`                                                |         `{}`         | **Specify custom Popper.js options.** <br /><br /> See the [Popper.js documentation](https://popper.js.org/popper-documentation.html) for more.                                                                                                                                                                                                                                                                             |\n| `role`                                                         |     `\"tooltip\"`      | **Specifies the `role` attribute on the tippy element.**                                                                                                                                                                                                                                                                                                                                                                    |\n| `showOnCreate`                                                 |       `false`        | **Determines if the tippy will be shown immediately once the instance is created (respecting `delay`).**                                                                                                                                                                                                                                                                                                                    |\n| **`sticky`** (available as a [plugin](../plugins/))            |       `false`        | **Ensures the tippy stays stuck to its reference element if it moves around or changes size while showing.** <br /><br /> Use `true` to check both `reference` and `popper` DOM rects, or use the strings `\"reference\"` or `\"popper\"` to check only one rect for improved performance (both are checked by default). <br /><br /> See the `updateDuration` prop to change the transition duration between position updates. |\n| `theme`                                                        |         `\"\"`         | **Themes added as classes (each separated by a space) to the tippy element's `classList`.** <br /><br /> See [Themes](../themes/) for details.                                                                                                                                                                                                                                                                              |\n| `touch`                                                        |        `true`        | **Determines if the tippy displays if the user is currently using touch input.** <br /><br /> Possible values: `boolean`, `\"hold\"`, `[\"hold\", number]`. <br /><br /> Use `\"hold\"` to use `touch` listeners instead, and e.g. `[\"hold\", 500]` to simulate \"long press\" behavior.                                                                                                                                             |\n| `trigger`                                                      | `\"mouseenter focus\"` | **The events (each separated by a space) which cause a tippy to show.** <br /><br /> Possible values: `\"mouseenter\"`, `\"focus\"`, `\"focusin\"`, `\"click\"`, `\"manual\"`. <br /><br /> Use `\"manual\"` to only trigger the tippy programmatically.                                                                                                                                                                                |\n| `triggerTarget`                                                |        `null`        | **Which element(s) the `trigger` event listeners are applied to instead of the reference element.** <br /><br /> Possible values: `null`, `Element`, or `Element[]`.                                                                                                                                                                                                                                                        |\n| `updateDuration`                                               |         `0`          | **The transition duration between position updates of the popper element.** <br/><br /> Useful for the `sticky` and `flipOnUpdate` props.                                                                                                                                                                                                                                                                                   |\n| `zIndex`                                                       |        `9999`        | **Determines the `z-index` of the tippy.**                                                                                                                                                                                                                                                                                                                                                                                  |\n"
  },
  {
    "path": "website/src/pages/v5/animations.mdx",
    "content": "---\ntitle: Animations\npath: /v5/animations/\nindex: 7\n---\n\nimport ImageTransition from '../../components/examples/ImageTransition';\nimport TextTransition from '../../components/examples/TextTransition';\n\nTippies use an opacity `fade` transition by default.\n\n### Included animations\n\nThe package comes with extra animations for you to use:\n\n- `shift-away`\n- `shift-toward`\n- `scale`\n- `perspective`\n\nThey need to be imported separately.\n\n```js\nimport 'tippy.js/animations/scale.css';\n```\n\nPass the animation name as the `animation` prop:\n\n```js\ntippy('button', {\n  animation: 'scale',\n});\n```\n\nEach of these animations also has 3 variants (normal, subtle, and extreme) using\nthe following format:\n\n```js\nimport 'tippy.js/animations/scale.css';\nimport 'tippy.js/animations/scale-subtle.css';\nimport 'tippy.js/animations/scale-extreme.css';\n```\n\n### Custom animations\n\nTo create your own animation:\n\n- Specify the animation name in the `[data-animation]` attribute selector\n- Target the visibility state of the tippy: `[data-state=\"hidden\"]` or\n  `[data-state=\"visible\"]`\n- Depending on the animation, target the placement of the tippy too: e.g.\n  `[data-placement^=\"top\"]`\n\n```css\n.tippy-tooltip[data-animation='rotate'][data-state='hidden'] {\n  opacity: 0;\n  transform: rotate(90deg);\n}\n```\n\n```js\ntippy('button', {\n  animation: 'rotate',\n});\n```\n\n### Inertia\n\nThere's a prop named `inertia` that adds an elastic inertial effect to the\ntippy, which is a limited CSS-only way to mimic spring physics.\n\n```js\ntippy('button', {\n  inertia: true,\n});\n```\n\nYou can customize this prop in your CSS:\n\n```css\n.tippy-tooltip[data-inertia][data-state='visible'] {\n  transition-timing-function: cubic-bezier(...);\n}\n```\n\n### Material filling effect\n\nImport the `animateFill` plugin, plus `dist/backdrop.css` &\n`animations/shift-away.css` stylesheets.\n\n```js\nimport tippy, {animateFill} from 'tippy.js';\nimport 'tippy.js/dist/backdrop.css';\nimport 'tippy.js/animations/shift-away.css';\n\ntippy(targets, {\n  animateFill: true,\n  plugins: [animateFill],\n});\n```\n\n### CSS animations\n\nMaybe plain transitions aren't enough for your use case. You can also use CSS\nanimations (e.g. `animate.css`):\n\n```js\ntippy('button', {\n  onMount(instance) {\n    const {tooltip} = instance.popperChildren;\n    requestAnimationFrame(() => {\n      tooltip.classList.add('animated');\n      tooltip.classList.add('wobble');\n    });\n  },\n  onHidden(instance) {\n    const {tooltip} = instance.popperChildren;\n    tooltip.classList.remove('animated');\n    tooltip.classList.remove('wobble');\n  },\n});\n```\n\nYou can also use `@keyframes` and add the `animation` property to your animation\nselector too.\n\n### Dimensions transition\n\nWhile a tippy is showing, the content inside of it may change. How do you\nsmoothly transition its dimensions? By default, it instantly changes size when\nthe content is updated. It turns out this is quite complex to do, but possible.\n\n#### Partially dynamic\n\nView the [CodePen demo](https://codepen.io/atomiks/pen/LgjMbW).\n"
  },
  {
    "path": "website/src/pages/v5/creating-tooltips.mdx",
    "content": "---\ntitle: Creating Tooltips\npath: /v5/creating-tooltips/\nindex: 2\n---\n\nGive elements you would like to give tooltips to a `data-tippy-content`\nattribute:\n\n```html\n<button data-tippy-content=\"Tooltip\">Text</button>\n<button data-tippy-content=\"Another Tooltip\">Text</button>\n```\n\nTo give them a tippy tooltip, call the `tippy()` function with a CSS selector\nmatching these elements:\n\n```js\ntippy('[data-tippy-content]');\n```\n\nThe `data-tippy-content` attribute allows you to give different tooltip content\nto many different elements, while only needing to initialize once.\n\nIf targeting a single element, you can use the `content` prop instead of the\nattribute:\n\n```js\ntippy('#singleElement', {\n  content: 'Tooltip',\n});\n```\n\nTippy will create tooltips for elements even if you forget to give them content,\nwhich creates an odd shape with no content, so ensure your CSS selector is\nspecific enough to guarantee their content.\n\n### Content types\n\nPlain text and HTML (string or element) are allowed.\n\nIf you're passing unknown user data to `content`, disable HTML for safety,\nunless explicitly sanitizing it:\n\n```js\ntippy('#singleElement', {\n  content: unsafeUserData,\n  allowHTML: false,\n});\n```\n\n### Target types\n\nThe first argument you pass to `tippy()` is the targets you want to give\ntooltips to. This can represent one or many different elements.\n\n```js\n// String (CSS selector matching elements on the document)\ntippy('#id');\ntippy('.class');\ntippy('[data-tippy-content]');\n\n// Element\ntippy(document.getElementById('my-element'));\n\n// Element[]\ntippy([element1, element2, element3]);\n\n// NodeList\ntippy(document.querySelectorAll('.my-elements'));\n```\n\n### Disabled elements\n\nIf an element is disabled, you will need to use a wrapper element (`<span>` or\n`<div>`) in order for the tippy to work. Elements with the disabled attribute\naren't interactive, meaning users cannot focus, hover, or click them to trigger\na tippy.\n\n<!-- prettier-ignore -->\n```html\n<!-- Won't work! -->\n<button data-tippy-content=\"Tooltip\" disabled>Text</button>\n\n<!-- Wrapper <span> will work -->\n<span data-tippy-content=\"Tooltip\" tabindex=\"0\">\n  <button disabled>Text</button>\n</span>\n```\n\nPlease note that this has accessibility concerns and should be avoided if\npossible.\n\n### SVG in IE11\n\nIf you need to support SVG elements in IE11, you will need to include a polyfill\nfor `SVGElement.prototype.contains`.\n\nThe polyfill is small:\n\n```js\nif (!SVGElement.prototype.contains) {\n  SVGElement.prototype.contains = HTMLDivElement.prototype.contains;\n}\n```\n"
  },
  {
    "path": "website/src/pages/v5/customizing-tooltips.mdx",
    "content": "---\ntitle: Customizing Tooltips\npath: /v5/customizing-tooltips/\nindex: 3\n---\n\nAs seen in the demo, the `tippy()` function takes an object of optional props as\na second argument to customize the tooltips being created:\n\n```js\ntippy('button', {\n  duration: 0,\n  arrow: false,\n  delay: [1000, 200],\n});\n```\n\nYou can also specify props on the element using data attributes:\n\n```html\n<button\n  data-tippy-duration=\"0\"\n  data-tippy-arrow=\"false\"\n  data-tippy-delay=\"[1000, 200]\"\n>\n  Text\n</button>\n```\n\nNote that only JSON values are valid in attributes.\n\nIt can be useful to use the function for \"global\" config and choose attributes\nfor individual config here and there:\n\n```html\n<button>Default</button>\n<button data-tippy-content=\"hello\">I have my own content</button>\n<button data-tippy-arrow=\"true\">I have my own option</button>\n```\n\n```js\n// Global config for all <button>s\ntippy('button', {\n  content: 'Global content',\n  trigger: 'click',\n});\n```\n\n### Default props\n\nOften you don't want to specify props over and over again when initializing\ntooltips. You can set the default props for every new tippy instance with the\n`tippy.setDefaultProps()` method:\n\n```js\ntippy.setDefaultProps({delay: 50});\n```\n"
  },
  {
    "path": "website/src/pages/v5/faq.mdx",
    "content": "---\ntitle: FAQ\npath: /v5/faq/\nindex: 16\n---\n\n### What syntax theme is used on this website?\n\nIt's a theme I made called\n[Moonlight](https://github.com/atomiks/moonlight-vscode-theme)!\n\n### Nothing is working\n\nMake sure Tippy's scripts are placed _before_ your own scripts, at the very\nbottom of the page, like so:\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>My page</title>\n  </head>\n  <body>\n    <button>Text</button>\n\n    <!-- Very end of the body -->\n    <script src=\"https://unpkg.com/popper.js@1\"></script>\n    <script src=\"https://unpkg.com/tippy.js@5\"></script>\n    <script>\n      tippy('button', {content: 'tooltip'});\n    </script>\n  </body>\n</html>\n```\n\n### My tooltip appears cut off or is not showing at all\n\nWhen using `interactive: true`, the tippy may be invisible or appear cut off if\nyour reference element is in a container with:\n\n- `position` (e.g. fixed, absolute, sticky)\n- `overflow: hidden`\n\nTo fix add the following prop (recommended):\n\n```js\ntippy(targets, {\n  // ...\n  popperOptions: {\n    positionFixed: true,\n  },\n});\n```\n\nOr, if the above causes issues:\n\n```js\ntippy(targets, {\n  // ...\n  appendTo: document.body,\n});\n```\n\n⚠️ For the latter, you need to be employing focus management for accessibility.\n\n### I'm getting Uncaught ReferenceError: process is not defined\n\nIf you're using the ESM or CJS versions and importing like this:\n\n```js\nimport tippy from 'tippy.js';\n// or\nconst tippy = require('tippy.js').default;\n```\n\nTippy uses a special expression to distinguish a development and production\nenvironment. For you, the developer, there are lots of warnings and error\nmessages to help your development experience. For your end users, all of this\nneeds to get stripped out because it reduces performance and increases bundle\nsize.\n\nTools like `create-react-app` and `Parcel` bundler handle this automatically.\n\n#### Browserify/Grunt/Gulp\n\n[View the following link](https://vuejs.org/v2/guide/deployment.html#With-Build-Tools).\n\n#### Rollup\n\nInstall the\n[`replace plugin`](https://www.npmjs.com/package/rollup-plugin-replace).\n\n```js\nimport replace from 'rollup-plugin-replace';\n\nexport default {\n  // ...\n  plugins: [\n    // Production config\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('production'),\n    }),\n    // OR development config\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('development'),\n    }),\n    // You can also use process.env.NODE_ENV and set the env variables when\n    // running the rollup command to merge the above into one call\n  ],\n};\n```\n\n### How do I use the animations or themes stylesheets with the CDN?\n\nFor brevity, this documentation uses `import` syntax and assumes a module\nbundler environment. If you're using the CDN version, then you'll be using\n`<link>` tags to import separate CSS stylesheets.\n\n[See the example here](../getting-started/#optional-extra-imports).\n\n### What are those \"iife\", \"esm\" and \"cjs\" initialisms?\n\nThey represent JavaScript formats. You don't need to know how they work, just\nwhich one you're using:\n\n| Initialism |                Full Name                | Usage                                          | Tree-Shaking?              |\n| ---------- | :-------------------------------------: | ---------------------------------------------- | -------------------------- |\n| `iife`     | Immediately Invoked Function Expression | Used via script tags in the browser (CDN)      | No                         |\n| `esm`      |            ECMAScript Module            | Used via `import` syntax in module bundlers    | Yes                        |\n| `cjs`      |             CommonJS Module             | Used via `require()` syntax in module bundlers | Only in `Parcel` currently |\n\nUsing `tippy.js` via the `esm` format is the most recommended way, since you get\nthe benefits of tree-shaking in all bundlers.\n\n### What global side effects are there?\n\nThere are global listeners to determine the user's current input type (e.g.\n`touch`), and other UX helpers.\n\n### I can't click things inside the tooltip\n\nTo enable interactivity, set the `interactive` prop to `true`.\n\n### My tooltip is hiding instantly after showing\n\nIf you're using a `focus` trigger, for example on an `<input>`, make sure you\nalso set `hideOnClick: false`.\n\n### Changing data-tippy-\\* attributes does not update the tooltip\n\nUpdating the data-tippy-\\* attribute on an element will currently not update the\ntooltip. You must use the [`setProps()` method](../methods/#setprops) on a Tippy\ninstance.\n\nFor example, let's say you want to update the `theme` for tooltips when changing\nbetween dark and light mode:\n\n```js\nconst instance = tippy(element, {theme: 'custom-dark'});\n\n// When clicking the theme toggle button, you can do this:\ninstance.setProps({theme: 'custom-light'});\n```\n\nIt's also possible to attach a `MutationObserver` to the reference elements and\nobserve mutations to attributes if need be, then call `.setProps()` with the new\nvalues.\n\n### Can I use the `title` attribute?\n\nYes. The `content` prop can be a function that receives the reference element as\nan argument and returns a string or element.\n\n```js\ntippy('button', {\n  content(reference) {\n    const title = reference.getAttribute('title');\n    reference.removeAttribute('title');\n    return title;\n  },\n});\n```\n\nThe `title` attribute should be removed once you have its content so the\nbrowser's default tooltip isn't displayed along with the tippy.\n\n#### Plugin\n\nYou can create a plugin for this to generalize the behavior:\n\n```js\nconst titleAttribute = {\n  name: 'titleAttribute',\n  defaultValue: true,\n  fn() {\n    return {\n      onCreate(instance) {\n        if (!instance.props.titleAttribute) {\n          return;\n        }\n\n        const title = instance.reference.getAttribute('title');\n\n        if (title) {\n          instance.setContent(title);\n          instance.reference.removeAttribute('title');\n        }\n      },\n    };\n  },\n};\n```\n\nNote that the plugin does not take into account dynamic titles. Be cautious of\nwhy you might need this in the first place.\n\n### What's the difference between an addon and a plugin?\n\nAn **addon** is an external function that calls the `tippy()` constructor\nbecause it's controlling or creating many different tippy instances.\n\nA **plugin** is a plain object that hooks into, and adds functionality, to a\nsingle tippy instance that has already already created.\n"
  },
  {
    "path": "website/src/pages/v5/getting-started.mdx",
    "content": "---\ntitle: Getting Started\npath: /v5/getting-started/\nindex: 1\n---\n\nThere are two ways to install the package.\n\n### 1. Package Manager\n\n```bash\n# npm\nnpm i tippy.js\n\n# Yarn\nyarn add tippy.js\n```\n\nIn your application, import the `tippy` module, and the core CSS:\n\n```js\nimport tippy from 'tippy.js';\nimport 'tippy.js/dist/tippy.css';\n```\n\nThis assumes you're using a module bundler like webpack, Rollup, or Parcel. If\nyou're getting an error message about `process` inside the browser,\n[see the FAQ for help.](../faq/#im-getting-uncaught-referenceerror-process-is-not-defined)\n\n### 2. CDN\n\n```html\n<script src=\"https://unpkg.com/popper.js@1\"></script>\n<script src=\"https://unpkg.com/tippy.js@5\"></script>\n```\n\nPlace them at the very bottom of the `<body>`, ensuring they are placed before\nyour own scripts. The version numbers after `@` are important, make sure they\ndon't get removed.\n\n#### Development version\n\nWhile developing, it's recommended to use the development file which includes\nhelpful warnings and error messages when something goes wrong:\n\n```html\n<script src=\"https://unpkg.com/popper.js@1\"></script>\n<script src=\"https://unpkg.com/tippy.js@5/dist/tippy-bundle.iife.js\"></script>\n```\n\nWhen you're finished developing (or deploying for production), you can remove\neverything after `@5` (the production file as listed before).\n\n### CSS\n\nTippy includes a CSS stylesheet by default for the base tooltip styling, fade\nanimation, CSS arrows, and other required CSS.\n\n#### CDN\n\nWhen including the script link above via CDN, the CSS stylesheet is injected\ninto its own `<style>` tag in `<head>`. If you have CSP enabled, you should use\n`dist/tippy.iife.js` and link the stylesheet `dist/tippy.css` separately instead\nof relying on injection.\n\n#### Contents\n\n[View the package contents on unpkg](https://unpkg.com/tippy.js@5/)\n\n- `dist/tippy-bundle.js` = Core JS + Core CSS injected into `<head>` (default\n  for CDN version)\n- `dist/tippy.js` = Core JS (default for ESM/CJS versions)\n- `dist/tippy.css` = Core CSS\n\n### Optional extra imports\n\nFor brevity, this documentation shows imports via a module bundler in Node. If\nyou're using the CDN, you'll be using `<link>` tags instead.\n\n> **Note**\n>\n> This is not a required import — it's just a demonstration of how you will\n> import extra parts of the library depending on your choice when reading the\n> documentation.\n\nThis optional extra import in the documentation:\n\n```js\nimport 'tippy.js/animations/scale.css';\n```\n\nIs equivalent to this using a CDN in the browser:\n\n```html\n<link\n  rel=\"stylesheet\"\n  href=\"https://unpkg.com/tippy.js@5/animations/scale.css\"\n/>\n```\n\n### Component wrappers\n\n- React: [@tippy.js/react](https://github.com/atomiks/tippy.js-react)\n\n### JavaScript syntax\n\nThis documentation is making use of new JavaScript features (ES6+) that old\nbrowsers like IE11 do not support. Although Tippy.js itself supports IE11, the\ncode written in these docs may need to be transpiled using a tool like Babel to\na compatible format if you want to copy and paste it.\n"
  },
  {
    "path": "website/src/pages/v5/html-content.mdx",
    "content": "---\ntitle: HTML Content\npath: /v5/html-content/\nindex: 5\n---\n\nThe `content` prop can accept a string, element, or function.\n\nTo interact with the content inside the tippy, set `interactive: true`.\n\n### String\n\n```js\ntippy('button', {\n  content: '<strong>Bolded content</strong>',\n});\n```\n\n> **Note**\n>\n> Ensure HTML strings containing user data are sanitized properly to prevent XSS\n> attacks.\n\n#### Element.innerHTML\n\nYou can pass in an element's `.innerHTML` string:\n\n<!-- prettier-ignore -->\n```html\n<div id=\"template\" style=\"display: none;\">\n  <strong>Bolded content</strong>\n</div>\n```\n\n```js\nconst template = document.getElementById('template');\n\ntippy('button', {\n  content: template.innerHTML,\n});\n```\n\n### Element\n\nYou can pass the element itself, which is useful for keeping event listeners\nattached (or when a framework is controlling elements inside):\n\n```js\nconst template = document.getElementById('example');\ntemplate.style.display = 'block';\n\ntippy(singleButton, {\n  content: template,\n});\n```\n\nThis differs from passing a `string` in that a single element can only exist in\na single tippy. The template will be moved from the document and into the tippy\nitself.\n\n### Template linking\n\nIf you have multiple references each with their own unique template, there is a\nway to link them with their associated template:\n\n```html\n<button data-template=\"one\">One</button>\n<button data-template=\"two\">Two</button>\n<button data-template=\"three\">Three</button>\n\n<div style=\"display: none;\">\n  <div id=\"one\">\n    <strong>Content for `one`</strong>\n  </div>\n  <div id=\"two\">\n    <strong>Content for `two`</strong>\n  </div>\n  <div id=\"three\">\n    <strong>Content for `three`</strong>\n  </div>\n</div>\n```\n\nWe can make `content` a function that receives the reference element (button in\nthis case) and returns template content:\n\n```js\ntippy('button', {\n  content(reference) {\n    const id = reference.getAttribute('data-template');\n    const template = document.getElementById(id);\n    return template.innerHTML;\n  },\n});\n```\n"
  },
  {
    "path": "website/src/pages/v5/lifecycle-hooks.mdx",
    "content": "---\ntitle: Lifecycle Hooks\npath: /v5/lifecycle-hooks/\nindex: 10\n---\n\nLifecycle hooks provide a way to run code in response to a certain part of a\ntippy's lifecycle. They are listed here in the usual order in which they occur.\nEvery lifecycle hook takes the [`instance`](../tippy-instance/) as its first\nargument.\n\nThese functions are how you hook into a tippy instance's lifecycle to add\nfunctionality via a [plugin](../plugins/).\n\n#### onCreate\n\nExecuted a single time when a tippy is first created.\n\n```js\ntippy(reference, {\n  onCreate(instance) {\n    // ...\n  },\n});\n```\n\n#### onTrigger\n\nExecuted when a tippy is triggered by a DOM event (e.g. mouseenter, focus,\nclick), but before it starts to show.\n\n```js\ntippy(reference, {\n  onTrigger(instance, event) {\n    // ...\n  },\n});\n```\n\n#### onShow\n\nExecuted when a tippy begins to show, but before it gets mounted to the DOM.\n\nYou can optionally return `false` to cancel the tippy from showing.\n\n```js\ntippy(reference, {\n  onShow(instance) {\n    // ...\n    return false; // cancels it\n  },\n});\n```\n\n> **Note:** plugins ignore `return false` due to compositional issues. Only a\n> tippy instance's own props can use this feature.\n\n#### onMount\n\nExecuted when the tippy element is mounted to the DOM.\n\n```js\ntippy(reference, {\n  onMount(instance) {\n    // ...\n  },\n});\n```\n\n#### onShown\n\nExecuted when a tippy has fully transitioned in.\n\n```js\ntippy(reference, {\n  onShown(instance) {\n    // ...\n  },\n});\n```\n\n#### onUntrigger\n\nExecuted when a tippy was untriggered by a DOM event (e.g. mouseleave, blur,\nclick), but before it starts to hide.\n\n```js\ntippy(reference, {\n  onUntrigger(instance, event) {\n    // ...\n  },\n});\n```\n\n#### onHide\n\nExecuted when a tippy begins to hide and transition out.\n\nYou can optionally return `false` to cancel the tippy from hiding.\n\n```js\ntippy(reference, {\n  onHide(instance) {\n    // ...\n    return false; // cancels it\n  },\n});\n```\n\n> **Note:** plugins ignore `return false` due to compositional issues. Only a\n> tippy instance's own props can use this feature.\n\n#### onHidden\n\nExecuted when a tippy has fully transitioned out and unmounted from the DOM.\n\n```js\ntippy(reference, {\n  onHidden(instance) {\n    // ...\n  },\n});\n```\n\n#### onBeforeUpdate\n\nExecuted before a tippy's props are updated (via `.setContent()` or\n`.setProps()`).\n\n```js\ntippy(reference, {\n  onBeforeUpdate(instance, updatedProps) {\n    // ...\n  },\n});\n```\n\n#### onAfterUpdate\n\nExecuted after a tippy's props are updated (via `.setContent()` or\n`.setProps()`).\n\n```js\ntippy(reference, {\n  onAfterUpdate(instance, updatedProps) {\n    // ...\n  },\n});\n```\n\n#### onDestroy\n\nExecuted a single time when a tippy is destroyed.\n\n```js\ntippy(reference, {\n  onDestroy(instance) {\n    // ...\n  },\n});\n```\n"
  },
  {
    "path": "website/src/pages/v5/methods.mdx",
    "content": "---\ntitle: Methods\npath: /v5/methods/\nindex: 9\n---\n\n### Instance methods\n\nMethods on instances allow you to control the tippy programmatically. See the\n[Tippy Instance](../tippy-instance/) page for details on accessing an instance.\n\n#### show\n\nProgrammatically show the tippy at any time:\n\n```js\ninstance.show(); // Default\ninstance.show(0); // 0ms transition duration\n```\n\n#### hide\n\nProgrammatically hide the tippy at any time:\n\n```js\ninstance.hide(); // Default\ninstance.hide(500); // 500ms transition duration\n```\n\n#### disable\n\nTemporarily prevent a tippy from showing or hiding:\n\n```js\ninstance.disable();\n```\n\n#### enable\n\nRe-enable a tippy:\n\n```js\ninstance.enable();\n```\n\n#### setProps\n\nYou can update any prop after the instance has been created. Pass an object of\nnew props in:\n\n```js\ninstance.setProps({\n  arrow: true,\n  animation: 'scale',\n});\n```\n\n#### setContent\n\nUpdating the `content` prop has its own method as a shortcut:\n\n```js\ninstance.setContent('New content');\n```\n\n#### destroy\n\nTo permanently destroy and clean up the instance, use this method:\n\n```js\ninstance.destroy();\n```\n\nThe `_tippy` property is deleted from the reference element upon destruction.\n\n### Static methods\n\nStatic methods belong to the `tippy` module for global behavior.\n\n#### setDefaultProps\n\nSet the default props for each new instance:\n\n```js\ntippy.setDefaultProps({\n  // Props\n});\n\n// Access the current default props\ntippy.defaultProps;\n```\n\n#### hideAll\n\nHide all visible tippies on the document:\n\n```js\nimport {hideAll} from 'tippy.js';\n\n// Use each tippy's own duration\nhideAll();\n// Hide them all instantly\nhideAll({duration: 0});\n// Hide them all except a particular one\nhideAll({exclude: tippyInstance});\nhideAll({exclude: referenceElement});\n```\n\nIn the CDN (`iife`) version, it's available as `tippy.hideAll()`.\n"
  },
  {
    "path": "website/src/pages/v5/misc.mdx",
    "content": "---\ntitle: Misc\npath: /v5/misc/\nindex: 15\n---\n\nimport EventDelegation from '../../components/examples/EventDelegation';\nimport TriggerTarget from '../../components/examples/TriggerTarget';\nimport mouseRest from '../../components/examples/mouseRestPlugin';\n\n### Custom position\n\nUse a Popper ReferenceObject:\n\n```js\ntippy(targets, {\n  // popperInstance will be available onCreate\n  lazy: false,\n  onCreate(instance) {\n    instance.popperInstance.reference = {\n      clientWidth: 0,\n      clientHeight: 0,\n      getBoundingClientRect() {\n        return {\n          // ...\n        };\n      },\n    };\n  },\n});\n```\n\n### Scrollable containers\n\nWhile scrolling the container, the reference element can leave the boundary\nview, meaning the tippy will appear to be attached to nothing. You can hide the\ntippy to prevent it from being seen:\n\n```css\n.tippy-tooltip[data-out-of-boundaries] {\n  opacity: 0;\n}\n```\n\nThis may not be ideal in all cases. You can include this attribute only on a\ntheme if necessary.\n\nOther cases:\n\n- If you want the tippy to be clipped by the scrolling container, use the props\n  `appendTo: 'parent'` and `boundary: scrollingContainer`.\n- Consider the prop `flipOnUpdate: true` if you want the tippy to flip to best\n  fit in view while the container is being scrolled.\n\n### Different trigger target\n\nYou may want the tippy to appear at a different location from its trigger (event\nlisteners) target. For example:\n\n<Demo>\n  <TriggerTarget />\n</Demo>\n\nFor this, you can utilize the `triggerTarget` prop:\n\n```js\nconst innerOrangeSpanElement = document.querySelector('span');\nconst outerDivElement = document.querySelector('div');\n\ntippy(innerOrangeSpanElement, {\n  triggerTarget: outerDivElement,\n});\n```\n\n### Touch devices\n\nTippy provides first-class support for touch devices. Tooltips can be tricky to\nget right on touch devices because of the nature of touch input.\n\n#### Buttons\n\nA tooltip on a button is generally used to convey information before the user\ndecides to click on it. On touch devices, this isn't possible because a tap is\nrequired to show the tooltip, which will fire a click event.\n\nOn iOS, a tap will show the tooltip but click events won't fire until a second\ntap. This allows the user to see the tooltip before deciding to click the\nbutton. On Android, clicking the button will show the tooltip and also fire a\nclick event.\n\nDepending on your use case, one of these will be preferred, so user agent\nchecking may be needed.\n\nIf neither behavior is preferred, consider using the `touchHold` prop which\nallows the user to see the tooltip while pressing and holding the button, but\nwon't fire a click event unless the click appears to be intentional.\n\n##### Setup\n\n```js\nconst button = document.querySelector('button');\nconst isIOS = /iPhone|iPad|iPod/.test(navigator.platform);\n```\n\n##### A: Make iOS behave like Android (single tap to click)\n\n```js\nbutton.addEventListener('click', () => {\n  // Your logic\n});\n\ntippy(button, {\n  onShow() {\n    if (isIOS) {\n      button.click();\n    }\n  },\n});\n```\n\n##### B: Make Android behave like iOS (double tap to click)\n\nTippy has a useful static property `tippy.currentInput`. This is a mutable\nobject whose properties change depending on the user's current input. Currently,\nit has a single property called `isTouch`, which is a boolean flag determining\nif the user is currently using touch input. This is a dynamic value because of\nhybrid devices which can use a mix of mouse and touch input.\n\n```js\nfunction emulateIOS(listener) {\n  let clicks = 0;\n\n  return function () {\n    clicks++;\n\n    if (clicks === 2 || isIOS || !tippy.currentInput.isTouch) {\n      clicks = 0;\n      listener.apply(this, arguments);\n    }\n  };\n}\n\nconst instance = tippy(button);\nconst onClick = emulateIOS(() => {\n  // Your logic\n});\n\nbutton.addEventListener('click', onClick);\n```\n\n#### Hold & long press\n\n```js\n// Will only show the tippy while the user is pressing the screen (not a tap)\ntippy(button, {\n  touch: 'hold',\n});\n\n// Will only show the tippy on a \"long press\" hold\ntippy(button, {\n  touch: ['hold', 500], // 500ms delay\n});\n```\n"
  },
  {
    "path": "website/src/pages/v5/motivation.mdx",
    "content": "---\ntitle: Motivation\npath: /v5/motivation/\nindex: 17\n---\n\n### Why tooltips and popovers?\n\nBoth are elements positioned near a \"reference\" element, and are hidden until\nthey are triggered. They help conserve space by hiding secondary information or\nfunctionality behind a hover or click. They are positioned outside the normal\nflow of the document so when they are triggered, they are overlaid on top of the\nexisting UI without disrupting the flow of content.\n\nTippy.js distinguishes them in the following way:\n\n- A **tooltip** is an element containing simple text content describing a\n  particular element. It's hidden until the user desires more information from\n  the element, e.g. before deciding to click a button.\n- A **popover** is an interactive HTML tooltip. It can be a dropdown, menu, or\n  any other kind of box that pops out from the normal flow of the document. This\n  type of element contains non-vital functionality and can be hidden behind a\n  click or hover to conserve space.\n\nBoth of these are called a \"tippy\" when using Tippy.js!\n\n### Tippy.js\n\n**Size: 5.5 KB (core)** (including Popper: 12.8 KB)\n\n> **Note**\n>\n> (core) means the core JS & CSS. If importing more themes, animations, plugins,\n> or addons, the size will increase.\n\nTippy is an abstraction over Popper and provides a set of features and defaults\nthat make creating tooltip and popover elements easy.\n\nBut, how does Tippy compare to other solutions?\n\n### Comparison with Popper.js\n\n**Size: 7.3 KB**\n\nPopper.js is a positioning engine, not a tooltip library. Popper's only goal is\nto position an absolutely positioned element (the tooltip) near another element\n(the reference).\n\nSince the element is absolutely positioned, naively centering it above the\nreference element can cause it to:\n\n- **Overflow the boundary** (viewport, window, scrollParent) and therefore get\n  cut off\n- **Overlap its reference element (due to overflow prevention)**, so it should\n  flip to the opposite side\n- **Detach from the reference element** if inside a scrolling container\n\nPopper solves all of these problems. The expected logic to do this is very\ncomplex, so this is effectively a \"baseline\" library if you want to even use\npopper elements (tooltips, popovers, dropdowns) in your app in the first place\nwithout them having poor UX.\n\nIf you want to build the appearance and behavior of your popper elements from\nscratch, this is a fantastic library. If you want \"out of the box\" (abstracted)\nbehavior, then using Tippy might be better.\n\nTippy takes advantage of Popper as a dependency, so you can use them together\nwithout incurring additional cost:\n\n```js\nimport Popper from 'popper.js';\nimport tippy from 'tippy.js';\n```\n\nIf you're using the CDN, the `Popper` constructor will already be available.\n\n### Comparison with CSS tooltip libraries like Microtip or Balloon.css\n\n**Size: 1 KB**\n\nCSS tooltips can be tiny in size, but come with some drawbacks:\n\n- Lack of positioning engine means overflow prevention & flipping are not\n  possible\n- Interactivity can be complicated or inaccessible\n- Using HTML content within them is cumbersome (especially with UI libraries\n  like React), with limited dynamism for updating content or reacting to state\n- No dynamic arrow positioning or features like `followCursor`\n\n### Comparison with Tooltipster\n\n**Size: 10 KB** (including jQuery: 40 KB)\n\nTooltipster is a fantastic library with very similar functionality, but requires\na jQuery dependency, unlike Tippy. To many people these days, this is a\ndeal-breaker! jQuery's minzipped size is about 30 KB, and Tooltipster including\nCSS is about 10 KB. To people using frameworks like React, Vue, or Angular, it\ncan be hard to deal with such a large dependency.\n"
  },
  {
    "path": "website/src/pages/v5/plugins.mdx",
    "content": "---\ntitle: Plugins\npath: /v5/plugins/\nindex: 14\n---\n\nPlugins are an extensible way to add functionality to tippy instances. By\nsplitting functionality into a plugin, components or routes that don't need the\nplugin are not burdened with its bundle size cost.\n\n### Exported plugins\n\nThese plugins are exported by the package:\n\n- `animateFill` <Emoji emoji=\"🖌️\" />\n- `followCursor`\n- `inlinePositioning`\n- `sticky`\n\n<Emoji emoji=\"🖌️\" />\nRequires importing the following CSS stylesheets to work:\n\n```js\nimport 'tippy.js/dist/backdrop.css';\nimport 'tippy.js/animations/shift-away.css';\n```\n\n### Usage\n\n#### CDN (iife)\n\nIncluded plugins (part of the [All Props](/all-props/) table) will work as\nnormal.\n\n```js\ntippy(targets, {\n  followCursor: true,\n});\n```\n\n#### Node (esm or cjs)\n\n```js\nimport tippy, {followCursor} from 'tippy.js';\n\ntippy(targets, {\n  followCursor: true,\n  plugins: [followCursor],\n});\n```\n\n### Creating your own custom plugin\n\nA plugin is created by defining an object with the following shape:\n\n```js\nconst plugin = {\n  // Optional (if the plugin provides a prop to use)\n  name: 'propName', // e.g. 'followCursor' or 'sticky'\n  defaultValue: 'anyValue',\n\n  // Required\n  fn(instance) {\n    // Internal state\n    return {\n      // Lifecycle hooks\n    };\n  },\n};\n```\n\nThe plugin's function `fn` returns an object of\n[lifecycle hooks](/lifecycle-hooks/).\n\nHere's an example of a plugin that causes a popper to hide if no elements within\nit are in focus (for interactivity):\n\n```js\nconst hideOnPopperBlur = {\n  name: 'hideOnPopperBlur',\n  defaultValue: true,\n  fn(instance) {\n    return {\n      onCreate() {\n        instance.popper.addEventListener('focusout', (event) => {\n          if (\n            instance.props.hideOnPopperBlur &&\n            event.relatedTarget &&\n            !instance.popper.contains(event.relatedTarget)\n          ) {\n            instance.hide();\n          }\n        });\n      },\n    };\n  },\n};\n\n// Our new prop is enabled by default (defaultValue: true)\ntippy(targets, {\n  plugins: [hideOnPopperBlur],\n});\n```\n\nPlugins are invoked per-instance and the plugin function definition takes the\ninstance as an argument, so you can use private variables to create internal\nstate in the plugin closure. This is how the `followCursor` plugin works.\n\n### TypeScript\n\nTypes that take `Props` (e.g. `Tippy`, `Delegate`, `CreateSingleton`) are\ngenerics that accept an extended props interface:\n\n```ts\nimport tippy, {Tippy, Props, Plugin, LifecycleHooks} from 'tippy.js';\n\ninterface CustomProps {\n  myCustomProp: boolean;\n}\n\ntype FilteredProps = CustomProps &\n  Omit<Props, keyof CustomProps | keyof LifecycleHooks>;\n\ntype ExtendedProps = FilteredProps & LifecycleHooks<FilteredProps>;\n\nexport const myCustomProp: Plugin<ExtendedProps> = {\n  name: 'myCustomProp',\n  defaultValue: false,\n  fn: () => ({}),\n};\n\nexport default (tippy as unknown) as Tippy<ExtendedProps>;\n```\n"
  },
  {
    "path": "website/src/pages/v5/themes.mdx",
    "content": "---\ntitle: Themes\npath: /v5/themes/\nindex: 6\n---\n\nTippies can have any custom styling via CSS.\n\n### Included themes\n\nThe package comes with themes for you to use:\n\n- `light`\n- `light-border`\n- `material`\n- `translucent`\n\nThey need to be imported separately.\n\n```js\nimport 'tippy.js/themes/light.css';\n```\n\nPass the theme name as the `theme` prop:\n\n```js\ntippy('button', {\n  theme: 'light',\n});\n```\n\n### Tippy elements\n\nTo learn how to create a theme, it's helpful to understand the basic structure\nof a tippy element:\n\n<!-- prettier-ignore -->\n```html\n<div class=\"tippy-popper\">\n  <div class=\"tippy-tooltip\" data-placement=\"top\">\n    <div class=\"tippy-content\">\n      My content\n    </div>\n  </div>\n</div>\n```\n\nA tippy is essentially three nested `div`s.\n\n- `tippy-popper` is the outermost node. It is what Popper.js uses to position\n  the tippy. You don't need to apply any styles to this element.\n- `tippy-tooltip` is the actual tooltip node.\n- `tippy-content` is the content node.\n\nDepending on the props supplied, there will exist other elements inside it:\n\n<!-- prettier-ignore -->\n```html\n<div class=\"tippy-popper\">\n  <div class=\"tippy-tooltip\" data-placement=\"top\">\n    <div class=\"tippy-backdrop\"></div> <!-- animateFill: true -->\n    <div class=\"tippy-arrow\"></div> <!-- arrow: true -->\n    <div class=\"tippy-content\">\n      My content\n    </div>\n  </div>\n</div>\n```\n\n### Creating a theme\n\nThemes are created by including a class on the `tippy-tooltip` element as part\nof a selector in the form `.tippy-tooltip.x-theme`. Let's demonstrate this by\ncreating our own theme called `tomato`:\n\n```css\n.tippy-tooltip.tomato-theme {\n  background-color: tomato;\n  color: yellow;\n}\n```\n\nTo apply the theme, specify a `theme` prop without the `-theme` suffix:\n\n```js\ntippy('button', {\n  theme: 'tomato',\n});\n```\n\n<Demo>\n  <Tippy theme=\"tomato\">\n    <Button>Tomato theme</Button>\n  </Tippy>\n</Demo>\n\n### Styling the arrow\n\nThere are two types of arrows:\n\n- CSS arrows (using `border-width`)\n- SVG arrows (using an `<svg>` element)\n\n#### CSS arrow\n\nTo style the default CSS arrow, you'll need to target each different base\nplacement using the `data-placement` attribute and apply it to the\n`.tippy-arrow` element:\n\n```css\n.tippy-tooltip.tomato-theme[data-placement^='top'] .tippy-arrow {\n  border-top-color: tomato;\n}\n.tippy-tooltip.tomato-theme[data-placement^='bottom'] .tippy-arrow {\n  border-bottom-color: tomato;\n}\n.tippy-tooltip.tomato-theme[data-placement^='left'] .tippy-arrow {\n  border-left-color: tomato;\n}\n.tippy-tooltip.tomato-theme[data-placement^='right'] .tippy-arrow {\n  border-right-color: tomato;\n}\n```\n\n#### SVG arrow\n\nFirst import the `svg-arrow.css` stylesheet for SVG arrow styling:\n\n```js\nimport 'tippy.js/dist/svg-arrow.css';\n```\n\nTo color an SVG arrow, specify `fill` and target `.tippy-svg-arrow`:\n\n<!-- prettier-ignore -->\n```css\n.tippy-tooltip.tomato-theme .tippy-svg-arrow {\n  fill: tomato;\n}\n```\n\nThe shape isn't dependent on the placement for styling, which is why it doesn't\nrequire the CSS arrow's more verbose styles.\n\nThere is a default round arrow SVG shape exported from the package for you to\nuse.\n\n#### CDN (iife)\n\n```js\ntippy(targets, {\n  arrow: tippy.roundArrow,\n});\n```\n\n#### Node (esm or cjs)\n\n```js\nimport {roundArrow} from 'tippy.js';\n\ntippy(targets, {\n  arrow: roundArrow,\n});\n```\n\n### Changing the arrow size\n\n#### Option 1: `transform: scale()`\n\nThis is the easiest technique and works for most cases:\n\n```css\n.tippy-tooltip.tomato-theme .tippy-arrow {\n  transform: scale(1.5);\n}\n```\n\n#### Option 2: Pixel increase\n\nIf your tippy theme has a `border` (e.g. the included `light-border` theme),\nthen the `transform: scale()` technique distorts the border width of the arrow.\nInstead, you will need to change the size of the arrow in pixels directly.\n\nYou will also need to change the size of the border pseudo-elements (`::before`\nand `::after`) as well. It's recommended to investigate the CSS of the arrow via\nDevTools.\n\n```css\n.tippy-tooltip.tomato-theme[data-placement^='top'] .tippy-arrow {\n  border-width: 12px 12px 0;\n  border-top-color: tomato;\n}\n\n/* And so on for each placement... */\n```\n\n#### Browser DevTools\n\nIt's highly recommended you inspect a tippy element via your browser's DevTools.\nAn easy way to do this is to give it `hideOnClick: false` and `trigger: 'click'`\nprops so that it stays visible when focus is switched to the DevTools window.\n\nThe tippy element gets appended to the very end of the `<body>`, so you should\nscroll down the elements panel. If `interactive: true`, then the tippy is\nappended to the reference element's parentNode instead.\n\n<Image name=\"browser-devtools-tippy-element.jpg\" />\n"
  },
  {
    "path": "website/src/pages/v5/tippy-instance.mdx",
    "content": "---\ntitle: Tippy Instance\npath: /v5/tippy-instance/\nindex: 8\n---\n\nA tippy instance is an individual tippy object. It has a bunch of properties and\nmethods that contain information and functionality to manipulate the tippy\nprogrammatically.\n\n### Accessing an instance\n\n`tippy()` creates new instances. It returns a single instance or an array of\ninstances depending on the type of argument it's supplied.\n\n#### Element\n\nThe instance is directly returned, as this represents a single target:\n\n```js\n// type Instance\nconst instance = tippy(document.querySelector('button'));\n```\n\n#### String, NodeList, Element[]\n\nAn array of instances are returned, as these represent multiple targets:\n\n```js\n// type Instance[]\nconst instances1 = tippy('button');\nconst instances2 = tippy([element1, element2]);\nconst instances3 = tippy(document.querySelectorAll('.btn'));\n```\n\n#### `_tippy` property\n\nIf you need to access the instance later, this property can be useful if you\ndidn't assign the instance(s) to a variable:\n\n```js\nconst button = document.querySelector('button');\ntippy(button);\nconst instance = button._tippy;\n```\n\nBoth the reference element and the popper element have the instance attached as\nthis property.\n\n### Shape and properties\n\n`instance` is a plain object. It's best to log it out yourself and investigate\nin DevTools:\n\n```js\nconsole.log(instance);\n```\n"
  },
  {
    "path": "website/src/pages/v6/accessibility.mdx",
    "content": "---\ntitle: Accessibility\npath: /v6/accessibility/\nindex: 11\n---\n\nTooltip and popovers are usually not mouse-only UI elements. If vital\nfunctionality or information is contained within them, they should be accessible\nto keyboard and touch inputs so that users who navigate interfaces without using\na mouse are not locked out. This is especially true for people with disabilities\nsuch as low vision who rely on screen reader technology to assist them with\nusing an application.\n\nTo ensure these users get the best possible experience, Tippy already employs\nbaked-in defaults to ensure accessibility. However, some special consideration\nshould be taken into account when using the library so you can be aware of\npotential accessibility problems that may arise.\n\n### Use natively focusable elements\n\nTooltips should only be applied to natively focusable elements like `<button>`\nor `<input>`. If you are using a `<div>` or `<span>` element, ensure you add\n`tabindex=\"0\"` so that it can receive focus.\n\n### Mouse, keyboard, and touch input\n\nThe default trigger for tooltips is `\"mouseenter focus\"` This means both a hover\nvia mouse and focus via keyboard navigation will trigger a tooltip. Both of\nthese events also cover touch devices via a tap, with some mobile browsers\nfiring `mouseenter` and others `focus` (or both).\n\n### Announcing tooltip content\n\nNon-interactive tooltips give the reference element an `aria-describedby`\nattribute once they show:\n\n```html\n<button aria-describedby=\"tippy-1\">Text</button>\n<div id=\"tippy-1\" data-tippy-root>\n  <!-- inner elements -->\n</div>\n```\n\nThis allows screen reader software to announce the tooltip content describing\nthe reference element once it's in focus.\n\n### Interactivity\n\nTippy uses two techniques to ensure interactive popovers are accessible:\n\n- `aria-expanded` attribute\n- `appendTo: \"parent\"`\n\nThis means once the reference element has focus, the assistive technology will\nlet the user know it has an expandable popover attached to it.\n\nOnce they open it, elements within the tippy can be tabbed to immediately once\nfocus has left the reference element. This relies on there being no more\nfocusable sibling elements after the reference element itself.\n\nBefore opening the popover:\n\n```html\n<div id=\"parent\">\n  <button aria-expanded=\"false\">Text</button>\n</div>\n```\n\nAfter opening the popover:\n\n```html\n<div id=\"parent\">\n  <button aria-expanded=\"true\">Text</button>\n  <div id=\"tippy-1\" data-tippy-root>\n    <!-- inner elements, with focusable content -->\n  </div>\n</div>\n```\n\nYou should wrap the reference element in its own parent element (`<div>` or\n`<span>`) if it's not the only focusable sibling element.\n\n#### Clipping issues\n\nSometimes, this behavior won't work for your app due to clipping issues. In this\ncase, you need to specify a custom `appendTo` element outside of the parent node\ncontext and use a focus management solution to handle keyboard navigation.\n[More details here](../faq/#my-tooltip-appears-cut-off-or-is-not-showing-at-all).\n"
  },
  {
    "path": "website/src/pages/v6/addons.mdx",
    "content": "---\ntitle: Addons\npath: /v6/addons/\nindex: 12\n---\n\nAddons are external functions that control or create many different Tippy\ninstances, and can be tree-shaken away by bundlers.\n\n### Singleton\n\nA singleton is a single tippy element that takes the place of an array of\nregular tippy instances.\n\nThis allows two things:\n\n- Smooth transitions of the tippy between many different reference element\n  targets\n- Elements with tooltips next to each other that have a `delay` can be \"grouped\"\n  so they appear to share a timeout, which greatly improves UX\n\nSee the [demo](/#singleton) for it in action.\n\n#### Usage\n\nPass an **array** of tippy instances to the `createSingleton` addon function,\nand a `delay` prop:\n\n```js\nimport tippy, {createSingleton} from 'tippy.js';\n\nconst tippyInstances = tippy('button');\nconst singleton = createSingleton(tippyInstances, {delay: 1000});\n```\n\nIn the CDN (`umd`) version, it's available as `tippy.createSingleton()`.\n\n#### Overrides\n\nYou may want the singleton instance to have some of its props overridden by the\nindividual tippy instances. For example the `placement` or `theme` if you'd like\nto reuse the singleton globally throughout many parts of the application.\n\nYou can do this by specifying the prop keys as an array with `overrides`:\n\n```js\ncreateSingleton(tippyInstances, {\n  placement: 'right',\n  theme: 'spaceship',\n  // The props in the current `tippyInstance` will override the ones above\n  overrides: ['placement', 'theme'],\n});\n```\n\n#### Smooth transitions\n\nUtilize the `moveTransition` prop, which is the transition between moves\n(position updates) of the tippy element:\n\n```js\nconst singleton = createSingleton(tippyInstances, {\n  delay: 1000,\n  moveTransition: 'transform 0.2s ease-out',\n});\n```\n\n### Showing specific tippy instance\n\nThe `.show()` method of singleton accepts an additional parameter:\n\n```js\n// Show first child tippy instance if no parameter given\nsingleton.show();\n\n// Show given child tippy instance\nsingleton.show(tippyInstances[1]);\n\n// Show child tippy instance related to given reference element\nsingleton.show(document.querySelector('button'));\n\n// Show child tippy instance at given index\nsingleton.show(2); // i.e equivalent to passing tippyInstances[2]\n```\n\n### Show instances in order\n\nThe `.showNext()` and `showPrevious()` methods allow you to loop through and\nshow the child tippy instances in forward or reverse order respectively,\nrelative to `tippyInstances` array given in `createSingleton`\n\n```js\n// if no child tippy is shown, show first one, otherwise show the next one\nsingleton.showNext();\n\n// if no child tippy is shown, show last one, otherwise show the previous one\nsingleton.showPrevious();\n```\n\nBoth methods will loop to the other end, like pac-man\n\n```js\nsingleton.show(0); // show first\nsingleton.showPrevious(); // loops back and shows last item\nsingleton.showNext(); // loops to the front and shows first item\n```\n\n#### Update\n\nYou can update the singleton's instances with the `.setInstances()` method:\n\n```js\nsingleton.setInstances(newTippyInstances);\n```\n\n#### Destroy\n\nWhen you call `singleton.destroy()`, the `tippyInstances` you passed as an\nargument will **not** be destroyed also. They are separate instances that can be\nreused again elsewhere. You should also destroy the tippy instances upon\ncleanup.\n\n---\n\n### Event delegation\n\nEvent delegation allows you to let a common parent element handle the creation\nof tippy instances for child elements.\n\nThis allows two things:\n\n- It prevents the need to create new instances for new child elements appended\n  to the parent.\n- It improves performance as the creation of the tippy instances is deferred\n  until they are triggered for the first time.\n\n#### Usage\n\nYour markup should have a structure like this example:\n\n```html\n<div class=\"parent\">\n  <button class=\"child\">Text</button>\n  <button class=\"child\">Text</button>\n  <button class=\"child\">Text</button>\n</div>\n```\n\nPass a `targets` argument to the `delegate()` addon function (the same type the\n`tippy()` function can accept) which represents the parent element(s) that\nshould act as a delegate, and a `target` prop representing a CSS selector that\nshould match the child elements which should receive a tippy.\n\n```js\nimport {delegate} from 'tippy.js';\n\ndelegate('#parent', {\n  target: '.child',\n});\n```\n\nIn the CDN (`umd`) version, it's available as `tippy.delegate()`\n\n#### Return type\n\nBecause `delegate()` can create many different instances, it returns an opaque\nvalue depending on the type supplied, just like `tippy()`.\n\n```js\nconst delegateInstances = delegate('.parent', {\n  target: '.child',\n}); // Instance[]\n\nconst delegateInstance = delegate(parentElement, {\n  target: '.child',\n}); // Instance\n```\n\n#### Cleanup\n\nBy default, when you destroy a delegate instance, it also destroys any child\ninstances that may have been created by it. If you want to prevent this\nbehavior, pass `false` as an argument:\n\n```js\nconst delegateInstance = delegate(parentElement, {\n  target: '.child',\n});\n\n// Prevents further creation and destroys any created child tippy instances\ndelegateInstance.destroy();\n// Prevents further creation only\ndelegateInstance.destroy(false);\n```\n\n#### Polyfill\n\nThis addon uses `Element.prototype.closest()`, which is not supported in older\nbrowsers. You will need to polyfill this method to get full support.\n"
  },
  {
    "path": "website/src/pages/v6/ajax.mdx",
    "content": "---\ntitle: AJAX\npath: /v6/ajax/\nindex: 10\n---\n\nimport Ajax from '../../components/examples/Ajax';\n\nInitiating AJAX requests is facilitated by lifecycle hooks. This allows you to\ndo very powerful things. For example, let's say you wanted to show a new image\ninside a tooltip each time it gets shown:\n\n<Demo>\n  <Ajax>Hover for a new image</Ajax>\n</Demo>\n\nLet's walk through a little tutorial to learn how to do this.\n\nFirst, let's setup our HTML:\n\n```html\n<button id=\"ajax-tippy\">Hover for a new image</button>\n```\n\nNow, let's add some JavaScript:\n\n```js\ntippy('#ajax-tippy', {\n  content: 'Loading...',\n});\n```\n\nHere's the result so far (nothing happens yet!):\n\n<Demo>\n  <Tippy content=\"Loading...\" animation=\"fade\" animateFill={false}>\n    <Button>Hover for a new image</Button>\n  </Tippy>\n</Demo>\n\nTo initiate the AJAX request every time the tippy shows, use the `onShow`\nlifecycle:\n\n```js\ntippy('#ajax-tippy', {\n  content: 'Loading...',\n  onShow(instance) {\n    // Code here is executed every time the tippy shows\n  },\n});\n```\n\nUsing `fetch`, we can fetch a random image from an Unsplash API:\n\n```js\ntippy('#ajax-tippy', {\n  // ...\n  onShow(instance) {\n    fetch('https://unsplash.it/200/?random')\n      .then((response) => response.blob())\n      .then((blob) => {\n        // Convert the blob into a URL\n        const url = URL.createObjectURL(blob);\n        // Create an image\n        const image = new Image();\n        image.width = 200;\n        image.height = 200;\n        image.style.display = 'block';\n        image.src = url;\n        // Update the tippy content with the image\n        instance.setContent(image);\n      })\n      .catch((error) => {\n        // Fallback if the network request failed\n        instance.setContent(`Request failed. ${error}`);\n      });\n  },\n});\n```\n\nThere are currently two problems with this:\n\n- When the tippy is hidden, it doesn't reset back to `Loading...`\n- If you quickly hover in and out of the tippy, it initiates many different\n  requests and each image rapidly replaces the old one as each request finishes\n\nThe first one can be solved by using the `onHidden` lifecycle, which is executed\nonce the tippy fully transitions out and is unmounted from the DOM:\n\n```js\ntippy('#ajax-tippy', {\n  // ...\n  onHidden(instance) {\n    instance.setContent('Loading...');\n  },\n});\n```\n\nThe second one requires some state:\n\n```js\ntippy('#ajax-tippy', {\n  // ...\n  onCreate(instance) {\n    // Setup our own custom state properties\n    instance._isFetching = false;\n    instance._src = null;\n    instance._error = null;\n  },\n  onShow(instance) {\n    if (instance._isFetching || instance._src || instance._error) {\n      return;\n    }\n\n    instance._isFetching = true;\n\n    fetch('https://unsplash.it/200/?random')\n      .then((response) => response.blob())\n      .then((blob) => {\n        const src = URL.createObjectURL(blob);\n        instance._src = src;\n        // ...\n      })\n      .catch((error) => {\n        instance._error = error;\n        instance.setContent(`Request failed. ${error}`);\n      })\n      .finally(() => {\n        instance._isFetching = false;\n      });\n  },\n  onHidden(instance) {\n    instance.setContent('Loading...');\n    // Unset these properties so new network requests can be initiated\n    instance._src = null;\n    instance._error = null;\n  },\n});\n```\n"
  },
  {
    "path": "website/src/pages/v6/all-props.mdx",
    "content": "---\ntitle: All Props\npath: /v6/all-props/\nindex: 4\n---\n\nimport {BOLD_HELLO} from '../../utils';\nimport RenderIcon from '../../components/RenderIcon';\nimport PluginIcon from '../../components/PluginIcon';\n\n\"Props\" are configurable properties you can pass optionally to the `tippy()`\nconstructor.\n\n```js\ntippy(targets, {\n  // props\n});\n```\n\n- [allowHTML](#allowhtml) <RenderIcon />\n- [animateFill](#animatefill) <RenderIcon /><PluginIcon />\n- [animation](#animation) <RenderIcon />\n- [appendTo](#appendto)\n- [aria](#aria)\n- [arrow](#arrow) <RenderIcon />\n- [content](#content) <RenderIcon />\n- [delay](#delay)\n- [duration](#duration) <RenderIcon />\n- [followCursor](#followcursor) <PluginIcon />\n- [getReferenceClientRect](#getreferenceclientrect)\n- [hideOnClick](#hideonclick)\n- [ignoreAttributes](#ignoreattributes)\n- [inertia](#inertia) <RenderIcon />\n- [inlinePositioning](#inlinepositioning) <PluginIcon />\n- [interactive](#interactive)\n- [interactiveBorder](#interactiveborder)\n- [interactiveDebounce](#interactivedebounce)\n- [maxWidth](#maxwidth) <RenderIcon />\n- [moveTransition](#movetransition)\n- [offset](#offset)\n- [onAfterUpdate](#onafterupdate)\n- [onBeforeUpdate](#onbeforeupdate)\n- [onClickOutside](#onclickoutside)\n- [onCreate](#oncreate)\n- [onDestroy](#ondestroy)\n- [onHidden](#onhidden)\n- [onHide](#onhide)\n- [onMount](#onmount)\n- [onShow](#onshow)\n- [onShown](#onshown) <RenderIcon />\n- [onTrigger](#ontrigger)\n- [onUntrigger](#onuntrigger)\n- [placement](#placement)\n- [plugins](#plugins)\n- [popperOptions](#popperoptions)\n- [render](#render)\n- [role](#role) <RenderIcon />\n- [showOnCreate](#showoncreate)\n- [sticky](#sticky) <PluginIcon />\n- [theme](#theme) <RenderIcon />\n- [touch](#touch)\n- [trigger](#trigger)\n- [triggerTarget](#triggertarget)\n- [zIndex](#zindex)\n\n---\n\n### allowHTML <RenderIcon large />\n\nDetermines if `content` strings are parsed as HTML instead of text.\n\n> **Warning**\n>\n> Make sure you are sanitizing any user data if rendering HTML to prevent XSS\n> attacks.\n\n```js\ntippy(targets, {\n  // default\n  allowHTML: false,\n  // parse `content` strings as HTML\n  allowHTML: true,\n});\n```\n\n<Demo>\n  <Tippy content={BOLD_HELLO} allowHTML={true}>\n    <Button>allowHTML: true</Button>\n  </Tippy>\n  <Tippy content=\"<b>Hello</b>\" allowHTML={false}>\n    <Button>allowHTML: false</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### animateFill <RenderIcon large /><PluginIcon large />\n\nDetermines if the background fill color of the tippy should be animated.\n\n```js\ntippy(targets, {\n  // default\n  animateFill: false,\n  // enable it\n  animateFill: true,\n});\n```\n\n> **Plugin**\n>\n> When using modules (esm), you must import this plugin to use it.\n>\n> You must also import the `dist/backdrop.css` & `animations/shift-away.css`\n> stylesheets for styling to work.\n\n```js\nimport tippy, {animateFill} from 'tippy.js';\nimport 'tippy.js/dist/backdrop.css';\nimport 'tippy.js/animations/shift-away.css';\n\ntippy(targets, {\n  animateFill: true,\n  plugins: [animateFill],\n});\n```\n\n<Demo>\n  <Tippy animateFill={true}>\n    <Button>animateFill: true</Button>\n  </Tippy>\n  <Tippy animateFill={false}>\n    <Button>animateFill: false</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### animation <RenderIcon large />\n\nThe type of transition animation. See [Animations](../animations/) for details.\n\n```js\ntippy(targets, {\n  // default\n  animation: 'fade',\n});\n```\n\n> **Note**\n>\n> This is `false` by default when using [Headless Tippy](../headless-tippy/).\n\n---\n\n### appendTo\n\nThe element to append the tippy to. If `interactive: true`, the default behavior\nis `appendTo: \"parent\"`. See [Accessibility](../accessibility/#interactivity)\nfor more information.\n\nSometimes the tippy needs to be appended to a different DOM context due to\naccessibility, clipping, or z-index issues.\n\n```js\ntippy(targets, {\n  // default (takes reference as an argument)\n  appendTo: () => document.body,\n  // append to reference's parentNode\n  appendTo: 'parent',\n  // append to an Element\n  appendTo: element,\n});\n```\n\n---\n\n### aria\n\nThe aria attribute configuration. Both properties are optional:\n\n- `content`: The `aria-*` attribute applied to the reference element to announce\n  the tippy content.\n- `expanded`: Whether to add an `aria-expanded` attribute to the reference\n  element.\n\n```js\ntippy(targets, {\n  // default\n  aria: {\n    // `null` when interactive: true, otherwise \"describedby\"\n    content: 'auto',\n    // matches `interactive` boolean\n    expanded: 'auto',\n  },\n\n  // announce as a label rather than a description\n  // the content will also be announced with `interactive: true`\n  aria: {\n    content: 'labelledby',\n  },\n\n  // to abide by strict WCAG 2.1 rules with `interactive: true` to make it\n  // hoverable if it's not actually interactive, but the content will still be\n  // announced\n  aria: {\n    content: 'describedby',\n  },\n\n  // disable completely, left up to you to control\n  aria: {\n    content: null,\n    expanded: false,\n  },\n});\n```\n\n---\n\n### arrow <RenderIcon large />\n\nDetermines if the tippy has an arrow.\n\n```js\ntippy(targets, {\n  // default\n  arrow: true,\n  // disable arrow\n  arrow: false,\n  // custom arrow string\n  arrow: '<svg>...</svg>',\n  // custom arrow element\n  arrow: svgElement,\n});\n```\n\n> **Warning**\n>\n> A string is parsed as `.innerHTML`. Don't pass unknown user data to this prop.\n\nTo use the default round arrow, import `roundArrow` from the package\n(`tippy.roundArrow` in the `umd` version) and pass it as the value.\n\nYou must also import `dist/svg-arrow.css` when using SVG arrows for styling to\nwork.\n\n```js\nimport tippy, {roundArrow} from 'tippy.js';\nimport 'tippy.js/dist/svg-arrow.css';\n\ntippy(targets, {\n  arrow: roundArrow,\n});\n```\n\n<Demo>\n  <Tippy arrow={true}>\n    <Button>arrow: true</Button>\n  </Tippy>\n  <Tippy arrow={false}>\n    <Button>arrow: false</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### content <RenderIcon large />\n\nThe content of the tippy.\n\n```js\ntippy(targets, {\n  // default\n  content: '',\n  // string\n  content: 'Hello',\n  // Element\n  content: document.createElement('div'),\n  // (reference) => string | Element\n  content: (reference) => reference.getAttribute('title'),\n});\n```\n\n> **Note**\n>\n> To render strings as HTML, set `allowHTML: true`. This can open you up to XSS\n> attacks, so be careful.\n\n---\n\n### delay\n\nDelay in ms once a trigger event is fired before a tippy shows or hides.\n\n```js\ntippy(targets, {\n  // default\n  delay: 0,\n  // show and hide delay are 100ms\n  delay: 100,\n  // show delay is 100ms, hide delay is 200ms\n  delay: [100, 200],\n  // show delay is 100ms, hide delay is the default\n  delay: [100, null],\n});\n```\n\n<Demo>\n  <Tippy delay={400}>\n    <Button>delay: 400</Button>\n  </Tippy>\n  <Tippy delay={[500, 250]}>\n    <Button>delay: [500, 250]</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### duration <RenderIcon large />\n\nDuration in ms of the transition animation.\n\n```js\ntippy(targets, {\n  // default\n  duration: [300, 250],\n  // show and hide durations are 100ms\n  duration: 100,\n  // show duration is 100ms, hide duration is 200ms\n  duration: [100, 200],\n  // show duration is 100ms, hide duration is the default\n  duration: [100, null],\n});\n```\n\n<Demo>\n  <Tippy duration={1000}>\n    <Button>duration: 1000</Button>\n  </Tippy>\n  <Tippy duration={[500, 0]}>\n    <Button>duration: [500, 0]</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### followCursor <PluginIcon large />\n\nDetermines if the tippy follows the user's mouse cursor.\n\n```js\ntippy(targets, {\n  // default\n  followCursor: false,\n  // follow on both x and y axes\n  followCursor: true,\n  // follow on x axis\n  followCursor: 'horizontal',\n  // follow on y axis\n  followCursor: 'vertical',\n  // follow until it shows (taking into account `delay`)\n  followCursor: 'initial',\n});\n```\n\n> **Plugin**\n>\n> When using modules (esm), you must import this plugin to use it.\n\n```js\nimport tippy, {followCursor} from 'tippy.js';\n\ntippy(targets, {\n  followCursor: true,\n  plugins: [followCursor],\n});\n```\n\n<Demo>\n  <Tippy followCursor={true}>\n    <Button>followCursor: true</Button>\n  </Tippy>\n  <Tippy followCursor=\"horizontal\">\n    <Button>followCursor: \"horizontal\"</Button>\n  </Tippy>\n  <Tippy followCursor=\"initial\" delay={400}>\n    <Button>followCursor: \"initial\"</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### getReferenceClientRect\n\nUsed as the positioning reference for the tippy.\n\n```js\ntippy(targets, {\n  // default (uses the reference passed as first argument)\n  getReferenceClientRect: null,\n  // function that returns a ClientRect object\n  getReferenceClientRect: () => ({\n    width: 100,\n    height: 100,\n    left: 100,\n    right: 200,\n    top: 100,\n    bottom: 200,\n  }),\n});\n```\n\n---\n\n### hideOnClick\n\nDetermines if the tippy hides upon clicking the reference or outside of the\ntippy. The behavior can depend upon the `trigger` events used.\n\n```js\ntippy(targets, {\n  // default\n  hideOnClick: true,\n  // never hide upon clicking\n  hideOnClick: false,\n  // hide only upon clicking the reference, but not outside\n  hideOnClick: 'toggle',\n});\n```\n\n`hideOnClick: true` with `trigger: \"click\"`:\n\n<Demo>\n  <Tippy hideOnClick={true} trigger=\"click\">\n    <Button>trigger: \"click\"</Button>\n  </Tippy>\n</Demo>\n\n`hideOnClick: \"toggle\"` with `trigger: \"click\"`:\n\n<Demo>\n  <Tippy hideOnClick=\"toggle\" trigger=\"click\">\n    <Button>trigger: \"click\"</Button>\n  </Tippy>\n</Demo>\n\n`hideOnClick: false` with `trigger: \"mouseenter\"` (a `click` trigger will never\nhide):\n\n<Demo>\n  <Tippy hideOnClick={false} trigger=\"mouseenter\">\n    <Button>trigger: \"mouseenter\"</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### ignoreAttributes\n\nWhen using UI (component) libraries like React, this is generally not necessary\nand slows down initialization perf a bit.\n\n```js\ntippy(targets, {\n  // default\n  ignoreAttributes: false,\n  // don't consider `data-tippy-*` attributes on the reference element\n  ignoreAttributes: true,\n});\n```\n\n---\n\n### inertia <RenderIcon large />\n\nDetermines if a (customizable) CSS spring-like animation is applied to the\ntransition animation.\n\nChanging the show duration to a higher value makes this look better.\n\n```js\ntippy(targets, {\n  // default\n  inertia: false,\n  // enable it\n  inertia: true,\n});\n```\n\n```css\n.tippy-box[data-inertia][data-state='visible'] {\n  transition-timing-function: cubic-bezier(...);\n}\n```\n\n<Demo>\n  <Tippy animation=\"scale\" inertia={true} duration={[400, 200]}>\n    <Button>animation: \"scale\"</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### inlinePositioning <PluginIcon large />\n\nProvides enhanced support for `display: inline` elements. It will choose the\nmost appropriate rect based on the placement.\n\n```js\ntippy(targets, {\n  // default\n  inlinePositioning: false,\n  // enable it\n  inlinePositioning: true,\n});\n```\n\n> **Plugin**\n>\n> When using modules (esm), you must import this plugin to use it.\n\n```js\nimport tippy, {inlinePositioning} from 'tippy.js';\n\ntippy(targets, {\n  inlinePositioning: true,\n  plugins: [inlinePositioning],\n});\n```\n\n---\n\n### interactive\n\nDetermines if the tippy has interactive content inside of it, so that it can be\nhovered over and clicked inside without hiding.\n\n```js\ntippy(targets, {\n  // default\n  interactive: false,\n  // enable it\n  interactive: true,\n});\n```\n\n> **Note**\n>\n> When `true`, the tippy will be appended to the `targets` parent element for\n> accessibility reasons by default. This means it can inherit styling, such as\n> `text-align: center`. If you are experiencing issues with positioning, add\n> `appendTo: () => document.body` to your props.\n\n<Demo>\n  <Tippy interactive={false}>\n    <Button>interactive: false</Button>\n  </Tippy>\n  <Tippy interactive={true}>\n    <Button>interactive: true</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### interactiveBorder\n\nDetermines the size of the invisible border around the tippy that will prevent\nit from hiding if the cursor left it.\n\n```js\ntippy(targets, {\n  // default\n  interactiveBorder: 2,\n  // 30px\n  interactiveBorder: 30,\n});\n```\n\n<Demo>\n  <Tippy interactive={true} interactiveBorder={5}>\n    <Button>interactiveBorder: 5</Button>\n  </Tippy>\n  <Tippy interactive={true} interactiveBorder={30}>\n    <Button>interactiveBorder: 30</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### interactiveDebounce\n\nDetermines the time in ms to debounce the interactive hide handler when the\ncursor leaves the tippy's interactive region.\n\nOffers a temporal (rather than spacial) alternative to `interactiveBorder`,\nalthough it can be used in conjunction with it.\n\n```js\ntippy(targets, {\n  // default\n  interactiveDebounce: 0,\n  // 75ms\n  interactiveDebounce: 75,\n});\n```\n\n<Demo>\n  <Tippy interactive={true} interactiveDebounce={0}>\n    <Button>interactiveDebounce: 0</Button>\n  </Tippy>\n  <Tippy interactive={true} interactiveDebounce={75}>\n    <Button>interactiveDebounce: 75</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### maxWidth <RenderIcon large />\n\nSpecifies the maximum width of the tippy. Useful to prevent it from being too\nhorizontally wide to read.\n\n```js\ntippy(targets, {\n  // default\n  maxWidth: 350,\n  // no maxWidth\n  maxWidth: 'none',\n});\n```\n\n<Demo>\n  <Tippy\n    content=\"A large amount of content to demonstrate the differences in maxWidth.\"\n    maxWidth=\"none\"\n  >\n    <Button>maxWidth: \"none\"</Button>\n  </Tippy>\n  <Tippy\n    content=\"A large amount of content to demonstrate the differences in maxWidth.\"\n    maxWidth={200}\n  >\n    <Button>maxWidth: 200</Button>\n  </Tippy>\n</Demo>\n\n> **Note**\n>\n> If the viewport's width is smaller than `maxWidth`, tippy's core CSS ensures\n> the tippy remains smaller than the screen.\n\n---\n\n### moveTransition\n\nSpecifies the transition applied to the root positioned popper node. This\ndescribes the transition between \"moves\" (or position updates) of the popper\nelement when it e.g. flips or changes target location.\n\n```js\ntippy(targets, {\n  // default\n  moveTransition: '',\n  // custom transition\n  moveTransition: 'transform 0.2s ease-out',\n});\n```\n\n---\n\n### offset\n\nDisplaces the tippy from its reference element in pixels (skidding and\ndistance).\n\nSee [Popper's docs](https://popper.js.org/docs/v2/modifiers/offset/) for\ndetails.\n\n```js\ntippy(targets, {\n  // default [skidding, distance]\n  offset: [0, 10],\n});\n```\n\n<Demo>\n  <Tippy offset={[20, 5]}>\n    <Button>offset: [20, 5]</Button>\n  </Tippy>\n  <Tippy offset={[10, 20]}>\n    <Button>offset: [10, 20]</Button>\n  </Tippy>\n</Demo>\n\n---\n\n### onAfterUpdate\n\nInvoked after the tippy has been updated (via `.setProps()`).\n\n```js\ntippy(targets, {\n  onAfterUpdate(instance, partialProps) {\n    // ...\n  },\n});\n```\n\n---\n\n### onBeforeUpdate\n\nInvoked before the tippy has been updated (via `.setProps()`).\n\n```js\ntippy(targets, {\n  onBeforeUpdate(instance, partialProps) {\n    // ...\n  },\n});\n```\n\n---\n\n### onClickOutside\n\nInvoked when the user clicks anywhere outside of the tippy or reference element.\n\n```js\ntippy(targets, {\n  onClickOutside(instance, event) {\n    // ...\n  },\n});\n```\n\n---\n\n### onCreate\n\nInvoked once the tippy has been created.\n\n```js\ntippy(targets, {\n  onCreate(instance) {\n    // ...\n  },\n});\n```\n\n---\n\n### onDestroy\n\nInvoked once the tippy has been destroyed.\n\n```js\ntippy(targets, {\n  onDestroy(instance) {\n    // ...\n  },\n});\n```\n\n---\n\n### onHidden\n\nInvoked once the tippy has been fully hidden and unmounted from the DOM.\n\n```js\ntippy(targets, {\n  onHidden(instance) {\n    // ...\n  },\n});\n```\n\n---\n\n### onHide\n\nInvoked once the tippy begins to hide.\n\n```js\ntippy(targets, {\n  onHide(instance) {\n    // ...\n  },\n});\n```\n\n> You can optionally `return false` from this lifecycle to cancel a hide based\n> on a condition.\n\n---\n\n### onMount\n\nInvoked once the tippy has been mounted to the DOM (and the popperInstance\ncreated).\n\n```js\ntippy(targets, {\n  onMount(instance) {\n    // ...\n  },\n});\n```\n\n---\n\n### onShow\n\nInvoked once the tippy begins to show.\n\n```js\ntippy(targets, {\n  onShow(instance) {\n    // ...\n  },\n});\n```\n\n> You can optionally `return false` from this lifecycle to cancel a show based\n> on a condition.\n\n---\n\n### onShown <RenderIcon large />\n\nInvoked once the tippy has been fully transitioned in.\n\n> **Note**\n>\n> Since this is achieved via CSS `transitionend`, it relies on your own event\n> listeners if using a custom `render` function. You'll need to call the\n> lifecycle manually in this case.\n\n```js\ntippy(targets, {\n  onShown(instance) {\n    // ...\n  },\n});\n```\n\n---\n\n### onTrigger\n\nInvoked once the tippy has been triggered by a DOM event (e.g. `mouseenter`).\n\n```js\ntippy(targets, {\n  onTrigger(instance, event) {\n    // ...\n  },\n});\n```\n\n---\n\n### onUntrigger\n\nInvoked once the tippy has been untriggered by a DOM event (e.g. `mouseleave`).\n\n```js\ntippy(targets, {\n  onUntrigger(instance, event) {\n    // ...\n  },\n});\n```\n\n---\n\n### placement\n\nThe _preferred_ placement of the tippy. Note that Popper's `flip` modifier can\nchange this to the opposite placement if it has more space.\n\n```js\ntippy(targets, {\n  // default\n  placement: 'top',\n\n  // full list:\n  placement: 'top-start',\n  placement: 'top-end',\n\n  placement: 'right',\n  placement: 'right-start',\n  placement: 'right-end',\n\n  placement: 'bottom',\n  placement: 'bottom-start',\n  placement: 'bottom-end',\n\n  placement: 'left',\n  placement: 'left-start',\n  placement: 'left-end',\n\n  // choose the side with most space\n  placement: 'auto',\n  placement: 'auto-start',\n  placement: 'auto-end',\n});\n```\n\n---\n\n### plugins\n\nPlugins to use. See [Plugins](../plugins/) for details.\n\n> **Note**\n>\n> If using `tippy.setDefaultProps()`, specifying default plugins causes the\n> default plugins to be merged with plugins specified in `tippy()` constructor\n> calls.\n\n```js\ntippy(targets, {\n  // default\n  plugins: [],\n});\n```\n\n---\n\n### popperOptions\n\nSpecifies custom Popper options. This gives you full control over the tippy's\npositioning. See [Popper's docs](https://popper.js.org/docs/v2/) for details.\n\n```js\ntippy(targets, {\n  // default\n  popperOptions: {},\n  // detailed example\n  popperOptions: {\n    strategy: 'fixed',\n    modifiers: [\n      {\n        name: 'flip',\n        options: {\n          fallbackPlacements: ['bottom', 'right'],\n        },\n      },\n      {\n        name: 'preventOverflow',\n        options: {\n          altAxis: true,\n          tether: false,\n        },\n      },\n    ],\n  },\n});\n```\n\n---\n\n### render\n\nSpecifies a custom render function to use. This allows you to create your own\ntippy element DOM from scratch. Note that all `render` (R) related props are\nentirely controlled by you when specifying a custom function.\n\nSee [Headless Tippy](../headless-tippy/) for details.\n\n---\n\n### role <RenderIcon large />\n\nSpecifies the `role` attribute on the tippy element.\n\n```js\ntippy(targets, {\n  // default\n  role: 'tooltip',\n});\n```\n\n---\n\n### showOnCreate\n\nDetermines if the tippy is shown once it gets created, respecting `delay`.\n\n```js\ntippy(targets, {\n  // default\n  showOnCreate: false,\n  // enable it\n  showOnCreate: true,\n});\n```\n\n---\n\n### sticky <PluginIcon large />\n\nDetermines if the tippy sticks to the reference element while it is mounted.\nThis is usually _not_ needed, but is useful if the reference element's position\nis animating, or to automatically update the tippy position without needing to\nmanually do it in certain cases where the DOM layout changes.\n\n> **Note**\n>\n> This has a performance cost since checks are run on every animation frame. Use\n> this only when necessary!\n\n```js\ntippy(targets, {\n  // default\n  sticky: false,\n  // enable it\n  sticky: true,\n  // only check the \"reference\" rect for changes\n  sticky: 'reference',\n  // only check the \"popper\" rect for changes\n  sticky: 'popper',\n});\n```\n\n> **Plugin**\n>\n> When using modules (esm), you must import this plugin to use it.\n\n```js\nimport tippy, {sticky} from 'tippy.js';\n\ntippy(targets, {\n  sticky: true,\n  plugins: [sticky],\n});\n```\n\n---\n\n### theme <RenderIcon large />\n\nDetermines the theme of the tippy element. The core CSS defaults to a dark\n`#333` theme. This can be overridden by a custom theme. See [Themes](../themes/)\nfor details.\n\n```js\ntippy(targets, {\n  // default\n  theme: '',\n  // custom theme\n  theme: 'tomato',\n});\n```\n\n---\n\n### touch\n\nDetermines the behavior on touch devices.\n\n```js\ntippy(targets, {\n  // default\n  touch: true,\n  // disable tippy from showing on touch devices\n  touch: false,\n  // require pressing & holding the screen to show it\n  touch: 'hold',\n  // same as above, but long-press behavior\n  touch: ['hold', 500],\n});\n```\n\n---\n\n### trigger\n\nDetermines the events that cause the tippy to show. Multiple event names are\nseparated by spaces.\n\n```js\ntippy(targets, {\n  // default\n  trigger: 'mouseenter focus',\n  // others:\n  trigger: 'click',\n  trigger: 'focusin',\n  trigger: 'mouseenter click',\n  // only programmatically trigger it\n  trigger: 'manual',\n});\n```\n\n---\n\n### triggerTarget\n\nThe element(s) that the trigger event listeners are added to. Allows you to\nseparate the tippy's positioning from its trigger source.\n\n```js\ntippy(targets, {\n  // default (reference is used)\n  triggerTarget: null,\n  // Element\n  triggerTarget: someElement,\n  // Element[]\n  triggerTarget: [someElement1, someElement2],\n});\n```\n\n---\n\n### zIndex\n\nSpecifies the `z-index` CSS on the root popper node.\n\n```js\ntippy(targets, {\n  // default\n  zIndex: 9999,\n});\n```\n"
  },
  {
    "path": "website/src/pages/v6/animations.mdx",
    "content": "---\ntitle: Animations\npath: /v6/animations/\nindex: 7\n---\n\nimport ImageTransition from '../../components/examples/ImageTransition';\nimport TextTransition from '../../components/examples/TextTransition';\n\nTippies use an opacity `fade` transition by default.\n\n### Included animations\n\nThe package comes with extra animations for you to use:\n\n- `shift-away`\n- `shift-toward`\n- `scale`\n- `perspective`\n\nThey need to be\n[imported separately](../getting-started/#optional-extra-imports).\n\n```js\nimport 'tippy.js/animations/scale.css';\n```\n\nPass the animation name as the `animation` prop:\n\n```js\ntippy('button', {\n  animation: 'scale',\n});\n```\n\nEach of these animations also has 3 variants (normal, subtle, and extreme) using\nthe following format:\n\n```js\nimport 'tippy.js/animations/scale.css';\nimport 'tippy.js/animations/scale-subtle.css';\nimport 'tippy.js/animations/scale-extreme.css';\n```\n\n### Custom animations\n\nTo create your own animation:\n\n- Specify the animation name in the `[data-animation]` attribute selector\n- Target the visibility state of the tippy: `[data-state=\"hidden\"]` or\n  `[data-state=\"visible\"]`\n- Depending on the animation, target the placement of the tippy too: e.g.\n  `[data-placement^=\"top\"]`\n\n```css\n.tippy-box[data-animation='rotate'][data-state='hidden'] {\n  opacity: 0;\n  transform: rotate(90deg);\n}\n```\n\n```js\ntippy('button', {\n  animation: 'rotate',\n});\n```\n\n### Inertia\n\nThere's a prop named `inertia` that adds an elastic inertial effect to the\ntippy, which is a limited CSS-only way to mimic spring physics.\n\n```js\ntippy('button', {\n  inertia: true,\n});\n```\n\nYou can customize this prop in your CSS:\n\n```css\n.tippy-box[data-inertia][data-state='visible'] {\n  transition-timing-function: cubic-bezier(...);\n}\n```\n\n### Material filling effect\n\n[Seen here](../../#material-filling-effect).\n\nImport the `animateFill` plugin, plus `dist/backdrop.css` &\n`animations/shift-away.css` stylesheets.\n\n```js\nimport tippy, {animateFill} from 'tippy.js';\nimport 'tippy.js/dist/backdrop.css';\nimport 'tippy.js/animations/shift-away.css';\n\ntippy(targets, {\n  animateFill: true,\n  plugins: [animateFill],\n});\n```\n\n### CSS animations\n\nMaybe plain transitions aren't enough for your use case. You can also use CSS\nanimations (e.g. `animate.css`):\n\n```js\ntippy('button', {\n  onMount(instance) {\n    const box = instance.popper.firstElementChild;\n    requestAnimationFrame(() => {\n      box.classList.add('animated');\n      box.classList.add('wobble');\n    });\n  },\n  onHidden(instance) {\n    const box = instance.popper.firstElementChild;\n    box.classList.remove('animated');\n    box.classList.remove('wobble');\n  },\n});\n```\n\nYou can also use `@keyframes` and add the `animation` property to your animation\nselector too.\n\n<!--\n### Dimensions transition\n\nWhile a tippy is showing, the content inside of it may change. How do you\nsmoothly transition its dimensions? By default, it instantly changes size when\nthe content is updated. It turns out this is quite complex to do, but possible.\n\n#### Partially dynamic\n\nView the [CodePen demo](https://codepen.io/atomiks/pen/LgjMbW).\n\n#### Fully dynamic\n\n<Demo>\n  <span>\n    <ImageTransition />\n  </span>\n  <TextTransition />\n</Demo>\n\nCode for fully dynamic transitions is still being developed and it is highly\nexperimental at this stage. The documentation will be updated once it's ready.\n-->\n"
  },
  {
    "path": "website/src/pages/v6/browser-support.mdx",
    "content": "---\ntitle: Browser Support\npath: /v6/browser-support/\nindex: 18\n---\n\nAll modern browsers are supported. Proxy mobile browsers like Opera Mini are not\nsupported.\n\n### IE11\n\nIE11 (and other older browsers) is supported with the following polyfills:\n\n- `Promise`\n- `Object.assign`\n- `Array.prototype.find`\n\nIf not already polyfilling these in your app, the following script tag using the\npolyfill.io service placed before Tippy's scripts will polyfill these.\n\n```html\n<script src=\"https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.find,Promise,Object.assign\"></script>\n```\n\nIt won't add extra cost (besides a negligible bundle size and HTTP request) to\nbrowsers that already support those built-in APIs.\n\n#### SVG in IE11\n\nIf you need to support SVG elements in IE11, you will need to include a polyfill\nfor `SVGElement.prototype.contains`.\n\nThe polyfill is small:\n\n```js\nif (!SVGElement.prototype.contains) {\n  SVGElement.prototype.contains = HTMLDivElement.prototype.contains;\n}\n```\n"
  },
  {
    "path": "website/src/pages/v6/constructor.mdx",
    "content": "---\ntitle: Constructor\npath: /v6/constructor/\nindex: 2\n---\n\nThe `tippy()` constructor (a plain function) creates individual tippy instances.\nTo give the tippy content you have two options:\n\n### Attribute\n\nWith some elements on the document:\n\n```html\n<button data-tippy-content=\"Tooltip\">Text</button>\n<button data-tippy-content=\"Another Tooltip\">Text</button>\n```\n\nCall the `tippy()` constructor with a CSS selector matching them:\n\n```js\ntippy('[data-tippy-content]');\n```\n\n### Prop\n\nIf targeting a single element, you can use the `content` prop instead of the\nattribute:\n\n```js\ntippy('#singleElement', {\n  content: 'Tooltip',\n});\n```\n\n> **Note**\n>\n> Tippy will create tooltips for elements even if you forget to give them\n> content, resulting in an odd small shaped tooltip. Ensure your CSS selector is\n> specific enough to guarantee their content.\n\n### Target types\n\nThe first argument you pass to `tippy()` is the targets you want to give\ntooltips to. This can represent one or many different elements.\n\n```js\n// String (CSS selector matching elements on the document)\ntippy('#id');\ntippy('.class');\ntippy('[data-tippy-content]');\n\n// Element\ntippy(document.getElementById('my-element'));\n\n// Element[]\ntippy([element1, element2, element3]);\n\n// NodeList\ntippy(document.querySelectorAll('.my-elements'));\n```\n\n### Disabled elements\n\nIf an element is disabled, you will need to use a wrapper element (`<span>` or\n`<div>`) in order for the tippy to work. Elements with the disabled attribute\naren't interactive, meaning users cannot focus, hover, or click them to trigger\na tippy.\n\n```html\n<!-- Won't work! -->\n<button data-tippy-content=\"Tooltip\" disabled>Text</button>\n\n<!-- Wrapper <span> will work -->\n<span data-tippy-content=\"Tooltip\" tabindex=\"0\">\n  <button disabled>Text</button>\n</span>\n```\n\nPlease note that this has accessibility concerns and should be avoided if\npossible.\n"
  },
  {
    "path": "website/src/pages/v6/customization.mdx",
    "content": "---\ntitle: Customization\npath: /v6/customization/\nindex: 3\n---\n\n`tippy()` takes an object of optional props (configuration properties) as a\nsecond argument to customize your tippies:\n\n```js\ntippy('button', {\n  duration: 0,\n  arrow: false,\n  delay: [1000, 200],\n});\n```\n\nThese can also be specified on the element using data attributes:\n\n```html\n<button\n  data-tippy-duration=\"0\"\n  data-tippy-arrow=\"false\"\n  data-tippy-delay=\"[1000, 200]\"\n>\n  Text\n</button>\n```\n\n> **Note**\n>\n> Only JSON is valid in attributes.\n\n### Mixing attributes and props\n\nIt can be useful to use the function for \"global\" config and choose attributes\nfor individual config here and there:\n\n```html\n<button>Default</button>\n<button data-tippy-content=\"hello\">I have my own content</button>\n<button data-tippy-arrow=\"true\">I have my own option</button>\n```\n\n```js\n// Global config for all <button>s\ntippy('button', {\n  content: 'Global content',\n  trigger: 'click',\n});\n```\n\n### Default props\n\nOften you don't want to specify props over and over again when initializing\ntooltips. You can set the default props for every new tippy instance with the\n`tippy.setDefaultProps()` method:\n\n```js\ntippy.setDefaultProps({delay: 50});\n```\n"
  },
  {
    "path": "website/src/pages/v6/faq.mdx",
    "content": "---\ntitle: FAQ\npath: /v6/faq/\nindex: 16\n---\n\n### What syntax theme is used on this website?\n\nIt's a theme I made called\n[Moonlight](https://github.com/atomiks/moonlight-vscode-theme)!\n\n### Nothing is working\n\nMake sure Tippy's scripts are placed _before_ your own scripts, at the very\nbottom of the page, like so:\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>My page</title>\n  </head>\n  <body>\n    <button>Text</button>\n\n    <!-- Very end of the body -->\n    <script src=\"https://unpkg.com/@popperjs/core@2\"></script>\n    <script src=\"https://unpkg.com/tippy.js@6\"></script>\n    <script>\n      tippy('button', {content: 'tooltip'});\n    </script>\n  </body>\n</html>\n```\n\n### My tooltip appears cut off or is not showing at all\n\nWhen using `interactive: true`, the tippy may be invisible or appear cut off if\nyour reference element is in a container with:\n\n- CSS `position`\n- CSS `overflow`\n\nThere are a couple of solutions.\n\n1. Specify an `appendTo` element outside of the clipping container context. This\n   requires a focus management solution usually.\n\n```js\ntippy(targets, {\n  // ...\n  appendTo: document.body,\n});\n```\n\n2. Use `strategy: \"fixed\"` (this has some quirks on some browsers like Safari\n   regarding updating the position on scroll), so avoid it if possible.\n\n```js\ntippy(targets, {\n  // ...\n  popperOptions: {\n    strategy: 'fixed',\n  },\n});\n```\n\n### I'm getting Uncaught ReferenceError: process is not defined\n\nIf you're using the ESM or CJS versions and importing like this:\n\n```js\nimport tippy from 'tippy.js';\n// or\nconst tippy = require('tippy.js').default;\n```\n\nTippy uses a special expression to distinguish a development and production\nenvironment. For you, the developer, there are lots of warnings and error\nmessages to help your development experience. For your end users, all of this\nneeds to get stripped out because it reduces performance and increases bundle\nsize.\n\nTools like `create-react-app` and `Parcel` bundler handle this automatically.\n\n#### Browserify/Grunt/Gulp\n\n[View the following link](https://vuejs.org/v2/guide/deployment.html#With-Build-Tools).\n\n#### Rollup\n\nInstall the\n[`replace plugin`](https://www.npmjs.com/package/@rollup/plugin-replace).\n\n```js\nimport replace from '@rollup/plugin-replace';\n\nexport default {\n  // ...\n  plugins: [\n    // Production config\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('production'),\n    }),\n    // OR development config\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('development'),\n    }),\n    // You can also use process.env.NODE_ENV and set the env variables when\n    // running the rollup command to merge the above into one call\n  ],\n};\n```\n\n### How do I use the animations or themes stylesheets with the CDN?\n\nFor brevity, this documentation uses `import` syntax and assumes a module\nbundler environment. If you're using the CDN version, then you'll be using\n`<link>` tags to import separate CSS stylesheets.\n\n[See the example here](../getting-started/#optional-extra-imports).\n\n### What global side effects are there?\n\nThere are global listeners to determine the user's current input type (e.g.\n`touch`), and other UX helpers.\n\n### I can't click things inside the tooltip\n\nTo enable interactivity, set the `interactive` prop to `true`.\n\n### My tooltip is hiding instantly after showing\n\nIf you're using a `focus` trigger, for example on an `<input>`, make sure you\nalso set `hideOnClick: false`.\n\n### Changing data-tippy-\\* attributes does not update the tooltip\n\nUpdating the data-tippy-\\* attribute on an element will currently not update the\ntooltip. You must use the [`setProps()` method](../methods/#setprops) on a Tippy\ninstance.\n\nFor example, let's say you want to update the `theme` for tooltips when changing\nbetween dark and light mode:\n\n```js\nconst instance = tippy(element, {theme: 'custom-dark'});\n\n// When clicking the theme toggle button, you can do this:\ninstance.setProps({theme: 'custom-light'});\n```\n\nIt's also possible to attach a `MutationObserver` to the reference elements and\nobserve mutations to attributes if need be, then call `.setProps()` with the new\nvalues.\n\n### Can I use the `title` attribute?\n\nYes. The `content` prop can be a function that receives the reference element as\nan argument and returns a string or element.\n\n```js\ntippy('button', {\n  content(reference) {\n    const title = reference.getAttribute('title');\n    reference.removeAttribute('title');\n    return title;\n  },\n});\n```\n\nThe `title` attribute should be removed once you have its content so the\nbrowser's default tooltip isn't displayed along with the tippy.\n\n#### Plugin\n\nYou can create a plugin for this to generalize the behavior:\n\n```js\nconst titleAttribute = {\n  name: 'titleAttribute',\n  defaultValue: true,\n  fn() {\n    return {\n      onCreate(instance) {\n        if (!instance.props.titleAttribute) {\n          return;\n        }\n\n        const title = instance.reference.getAttribute('title');\n\n        if (title) {\n          instance.setContent(title);\n          instance.reference.removeAttribute('title');\n        }\n      },\n    };\n  },\n};\n```\n\nNote that the plugin does not take into account dynamic titles. Be cautious of\nwhy you might need this in the first place.\n\n### What's the difference between an addon and a plugin?\n\nAn **addon** is an external function that calls the `tippy()` constructor\nbecause it's controlling or creating many different tippy instances.\n\nA **plugin** is a plain object that hooks into, and adds functionality, to a\nsingle tippy instance that has already created.\n"
  },
  {
    "path": "website/src/pages/v6/getting-started.mdx",
    "content": "---\ntitle: Getting Started\npath: /v6/getting-started/\nindex: 1\n---\n\nThere are two ways to install the package.\n\n### 1. Package Manager\n\n```bash\n# npm\nnpm i tippy.js\n\n# Yarn\nyarn add tippy.js\n```\n\nIn your application, import the `tippy` module, and the core CSS:\n\n```js\nimport tippy from 'tippy.js';\nimport 'tippy.js/dist/tippy.css'; // optional for styling\n```\n\nThis assumes you're using a module bundler like webpack, Rollup, or Parcel. If\nyou're getting an error message about `process` inside the browser,\n[see the FAQ for help.](../faq/#im-getting-uncaught-referenceerror-process-is-not-defined)\n\nThe core CSS is not required, but provides a base styling for you to use. If\nyou'd like to use Tippy \"headless\" without any of the default element rendering\nor CSS, use [Headless Tippy](../headless-tippy/).\n\n### 2. CDN\n\n```html\n<!-- Development -->\n<script src=\"https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js\"></script>\n<script src=\"https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js\"></script>\n\n<!-- Production -->\n<script src=\"https://unpkg.com/@popperjs/core@2\"></script>\n<script src=\"https://unpkg.com/tippy.js@6\"></script>\n```\n\nPlace them at the very bottom of the `<body>`, ensuring they are placed before\nyour own scripts. The version numbers after `@` are important, make sure they\ndon't get removed.\n\n> **Note**\n>\n> The CSS automatically gets injected into `<head>` with the CDN\n> (`tippy-bundle`). With CSP enabled, you may need to separately link\n> `dist/tippy.css` and use `dist/tippy.umd.min.js` instead.\n\n### Usage\n\n```html\n<html>\n  <head>\n    <title>Tippy</title>\n  </head>\n  <body>\n    <button id=\"myButton\">My button</button>\n\n    <script src=\"https://unpkg.com/@popperjs/core@2\"></script>\n    <script src=\"https://unpkg.com/tippy.js@6\"></script>\n    <script>\n      // With the above scripts loaded, you can call `tippy()` with a CSS\n      // selector and a `content` prop:\n      tippy('#myButton', {\n        content: 'My tooltip!',\n      });\n    </script>\n  </body>\n</html>\n```\n\n### Component Wrappers\n\n#### React\n\nUsing React? Use the\n[official component package](https://github.com/atomiks/tippyjs-react) which\nintegrates well with React, allowing you to use Tippy declaratively.\n\n#### Ember\n\nThere is the unofficial [ember-tippy](https://github.com/nag5000/ember-tippy) addon\nfor Emberistas.\n\n### Optional extra imports\n\nFor brevity, this documentation shows imports via a module bundler in Node. If\nyou're using the CDN, you'll be using `<link>` tags instead.\n\nThis **optional** extra import in the documentation:\n\n```js\nimport 'tippy.js/animations/scale.css';\n```\n\nIs equivalent to this using a CDN in the browser:\n\n```html\n<link\n  rel=\"stylesheet\"\n  href=\"https://unpkg.com/tippy.js@6/animations/scale.css\"\n/>\n```\n"
  },
  {
    "path": "website/src/pages/v6/headless-tippy.mdx",
    "content": "---\ntitle: Headless Tippy\npath: /v6/headless-tippy/\nindex: 14\n---\n\n\"Headless Tippy\" refers to Tippy without any of the default element rendering or\nCSS. This allows you to create your own element from scratch and use Tippy for\nits logic only.\n\nThis means all props marked with the R symbol in [All Props](../all-props/) no\nlonger \"work\" by default, since it's your responsibility to create these\nfeatures.\n\n### Imports\n\nReplace your imports:\n\n```diff\n- import tippy from 'tippy.js';\n+ import tippy from 'tippy.js/headless';\n```\n\n```diff\n- <script src=\"https://unpkg.com/tippy.js@6\"></script>\n+ <script src=\"https://unpkg.com/tippy.js@6/headless/dist/tippy-headless.umd.min.js\"></script>\n```\n\nWhen using Headless Tippy, all imports (e.g. `followCursor`) should also be\nspecified from this import, otherwise you will end up with duplicate code bloat.\n\n```js\nimport tippy, {followCursor} from 'tippy.js/headless';\n```\n\n#### Use in conjunction with Default Tippy\n\nYou can use Tippy in headless mode when using the default import as well, but\nyou should disable animations by default:\n\n```js\nimport tippy from 'tippy.js';\n\n// This ensures your tippy will unmount if you haven't yet implemented\n// animations.\ntippy.setDefaultProps({animation: false});\n```\n\n### Usage\n\nThe `render` prop is how you create your own tippy element:\n\n```js\nimport tippy from 'tippy.js/headless';\n\ntippy(targets, {\n  content: 'Hello!',\n  render(instance) {\n    // The recommended structure is to use the popper as an outer wrapper\n    // element, with an inner `box` element\n    const popper = document.createElement('div');\n    const box = document.createElement('div');\n\n    popper.appendChild(box);\n\n    box.className = 'my-custom-class';\n    box.textContent = instance.props.content;\n\n    function onUpdate(prevProps, nextProps) {\n      // DOM diffing\n      if (prevProps.content !== nextProps.content) {\n        box.textContent = nextProps.content;\n      }\n    }\n\n    // Return an object with two properties:\n    // - `popper` (the root popper element)\n    // - `onUpdate` callback whenever .setProps() or .setContent() is called\n    return {\n      popper,\n      onUpdate, // optional\n    };\n  },\n});\n```\n\n### Animations\n\nWhen using Headless Tippy, animations are not enabled (`animation: false`) by\ndefault.\n\nTo enable animations, set `animation: true` (or a `string`) — this will require\nyou to invoke `instance.unmount()` whenever your hide animation completes.\n\n```js\ntippy(targets, {\n  animation: true,\n  onHide(instance) {\n    // perform your hide animation in here, then once it completes, call\n    // instance.unmount()\n\n    // Example: unmounting must be async (like a real animation)\n    requestAnimationFrame(instance.unmount);\n  },\n});\n```\n\n### Mutations\n\nTippy performs a few mutations to your popper element, so you should avoid\nspecifying these:\n\n#### Attributes\n\n- `id` attribute is set (for accessibility)\n- `data-tippy-root` attribute is set (to allow for nesting)\n\n#### Properties\n\n- `_tippy` property is set on it (to allow for nesting)\n\n#### Styles\n\n- `pointerEvents` is changed based on the `interactive` prop\n- `transition` is changed based on the `moveTransition` prop\n- `zIndex` is changed based on the `zIndex` prop\n"
  },
  {
    "path": "website/src/pages/v6/html-content.mdx",
    "content": "---\ntitle: HTML Content\npath: /v6/html-content/\nindex: 5\n---\n\nThe `content` prop can accept a string, element, or function.\n\nTo interact with the content inside the tippy, set `interactive: true`.\n\n### String\n\n```js\ntippy('button', {\n  content: '<strong>Bolded content</strong>',\n  allowHTML: true,\n});\n```\n\n> **Note**\n>\n> Ensure HTML strings containing user data are sanitized properly to prevent XSS\n> attacks.\n\n#### Element.innerHTML\n\nYou can pass in an element's `.innerHTML` string:\n\n<!-- prettier-ignore -->\n```html\n<div id=\"template\" style=\"display: none;\">\n  <strong>Bolded content</strong>\n</div>\n```\n\n```js\nconst template = document.getElementById('template');\n\ntippy('button', {\n  content: template.innerHTML,\n  allowHTML: true,\n});\n```\n\n### Element\n\nYou can pass the element itself, which is useful for keeping event listeners\nattached (or when a framework is controlling elements inside):\n\n```js\nconst template = document.getElementById('example');\ntemplate.style.display = 'block';\n\ntippy(singleButton, {\n  content: template,\n});\n```\n\nThis differs from passing a `string` in that a single element can only exist in\na single tippy. The template will be moved from the document and into the tippy\nitself.\n\n### Template linking\n\nIf you have multiple references each with their own unique template, there is a\nway to link them with their associated template:\n\n```html\n<button data-template=\"one\">One</button>\n<button data-template=\"two\">Two</button>\n<button data-template=\"three\">Three</button>\n\n<div style=\"display: none;\">\n  <div id=\"one\">\n    <strong>Content for `one`</strong>\n  </div>\n  <div id=\"two\">\n    <strong>Content for `two`</strong>\n  </div>\n  <div id=\"three\">\n    <strong>Content for `three`</strong>\n  </div>\n</div>\n```\n\nWe can make `content` a function that receives the reference element (button in\nthis case) and returns template content:\n\n```js\ntippy('button', {\n  content(reference) {\n    const id = reference.getAttribute('data-template');\n    const template = document.getElementById(id);\n    return template.innerHTML;\n  },\n  allowHTML: true,\n});\n```\n"
  },
  {
    "path": "website/src/pages/v6/methods.mdx",
    "content": "---\ntitle: Methods\npath: /v6/methods/\nindex: 9\n---\n\n### Instance methods\n\nMethods on instances allow you to control the tippy programmatically. See the\n[Tippy Instance](../tippy-instance/) page for details on accessing an instance.\n\n#### show\n\nProgrammatically show the tippy at any time:\n\n```js\ninstance.show();\n```\n\n#### hide\n\nProgrammatically hide the tippy at any time:\n\n```js\ninstance.hide();\n```\n\n#### hideWithInteractivity\n\n> Available from `v6.2.0`\n\nWill hide the tippy only if the cursor is outside of the tippy's interactive\nregion. This allows you to programmatically hook into `interactive` behavior\nupon a `mouseleave` event if implementing custom event listeners.\n\n```js\n// Required: pass the mouse event object in from your event listener\ninstance.hideWithInteractivity(mouseEvent);\n```\n\n#### disable\n\nTemporarily prevent a tippy from showing or hiding:\n\n```js\ninstance.disable();\n```\n\n#### enable\n\nRe-enable a tippy:\n\n```js\ninstance.enable();\n```\n\n#### setProps\n\nYou can update any prop after the instance has been created. Pass an object of\nnew props in:\n\n```js\ninstance.setProps({\n  arrow: true,\n  animation: 'scale',\n});\n```\n\n#### setContent\n\nUpdating the `content` prop has its own method as a shortcut:\n\n```js\ninstance.setContent('New content');\n```\n\n#### unmount\n\nUnmount the tippy from the DOM:\n\n```js\ninstance.unmount();\n```\n\nThis allows you to integrate spring animation libraries as an alternative to\nCSS. For instance, you'd call this in their `onComplete()` (or equivalent)\ncallback.\n\n#### clearDelayTimeouts\n\nClears the instance's `delay` timeouts. There will likely be only very rare use\ncases for this.\n\n```js\ninstance.clearDelayTimeouts();\n```\n\n#### destroy\n\nTo permanently destroy and clean up the instance, use this method:\n\n```js\ninstance.destroy();\n```\n\nThe `_tippy` property is deleted from the reference element upon destruction.\n\n### Static methods\n\nStatic methods belong to the `tippy` module for global behavior.\n\n#### setDefaultProps\n\nSet the default props for each new instance:\n\n```js\ntippy.setDefaultProps({\n  // Props\n});\n\n// Access the current default props\ntippy.defaultProps;\n```\n\n#### hideAll\n\nHide all visible tippies on the document:\n\n```js\nimport {hideAll} from 'tippy.js';\n\n// Use each tippy's own duration\nhideAll();\n// Hide them all instantly\nhideAll({duration: 0});\n// Hide them all except a particular one\nhideAll({exclude: tippyInstance});\nhideAll({exclude: referenceElement});\n```\n\nIn the CDN (`umd`) version, it's available as `tippy.hideAll()`.\n"
  },
  {
    "path": "website/src/pages/v6/misc.mdx",
    "content": "---\ntitle: Misc\npath: /v6/misc/\nindex: 15\n---\n\nimport EventDelegation from '../../components/examples/EventDelegation';\nimport TriggerTarget from '../../components/examples/TriggerTarget';\nimport ContextMenu from '../../components/examples/ContextMenu';\n\n### Context menu\n\n```js\nconst rightClickableArea = document.querySelector('#container');\n\nconst instance = tippy(rightClickableArea, {\n  content: 'Context menu',\n  placement: 'right-start',\n  trigger: 'manual',\n  interactive: true,\n  arrow: false,\n  offset: [0, 0],\n});\n\nrightClickableArea.addEventListener('contextmenu', (event) => {\n  event.preventDefault();\n\n  instance.setProps({\n    getReferenceClientRect: () => ({\n      width: 0,\n      height: 0,\n      top: event.clientY,\n      bottom: event.clientY,\n      left: event.clientX,\n      right: event.clientX,\n    }),\n  });\n\n  instance.show();\n});\n```\n\n<Demo>\n  <ContextMenu />\n</Demo>\n\n### Different trigger target\n\nYou may want the tippy to appear at a different location from its trigger (event\nlisteners) target. For example:\n\n<Demo>\n  <TriggerTarget />\n</Demo>\n\nFor this, you can utilize the `triggerTarget` prop:\n\n```js\nconst innerOrangeSpanElement = document.querySelector('span');\nconst outerDivElement = document.querySelector('div');\n\ntippy(innerOrangeSpanElement, {\n  triggerTarget: outerDivElement,\n});\n```\n\n### Touch devices\n\nTippy provides first-class support for touch devices. Tooltips can be tricky to\nget right on touch devices because of the nature of touch input.\n\n#### Buttons\n\nA tooltip on a button is generally used to convey information before the user\ndecides to click on it. On touch devices, this isn't possible because a tap is\nrequired to show the tooltip, which will fire a click event.\n\nOn iOS, a tap will show the tooltip but click events won't fire until a second\ntap. This allows the user to see the tooltip before deciding to click the\nbutton. On Android, clicking the button will show the tooltip and also fire a\nclick event.\n\nDepending on your use case, one of these will be preferred, so user agent\nchecking may be needed.\n\nIf neither behavior is preferred, consider using the `touchHold` prop which\nallows the user to see the tooltip while pressing and holding the button, but\nwon't fire a click event unless the click appears to be intentional.\n\n##### Setup\n\n```js\nconst button = document.querySelector('button');\nconst isIOS = /iPhone|iPad|iPod/.test(navigator.platform);\n```\n\n##### A: Make iOS behave like Android (single tap to click)\n\n```js\nbutton.addEventListener('click', () => {\n  // Your logic\n});\n\ntippy(button, {\n  onShow() {\n    if (isIOS) {\n      button.click();\n    }\n  },\n});\n```\n\n##### B: Make Android behave like iOS (double tap to click)\n\nTippy has a useful static property `tippy.currentInput`. This is a mutable\nobject whose properties change depending on the user's current input. Currently,\nit has a single property called `isTouch`, which is a boolean flag determining\nif the user is currently using touch input. This is a dynamic value because of\nhybrid devices which can use a mix of mouse and touch input.\n\n```js\nfunction emulateIOS(listener) {\n  let clicks = 0;\n\n  return function () {\n    clicks++;\n\n    if (clicks === 2 || isIOS || !tippy.currentInput.isTouch) {\n      clicks = 0;\n      listener.apply(this, arguments);\n    }\n  };\n}\n\nconst instance = tippy(button);\nconst onClick = emulateIOS(() => {\n  // Your logic\n});\n\nbutton.addEventListener('click', onClick);\n```\n\n#### Hold & long press\n\n```js\n// Will only show the tippy while the user is pressing the screen (not a tap)\ntippy(button, {\n  touch: 'hold',\n});\n\n// Will only show the tippy on a \"long press\" hold\ntippy(button, {\n  touch: ['hold', 500], // 500ms delay\n});\n```\n"
  },
  {
    "path": "website/src/pages/v6/motivation.mdx",
    "content": "---\ntitle: Motivation\npath: /v6/motivation/\nindex: 17\n---\n\n### Why tooltips and popovers?\n\nBoth are elements positioned near a \"reference\" element, and are hidden until\nthey are triggered. They help conserve space by hiding secondary information or\nfunctionality behind a hover or click. They are positioned outside the normal\nflow of the document so when they are triggered, they are overlaid on top of the\nexisting UI without disrupting the flow of content.\n\nTippy.js distinguishes them in the following way:\n\n- A **tooltip** is an element containing simple text content describing a\n  particular element. It's hidden until the user desires more information from\n  the element, e.g. before deciding to click a button.\n- A **popover** is an interactive HTML tooltip. It can be a dropdown, menu, or\n  any other kind of box that pops out from the normal flow of the document. This\n  type of element contains non-vital functionality and can be hidden behind a\n  click or hover to conserve space.\n\nBoth of these are called a \"tippy\" when using Tippy.js!\n\n### Tippy.js\n\n**Size: 4.5 kB minzip (core)** (including Popper: 10.5 kB)\n\n> **Note**\n>\n> (core) means the core JS & CSS. If importing more themes, animations, plugins,\n> or addons, the size will increase.\n\nTippy is an abstraction over Popper and provides a set of features and defaults\nthat make creating tooltip and popover elements easy.\n\nBut, how does Tippy compare to other solutions?\n\n### Comparison with Popper.js\n\n**Size: 6 kB minzip** (full)\n\nPopper.js is a positioning engine, not a tooltip library. Popper's only goal is\nto position an absolutely positioned element (the tooltip) near another element\n(the reference).\n\nIf you want to build the appearance and behavior of your popper elements from\nscratch, this is a fantastic library. If you want \"out of the box\" (abstracted)\nbehavior, then using Tippy might be better.\n\nTippy takes advantage of Popper as a dependency, so you can use them together\nwithout incurring additional cost:\n\n```js\nimport {createPopper} from '@popperjs/core';\nimport tippy from 'tippy.js';\n```\n\nIf you're using the CDN, the `Popper.createPopper()` constructor will already be\navailable.\n\n### Comparison with CSS tooltip libraries like Microtip or Balloon.css\n\n**Size: 1 kB minzip**\n\nCSS tooltips can be tiny in size, but come with some drawbacks:\n\n- Lack of positioning engine means overflow prevention & flipping are not\n  possible\n- Interactivity can be complicated or inaccessible\n- Using HTML content within them is cumbersome (especially with UI libraries\n  like React), with limited dynamism for updating content or reacting to state\n- No dynamic arrow positioning or features like `followCursor`\n\n### Comparison with Tooltipster\n\n**Size: 10 kB minzip** (including jQuery: 40 kB)\n\nTooltipster is a fantastic library with very similar functionality, but requires\na jQuery dependency, unlike Tippy. To many people these days, this is a\ndeal-breaker! jQuery's minzipped size is about 30 KB, and Tooltipster including\nCSS is about 10 KB. To people using frameworks like React, Vue, or Angular, it\ncan be hard to deal with such a large dependency.\n"
  },
  {
    "path": "website/src/pages/v6/plugins.mdx",
    "content": "---\ntitle: Plugins\npath: /v6/plugins/\nindex: 13\n---\n\nPlugins are an extensible way to add functionality to tippy instances. By\nsplitting functionality into a plugin, components or routes that don't need the\nplugin are not burdened with its bundle size cost.\n\n### Exported plugins\n\nThese plugins are exported by the package:\n\n- `animateFill`\n- `followCursor`\n- `inlinePositioning`\n- `sticky`\n\n### Usage\n\n#### CDN (umd)\n\nIncluded plugins (part of the [All Props](/all-props/) table) will work as\nnormal.\n\n```js\ntippy(targets, {\n  followCursor: true,\n});\n```\n\n#### Modules (esm)\n\nModules have the benefit of tree-shaking, so explicitly importing the plugin is\nrequired:\n\n```js\nimport tippy, {followCursor} from 'tippy.js';\n\ntippy(targets, {\n  followCursor: true,\n  plugins: [followCursor],\n});\n```\n\n### Creating your own custom plugin\n\nA plugin is created by defining an object with the following shape:\n\n```js\nconst plugin = {\n  // Optional (if the plugin provides a prop to use)\n  name: 'propName', // e.g. 'followCursor' or 'sticky'\n  defaultValue: 'anyValue',\n\n  // Required\n  fn(instance) {\n    // Internal state\n    return {\n      // Lifecycle hooks\n    };\n  },\n};\n```\n\nThe plugin's function `fn` returns an object of lifecycle hooks. Plugins are\ninvoked per-instance and the plugin function definition takes the instance as an\nargument, so you can use private variables to create internal state in the\nplugin closure.\n\nHere are some examples:\n\n#### hideOnPopperBlur\n\nCauses a popper to hide if no elements within it are in focus.\n\n```js\nconst hideOnPopperBlur = {\n  name: 'hideOnPopperBlur',\n  defaultValue: true,\n  fn(instance) {\n    return {\n      onCreate() {\n        instance.popper.addEventListener('focusout', (event) => {\n          if (\n            instance.props.hideOnPopperBlur &&\n            event.relatedTarget &&\n            !instance.popper.contains(event.relatedTarget)\n          ) {\n            instance.hide();\n          }\n        });\n      },\n    };\n  },\n};\n```\n\n#### globalStore\n\nManages tippy instances within a global store.\n\n```js\nlet tippyInstances = [];\n\nconst globalStore = {\n  fn(instance) {\n    return {\n      onCreate() {\n        tippyInstances.push(instance);\n      },\n      onDestroy() {\n        tippyInstances = tippyInstances.filter((i) => i !== instance);\n      },\n    };\n  },\n};\n\n// APIs to manipulate all tippy instances\nexport function updateAll(props) {\n  tippyInstances.forEach((instance) => {\n    instance.setProps(props);\n  });\n}\n```\n\n#### hideOnEsc\n\nHides the tippy when the escape key is pressed.\n\n```js\nconst hideOnEsc = {\n  name: 'hideOnEsc',\n  defaultValue: true,\n  fn({hide}) {\n    function onKeyDown(event) {\n      if (event.keyCode === 27) {\n        hide();\n      }\n    }\n\n    return {\n      onShow() {\n        document.addEventListener('keydown', onKeyDown);\n      },\n      onHide() {\n        document.removeEventListener('keydown', onKeyDown);\n      },\n    };\n  },\n};\n```\n\n<Demo>\n  <Tippy hideOnEsc>\n    <Button>Focus me then press `esc`</Button>\n  </Tippy>\n</Demo>\n\n### TypeScript\n\nTypes that take `Props` (e.g. `Tippy`, `Delegate`, `CreateSingleton`) are\ngenerics that accept an extended props interface:\n\n```ts\nimport tippy, {Tippy, Props, Plugin, LifecycleHooks} from 'tippy.js';\n\ninterface CustomProps {\n  myCustomProp: boolean;\n}\n\ntype FilteredProps = CustomProps &\n  Omit<Props, keyof CustomProps | keyof LifecycleHooks>;\n\ntype ExtendedProps = FilteredProps & LifecycleHooks<FilteredProps>;\n\nexport const myCustomProp: Plugin<ExtendedProps> = {\n  name: 'myCustomProp',\n  defaultValue: false,\n  fn: () => ({}),\n};\n\nexport default (tippy as unknown) as Tippy<ExtendedProps>;\n```\n"
  },
  {
    "path": "website/src/pages/v6/themes.mdx",
    "content": "---\ntitle: Themes\npath: /v6/themes/\nindex: 6\n---\n\nTippies can have any custom styling via CSS.\n\n### Included themes\n\nThe package comes with themes for you to use:\n\n- `light`\n- `light-border`\n- `material`\n- `translucent`\n\nThey need to be\n[imported separately](../getting-started/#optional-extra-imports).\n\n```js\nimport 'tippy.js/themes/light.css';\n```\n\nPass the theme name as the `theme` prop:\n\n```js\ntippy('button', {\n  theme: 'light',\n});\n```\n\n### Tippy elements\n\nTo learn how to create a theme, it's helpful to understand the basic structure\nof a tippy element:\n\n<!-- prettier-ignore -->\n```html\n<div data-tippy-root>\n  <div class=\"tippy-box\" data-placement=\"top\">\n    <div class=\"tippy-content\">\n      My content\n    </div>\n  </div>\n</div>\n```\n\nA tippy is essentially three nested `div`s.\n\n- `[data-tippy-root]` is the outermost node. It is what Popper uses to position\n  the tippy. You don't need to apply any styles to this element.\n- `tippy-box` is the actual box node.\n- `tippy-content` is the content node.\n\nDepending on the props supplied, there will exist other elements inside it:\n\n<!-- prettier-ignore -->\n```html\n<div data-tippy-root>\n  <div class=\"tippy-box\" data-placement=\"top\">\n    <div class=\"tippy-backdrop\"></div> <!-- animateFill: true -->\n    <div class=\"tippy-arrow\"></div> <!-- arrow: true -->\n    <div class=\"tippy-content\">\n      My content\n    </div>\n  </div>\n</div>\n```\n\n### Creating a theme\n\nThemes are created by including a class on the `tippy-box` element as part of a\nselector in the form `.tippy-box[data-theme~='theme']`. Let's demonstrate this\nby creating our own theme called `tomato`:\n\n```css\n.tippy-box[data-theme~='tomato'] {\n  background-color: tomato;\n  color: yellow;\n}\n```\n\nTo apply the theme:\n\n```js\ntippy(targets, {\n  theme: 'tomato',\n});\n```\n\n<Demo>\n  <Tippy theme=\"tomato\">\n    <Button>Tomato theme</Button>\n  </Tippy>\n</Demo>\n\n> **What is `~=`?**\n>\n> Since `theme` can have multiple names, it allows you to target a single theme\n> inside the space-separated list. Visit\n> [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)\n> for more information.\n\n### Styling the arrow\n\nThere are two types of arrows:\n\n- CSS arrows (using `border-width`)\n- SVG arrows (using an `<svg>` element)\n\n#### CSS arrow\n\nTo style the default CSS arrow, target each different base placement using the\n`data-placement` attribute and apply it to the `.tippy-arrow` element's\n`::before` pseudo-element:\n\n<!-- prettier-ignore -->\n```css\n.tippy-box[data-theme~='tomato'][data-placement^='top'] > .tippy-arrow::before {\n  border-top-color: tomato;\n}\n.tippy-box[data-theme~='tomato'][data-placement^='bottom'] > .tippy-arrow::before {\n  border-bottom-color: tomato;\n}\n.tippy-box[data-theme~='tomato'][data-placement^='left'] > .tippy-arrow::before {\n  border-left-color: tomato;\n}\n.tippy-box[data-theme~='tomato'][data-placement^='right'] > .tippy-arrow::before {\n  border-right-color: tomato;\n}\n```\n\n#### SVG arrow\n\nFirst import the `svg-arrow.css` stylesheet for SVG arrow styling:\n\n```js\nimport 'tippy.js/dist/svg-arrow.css';\n```\n\nTo color an SVG arrow, specify `fill` and target `.tippy-svg-arrow`:\n\n<!-- prettier-ignore -->\n```css\n.tippy-box[data-theme~='tomato'] > .tippy-svg-arrow {\n  fill: tomato;\n}\n```\n\nThe shape isn't dependent on the placement for styling, which is why it doesn't\nrequire the CSS arrow's more verbose styles.\n\nThere is a default round arrow SVG shape exported from the package for you to\nuse.\n\n#### CDN (`umd`)\n\n```js\ntippy(targets, {\n  arrow: tippy.roundArrow,\n});\n```\n\n#### Modules (`esm`)\n\n```js\nimport {roundArrow} from 'tippy.js';\n\ntippy(targets, {\n  arrow: roundArrow,\n});\n```\n\n<Demo>\n  <Tippy theme=\"tomato\">\n    <Button>CSS arrow</Button>\n  </Tippy>\n  <Tippy theme=\"tomato\" arrow=\"round\">\n    <Button>SVG arrow</Button>\n  </Tippy>\n</Demo>\n\n### Changing the arrow size\n\n#### Option 1: `transform: scale()`\n\nThis is the easiest technique and works for most cases:\n\n```css\n.tippy-box[data-theme~='tomato'] > .tippy-arrow::before {\n  transform: scale(1.5);\n}\n```\n\n#### Option 2: Pixel increase\n\nIf your tippy theme has a `border` (e.g. the included `light-border` theme),\nthen the `transform: scale()` technique distorts the border width of the arrow.\nInstead, you will need to change the size of the arrow in pixels directly.\n\n<Demo>\n  <Tippy theme=\"tomato scaled-arrow\">\n    <Button>Scaled arrow</Button>\n  </Tippy>\n</Demo>\n\n### Arrow border\n\nThere is a stylesheet to aid in adding borders to your tippies:\n\n```js\nimport 'tippy.js/dist/border.css';\n```\n\nThis adds color inheritance for borders when using the default CSS arrow, and\naids in creating SVG arrow borders.\n\n#### CSS arrow\n\n```css\n/* The border of the arrow will now match the border of the box */\n.tippy-box[data-theme~='tomato'] {\n  background: tomato;\n  border: 1px solid yellow;\n}\n```\n\n#### SVG arrow\n\nDuplicate the SVG arrow so that there are two of them, like so:\n\n```js\ntippy(targets, {\n  // concatenates the two SVG strings together\n  arrow: roundArrow + roundArrow,\n});\n```\n\n```css\n/* The border */\n.tippy-box[data-theme~='tomato'] > .tippy-svg-arrow > svg:first-child {\n  fill: yellow;\n}\n\n/* The fill */\n.tippy-box[data-theme~='tomato'] > .tippy-svg-arrow > svg:last-child {\n  fill: tomato;\n}\n```\n\n### Browser DevTools\n\nIt's highly recommended you inspect a tippy element via your browser's DevTools.\nAn easy way to do this is to give it `hideOnClick: false` and `trigger: 'click'`\nprops so that it stays visible when focus is switched to the DevTools window.\n\nThe tippy element gets appended to the very end of the `<body>`, so you should\nscroll down the elements panel. If `interactive: true`, then the tippy is\nappended to the reference element's parentNode instead.\n"
  },
  {
    "path": "website/src/pages/v6/tippy-instance.mdx",
    "content": "---\ntitle: Tippy Instance\npath: /v6/tippy-instance/\nindex: 8\n---\n\nA tippy instance is an individual tippy object. It has a bunch of properties and\nmethods that contain information and functionality to manipulate the tippy\nprogrammatically.\n\n### Accessing an instance\n\n`tippy()` creates new instances. It returns a single instance or an array of\ninstances depending on the type of argument it's supplied.\n\n#### Element\n\nThe instance is directly returned, as this represents a single target:\n\n```js\n// type Instance\nconst instance = tippy(document.querySelector('button'));\n```\n\n#### String, NodeList, Element[]\n\nAn array of instances are returned, as these represent multiple targets:\n\n```js\n// type Instance[]\nconst instances1 = tippy('button');\nconst instances2 = tippy([element1, element2]);\nconst instances3 = tippy(document.querySelectorAll('.btn'));\n```\n\n#### `_tippy` property\n\nIf you need to access the instance later, this property can be useful if you\ndidn't assign the instance(s) to a variable:\n\n```js\nconst button = document.querySelector('button');\ntippy(button);\nconst instance = button._tippy;\n```\n\nBoth the reference element and the popper element have the instance attached as\nthis property.\n\n### Shape and properties\n\n`instance` is a plain object. It's best to log it out yourself and investigate\nin DevTools:\n\n```js\nconsole.log(instance);\n```\n"
  },
  {
    "path": "website/src/utils.js",
    "content": "import React from 'react';\nimport {version} from '../../package.json';\n\nexport const CURRENT_MAJOR = `v${version.split('.')[0]}`;\nexport const HOME_PATHS = ['/', '/tippyjs/'];\nexport const BOLD_HELLO = <strong>Hello</strong>;\n\nfunction shouldShowLink(path, currentPath) {\n  const version = getVersionFromPath(path);\n\n  // Default to latest docs\n  if (HOME_PATHS.includes(currentPath)) {\n    return path.includes(CURRENT_MAJOR);\n  }\n\n  return currentPath.includes(version);\n}\n\nexport function sortActivePages(edges, location) {\n  return [...edges]\n    .sort((a, b) => a.node.frontmatter.index - b.node.frontmatter.index)\n    .filter(\n      ({node}) =>\n        shouldShowLink(node.frontmatter.path, location.pathname) ||\n        (HOME_PATHS.includes(node.frontmatter.path) &&\n          getVersionFromPath(location.pathname) === CURRENT_MAJOR)\n    );\n}\n\nexport function getVersionFromPath(path) {\n  return (path.match(/\\/(v\\d+?)\\//) || [null, CURRENT_MAJOR])[1];\n}\n\nexport const ALL_PLACEMENTS = ['top', 'right', 'bottom', 'left'].reduce(\n  (acc, placement) => {\n    return acc.concat(placement, `${placement}-start`, `${placement}-end`);\n  },\n  []\n);\n\nexport const EXTRA_ANIMATIONS = [\n  'shift-away',\n  'shift-toward',\n  'scale',\n  'perspective',\n].reduce((acc, animation) => {\n  return acc.concat(animation, `${animation}-subtle`, `${animation}-extreme`);\n}, []);\n"
  }
]