<file_sep># Add-ons

The core package aims to be lightweight and dependence free. While the add-ons are wrapping popular packages into the consistent API style.


## Head - [`@vueuse/head`](https://github.com/vueuse/head) <carbon-link class="external-link"/>
Document head manager for Vue 3. SSR ready. Created and maintained by [@egoist](https://github.com/egoist)

## Motion - [`@vueuse/motion`](https://github.com/vueuse/motion) <carbon-link class="external-link"/>

**Vue Composables** putting your **components** in **motion**.

- 🏎 **Smooth animations** based on [**Popmotion**](https://popmotion.io/)
- 🎮 **Declarative** API
- 🚀 **Plug** & **play** with **10+ presets**
- ✅ Supports **Vue 2 & 3** using [**vue-demi**](https://github.com/antfu/vue-demi)
- 🚚 Supports **Nuxt** using [**nuxt-use-motion**](https://github.com/Tahul/nuxt-use-motion)
- ✨ Written in **TypeScript**
- 🏋️‍♀️ Lightweight with **<20kb** bundle size

> Created and maintained by [@Tahul](https://github.com/Tahul)

## Gesture - [`@vueuse/gesture`](https://github.com/vueuse/gesture) <carbon-link class="external-link"/>

**Vue Composables** making your app **interactive**

- 🚀 **Plug** & **play**
- 🕹 **Mouse** & **Touch** support
- 🎮 **Directives** support (**v-drag**, **v-pinch**, **v-move**...)
- ✨ Written in **TypeScript**
- ✅ Supports **Vue 2 & 3** using [**vue-demi**](https://github.com/antfu/vue-demi)
- 🤹 Plays well with [**vueuse/motion**](https://github.com/vueuse/motion) or **any other** animation solution

> Created and maintained by [@Tahul](https://github.com/Tahul)

## Sound - [`@vueuse/sound`](https://github.com/vueuse/sound) <carbon-link class="external-link"/>
Vue composables for playing sound effects.

- 👂 Lets your website **communicate** using 2 **human senses** instead of 1
- 🔥 Built with **Vue** Composition API
- ✅ Supports **Vue 2 & 3** using [**vue-demi**](https://github.com/antfu/vue-demi)
- 🚚 Supports **Nuxt** using [**nuxt-use-sound**](https://github.com/Tahul/nuxt-use-sound)
- ⚡️ **<1kb** bytes (gzip) in your **bundle**! **~10kb** loaded **async**.
- ✨ Built with **TypeScript**
- 🗣 Uses a powerful, battle-tested audio utility: [**Howler.js**](https://howlerjs.com/)

> Created and maintained by [@Tahul](https://github.com/Tahul)

<!--GENERATED LIST, DO NOT MODIFY MANUALLY-->
<!--ADDONS_LIST_STARTS-->
## Router - [`@vueuse/router`](https://vueuse.org/router/README.html)
Utilities for vue-router
  - [`useRouteHash`](https://vueuse.org/router/useRouteHash/) — shorthand for reactive route.hash
  - [`useRouteQuery`](https://vueuse.org/router/useRouteQuery/) — shorthand for reactive route.query


## Integrations - [`@vueuse/integrations`](https://vueuse.org/integrations/README.html)
Integration wrappers for utility libraries
  - [`useAxios`](https://vueuse.org/integrations/useAxios/) — wrapper for [`axios`](https://github.com/axios/axios)
  - [`useCookies`](https://vueuse.org/integrations/useCookies/) — wrapper for [`universal-cookie`](https://www.npmjs.com/package/universal-cookie)
  - [`useDrauu`](https://vueuse.org/integrations/useDrauu/) — reactive instance for [drauu](https://github.com/antfu/drauu)
  - [`useFocusTrap`](https://vueuse.org/integrations/useFocusTrap/) — reactive wrapper for [`focus-trap`](https://github.com/focus-trap/focus-trap)
  - [`useFuse`](https://vueuse.org/integrations/useFuse/) — reactive wrapper for [Fuse.js](https://github.com/krisk/fuse)
  - [`useJwt`](https://vueuse.org/integrations/useJwt/) — wrapper for [`jwt-decode`](https://github.com/auth0/jwt-decode)
  - [`useNProgress`](https://vueuse.org/integrations/useNProgress/) — reactive wrapper for [`nprogress`](https://github.com/rstacruz/nprogress)
  - [`useQRCode`](https://vueuse.org/integrations/useQRCode/) — wrapper for [`qrcode`](https://github.com/soldair/node-qrcode)


## RxJS - [`@vueuse/rxjs`](https://vueuse.org/rxjs/README.html)
Enables RxJS reactive functions in Vue
  - [`from`](https://vueuse.org/rxjs/from/) — / fromEvent
  - [`toObserver`](https://vueuse.org/rxjs/toObserver/) — sugar function to convert a ref in an observer
  - [`useObservable`](https://vueuse.org/rxjs/useObservable/) — use an Observable
  - [`useSubscription`](https://vueuse.org/rxjs/useSubscription/) — uses subscriptions without worry about unsubscribing to it or memory leaks


## Firebase - [`@vueuse/firebase`](https://vueuse.org/firebase/README.html)
Enables realtime bindings for Firebase
  - [`useAuth`](https://vueuse.org/firebase/useAuth/) — reactive [Firebase Auth](https://firebase.google.com/docs/auth) binding
  - [`useFirestore`](https://vueuse.org/firebase/useFirestore/) — reactive [Firestore](https://firebase.google.com/docs/firestore) binding
  - [`useRTDB`](https://vueuse.org/firebase/useRTDB/) — reactive [Firebase Realtime Database](https://firebase.google.com/docs/database) binding


## Electron - [`@vueuse/electron`](https://vueuse.org/electron/README.html)
Electron renderer process modules for VueUse
  - [`useIpcRenderer`](https://vueuse.org/electron/useIpcRenderer/) — provides [ipcRenderer](https://www.electronjs.org/docs/api/ipc-renderer) and it's all APIs
  - [`useIpcRendererInvoke`](https://vueuse.org/electron/useIpcRendererInvoke/) — reactive [ipcRenderer.invoke API](https://www.electronjs.org/docs/api/ipc-renderer#ipcrendererinvokechannel-args) result
  - [`useIpcRendererOn`](https://vueuse.org/electron/useIpcRendererOn/) — use [ipcRenderer.on](https://www.electronjs.org/docs/api/ipc-renderer#ipcrendereronchannel-listener) with ease and [ipcRenderer.removeListener](https://www.electronjs.org/docs/api/ipc-renderer#ipcrendererremovelistenerchannel-listener) automatically on unmounted
  - [`useZoomFactor`](https://vueuse.org/electron/useZoomFactor/) — reactive [WebFrame](https://www.electronjs.org/docs/api/web-frame#webframe) zoom factor
  - [`useZoomLevel`](https://vueuse.org/electron/useZoomLevel/) — reactive [WebFrame](https://www.electronjs.org/docs/api/web-frame#webframe) zoom level


<!--ADDONS_LIST_ENDS-->
<file_sep>export * from './useAxios'
export * from './useCookies'
export * from './useDrauu'
export * from './useFocusTrap'
export * from './useFuse'
export * from './useJwt'
export * from './useNProgress'
export * from './useQRCode'
<file_sep>import { resolve, join, relative } from 'path'
import fs from 'fs-extra'
import matter from 'gray-matter'
import fg from 'fast-glob'
import parser from 'prettier/parser-typescript'
import prettier from 'prettier'
import YAML from 'js-yaml'
import { packages } from '../meta/packages'
import { PackageIndexes, VueUseFunction, VueUsePackage } from '../meta/types'

const DOCS_URL = 'https://vueuse.org'
const GITHUB_BLOB_URL = 'https://github.com/vueuse/vueuse/blob/main/packages'

const DIR_ROOT = resolve(__dirname, '..')
const DIR_SRC = resolve(__dirname, '../packages')
const DIR_TYPES = resolve(__dirname, '../types/packages')

export async function getTypeDefinition(pkg: string, name: string): Promise<string | undefined> {
  const typingFilepath = join(DIR_TYPES, `${pkg}/${name}/index.d.ts`)

  if (!fs.existsSync(typingFilepath))
    return

  let types = await fs.readFile(typingFilepath, 'utf-8')

  if (!types)
    return

  // clean up types
  types = types
    .replace(/import\(.*?\)\./g, '')
    .replace(/import[\s\S]+?from ?["'][\s\S]+?["']/g, '')

  return prettier
    .format(
      types,
      {
        semi: false,
        parser: 'typescript',
        plugins: [parser],
      },
    )
    .trim()
}

export function hasDemo(pkg: string, name: string) {
  return fs.existsSync(join(DIR_SRC, pkg, name, 'demo.vue'))
}

export function getFunctionHead(pkg: string, name: string) {
  let head = packages.find(p => p.name === pkg)!.addon
    ? `available in add-on [\`@vueuse/${pkg}\`](/${pkg}/README)`
    : ''

  if (head)
    head = `\n::: tip\n${head}\n:::\n`

  return head
}

export async function getFunctionFooter(pkg: string, name: string) {
  const URL = `${GITHUB_BLOB_URL}/${pkg}/${name}`

  const hasDemo = fs.existsSync(join(DIR_SRC, pkg, name, 'demo.vue'))

  const types = await getTypeDefinition(pkg, name)

  const typingSection = types && `## Type Declarations\n\n\`\`\`typescript\n${types.trim()}\n\`\`\``

  const links = ([
    ['Source', `${URL}/index.ts`],
    hasDemo ? ['Demo', `${URL}/demo.vue`] : undefined,
    ['Docs', `${URL}/index.md`],
  ])
    .filter(i => i)
    .map(i => `[${i![0]}](${i![1]})`).join(' • ')

  const sourceSection = `## Source\n\n${links}\n`

  return `${typingSection || ''}\n\n${sourceSection}\n`
}

export async function listFunctions(dir: string, ignore: string[] = []) {
  const files = await fg('*', {
    onlyDirectories: true,
    cwd: dir,
    ignore: [
      '_*',
      'dist',
      'node_modules',
      ...ignore,
    ],
  })
  files.sort()
  return files
}

export async function readIndexes() {
  const indexes: PackageIndexes = {
    packages: {},
    categories: [],
    functions: [],
  }

  for (const info of packages) {
    const dir = join(DIR_SRC, info.name)

    const functions = await listFunctions(dir)

    const pkg: VueUsePackage = {
      ...info,
      dir: relative(DIR_ROOT, dir).replace(/\\/g, '/'),
      docs: info.addon ? `${DOCS_URL}/${info.name}/README.html` : undefined,
    }

    indexes.packages[info.name] = pkg

    for (const fnName of functions) {
      const mdPath = join(dir, fnName, 'index.md')

      const fn: VueUseFunction = {
        name: fnName,
        package: pkg.name,
      }

      if (fs.existsSync(join(dir, fnName, 'component.ts')))
        fn.component = true
      if (fs.existsSync(join(dir, fnName, 'directive.ts')))
        fn.directive = true

      if (!fs.existsSync(mdPath)) {
        fn.internal = true
        indexes.functions.push(fn)
        continue
      }

      fn.docs = `${DOCS_URL}/${pkg.name}/${fnName}/`

      const mdRaw = await fs.readFile(join(dir, fnName, 'index.md'), 'utf-8')

      const { content: md, data: frontmatter } = matter(mdRaw)
      const category = frontmatter.category

      let description = (md
        .replace(/\r\n/g, '\n')
        .match(/# \w+[\s\n]+(.+?)(?:, |\. |\n|\.\n)/m) || []
      )[1] || ''

      description = description.trim()
      description = description.charAt(0).toLowerCase() + description.slice(1)

      fn.category = ['core', 'shared'].includes(pkg.name) ? category : `@${pkg.display}`
      fn.description = description

      if (description.includes('DEPRECATED'))
        fn.depreacted = true

      indexes.functions.push(fn)
    }
  }

  indexes.categories = getCategories(indexes.functions)

  return indexes
}

export function getCategories(functions: VueUseFunction[]): string[] {
  return uniq(
    functions
      .filter(i => !i.internal)
      .map(i => i.category)
      .filter(Boolean),
  ).sort()
}

export async function updateImport({ packages, functions }: PackageIndexes) {
  for (const { name, dir, manualImport } of Object.values(packages)) {
    if (manualImport)
      continue

    let imports: string[]
    if (name === 'components') {
      imports = functions
        .sort((a, b) => a.name.localeCompare(b.name))
        .flatMap((fn) => {
          const arr: string[] = []

          // don't include integration components
          if (fn.package === 'integrations')
            return arr

          if (fn.component)
            arr.push(`export * from '../${fn.package}/${fn.name}/component'`)
          if (fn.directive)
            arr.push(`export * from '../${fn.package}/${fn.name}/directive'`)
          return arr
        })
    }
    else {
      imports = functions
        .filter(i => i.package === name)
        .map(f => f.name)
        .sort()
        .map(name => `export * from './${name}'`)
    }

    if (name === 'core') {
      imports.push(
        'export * from \'./types\'',
        'export * from \'@vueuse/shared\'',
      )
    }

    await fs.writeFile(join(dir, 'index.ts'), `${imports.join('\n')}\n`)
  }
}

export function uniq<T extends any[]>(a: T) {
  return Array.from(new Set(a))
}

export function stringifyFunctions(functions: VueUseFunction[], title = true) {
  let list = ''

  const categories = getCategories(functions)

  for (const category of categories) {
    if (category.startsWith('_'))
      continue

    if (title)
      list += `### ${category}\n`

    const categoryFunctions = functions.filter(i => i.category === category).sort((a, b) => a.name.localeCompare(b.name))

    for (const { name, docs, description, depreacted } of categoryFunctions) {
      if (depreacted)
        continue

      const desc = description ? ` — ${description}` : ''
      list += `  - [\`${name}\`](${docs})${desc}\n`
    }
    list += '\n'
  }
  return list
}

export function replacer(code: string, value: string, key: string, insert: 'head' | 'tail' | 'none' = 'none') {
  const START = `<!--${key}_STARTS-->`
  const END = `<!--${key}_ENDS-->`
  const regex = new RegExp(`${START}[\\s\\S]*?${END}`, 'im')

  const target = value ? `${START}\n${value}\n${END}` : `${START}${END}`

  if (!code.match(regex)) {
    if (insert === 'none')
      return code
    else if (insert === 'head')
      return `${target}\n\n${code}`
    else
      return `${code}\n\n${target}`
  }

  return code.replace(regex, target)
}

export async function updatePackageREADME({ packages, functions }: PackageIndexes) {
  for (const { name, dir } of Object.values(packages)) {
    const readmePath = join(dir, 'README.md')

    if (!fs.existsSync(readmePath))
      continue

    const functionMD = stringifyFunctions(functions.filter(i => i.package === name), false)
    let readme = await fs.readFile(readmePath, 'utf-8')
    readme = replacer(readme, functionMD, 'FUNCTIONS_LIST')

    await fs.writeFile(readmePath, `${readme.trim()}\n`, 'utf-8')
  }
}

export async function updateIndexREADME({ packages, functions }: PackageIndexes) {
  let readme = await fs.readFile('README.md', 'utf-8')

  const functionsCount = functions.filter(i => !i.internal).length

  readme = readme.replace(/img\.shields\.io\/badge\/-(.+?)%20functions/, `img.shields.io/badge/-${functionsCount}%20functions`)

  await fs.writeFile('README.md', `${readme.trim()}\n`, 'utf-8')
}

export async function updateFunctionsMD({ packages, functions }: PackageIndexes) {
  let mdFn = await fs.readFile('packages/functions.md', 'utf-8')

  const coreFunctions = functions.filter(i => ['core', 'shared'].includes(i.package))
  const functionListMD = stringifyFunctions(coreFunctions)

  mdFn = replacer(mdFn, functionListMD, 'FUNCTIONS_LIST')
  await fs.writeFile('packages/functions.md', mdFn, 'utf-8')

  let mdAddons = await fs.readFile('packages/add-ons.md', 'utf-8')

  const addons = Object.values(packages)
    .filter(i => i.addon && !i.deprecated)
    .map(({ docs, name, display, description }) => {
      return `## ${display} - [\`@vueuse/${name}\`](${docs})\n${description}\n${
        stringifyFunctions(functions.filter(i => i.package === name), false)}`
    })
    .join('\n')

  mdAddons = replacer(mdAddons, addons, 'ADDONS_LIST')

  await fs.writeFile('packages/add-ons.md', mdAddons, 'utf-8')
}

export async function updateFunctionREADME(indexes: PackageIndexes) {
  const hasTypes = fs.existsSync(DIR_TYPES)

  if (!hasTypes)
    console.warn('No types dist found, run `npm run build:types` first.')

  for (const fn of indexes.functions) {
    const mdPath = `packages/${fn.package}/${fn.name}/index.md`
    if (!fs.existsSync(mdPath))
      continue

    let readme = await fs.readFile(mdPath, 'utf-8')

    const { content, data = {} } = matter(readme)

    data.category = fn.category || 'Unknown'

    readme = `---\n${YAML.dump(data)}---\n\n${content.trim()}`

    await fs.writeFile(mdPath, `${readme.trim()}\n`, 'utf-8')
  }
}

export async function updatePackageJSON(indexes: PackageIndexes) {
  const { version } = await fs.readJSON('package.json')

  for (const { name, description, author, submodules, iife } of packages) {
    const packageDir = join(DIR_SRC, name)
    const packageJSONPath = join(packageDir, 'package.json')
    const packageJSON = await fs.readJSON(packageJSONPath)

    packageJSON.version = version
    packageJSON.description = description || packageJSON.description
    packageJSON.author = author || '<NAME> <https://github.com/antfu>'
    packageJSON.bugs = {
      url: 'https://github.com/vueuse/vueuse/issues',
    }
    packageJSON.homepage = name === 'core'
      ? 'https://github.com/vueuse/vueuse#readme'
      : `https://github.com/vueuse/vueuse/tree/main/packages/${name}#readme`
    packageJSON.main = './index.cjs'
    packageJSON.types = './index.d.ts'
    packageJSON.module = './index.mjs'
    if (iife !== false) {
      packageJSON.unpkg = './index.iife.min.js'
      packageJSON.jsdelivr = './index.iife.min.js'
    }
    packageJSON.exports = {
      '.': {
        import: './index.mjs',
        require: './index.cjs',
      },
      './*': './*',
    }

    if (submodules) {
      indexes.functions
        .filter(i => i.package === name)
        .forEach((i) => {
          packageJSON.exports[`./${i.name}`] = {
            import: `./${i.name}.mjs`,
            require: `./${i.name}.cjs`,
          }
          if (i.component) {
            packageJSON.exports[`./${i.name}/component`] = {
              import: `./${i.name}/component.mjs`,
              require: `./${i.name}/component.cjs`,
            }
          }
        })
    }

    await fs.writeJSON(packageJSONPath, packageJSON, { spaces: 2 })
  }
}
<file_sep>---
category: Sensors
---

# useElementHover

Reactive element's hover state.

## Usage

```vue
<template>
  <button ref="myHoverableElement">
    {{ isHovered }}
  </button>
</template>

<script setup>
import { useElementHover } from '@vueuse/core'

const myHoverableElement = ref()
const isHovered = useElementHover(myHoverableElement)
</script>
```
<file_sep>---
category: '@Integrations'
---

# useFuse

Reactive wrapper for [Fuse.js](https://github.com/krisk/fuse).

## Install

### NPM

```bash
npm install fuse.js
```

### Yarn

```bash
yarn add fuse.js
```

## Usage

```ts
import { ref } from 'vue'
import { useFuse } from '@vueuse/integrations/useFuse'

const data = [
  '<NAME>',
  '<NAME>',
  '<NAME>',
  '<NAME>',
  '<NAME>',
]

const input = ref('<NAME>')

const { results } = useFuse(input, data)

/*
 * Results:
 *
 * { "item": "<NAME>", "index": 1 }
 * { "item": "<NAME>", "index": 0 }
 * { "item": "<NAME>", "index": 2 }
 *
 */
```
<file_sep>---
category: '@Integrations'
---

# useFocusTrap

Reactive wrapper for [`focus-trap`](https://github.com/focus-trap/focus-trap)

For more info on what options can be passed see [`createOptions`](https://github.com/focus-trap/focus-trap#createfocustrapelement-createoptions) in the `focus-trap` docs.

## Usage

**Basic Usage**

```html
<script setup>
import { ref } from 'vue'
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'

const target = ref()
const { hasFocus, activate, deactivate } = useFocusTrap(target)
</script>

<template>
  <div>
    <button @click="activate()">Activate</button>
    <div ref="target">
      <span>Has Focus: {{ hasFocus }}</span>
      <input type="text" />
      <button @click="deactivate()">Deactivate</button>
    </div>
  </div>
</template>
```

**Automatically Focus**

```html
<script setup>
import { ref } from 'vue'
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'

const target = ref()
const { hasFocus, activate, deactivate } = useFocusTrap(target, { immediate: true })
</script>

<template>
  <div>
    <div ref="target">...</div>
  </div>
</template>
```

## Using Component

This function can't properly activate focus on elements with conditional rendering. In this case, you can use the `UseFocusTrap` component. Focus Trap will be activated automatically on mounting this component and deactivated on unmount.

```html
<script setup>
import { ref } from 'vue'
import { UseFocusTrap } from '@vueuse/integrations/useFocusTrap/component'

const show = ref(false)
</script>

<template>
  <UseFocusTrap v-if="show">
    <div class="modal">...</div>
  </UseFocusTrap>
</template>

```
<file_sep>---
category: Sensors
---

# useScroll

Reactive scroll position and state

## Usage

```html
<script setup lang="ts">
import { useScroll } from '@vueuse/core'

const el = ref<HTMLElement | null>(null)
const { x, y, isScrolling, arrivedState } = useScroll(el)
</script>

<template>
  <div ref="el"></div>
</template>
```

```js
// With offsets
const { x, y, isScrolling, arrivedState } = useScroll(el, {
  offset: { top: 30, bottom: 30, right: 30, left: 30 },
})
```
<file_sep>/* eslint-disable @typescript-eslint/no-var-requires */

const disabled = [
  'useFetch',
  'toRefs',
]

/**
 * Auto import for VueUse in Nuxt
 * Usage:
 *
 * ```ts
 * // nuxt.config.js
 * export deafult {
 *   buildModules: [
 *     '@vueuse/core/nuxt'
 *   ]
 * }
 * ```
 */
module.exports = function() {
  const { nuxt } = this

  nuxt.hook('autoImports:sources', (sources) => {
    sources.push({
      from: '@vueuse/core',
      names: require('./indexes.json')
        .functions
        .filter(i => (i.package === 'core' || i.package === 'shared') && !i.internal)
        .map(i => i.name)
        .filter(i => i.length >= 4 && !disabled.includes(i)),
    })
  })
}
<file_sep>import { ref, unref } from 'vue-demi'
import { Fn, Pausable, MaybeRef } from './types'

export type FunctionArgs<Args extends any[] = any[], Return = void> = (...args: Args) => Return

export interface FunctionWrapperOptions<Args extends any[] = any[], This = any> {
  fn: FunctionArgs<Args, This>
  args: Args
  thisArg: This
}

export type EventFilter<Args extends any[] = any[], This = any> = (
  invoke: Fn,
  options: FunctionWrapperOptions<Args, This>
) => void

export interface ConfigurableEventFilter {
  /**
   * Filter for if events should to be received.
   *
   * @see https://vueuse.org/guide/config.html#event-filters
   */
  eventFilter?: EventFilter
}

/**
 * @internal
 */
export function createFilterWrapper<T extends FunctionArgs>(filter: EventFilter, fn: T) {
  function wrapper(this: any, ...args: any[]) {
    filter(() => fn.apply(this, args), { fn, thisArg: this, args })
  }

  return wrapper as any as T
}

export const bypassFilter: EventFilter = (invoke) => {
  return invoke()
}

/**
 * Create an EventFilter that debounce the events
 *
 * @param ms
 */
export function debounceFilter(ms: MaybeRef<number>) {
  let timer: ReturnType<typeof setTimeout> | undefined

  const filter: EventFilter = (invoke) => {
    const duration = unref(ms)

    if (timer)
      clearTimeout(timer)

    if (duration <= 0)
      return invoke()

    timer = setTimeout(invoke, duration)
  }

  return filter
}

/**
 * Create an EventFilter that throttle the events
 *
 * @param ms
 * @param [trailing=true]
 * @param [leading=true]
 */
export function throttleFilter(ms: MaybeRef<number>, trailing = true, leading = true) {
  let lastExec = 0
  let timer: ReturnType<typeof setTimeout> | undefined
  let preventLeading = !leading

  const clear = () => {
    if (timer) {
      clearTimeout(timer)
      timer = undefined
    }
  }

  const filter: EventFilter = (invoke) => {
    const duration = unref(ms)
    const elapsed = Date.now() - lastExec

    clear()

    if (duration <= 0) {
      lastExec = Date.now()
      return invoke()
    }

    if (elapsed > duration) {
      lastExec = Date.now()
      if (preventLeading) preventLeading = false
      else invoke()
    }
    else if (trailing) {
      timer = setTimeout(() => {
        lastExec = Date.now()
        if (!leading) preventLeading = true
        clear()
        invoke()
      }, duration)
    }

    if (!leading && !timer) timer = setTimeout(() => preventLeading = true, duration)
  }

  return filter
}

/**
 * EventFilter that gives extra controls to pause and resume the filter
 *
 * @param extendFilter  Extra filter to apply when the PausableFilter is active, default to none
 *
 */
export function pausableFilter(extendFilter: EventFilter = bypassFilter): Pausable & { eventFilter: EventFilter } {
  const isActive = ref(true)

  function pause() {
    isActive.value = false
  }
  function resume() {
    isActive.value = true
  }

  const eventFilter: EventFilter = (...args) => {
    if (isActive.value)
      extendFilter(...args)
  }

  return { isActive, pause, resume, eventFilter }
}
<file_sep>export * from './and'
export * from './biSyncRef'
export * from './controlledComputed'
export * from './controlledRef'
export * from './createEventHook'
export * from './createGlobalState'
export * from './createSharedComposable'
export * from './debouncedWatch'
export * from './eagerComputed'
export * from './extendRef'
export * from './get'
export * from './ignorableWatch'
export * from './isDefined'
export * from './makeDestructurable'
export * from './not'
export * from './or'
export * from './pausableWatch'
export * from './reactify'
export * from './reactifyObject'
export * from './reactivePick'
export * from './refDefault'
export * from './set'
export * from './syncRef'
export * from './throttledWatch'
export * from './toReactive'
export * from './toRefs'
export * from './tryOnBeforeUnmount'
export * from './tryOnMounted'
export * from './tryOnScopeDispose'
export * from './tryOnUnmounted'
export * from './until'
export * from './useCounter'
export * from './useDebounce'
export * from './useDebounceFn'
export * from './useInterval'
export * from './useIntervalFn'
export * from './useLastChanged'
export * from './useThrottle'
export * from './useThrottleFn'
export * from './useTimeout'
export * from './useTimeoutFn'
export * from './useToggle'
export * from './utils'
export * from './watchAtMost'
export * from './watchOnce'
export * from './watchWithFilter'
export * from './whenever'
<file_sep>import { ConfigurableFlush, watchWithFilter, ConfigurableEventFilter, MaybeRef, RemoveableRef } from '@vueuse/shared'
import { ref, Ref, unref, shallowRef } from 'vue-demi'
import { useEventListener } from '../useEventListener'
import { ConfigurableWindow, defaultWindow } from '../_configurable'

export type Serializer<T> = {
  read(raw: string): T
  write(value: T): string
}

export const StorageSerializers: Record<'boolean' | 'object' | 'number' | 'any' | 'string' | 'map' | 'set', Serializer<any>> = {
  boolean: {
    read: (v: any) => v === 'true',
    write: (v: any) => String(v),
  },
  object: {
    read: (v: any) => JSON.parse(v),
    write: (v: any) => JSON.stringify(v),
  },
  number: {
    read: (v: any) => Number.parseFloat(v),
    write: (v: any) => String(v),
  },
  any: {
    read: (v: any) => v,
    write: (v: any) => String(v),
  },
  string: {
    read: (v: any) => v,
    write: (v: any) => String(v),
  },
  map: {
    read: (v: any) => new Map(JSON.parse(v)),
    write: (v: any) => JSON.stringify(Array.from((v as Map<any, any>).entries())),
  },
  set: {
    read: (v: any) => new Set(JSON.parse(v)),
    write: (v: any) => JSON.stringify(Array.from((v as Set<any>).entries())),
  },
}

export type StorageLike = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>

export interface StorageOptions<T> extends ConfigurableEventFilter, ConfigurableWindow, ConfigurableFlush {
  /**
   * Watch for deep changes
   *
   * @default true
   */
  deep?: boolean

  /**
   * Listen to storage changes, useful for multiple tabs application
   *
   * @default true
   */
  listenToStorageChanges?: boolean

  /**
   * Write the default value to the storage when it does not existed
   *
   * @default true
   */
  writeDefaults?: boolean

  /**
   * Custom data serialization
   */
  serializer?: Serializer<T>

  /**
   * On error callback
   *
   * Default log error to `console.error`
   */
  onError?: (error: unknown) => void

  /**
   * Use shallow ref as reference
   *
   * @default false
   */
  shallow?: boolean
}

export function useStorage(key: string, initialValue: MaybeRef<string>, storage?: StorageLike, options?: StorageOptions<string>): RemoveableRef<string>
export function useStorage(key: string, initialValue: MaybeRef<boolean>, storage?: StorageLike, options?: StorageOptions<boolean>): RemoveableRef<boolean>
export function useStorage(key: string, initialValue: MaybeRef<number>, storage?: StorageLike, options?: StorageOptions<number>): RemoveableRef<number>
export function useStorage<T> (key: string, initialValue: MaybeRef<T>, storage?: StorageLike, options?: StorageOptions<T>): RemoveableRef<T>
export function useStorage<T = unknown> (key: string, initialValue: MaybeRef<null>, storage?: StorageLike, options?: StorageOptions<T>): RemoveableRef<T>

/**
 * Reactive LocalStorage/SessionStorage.
 *
 * @see https://vueuse.org/useStorage
 * @param key
 * @param initialValue
 * @param storage
 * @param options
 */
export function useStorage<T extends(string|number|boolean|object|null)> (
  key: string,
  initialValue: MaybeRef<T>,
  storage: StorageLike | undefined = defaultWindow?.localStorage,
  options: StorageOptions<T> = {},
): RemoveableRef<T> {
  const {
    flush = 'pre',
    deep = true,
    listenToStorageChanges = true,
    writeDefaults = true,
    shallow,
    window = defaultWindow,
    eventFilter,
    onError = (e) => {
      console.error(e)
    },
  } = options

  const rawInit: T = unref(initialValue)

  const type = rawInit == null
    ? 'any'
    : rawInit instanceof Set
      ? 'set'
      : rawInit instanceof Map
        ? 'map'
        : typeof rawInit === 'boolean'
          ? 'boolean'
          : typeof rawInit === 'string'
            ? 'string'
            : typeof rawInit === 'object'
              ? 'object'
              : Array.isArray(rawInit)
                ? 'object'
                : !Number.isNaN(rawInit)
                  ? 'number'
                  : 'any'

  const data = (shallow ? shallowRef : ref)(initialValue) as Ref<T>
  const serializer = options.serializer ?? StorageSerializers[type]

  function read(event?: StorageEvent) {
    if (!storage || (event && event.key !== key))
      return

    try {
      const rawValue = event ? event.newValue : storage.getItem(key)
      if (rawValue == null) {
        data.value = rawInit
        if (writeDefaults && rawInit !== null)
          storage.setItem(key, serializer.write(rawInit))
      }
      else {
        data.value = serializer.read(rawValue)
      }
    }
    catch (e) {
      onError(e)
    }
  }

  read()

  if (window && listenToStorageChanges)
    useEventListener(window, 'storage', e => setTimeout(() => read(e), 0))

  if (storage) {
    watchWithFilter(
      data,
      () => {
        try {
          if (data.value == null)
            storage.removeItem(key)
          else
            storage.setItem(key, serializer.write(data.value))
        }
        catch (e) {
          onError(e)
        }
      },
      {
        flush,
        deep,
        eventFilter,
      },
    )
  }

  return data as RemoveableRef<T>
}
<file_sep>import { getCurrentInstance, onMounted, onUpdated, customRef, Ref } from 'vue-demi'

/**
 * Shorthand for binding ref to template element.
 *
 * @see https://vueuse.org/templateRef
 * @param key
 * @param initialValue
 */
export function templateRef<T extends HTMLElement | SVGElement | null>(
  key: string,
  initialValue: T | null = null,
): Readonly<Ref<T>> {
  const instance = getCurrentInstance()
  let _trigger = () => {}

  const element = customRef((track, trigger) => {
    _trigger = trigger
    return {
      get() {
        track()
        return instance?.proxy?.$refs[key] ?? initialValue
      },
      set() {},
    }
  })

  onMounted(_trigger)
  onUpdated(_trigger)

  return element as Readonly<Ref<T>>
}
<file_sep>::: tip
📰 [Recently updated functions](/recently-updated)
:::

# Core Functions

<!--GENERATED LIST, DO NOT MODIFY MANUALLY-->
<!--FUNCTIONS_LIST_STARTS-->
### Animation
  - [`useInterval`](https://vueuse.org/shared/useInterval/) — reactive counter increases on every interval
  - [`useIntervalFn`](https://vueuse.org/shared/useIntervalFn/) — wrapper for `setInterval` with controls
  - [`useNow`](https://vueuse.org/core/useNow/) — reactive current Date instance
  - [`useRafFn`](https://vueuse.org/core/useRafFn/) — call function on every `requestAnimationFrame`
  - [`useTimeout`](https://vueuse.org/shared/useTimeout/) — update value after a given time with controls
  - [`useTimeoutFn`](https://vueuse.org/shared/useTimeoutFn/) — wrapper for `setTimeout` with controls
  - [`useTimestamp`](https://vueuse.org/core/useTimestamp/) — reactive current timestamp
  - [`useTransition`](https://vueuse.org/core/useTransition/) — transition between values

### Browser
  - [`useActiveElement`](https://vueuse.org/core/useActiveElement/) — reactive `document.activeElement`
  - [`useBreakpoints`](https://vueuse.org/core/useBreakpoints/) — reactive viewport breakpoints
  - [`useBrowserLocation`](https://vueuse.org/core/useBrowserLocation/) — reactive browser location
  - [`useClipboard`](https://vueuse.org/core/useClipboard/) — reactive [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API)
  - [`useCssVar`](https://vueuse.org/core/useCssVar/) — manipulate CSS variables
  - [`useDark`](https://vueuse.org/core/useDark/) — reactive dark mode with auto data persistence
  - [`useEventListener`](https://vueuse.org/core/useEventListener/) — use EventListener with ease
  - [`useFavicon`](https://vueuse.org/core/useFavicon/) — reactive favicon
  - [`useFetch`](https://vueuse.org/core/useFetch/) — reactive [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) provides the ability to abort requests
  - [`useFullscreen`](https://vueuse.org/core/useFullscreen/) — reactive [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
  - [`useMediaControls`](https://vueuse.org/core/useMediaControls/) — reactive media controls for both `audio` and `video` elements
  - [`useMediaQuery`](https://vueuse.org/core/useMediaQuery/) — reactive [Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries)
  - [`usePermission`](https://vueuse.org/core/usePermission/) — reactive [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API)
  - [`usePreferredColorScheme`](https://vueuse.org/core/usePreferredColorScheme/) — reactive [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) media query
  - [`usePreferredDark`](https://vueuse.org/core/usePreferredDark/) — reactive dark theme preference
  - [`usePreferredLanguages`](https://vueuse.org/core/usePreferredLanguages/) — reactive [Navigator Languages](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages)
  - [`useScriptTag`](https://vueuse.org/core/useScriptTag/) — script tag injecting
  - [`useShare`](https://vueuse.org/core/useShare/) — reactive [Web Share API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
  - [`useTitle`](https://vueuse.org/core/useTitle/) — reactive document title
  - [`useUrlSearchParams`](https://vueuse.org/core/useUrlSearchParams/) — reactive [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
  - [`useWakeLock`](https://vueuse.org/core/useWakeLock/) — reactive [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API) provides a way to prevent devices from dimming or locking the screen when an application needs to keep running

### Component
  - [`computedInject`](https://vueuse.org/core/computedInject/) — combine computed and inject
  - [`templateRef`](https://vueuse.org/core/templateRef/) — shorthand for binding ref to template element
  - [`tryOnBeforeUnmount`](https://vueuse.org/shared/tryOnBeforeUnmount/) — safe `onBeforeUnmount`
  - [`tryOnMounted`](https://vueuse.org/shared/tryOnMounted/) — safe `onMounted`
  - [`tryOnScopeDispose`](https://vueuse.org/shared/tryOnScopeDispose/) — safe `onScopeDispose`
  - [`tryOnUnmounted`](https://vueuse.org/shared/tryOnUnmounted/) — safe `onUnmounted`
  - [`unrefElement`](https://vueuse.org/core/unrefElement/) — unref for dom element
  - [`useTemplateRefsList`](https://vueuse.org/core/useTemplateRefsList/) — shorthand for binding refs to template elements and components inside `v-for`
  - [`useVirtualList`](https://vueuse.org/core/useVirtualList/) — composable virtual list
  - [`useVModel`](https://vueuse.org/core/useVModel/) — shorthand for v-model binding
  - [`useVModels`](https://vueuse.org/core/useVModels/) — shorthand for props v-model binding

### Formatters
  - [`useTimeAgo`](https://vueuse.org/core/useTimeAgo/) — reactive time ago

### Misc
  - [`useEventSource`](https://vueuse.org/core/useEventSource/) — an [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) or [Server-Sent-Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) instance opens a persistent connection to an HTTP server
  - [`useWebSocket`](https://vueuse.org/core/useWebSocket/) — reactive [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket) client
  - [`useWebWorker`](https://vueuse.org/core/useWebWorker/) — simple [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) registration and communication
  - [`useWebWorkerFn`](https://vueuse.org/core/useWebWorkerFn/) — run expensive function without blocking the UI

### Sensors
  - [`onClickOutside`](https://vueuse.org/core/onClickOutside/) — listen for clicks outside of an element
  - [`onKeyStroke`](https://vueuse.org/core/onKeyStroke/) — listen for keyboard key being stroked
  - [`onStartTyping`](https://vueuse.org/core/onStartTyping/) — fires when users start typing on non-editable elements
  - [`useBattery`](https://vueuse.org/core/useBattery/) — reactive [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API)
  - [`useDeviceMotion`](https://vueuse.org/core/useDeviceMotion/) — reactive [DeviceMotionEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent)
  - [`useDeviceOrientation`](https://vueuse.org/core/useDeviceOrientation/) — reactive [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent)
  - [`useDevicePixelRatio`](https://vueuse.org/core/useDevicePixelRatio/) — reactively track [`window.devicePixelRatio`](https://developer.mozilla.org/ru/docs/Web/API/Window/devicePixelRatio)
  - [`useDevicesList`](https://vueuse.org/core/useDevicesList/) — reactive [enumerateDevices](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices) listing avaliable input/output devices
  - [`useDisplayMedia`](https://vueuse.org/core/useDisplayMedia/) — reactive [`mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) streaming
  - [`useDocumentVisibility`](https://vueuse.org/core/useDocumentVisibility/) — reactively track [`document.visibilityState`](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState)
  - [`useDraggable`](https://vueuse.org/core/useDraggable/) — make elements draggable
  - [`useElementBounding`](https://vueuse.org/core/useElementBounding/) — reactive [bounding box](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) of an HTML element
  - [`useElementHover`](https://vueuse.org/core/useElementHover/) — reactive element's hover state
  - [`useElementSize`](https://vueuse.org/core/useElementSize/) — reactive size of an HTML element
  - [`useElementVisibility`](https://vueuse.org/core/useElementVisibility/) — tracks the visibility of an element within the viewport
  - [`useGeolocation`](https://vueuse.org/core/useGeolocation/) — reactive [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API)
  - [`useIdle`](https://vueuse.org/core/useIdle/) — tracks whether the user is being inactive
  - [`useIntersectionObserver`](https://vueuse.org/core/useIntersectionObserver/) — detects that a target element's visibility
  - [`useKeyModifier`](https://vueuse.org/core/useKeyModifier/) — reactive [Modifier State](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState)
  - [`useMagicKeys`](https://vueuse.org/core/useMagicKeys/) — reactive keys pressed state
  - [`useMouse`](https://vueuse.org/core/useMouse/) — reactive mouse position
  - [`useMouseInElement`](https://vueuse.org/core/useMouseInElement/) — reactive mouse position related to an element
  - [`useMousePressed`](https://vueuse.org/core/useMousePressed/) — reactive mouse pressing state
  - [`useMutationObserver`](https://vueuse.org/core/useMutationObserver/) — watch for changes being made to the DOM tree
  - [`useNetwork`](https://vueuse.org/core/useNetwork/) — reactive [Network status](https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API)
  - [`useOnline`](https://vueuse.org/core/useOnline/) — reactive online state
  - [`usePageLeave`](https://vueuse.org/core/usePageLeave/) — reactive state to show whether the mouse leaves the page
  - [`useParallax`](https://vueuse.org/core/useParallax/) — create parallax effect easily
  - [`usePointer`](https://vueuse.org/core/usePointer/) — reactive [pointer state](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events)
  - [`usePointerSwipe`](https://vueuse.org/core/usePointerSwipe/) — reactive swipe detection based on [PointerEvents](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent)
  - [`useResizeObserver`](https://vueuse.org/core/useResizeObserver/) — reports changes to the dimensions of an Element's content or the border-box
  - [`useScroll`](https://vueuse.org/core/useScroll/) — reactive scroll position and state
  - [`useSpeechRecognition`](https://vueuse.org/core/useSpeechRecognition/) — reactive [SpeechRecognition](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition)
  - [`useSpeechSynthesis`](https://vueuse.org/core/useSpeechSynthesis/) — reactive [SpeechSynthesis](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis)
  - [`useSwipe`](https://vueuse.org/core/useSwipe/) — reactive swipe detection based on [`TouchEvents`](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent)
  - [`useUserMedia`](https://vueuse.org/core/useUserMedia/) — reactive [`mediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) streaming
  - [`useWindowFocus`](https://vueuse.org/core/useWindowFocus/) — reactively track window focus with `window.onfocus` and `window.onblur` events
  - [`useWindowScroll`](https://vueuse.org/core/useWindowScroll/) — reactive window scroll
  - [`useWindowSize`](https://vueuse.org/core/useWindowSize/) — reactive window size

### State
  - [`createGlobalState`](https://vueuse.org/shared/createGlobalState/) — keep states in the global scope to be reusable across Vue instances
  - [`createSharedComposable`](https://vueuse.org/shared/createSharedComposable/) — make a composable function usable with multiple Vue instances
  - [`useLocalStorage`](https://vueuse.org/core/useLocalStorage/) — reactive [LocalStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)
  - [`useSessionStorage`](https://vueuse.org/core/useSessionStorage/) — reactive [SessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)
  - [`useStorage`](https://vueuse.org/core/useStorage/) — reactive [LocalStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)/[SessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)

### Utilities
  - [`and`](https://vueuse.org/shared/and/) — `AND` condition for refs
  - [`asyncComputed`](https://vueuse.org/core/asyncComputed/) — computed for async functions
  - [`autoResetRef`](https://vueuse.org/core/autoResetRef/) — a ref which will be reset to the default value after some time
  - [`biSyncRef`](https://vueuse.org/shared/biSyncRef/) — two-way refs synchronization
  - [`controlledComputed`](https://vueuse.org/shared/controlledComputed/) — explicitly define the deps of computed
  - [`controlledRef`](https://vueuse.org/shared/controlledRef/) — fine-grained controls over ref and its reactivity
  - [`createEventHook`](https://vueuse.org/shared/createEventHook/) — utility for creating event hooks
  - [`eagerComputed`](https://vueuse.org/shared/eagerComputed/) — eager computed without lazy evaluation
  - [`extendRef`](https://vueuse.org/shared/extendRef/) — add extra attributes to Ref
  - [`get`](https://vueuse.org/shared/get/) — shorthand for accessing `ref.value`
  - [`isDefined`](https://vueuse.org/shared/isDefined/) — non-nullish checking type guard for Ref
  - [`makeDestructurable`](https://vueuse.org/shared/makeDestructurable/) — make isomorphic destructurable for object and array at the same time
  - [`not`](https://vueuse.org/shared/not/) — `NOT` condition for ref
  - [`or`](https://vueuse.org/shared/or/) — `OR` conditions for refs
  - [`reactify`](https://vueuse.org/shared/reactify/) — converts plain functions into reactive functions
  - [`reactifyObject`](https://vueuse.org/shared/reactifyObject/) — apply `reactify` to an object
  - [`reactivePick`](https://vueuse.org/shared/reactivePick/) — reactively pick fields from a reactive object
  - [`refDefault`](https://vueuse.org/shared/refDefault/) — apply default value to a ref
  - [`set`](https://vueuse.org/shared/set/) — shorthand for `ref.value = x`
  - [`syncRef`](https://vueuse.org/shared/syncRef/) — keep target refs in sync with a source ref
  - [`toReactive`](https://vueuse.org/shared/toReactive/) — converts ref to reactive
  - [`toRefs`](https://vueuse.org/shared/toRefs/) — extended [`toRefs`](https://v3.vuejs.org/api/refs-api.html#torefs) that also accepts refs of an object
  - [`useAsyncState`](https://vueuse.org/core/useAsyncState/) — reactive async state
  - [`useConfirmDialog`](https://vueuse.org/core/useConfirmDialog/) — creates event hooks to support modals and confirmation dialog chains
  - [`useCounter`](https://vueuse.org/shared/useCounter/) — basic counter with utility functions
  - [`useDebounce`](https://vueuse.org/shared/useDebounce/) — debounce execution of a ref value
  - [`useDebouncedRefHistory`](https://vueuse.org/core/useDebouncedRefHistory/) — shorthand for `useRefHistory` with debounced filter
  - [`useDebounceFn`](https://vueuse.org/shared/useDebounceFn/) — debounce execution of a function
  - [`useEventBus`](https://vueuse.org/core/useEventBus/) — a basic event bus
  - [`useLastChanged`](https://vueuse.org/shared/useLastChanged/) — records the timestamp of the last change
  - [`useManualRefHistory`](https://vueuse.org/core/useManualRefHistory/) — manually track the change history of a ref when the using calls `commit()`
  - [`useRefHistory`](https://vueuse.org/core/useRefHistory/) — track the change history of a ref
  - [`useThrottle`](https://vueuse.org/shared/useThrottle/) — throttle changing of a ref value
  - [`useThrottledRefHistory`](https://vueuse.org/core/useThrottledRefHistory/) — shorthand for `useRefHistory` with throttled filter
  - [`useThrottleFn`](https://vueuse.org/shared/useThrottleFn/) — throttle execution of a function
  - [`useToggle`](https://vueuse.org/shared/useToggle/) — a boolean switcher with utility functions

### Watch
  - [`debouncedWatch`](https://vueuse.org/shared/debouncedWatch/) — debounced watch
  - [`ignorableWatch`](https://vueuse.org/shared/ignorableWatch/) — ignorable watch
  - [`pausableWatch`](https://vueuse.org/shared/pausableWatch/) — pausable watch
  - [`throttledWatch`](https://vueuse.org/shared/throttledWatch/) — throttled watch
  - [`until`](https://vueuse.org/shared/until/) — promised one-time watch for changes
  - [`watchAtMost`](https://vueuse.org/shared/watchAtMost/) — `watch` with the number of times triggered
  - [`watchOnce`](https://vueuse.org/shared/watchOnce/) — `watch` that only triggers once
  - [`watchWithFilter`](https://vueuse.org/shared/watchWithFilter/) — `watch` with additional EventFilter control
  - [`whenever`](https://vueuse.org/shared/whenever/) — shorthand for watching value to be truthy


<!--FUNCTIONS_LIST_ENDS-->

<br>

More functions avaliable in [Add-ons](./add-ons).
<file_sep>import { ref, reactive } from 'vue-demi'
import { useThrottleFn, useDebounceFn, noop, MaybeRef } from '@vueuse/shared'
import { useEventListener } from '../useEventListener'

export interface UseScrollOptions {
  /**
   * Throttle time for scroll event,it’s disabled by default.
   *
   * @default 0
   */
  throttle?: number

  /**
   * The check time when scrolling ends.
   * This configuration will be setting to (throttle + idle) when the `throttle` is configured.
   *
   * @default 200
   */
  idle?: number

  /**
   * Offset arrived states by x pixels
   *
   */
  offset?: {
    left?: number
    right?: number
    top?: number
    bottom?: number
  }

  /**
   * Trigger it when scrolling.
   *
   */
  onScroll?: () => void

  /**
   * Trigger it when scrolling ends.
   *
   */
  onStop?: () => void

  /**
   * Listener options for scroll event.
   *
   * @default {capture: false, passive: true}
   */
  eventListenerOptions?: boolean | AddEventListenerOptions
}

/**
 * Reactive scroll.
 *
 * @see https://vueuse.org/useScroll
 * @param element
 * @param options
 */

export function useScroll(
  element: MaybeRef<HTMLElement | SVGElement | Window | Document | null | undefined>,
  options: UseScrollOptions = {},
) {
  const {
    throttle = 0,
    idle = 200,
    onStop = noop,
    onScroll = noop,
    offset = {
      left: 0,
      right: 0,
      top: 0,
      bottom: 0,
    },
    eventListenerOptions = {
      capture: false,
      passive: true,
    },
  } = options

  const x = ref(0)
  const y = ref(0)
  const isScrolling = ref(false)
  const arrivedState = reactive({
    left: true,
    right: false,
    top: true,
    bottom: false,
  })

  if (element) {
    const onScrollEnd = useDebounceFn(() => {
      isScrolling.value = false
      onStop()
    }, throttle + idle)

    const onScrollHandler = (e: Event) => {
      const eventTarget = (
        e.target === document ? (e.target as Document).documentElement : e.target
      ) as HTMLElement

      const scrollLeft = eventTarget.scrollLeft
      arrivedState.left = scrollLeft <= 0 + (offset.left || 0)
      arrivedState.right
          = scrollLeft + eventTarget.clientWidth >= eventTarget.scrollWidth - (offset.right || 0)
      x.value = scrollLeft

      const scrollTop = eventTarget.scrollTop
      arrivedState.top = scrollTop <= 0 + (offset.top || 0)
      arrivedState.bottom
          = scrollTop + eventTarget.clientHeight >= eventTarget.scrollHeight - (offset.bottom || 0)
      y.value = scrollTop

      isScrolling.value = true
      onScrollEnd()
      onScroll()
    }

    useEventListener(
      element,
      'scroll',
      throttle ? useThrottleFn(onScrollHandler, throttle) : onScrollHandler,
      eventListenerOptions,
    )
  }

  return {
    x,
    y,
    isScrolling,
    arrivedState,
  }
}

export type UseScrollReturn = ReturnType<typeof useScroll>
<file_sep>import { until } from '@vueuse/shared'
import fetchMock from 'jest-fetch-mock'
import { nextTick, ref } from 'vue-demi'
import { createFetch, useFetch } from '.'

describe('useFetch', () => {
  beforeEach(() => {
    fetchMock.resetMocks()
    fetchMock.enableMocks()
    fetchMock.doMock()
  })

  test('should have status code of 200 and message of Hello World', async() => {
    fetchMock.mockResponse('Hello World', { status: 200 })

    const { data, statusCode, isFinished } = useFetch('https://example.com')

    await until(isFinished).toBe(true)

    expect(statusCode.value).toBe(200)
    expect(data.value).toBe('Hello World')
  })

  test('should be able to use the Headers object', async() => {
    fetchMock.mockResponse('Hello World', { status: 200 })

    const myHeaders = new Headers()
    myHeaders.append('Authorization', 'test')

    const { statusCode, isFinished } = useFetch('https://example.com', { headers: myHeaders })

    await until(isFinished).toBe(true)

    expect(statusCode.value).toBe(200)
    expect(fetchMock.mock.calls[0][1]!.headers).toMatchObject({ authorization: 'test' })
  })

  test('should parse response as json', async() => {
    fetchMock.mockResponse(JSON.stringify({ message: 'Hello World' }), { status: 200 })

    const { data, isFinished } = useFetch('https://example.com').json()

    await until(isFinished).toBe(true)

    expect(data.value).toStrictEqual({ message: 'Hello World' })
  })

  test('should have an error on 400', async() => {
    fetchMock.mockResponse('', { status: 400 })

    const { error, statusCode, isFinished } = useFetch('https://example.com')

    await until(isFinished).toBe(true)

    expect(statusCode.value).toBe(400)
    expect(error.value).toBe('Bad Request')
  })

  test('should abort request and set aborted to true', async() => {
    fetchMock.mockResponse(() => new Promise(resolve => setTimeout(() => resolve({ body: 'ok' }), 1000)))

    const { aborted, abort, isFinished, execute } = useFetch('https://example.com')

    setTimeout(() => abort(), 0)

    await until(isFinished).toBe(true)
    expect(aborted.value).toBe(true)

    execute()

    setTimeout(() => abort(), 0)

    await until(isFinished).toBe(true)
    expect(aborted.value).toBe(true)
  })

  test('should not call if immediate is false', async() => {
    fetchMock.mockResponse('')

    useFetch('https://example.com', { immediate: false })
    await nextTick()

    expect(fetchMock).toBeCalledTimes(0)
  })

  test('should refetch if refetch is set to true', async() => {
    fetchMock.mockResponse('')

    const url = ref('https://example.com')
    const { isFinished } = useFetch(url, { refetch: true })

    await until(isFinished).toBe(true)
    url.value = 'https://example.com/test'
    await nextTick()
    await until(isFinished).toBe(true)

    expect(fetchMock).toBeCalledTimes(2)
  })

  test('should auto refetch when the refetch is set to true and the payload is a ref', async() => {
    fetchMock.mockResponse(JSON.stringify({ message: 'Hello World' }), { status: 200 })
    const param = ref({ num: 1 })
    const { isFinished } = useFetch('https://example.com', { refetch: true }).post(param)

    await until(isFinished).toBe(true)
    param.value.num = 2
    await nextTick()
    await until(isFinished).toBe(true)

    expect(fetchMock).toBeCalledTimes(2)
  })

  test('should create an instance of useFetch with a base url', async() => {
    fetchMock.mockResponse('')

    const useMyFetch = createFetch({ baseUrl: 'https://example.com', fetchOptions: { headers: { Authorization: 'test' } } })
    const { isFinished } = useMyFetch('test', { headers: { 'Accept-Language': 'en-US' } })

    await until(isFinished).toBe(true)

    expect(fetchMock.mock.calls[0][1]!.headers).toMatchObject({ 'Authorization': 'test', 'Accept-Language': 'en-US' })
    expect(fetchMock.mock.calls[0][0]).toEqual('https://example.com/test')
  })

  test('should run the beforeFetch function and add headers to the request', async() => {
    fetchMock.mockResponse('')

    const { isFinished } = useFetch('https://example.com', { headers: { 'Accept-Language': 'en-US' } }, {
      beforeFetch({ options }) {
        options.headers = {
          ...options.headers,
          Authorization: 'my-auth-token',
        }

        return { options }
      },
    })

    await until(isFinished).toBe(true)

    expect(fetchMock.mock.calls[0][1]!.headers).toMatchObject({ 'Authorization': 'my-auth-token', 'Accept-Language': 'en-US' })
  })

  test('should run the beforeFetch function and cancel the request', async() => {
    fetchMock.mockResponse('')

    const { execute } = useFetch('https://example.com', {
      immediate: false,
      beforeFetch({ cancel }) {
        cancel()
      },
    })

    await execute()

    expect(fetchMock).toBeCalledTimes(0)
  })

  test('should run the afterFetch function', async() => {
    fetchMock.mockResponse(JSON.stringify({ title: 'HxH' }), { status: 200 })

    const { isFinished, data } = useFetch('https://example.com', {
      afterFetch(ctx) {
        if (ctx.data.title === 'HxH')
          ctx.data.title = 'Hunter x Hunter'

        return ctx
      },
    }).json()

    await until(isFinished).toBe(true)
    expect(data.value).toStrictEqual({ title: 'Hunter x Hunter' })
  })

  test('should run the onFetchError function', async() => {
    fetchMock.mockResponse(JSON.stringify({ title: 'HxH' }), { status: 400 })

    const { isFinished, data, statusCode } = useFetch('https://example.com', {
      onFetchError(ctx) {
        if (ctx.data.title === 'HxH')
          ctx.data.title = 'Hunter x Hunter'

        return ctx
      },
    }).json()

    await until(isFinished).toBe(true)
    expect(statusCode.value).toStrictEqual(400)
    expect(data.value).toStrictEqual({ title: 'Hunter x Hunter' })
  })

  test('should run the onFetchError function when network error', async() => {
    fetchMock.mockResponse('Internal Server Error', { status: 500 })

    const { isFinished, data, statusCode } = useFetch('https://example.com', {
      onFetchError(ctx) {
        ctx.data = { title: 'Hunter x Hunter' }

        return ctx
      },
    }).json()

    await until(isFinished).toBe(true)
    expect(statusCode.value).toStrictEqual(500)
    expect(data.value).toStrictEqual({ title: 'Hunter x Hunter' })
  })

  test('should emit onFetchResponse event', async() => {
    let didEventFire = false
    const { isFinished, onFetchResponse } = useFetch('https://example.com')

    onFetchResponse(() => {
      didEventFire = true
    })

    await until(isFinished).toBe(true)
    expect(didEventFire).toBe(true)
  })

  test('should emit onFetchResponse event', async() => {
    fetchMock.mockResponse('', { status: 200 })

    let didResponseEventFire = false
    let didErrorEventFire = false
    let didFinallyEventFire = false
    const { isFinished, onFetchResponse, onFetchError, onFetchFinally } = useFetch('https://example.com')

    onFetchResponse(() => didResponseEventFire = true)
    onFetchError(() => didErrorEventFire = true)
    onFetchFinally(() => didFinallyEventFire = true)

    await until(isFinished).toBe(true)
    expect(didResponseEventFire).toBe(true)
    expect(didErrorEventFire).toBe(false)
    expect(didFinallyEventFire).toBe(true)
  })

  test('should emit onFetchError event', async() => {
    fetchMock.mockResponse('', { status: 400 })

    let didResponseEventFire = false
    let didErrorEventFire = false
    let didFinallyEventFire = false
    const { isFinished, onFetchResponse, onFetchError, onFetchFinally } = useFetch('https://example.com')

    onFetchResponse(() => didResponseEventFire = true)
    onFetchError(() => didErrorEventFire = true)
    onFetchFinally(() => didFinallyEventFire = true)

    await until(isFinished).toBe(true)
    expect(didResponseEventFire).toBe(false)
    expect(didErrorEventFire).toBe(true)
    expect(didFinallyEventFire).toBe(true)
  })

  test('setting the request method w/ get and return type w/ json', async() => {
    fetchMock.mockResponse(JSON.stringify({ message: 'Hello World' }), { status: 200 })

    const { data, isFinished } = useFetch('https://example.com').get().json()

    await until(isFinished).toBe(true)

    expect(data.value).toStrictEqual({ message: 'Hello World' })
  })

  test('setting the request method w/ post and return type w/ text', async() => {
    fetchMock.mockResponse(JSON.stringify({ message: 'Hello World' }), { status: 200 })

    const { data, isFinished } = useFetch('https://example.com').post().text()

    await until(isFinished).toBe(true)

    expect(data.value).toStrictEqual(JSON.stringify({ message: 'Hello World' }))
  })

  test('allow setting response type before doing request', async() => {
    fetchMock.mockResponse(JSON.stringify({ message: 'Hello World' }), { status: 200 })

    const shell = useFetch('https://example.com', {
      immediate: false,
    }).get().text()
    shell.json()
    shell.execute()
    const { isFinished, data } = shell
    await until(isFinished).toBe(true)

    expect(data.value).toStrictEqual({ message: 'Hello World' })
  })

  test('not allowed setting response type while doing request', async() => {
    fetchMock.mockResponse(JSON.stringify({ message: 'Hello World' }), { status: 200 })

    const shell = useFetch('https://example.com').get().text()
    const { isFetching, isFinished, data } = shell
    await until(isFetching).toBe(true)
    shell.json()
    await until(isFinished).toBe(true)

    expect(data.value).toStrictEqual(JSON.stringify({ message: 'Hello World' }))
  })

  test('should abort request when timeout reached', async() => {
    fetchMock.mockResponse(() => new Promise(resolve => setTimeout(() => resolve({ body: 'ok' }), 1000)))

    const { aborted, isFinished, execute } = useFetch('https://example.com', { timeout: 10 })

    await until(isFinished).toBe(true)
    expect(aborted.value).toBe(true)

    execute()

    await until(isFinished).toBe(true)
    expect(aborted.value).toBe(true)
  })

  test('should not abort request when timeout is not reached', async() => {
    fetchMock.mockResponse(JSON.stringify({ message: 'Hello World' }), { status: 200 })

    const shell = useFetch('https://example.com', { timeout: 100 }).get().text()
    const { isFetching, isFinished, data } = shell
    await until(isFetching).toBe(true)
    shell.json()
    await until(isFinished).toBe(true)

    expect(data.value).toStrictEqual(JSON.stringify({ message: 'Hello World' }))
  })
})
<file_sep>import { Ref, ref } from 'vue-demi'
import { MaybeRef } from '@vueuse/shared'
import { useEventListener } from '../useEventListener'

export function useElementHover(el: MaybeRef<EventTarget>): Ref<boolean> {
  const isHovered = ref(false)

  useEventListener(el, 'mouseenter', () => isHovered.value = true)
  useEventListener(el, 'mouseleave', () => isHovered.value = false)

  return isHovered
}
<file_sep>import { Ref, ref, shallowRef } from 'vue-demi'
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, CancelTokenSource, AxiosInstance } from 'axios'

export interface UseAxiosReturn<T> {

  /**
   * Axios Response
   */
  response: Ref<AxiosResponse<T> | undefined>

  /**
   * Axios response data
   */
  data: Ref<T | undefined>

  /**
   * Indicates if the request has finished
   */
  isFinished: Ref<boolean>

  /**
   * Indicates if the request is currently loading
   */
  isLoading: Ref<boolean>

  /**
   * Indicates if the request was canceled
   */
  aborted: Ref<boolean>

  /**
   * Any errors that may have occurred
   */
  error: Ref<AxiosError<T> | undefined>

  /**
   * Aborts the current request
   */
  abort: (message?: string | undefined) => void
}

export function useAxios<T = any>(url: string, config?: AxiosRequestConfig): UseAxiosReturn<T>
export function useAxios<T = any>(url: string, instance?: AxiosInstance): UseAxiosReturn<T>
export function useAxios<T = any>(url: string, config: AxiosRequestConfig, instance: AxiosInstance): UseAxiosReturn<T>

/**
 * Wrapper for axios.
 *
 * @see https://vueuse.org/useAxios
 * @param url
 * @param config
 */
export function useAxios<T = any>(url: string, ...args: any[]) {
  let config: AxiosRequestConfig = {}
  let instance: AxiosInstance = axios

  if (args.length > 0) {
    /**
     * Unable to use `instanceof` here becuase of (https://github.com/axios/axios/issues/737)
     * so instead we are checking if there is a `requset` on the object to see if it is an
     * axios instance
     */
    if ('request' in args[0])
      instance = args[0]
    else
      config = args[0]
  }

  if (args.length > 1) {
    if ('request' in args[1])
      instance = args[1]
  }

  const response = shallowRef<AxiosResponse<T>>()
  const data = shallowRef<T>()
  const isFinished = ref(false)
  const isLoading = ref(true)
  const aborted = ref(false)
  const error = shallowRef<AxiosError<T>>()

  const cancelToken: CancelTokenSource = axios.CancelToken.source()
  const abort = (message?: string) => {
    if (isFinished.value || !isLoading.value) return

    cancelToken.cancel(message)
    aborted.value = true
    isLoading.value = false
    isFinished.value = false
  }

  instance(url, { ...config, cancelToken: cancelToken.token })
    .then((r: any) => {
      response.value = r
      data.value = r.data
    })
    .catch((e: any) => {
      error.value = e
    })
    .finally(() => {
      isLoading.value = false
      isFinished.value = true
    })

  return {
    response,
    data,
    error,
    finished: isFinished,
    loading: isLoading,
    isFinished,
    isLoading,
    cancel: abort,
    canceled: aborted,
    aborted,
    abort,
  }
}
<file_sep>import Fuse from 'fuse.js'
import { ref, computed, watch, unref, ComputedRef } from 'vue-demi'
import { MaybeRef } from '@vueuse/shared'

export type FuseOptions<T> = Fuse.IFuseOptions<T>
export type UseFuseOptions<T> = {
  fuseOptions?: FuseOptions<T>
  resultLimit?: number
  matchAllWhenSearchEmpty?: boolean
}

export function useFuse<DataItem>(
  search: MaybeRef<string>,
  data: MaybeRef<DataItem[]>,
  options?: MaybeRef<UseFuseOptions<DataItem>>,
) {
  const createFuse = (data: MaybeRef<DataItem[]>, options?: FuseOptions<DataItem>) => {
    const _options = options

    return new Fuse(
      unref(data) ?? [],
      _options,
    )
  }

  const fuse = ref(createFuse(data, unref(options)?.fuseOptions))

  watch(
    () => unref(options)?.fuseOptions,
    (newOptions) => { fuse.value = createFuse(data, newOptions) },
    { deep: true },
  )

  watch(
    () => unref(data),
    (newData) => { fuse.value.setCollection(newData) },
    { deep: true },
  )

  const results: ComputedRef<Fuse.FuseResult<DataItem>[]> = computed(() => {
    // This will also be recomputed when `data` changes, as it causes a change
    // to the Fuse instance, which is tracked here.
    if (unref(options)?.matchAllWhenSearchEmpty && !unref(search))
      return unref(data).map((item, index) => ({ item, refIndex: index }))

    const limit = unref(options)?.resultLimit
    return fuse.value.search(unref(search), (limit ? { limit } : undefined))
  })

  return {
    results,
  }
}

export type UseFuseReturn = ReturnType<typeof useFuse>
