[
  {
    "path": ".eslintignore",
    "content": "/dist\n/docs\n/test\n/docs\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  env: {\n    browser: true,\n    es2021: true\n  },\n  extends: [\n    'plugin:react/recommended',\n    'standard-with-typescript'\n  ],\n  parserOptions: {\n    project: './tsconfig.json',\n    ecmaVersion: 'latest',\n    sourceType: 'module'\n  },\n  plugins: [\n    'react'\n  ],\n  rules: {\n    'max-len': [\n      'error',\n      {\n        code: 140\n      }\n    ],\n    semi: [\n      2,\n      'never'\n    ],\n    '@typescript-eslint/semi': 'off',\n    'linebreak-style': 'off',\n    'object-curly-newline': 'off',\n    'react/jsx-filename-extension': 'off',\n    'import/no-named-as-default': 'off',\n    'import/no-named-as-default-member': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/strict-boolean-expressions': 'off',\n    '@typescript-eslint/no-non-null-assertion': 'off',\n    '@typescript-eslint/no-invalid-void-type': 'off'\n  },\n  overrides: [\n    {\n      files: [\n        '*.test.js',\n        '*.spec.js',\n        '*.test.jsx',\n        '*.spec.jsx'\n      ],\n      globals: {\n        expect: 'readonly',\n        should: 'readonly',\n        sinon: 'readonly'\n      },\n      rules: {\n        'no-unused-expressions': 'off'\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--- Provide a general summary of your changes in the Title above -->\n\n## Description\n<!--- Describe your changes in detail -->\n\n## Related Issue\n<!--- This project only accepts pull requests related to open issues -->\n<!--- If suggesting a new feature or change, please discuss it in an issue first -->\n<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->\n<!--- Please link to the issue here: -->\n\n## Motivation and Context\n<!--- Why is this change required? What problem does it solve? -->\n<!--- If it fixes an open issue, please link to the issue here. -->\n\n## How Has This Been Tested?\n<!--- Please describe in detail how you tested your changes. -->\n<!--- Include details of your testing environment, and the tests you ran to -->\n<!--- see how your change affects other areas of the code, etc. -->\n\n## Screenshots (if appropriate):\n"
  },
  {
    "path": ".github/tests_checker.yml",
    "content": "comment: 'Hello, thank you for contributing! It looks like your PR introduces new code that has not been tested, please make to add some tests as soon as you can.',\nfileExtensions: ['.ts', '.js']\ntestDir: 'test'\n"
  },
  {
    "path": ".github/workflows/branch-tests.yml",
    "content": "name: Tests\n\non:\n  push:\n    branches-ignore:\n      - master\n  pull_request:\n    branches-ignore:\n      - master\n\njobs:\n  test:\n    if: \"!contains(github.event.head_commit.message, 'skip ci')\"\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          node-version: 18.14\n\n      - run: npm install\n      - run: npm run lint\n      - run: npm run build\n      - run: npm test\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI/CD\n\nenv:\n  CI: true\n\non:\n  push:\n    branches: [ master ]\n    paths-ignore:\n      - 'docs/**'\n      - '*.md'\njobs:\n  ci-cd:\n    if: \"!contains(github.event.head_commit.message, 'skip ci')\"\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          node-version: 18.14\n          registry-url: https://registry.npmjs.org/\n\n      - name: NPM Install\n        run: npm install\n\n      - name: Build\n        run: npm run build\n\n      - name: Tests (with coverage)\n        run: npm test -- --coverage\n\n      - name: Coveralls GitHub Action\n        uses: coverallsapp/github-action@v2\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build website (Github pages)\n        run: npm run build-doc --if-present\n\n      - name: Publish website on GitHub Pages\n        uses: crazy-max/ghaction-github-pages@v3\n        with:\n          build_dir: dist-ghpages\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Prepare distribution\n        run: |\n          node scripts/generate-exports.js\n          cp package.json README.md LICENSE.txt CHANGELOG.md CONTRIBUTING.md CODE_OF_CONDUCT.md ./dist\n\n      - name: Publish\n        run: |\n          npm pack\n          npx semantic-release\n        working-directory: ./dist\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "################  NODE.JS\n# 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 (https://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# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# next.js build output\n.next\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless\n\n################  VISUAL STUDIO CODE\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\n################  LINUX\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n################  MAC OS\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n################  WINDOWS\n# Windows thumbnail cache files\nThumbs.db\nehthumbs.db\nehthumbs_vista.db\n\n# Dump file\n*.stackdump\n\n# Folder styleguidist file\n[Dd]esktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n################  JETBRAINS\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/**/dictionaries\n.idea/**/shelf\n\n# Sensitive or high-churn files\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n.idea/**/dbnavigator.xml\n\n# Gradle\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# CMake\ncmake-build-debug/\ncmake-build-release/\n\n# Mongo Explorer plugin\n.idea/**/mongoSettings.xml\n\n# File-based project format\n*.iws\n\n# IntelliJ\nout/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Cursive Clojure plugin\n.idea/replstate.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n# Editor-based Rest Client\n.idea/httpRequests\n\n\n################  SUBLIME TEXT\n# Cache files for Sublime Text\n*.tmlanguage.cache\n*.tmPreferences.cache\n*.stTheme.cache\n\n# Workspace files are user-specific\n*.sublime-workspace\n\n# Project files should be checked into the repository, unless a significant\n# proportion of contributors will probably not be using Sublime Text\n# *.sublime-project\n\n# SFTP configuration file\nsftp-config.json\n\n# Package control specific files\nPackage Control.last-run\nPackage Control.ca-list\nPackage Control.ca-bundle\nPackage Control.system-ca-bundle\nPackage Control.cache/\nPackage Control.ca-certs/\nPackage Control.merged-ca-bundle\nPackage Control.user-ca-bundle\noscrypto-ca-bundle.crt\nbh_unicode_properties.cache\n\n# Sublime-github package stores a github token in this file\n# https://packagecontrol.io/packages/sublime-github\nGitHub.sublime-settings\n\n.idea/\n\ndist/\ndist-ghpages/\n\ncoverage.lcov\n\n## as it is intended for projects not libraries\nyarn.lock\npackage-lock.json\n"
  },
  {
    "path": ".huskyrc",
    "content": "{\n \"hooks\": {\n   \"pre-commit\": \"npm run lint\"\n }\n}\n"
  },
  {
    "path": ".mocharc.json",
    "content": "{\n  \"require\": [\n    \"jsdom-global/register\",\n    \"@babel/register\",\n    \"regenerator-runtime/runtime\",\n    \"mock-local-storage\",\n    \"./test/_setup.js\"\n  ]\n}\n"
  },
  {
    "path": ".npmrc",
    "content": "save-exact=true"
  },
  {
    "path": ".nycrc",
    "content": "{\n  \"all\": true,\n  \"reporter\": [\"lcov\"],\n  \"check-coverage\": true,\n  \"extension\": [ \".js\" ],\n  \"include\": [ \"dist/*.js\" ],\n  \"exclude\": [ \"dist/index.js\", \"dist/_virtual/**/*.js\" ],\n  \"branches\": 50,\n  \"lines\": 80,\n  \"functions\": 70,\n  \"statements\": 70\n}\n"
  },
  {
    "path": ".releaserc.json",
    "content": "{\n  \"branches\": [\n    \"master\"\n  ],\n  \"tagFormat\": \"v${version}\",\n  \"plugins\": [\n    \"@semantic-release/commit-analyzer\",\n    [\n      \"@semantic-release/exec\",\n      {\n        \"successCmd\": \"node ../scripts/update-version.js ${nextRelease.version} && node ../scripts/generate-exports.js && sh ../scripts/commit-version.sh ${nextRelease.version}\"\n      }\n    ],\n    \"@semantic-release/npm\",\n    \"@semantic-release/changelog\",\n    [\n      \"@semantic-release/git\",\n      {\n        \"assets\": [\n          \"../package.json\"\n        ],\n        \"message\": \"chore(release): ${nextRelease.version} [skip ci]\\n\\n${nextRelease.notes}\"\n      }\n    ],\n    \"@semantic-release/github\"\n  ]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres\nto [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n\n## [0.1.0] - 2019-12-18\n\n### Added\n\n- Create package.json\n- Setup .gitignore\n- Add a CHANGELOG.md\n- Add a Readme.md and a Contributing.md\n- Add Styleguidist\n- Add ESLint\n- Add Stylelint\n- Tests\n- Build System\n- useCallbackRef hook & tests\n- useDidMount hook & tests\n- useWillUnmount hook & tests\n- useLifecycle hook & tests\n- useWindowResize hook & tests\n- Auto-generating documentation script\n\n## [0.2.0] - 2019-12-20\n\n### Added\n\n- useDebouncedFn hook & tests\n\n## [0.3.0] - 2019-12-21\n\n### Added\n\n- useMouseEvents hook & tests\n- useMouseState hook & tests\n- useMouse hook & tests\n\n## [0.3.1] - 2019-12-23\n\n### Fixed\n\n- Adding babel-plugin-istanbul to solve [this issue with istanbul/nyc](https://github.com/istanbuljs/nyc/issues/706)\n\n## [0.4.0] - 2019-12-23\n\n### Added\n\n- Adding playground build as a gitpages website\n- Adding better documentation\n\n## [0.5.0] - 2019-12-24\n\n### Added\n\n- useInterval hook & tests\n- useTimeout hook & tests\n\n## [0.5.1] - 2019-12-24\n\n### Fixed\n\n- Build workflow performs tests twice\n\n## [0.6.0] - 2019-12-24\n\n### Added\n\n- useThrottledFn hook & tests\n- debounce and throttle utilities\n\n## [0.7.0] - 2019-12-24\n\n### Added\n\n- useWindowScroll hook & tests\n\n## [0.8.0] - 2019-12-28\n\n### Added\n\n- useGlobalEvent hook & tests\n\n## [0.8.1] - 2019-12-28\n\n### Fixed\n\n- Few documentation typos\n\n## [0.8.2] - 2019-12-28\n\n### Fixed\n\n- Few documentation typos\n- README image\n\n### Added\n\n- Types support\n\n## [0.8.3] - 2019-12-28\n\n### Fixed\n\n- Few documentation typos\n\n## [0.9.0] - 2019-12-29\n\n### Fixed\n\n- usePreviousValue hook & tests\n\n## [0.9.1] - 2019-12-29\n\n### Fixed\n\n- peerDependencies\n- build was missing\n- usePreviousValue types were missing\n\n## [0.9.2] - 2019-12-29\n\n### Fixed\n\n- React & ReactDom moved to `devDependencies`\n\n## [0.9.3] - 2019-12-29\n\n### Fixed\n\n- Package name for public usage\n\n## [0.10.0] - 2019-12-30\n\n### Added\n\n- Code of conduct\n- Contributing guidelines\n- issue template\n- pull request template\n\n## [0.10.1] - 2019-12-30\n\n### Fixed\n\n- correct package.json version\n- dependencies update\n\n## [0.11.0] - 2019-12-30\n\n### Added\n\n- Rewriting `useMouseHandler` into `useMouseEvents`\n\n### Fixed\n\n- documentation typos\n\n## [0.11.1] - 2019-12-31\n\n### Fixed\n\n- documentation typos\n\n## [0.12.0] - 2019-12-31\n\n### Added\n\n- useGeolocationEvents hook & tests\n- useGeolocationState hook & tests\n- useGeolocation hook & tests\n\n## [0.13.0] - 2020-01-02\n\n### Added\n\n- useMediaQuery hook & tests\n- change the order of the listed hooks into the Readme.md file\n\n### Fixed\n\n- `useOnMount` renamed to `useDidMount`\n\n## [0.13.1] - 2020-01-02\n\n### Fixed\n\n- Usage example image\n\n## [0.13.2] - 2020-01-02\n\n### Fixed\n\n- improved `useCallbackRef` documentation\n- changed lib logo\n\n## [0.13.3] - 2020-01-05\n\n### Fixed\n\n- removed wrong `useCallbackRef` dependencies\n- dependency check on other event related hooks\n\n## [0.13.4] - 2020-01-06\n\n### Fixed\n\n- Switching CI to Travis\n\n## [0.13.5] - 2020-01-06\n\n### Fixed\n\n- useTimeout refactory\n\n## [0.13.6] - 2020-01-07\n\n### Fixed\n\n- few hooks refactory\n- Improved documentation by a better use of Styleguidist\n- Improved types\n\n## [0.13.7] - 2020-01-07\n\n### Fixed\n\n- `usePrev` renamed to `usePreviousValue`\n\n## [0.13.8] - 2020-01-09\n\n### Fixed\n\n- Fix on `usePreviousValue` type\n\n## [0.13.9] - 2020-01-09\n\n### Fixed\n\n- Fixing CI\n\n## [0.14.0] - 2020-01-10\n\n### Added\n\n- useValueHistory hook & tests\n\n## [0.15.0] - 2020-01-10\n\n### Added\n\n- useOnlineState hook\n\n## [0.16.0] - 2020-01-10\n\n### Added\n\n- Repository ownership changed from `antonioru` to `beautifulinteractions`\n\n## [0.17.0] - 2020-01-10\n\n### Added\n\n- useViewportSpy hook & tests\n- Improved documentation\n\n## [0.17.1] - 2020-01-10\n\n### Fixed\n\n- types reference into package.json\n\n## [0.17.2] - 2020-01-12\n\n### Fixed\n\n- Fixed license in package.json\n\n## [0.18.0] - 2020-01-13\n\n### Added\n\n- useDragEvents hook & tests\n- useDrag hook\n\n### Fixed\n\n- event handlers uses the right parameters and avoid using (...args)\n- `useCallbackRef` has been reverted to an internal utility\n\n## [0.18.1] - 2020-01-14\n\n### Fixed\n\n- Build removed from the source package\n\n## [0.18.2] - 2020-01-20\n\n### Fixed\n\n- useOnlineState returns true when the device does not support the `online/offline` state assuming the app is already online\n- Improved test\n\n## [0.19.0] - 2020-01-21\n\n### Added\n\n- useConditionalTimeout hook & tests\n\n### Fixed\n\n- adding react and react-dom as dev-dependencies\n\n## [0.19.1] - 2020-01-21\n\n### Fixed\n\n- adding types for useConditionalTimeout\n\n## [0.19.2] - 2020-01-22\n\n### Fixed\n\n- Updated typings for cancelable functions. Updated docs.\n\n## [0.19.3] - 2020-01-25\n\n### Added\n\n- Support windows. Add .npmrc for saving exact version of dependencies\n\n## [0.19.4] - 2020-01-25\n\n### Fixed\n\n- Updating dependencies\n- Improving documentation by using `beautiful-react-ui` components\n\n## [0.20.0] - 2020-01-27\n\n### Added\n\n- useValidatedState hook & tests\n\n## [0.20.1] - 2020-01-27\n\n### Fixed\n\n- Adding useValidatedState into README.md\n- Rewriting README.md\n- Moved beautiful-react-ui from dependencies to dev-dependencies\n\n## [0.21.0] - 2020-02-17\n\n### Added\n\n- useRequestAnimationFrame hook & tests\n\n## [0.21.1] - 2020-02-20\n\n### Fixed\n\n- Fix isSupported when window is not defined to allow SSR\n\n## [0.22.0] - 2020-02-21\n\n### Added\n\n- useLocalStorage hook & tests & docs & types\n\n## [0.22.1] - 2020-02-21\n\n### Fixed\n\n- improving SSR check and window.* check before usage\n- adding SSR warning to `useRequestAnimationFrame`\n- improving `useLocalStorage` documentation\n\n## [0.22.2] - 2020-02-21\n\n### Fixed\n\n- dependencies update\n\n## [0.22.3] - 2020-03-11\n\n### Added\n\n- Adding Chinese translation of README.md\n\n## [0.22.4] - 2020-03-11\n\n### Fixed\n\n- Fixing missing links between README.md files\n\n## [0.22.5] - 2020-03-12\n\n### Added\n\n- Adding Italian translation of README.md\n\n## [0.22.6] - 2020-03-12\n\n### Fixed\n\n- Fixing missing image links in italian Readme.md\n\n## [0.22.7] - 2020-03-12\n\n### Fixed\n\n- Adding Spanish translation of README.md\n\n## [0.22.8] - 2020-03-14\n\n### Fixed\n\n- Adding Ukranian translation of README.md\n\n## [0.22.9] - 2020-03-14\n\n### Fixed\n\n- Fixing package version\n\n## [0.22.10] - 2020-03-17\n\n### Fixed\n\n- Adding Polish translation of README.md\n\n## [0.22.11] - 2020-03-17\n\n### Fixed\n\n- Fixing Polish translation of README.md\n\n## [0.22.12] - 2020-03-17\n\n### Fixed\n\n- Fixing links to hooks in language specific README files\n\n## [0.23.0] - 2020-03-17\n\n### Added\n\n- useDropZone hook & tests\n\n## [0.23.1] - 2020-03-18\n\n### Fixed\n\n- Fixing links in Contributing section and minor typos in language specific README files\n\n## [0.24.0] - 2020-03-26\n\n### Added\n\n- useStorage hook & tests\n\n## [0.24.1] - 2020-05-09\n\n### Fixed\n\n- adding SSR warning to `useLocalStorage` hook\n- adding warning to `useLocalStorage` hook if `localStorage` is not in `window` object\n- adding new test for `useLocalStorage` hook that checks that `localStorage` in `window` object\n\n## [0.25.0] - 2020-05-09\n\n### Changed\n\n- Improved build system by removing gulp and introducing rollup\n- tests directory from `src` to `tests`\n- Dependencies updated\n\n## [0.25.1] - 2020-05-10\n\n### Changed\n\n- Tests improved by running them from the dist folder\n\n## [0.25.2] - 2020-05-12\n\n### Changed\n\n- Fixed double `npm run build-doc` script run before deploy\n\n## [0.25.3] - 2020-06-16\n\n### Fixed\n\n- Type declaration fix for `useDebouncedFn` and `useThrottledFn`\n\n## [0.25.4] - 2020-06-16\n\n### Fixed\n\n- useInterval, clear the previous interval when the milliseconds value changes.\n\n## [0.25.5] - 2020-06-17\n\n### Fixed\n\n- Introducing ESModules build\n\n## [0.25.6] - 2020-07-03\n\n### Fixed\n\n- `module` property added to `package.jsoin` to support ESModules\n\n## [0.26.0] - 2020-07-06\n\n### Added\n\n- useSessionStorage hook & documentation\n- useStorage refactory\n- useStorage types refactory\n\n## [0.27.0] - 2020-07-06\n\n### Added\n\n- useResizeObserver hook & documentation\n\n## [0.27.1] - 2020-07-08\n\n### Fixed\n\n- useStorage throws an error on server side rendering as the window object is not defined yet\n\n## [0.27.2] - 2020-07-16\n\n### Fixed\n\n- useInterval clear function is now correctly used as useEffect cleanup\n- Rollup configuration `preserveModules` bug\n\n## [0.27.3] - 2020-08-12\n\n### Fixed\n\n- useTimeout clear function is now correctly used as useEffect cleanup\n- CI minor issues\n\n## [0.27.4] - 2020-08-15\n\n### Added\n\n- `useValueHistory` can now be used with distinct history\n\n### Fixed\n\n- dependencies update\n- CI minor issues\n\n## [0.28.0] - 2020-08-15\n\n### Added\n\n- `useDefaultedState` hook and tests\n\n## [0.29.0] - 2020-08-31\n\n### Added\n\n- `useObservable` hook and tests\n\n### Fixed\n\n- CI minor issues\n\n## [0.30.0] - 2020-09-04\n\n### Added\n\n- `useSystemVoices` hook and tests\n- `useSpeechSynthesis` hook and tests\n\n## [0.30.1] - 2020-09-11\n\n### Fixed\n\n- `useLocalStoreage` types fix\n\n## [0.30.2] - 2020-09-27\n\n### Added\n\n- Better dist package\n\n## [0.30.3] - 2020-09-27\n\n### Fixed\n\n- CI bugfix\n\n## [0.30.4] - 2020-09-27\n\n### Fixed\n\n- Wrong path settings in package.json causes the library to be empty\n\n## [0.30.5] - 2020-09-27\n\n### Fixed\n\n- Wrong CI settings causes the library to be empty\n\n## [0.30.6] - 2020-10-09\n\n### Fixed\n\n- Webpack 5 error with the `isDevelopment` constant\n\n## [0.31.0] - 2020-10-09\n\n### Added\n\n- `useRenderInfo` hook and tests\n\n## [0.31.1] - 2020-10-09\n\n### Added\n\n- Support for SSR in `isAPISupport`\n\n### Fixed\n\n- Documentation link\n\n## [0.32.0] - 2021-05-06\n\n### Added\n\n- `useTouchEvents`, `useTouchState` hook\n- `useSwipe`, `useHorizontalSwipe` and `useVerticalSwipe` hook\n\n### Fixed\n\n- `useMouseEvents` flaws\n- improved docs\n\n### Removed\n\n- `useConditionalTimeout` hook\n\n## [0.32.1] - 2021-05-07\n\n### Fixed\n\n- `useSwipe` typings\n\n### Removed\n\n- `useConditionalTimeout` hook\n\n## [0.33.0] - 2021-05-08\n\n### Added\n\n- `useSwipeEvents` hook\n\n### Fixed\n\n- typings module\n\n## [0.33.1] - 2021-05-09\n\n### Fixed\n\n- `useSwipe` types\n\n## [0.33.2] - 2021-05-09\n\n### Fixed\n\n- converted `HandlerSetter` type to better generic type\n\n## [0.33.3] - 2021-05-09\n\n### Fixed\n\n- `useSwipeEvents` swipe performing only once in the same direction\n\n## [0.33.4] - 2021-05-09\n\n### Fixed\n\n- `HandlerSetter` types a function taking another function as parameter\n\n## [0.33.5] - 2021-05-12\n\n### Fixed\n\n- index exports `useHorizontalSwipe` and  `useVerticalSwipe`\n\n## [0.34.0] - 2021-05-12\n\n### Added\n\n- `useSwipeEvents` exports `onSwipeMove`\n\n### Fixed\n\n- `useMediaQuery` addEventListener bug\n\n## [0.34.1] - 2021-05-12\n\n### Fixed\n\n- removed useless console.log from `useSwipe`\n\n## [0.35.0] - 2021-05-12\n\n### Added\n\n- `useSwipeEvents` exports`onSwipeEnd`,`onSwipeStart`\n\n## [1.0.0] - 2021-08-27\n\n### Change\n\n- Complete typescript rewrite\n\n## [1.0.1] - 2021-08-27\n\n### Fixed\n\n- Changing to the handler function do not cause the handler setter refs to update\n\n## [1.0.2] - 2021-10-06\n\n### Fixed\n\n- Updating useGlobalEvent ref to the provided function\n\n## [1.0.3] - 2022-01-26\n\n### Fixed\n\n- Updating useValueHistory's misuse of Array.prototype.filter to update history.current\n\n## [1.0.4] - 2022-01-27\n\n### Fixed\n\n- Type definitions on useResizeObserver\n\n## [1.0.5] - 2022-01-27\n\n### Fixed\n\n- Refs are typed as RefObject<T>, which is more correct as they are React-managed refs.\n\n## [1.0.6] - 2022-01-27\n\n### Fixed\n\n- `useDebouncedFn` and `useThrottledFn` refs\n\n## [1.2.0] - 2022-01-27\n\n### Added\n\n- rewriting `useDebouncedFn` and `useThrottledFn` as `useDebouncedCallback` and `useThrottledCallback`\n- `useDebouncedCallback` and `useThrottledCallback` improvements\n\n## [1.2.1] - 2022-02-14\n\n### Fixed\n\n- Reverted rewrite of `useDebouncedFn` and `useThrottledFn`, as they were breaking changes. Will release those as `2.0.0`.\n\n## [2.0.0] - 2022-05-05\n\n### Added\n\n- rewriting `useDebouncedFn` and `useThrottledFn` as `useDebouncedCallback` and `useThrottledCallback` - BREAKING CHANGE\n- `useDebouncedCallback` and `useThrottledCallback` improvements\n\n## [2.0.1] - 2022-06-11\n\n### Fixed\n\n- fixes useConditionalTimeout clearing function\n\n## [2.1.0] - 2022-06-11\n\n### Added\n\n- introduces `useInfiniteScroll`\n\n## [3.0.0] - 2022-06-12\n\n### Added\n\n- rewrite of useEvent and useGlobalEvent as well as the hooks using those\n\n## [3.1.0] - 2022-06-13\n\n### Added\n\n- introduces `useViewportState`\n\n## [3.1.1] - 2022-06-13\n\n### fixes\n\n- fix(release): updates release process and changelog\n\n## [3.1.2] - 2022-06-13\n\nErrored release\n\n## [3.1.3] - 2022-06-13\n\nErrored release\n\n## [3.1.4] - 2022-06-14\n\n### Fixes\n\n- Fixes CI, semantic-release\n\n## [3.1.5] - 2022-06-14\n\n### Fixes\n\n- fix(useQueryParam): revert to version 5 of react-router-dom\n\n## [3.1.6] - 2022-06-14\n\n### Fixes\n\n- useQueryParams, adds support for param deletion\n\n## [3.2.0] - 2022-06-14\n\n### Adds\n\n- useQueryParams, adds support for param deletion\n\n## [3.2.1] - 2022-06-14\n\n### Fixes\n\n- useQueryParams types\n\n## [3.2.2] - 2022-06-14\n\n### Fixes\n\n- CI\n\n## [3.3.0] - 2022-06-14\n\n### Fixes\n\n- feat(useQueryParams): adds useQueryParams\n\n## [3.3.0] - 2022-06-20\n\n### Adds\n\n- feat(useQueryParams): adds useQueryParams\n\n## [3.3.1] - 2022-06-20\n\n### Fixes\n\n- useQueryParams and useQueryParam state bugs\n\n## [3.4.0] - 2022-06-22\n\n### Adds\n\n- feat(timeouts): increase the general timeout/delay value\n\n## [3.5.0] - 2022-06-23\n\n### Added\n\n- feat(hook): introduces useURLSearchParams\n\n## [3.5.1] - 2022-06-25\n\n### Fixes\n\n- error handling for useStorage hook\n- add more types for useStorage hook, fix bug where storage wasn't being set on initial render\n\n## [3.5.2] - 2022-06-27\n\n### Fixes\n\n- wrap setValue from useStorage hook in useCallback to persist reference\n\n## [3.5.2] - 2022-06-27\n\n### Fixes\n\n- wrap setValue from useSt\n\n## [3.6.0] - 2022-06-27\n\n### Adds\n\n- useCookie hook\n\n## [3.6.1] - 2022-06-27\n\n### Fixes\n\n- wraps useStorage's setValue in a useCallback hook\n\n## [3.6.2] - 2022-06-28\n\n### Fixes\n\n- useTimeout return type\n\n## [3.7.0] - 2022-07-08\n\n### Fixes\n\n- moves type checking functions into a separate utility\n\n## [3.7.1] - 2022-08-09\n\n### Fixes\n\n- allow user to pass 'passive' flag events-related hooks\n\n## [3.8.0] - 2022-08-09\n\n### Adds\n\n- Improves 'passive' events flag\n\n## [3.9.0] - 2022-08-09\n\n### Adds\n\n- useAudio hook\n\n## [3.10.0] - 2022-08-09\n\n### Adds\n\n- useDarkMode hook\n\n## [3.11.0] - 2022-08-19\n\n### Adds\n\n- useToggle hook\n\n## [3.11.1] - 2022-08-19\n\n### Fixes\n\n- useToggle types\n\n## [3.11.2] - 2023-01-11\n\n### Fix\n\n- `warnOnce` function to make sure the warning messages are displayed only once\n\n## [3.12.0] - 2023-01-11\n\n### Adds\n\n- improve `useInfiniteScroll` code\n\n## [3.12.1] - 2023-01-11\n\n### Fixes\n\n- Fixes `useInfiniteScroll` not working on Windows machines\n\n## [3.12.2] - 2023-01-11\n\n### Fixes\n\n- Fixes `useInfiniteScroll` console.error message\n\n## [3.12.3] - 2023-02-16\n\n### Fixes\n\n- `useLocalStorage` and `useSessionStorage` no longer return a new `setValue` function everytime `setValue` is called\n\n## [4.0.0] - 2023-03-13\n\n### Breaking Changes\n\n- Removes `index.ts` file from `src` folder\n- Updates dependencies\n- Improves documentation\n- Improves types\n\n## [4.1.0] - 2023-03-13\n\n### Adds\n\n- `useMutableState` hook\n\n## [4.1.1] - 2023-03-13\n\n### Fixes\n\n- wrong dependency in package.json\n\n## [4.2.0] - 2023-03-18\n\n### Adds\n\n- `useLongPress` hook\n\n### Fixes\n\n- Deprecated GitHub actions version\n\n## [4.2.1] - 2023-03-18\n\n### Fixes\n\n- package.json specifiers (exports)\n\n## [4.3.0] - 2023-03-19\n\n### Adds\n\n- `useSpeechRecognition` hook\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our community include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders via the contact from at [Beautiful Interactions website](https://www.beautifulinteractions.com/). All complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the reporter of any incident.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,\navailable at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to this library\n\nFirst of all, thanks for taking the time to contribute! 😬\n\nThe following is a set of guidelines for contributing to this library, these are mostly guidelines, not rules.\n\nUse your best judgment, and feel free to propose changes to this document in a pull request.\n\n#### Table Of Contents\n\n[Code of Conduct](#code-of-conduct)\n\n[How Can I Contribute?](#how-can-i-contribute)\n  * [Reporting Bugs](#reporting-bugs)\n  * [Suggesting Enhancements](#suggesting-enhancements)\n  * [Your First Code Contribution](#your-first-code-contribution)\n  * [Pull Requests](#pull-requests)\n\n[Styleguides](#styleguides)\n  * [Git Commit Messages](#git-commit-messages)\n\n[Additional Notes](#additional-notes)\n  * [Issue and Pull Request Labels](#issue-and-pull-request-labels)\n\n## Code of Conduct\n\nThis project and everyone participating in it is governed by the [Project Code of Conduct](./CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. \n## How Can I Contribute?\n\n### Reporting Bugs\n\nThis section guides you through submitting a bug report for this library. \nFollowing these guidelines helps maintainers and the community understand your report, reproduce the behavior and find related reports.\n\nBefore creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. \nWhen you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). \n\n> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.\n\n#### Before Submitting A Bug Report\n\n* Perform a search to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one.\n\n#### How Do I Submit A (Good) Bug Report?\n\nBugs are tracked as [GitHub issues](https://guides.github.com/features/issues/).\nExplain the problem and include additional details to help maintainers reproduce the problem:\n\n* **Use a clear and descriptive title** for the issue to identify the problem.\n* **Describe the exact steps which reproduce the problem** in as many details as possible. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you moved the cursor to the end of a line, explain if you used the mouse or a keyboard shortcut and if so which one?\n* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use Markdown code blocks.\n* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.\n* **Explain which behavior you expected to see instead and why.**\n* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.\n* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.\n\nProvide more context by answering these questions:\n\n* **Where were you using the library and what for?** Please provide detailed information on the project where you were using the library and how you were using it.\n* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.\n\nInclude details about your Browser and environment:\n\n* **Which Browser and which version are you using?**\n\n### Suggesting Enhancements\n\nThis section guides you through submitting an enhancement suggestion for this library, including completely new features and minor improvements to existing functionality. \nFollowing these guidelines helps maintainers and the community understand your suggestion and find related suggestions.\n\nBefore creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). \n\n#### Before Submitting An Enhancement Suggestion\n\n* **Check if there's already a feature which provides that enhancement.**\n* **Perform a search to see if the enhancement has already been suggested.** If it has, add a comment to the existing issue instead of opening a new one.\n\n#### How Do I Submit A (Good) Enhancement Suggestion?\n\nEnhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/).\nCreate an issue on that repository and provide the following information:\n\n* **Use a clear and descriptive title** for the issue to identify the suggestion.\n* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.\n* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as Markdown code blocks.\n* **Describe the current behavior** and **explain which behavior you expected to see instead** and why.\n* **Include screenshots and animated GIFs** which help you demonstrate the steps. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.\n* **Explain why this enhancement would be useful** to this library users.\n\n### Your First Code Contribution\n\nUnsure where to begin contributing to this library? \nYou can start by looking through these `beginner` and `help-wanted` issues:\n\n* [Beginner issues][beginner] - issues which should only require a few lines of code, and a test or two.\n* [Help wanted issues][help-wanted] - issues which should be a bit more involved than `beginner` issues.\n\nBoth issue lists are sorted by total number of comments. While not perfect, number of comments is a reasonable proxy for impact a given change will have.\n\n#### Local development\n\nThis library can be developed locally. For instructions on how to do this, check the [README file](README.md)\n\n### Pull Requests\n\nThe process described here has several goals:\n\n- Maintain a good code quality\n- Fix problems that are important to users\n- Engage the community in working toward the best possible version of this library\n- Enable a sustainable system for maintainers to review contributions\n\nPlease follow these steps to have your contribution considered by the maintainers:\n\n1. Follow all instructions in [the template](.github/PULL_REQUEST_TEMPLATE.md)\n2. Follow the [styleguides](#styleguides)\n3. After you submit your pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) are passing. <details><summary>What if the status checks are failing?</summary>If a status check is failing, and you believe that the failure is unrelated to your change, please leave a comment on the pull request explaining why you believe the failure is unrelated. A maintainer will re-run the status check for you. If we conclude that the failure was a false positive, then we will open an issue to track that problem with our status check suite.</details>\n\nWhile the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.\n\n## Styleguides\n\n### Git Commit Messages\n\n* Use the present tense (\"Add feature\" not \"Added feature\")\n* Use the imperative mood (\"Move cursor to...\" not \"Moves cursor to...\")\n* Limit the first line to 72 characters or less\n* Reference issues and pull requests liberally after the first line\n* When only changing documentation, include `[ci skip]` in the commit title\n* Consider starting the commit message with an applicable emoji:\n    * :art: `:art:` when improving the format/structure of the code\n    * :racehorse: `:racehorse:` when improving performance\n    * :non-potable_water: `:non-potable_water:` when plugging memory leaks\n    * :memo: `:memo:` when writing docs\n    * :penguin: `:penguin:` when fixing something on Linux\n    * :apple: `:apple:` when fixing something on macOS\n    * :checkered_flag: `:checkered_flag:` when fixing something on Windows\n    * :bug: `:bug:` when fixing a bug\n    * :fire: `:fire:` when removing code or files\n    * :green_heart: `:green_heart:` when fixing the CI build\n    * :white_check_mark: `:white_check_mark:` when adding tests\n    * :lock: `:lock:` when dealing with security\n    * :arrow_up: `:arrow_up:` when upgrading dependencies\n    * :arrow_down: `:arrow_down:` when downgrading dependencies\n    * :shirt: `:shirt:` when removing linter warnings\n\n## Additional Notes\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue,\nemail, or any other method with the owners of this repository before making a change.\n\nPlease note we have a code of conduct, please follow it in all your interactions with the project.\n\n## Pull Request Process\n\nHere's a quick check list for a good pull request (PR):\n\n1.  Ensure any install or build dependencies are removed before the end of the layer when doing a\n    build.\n2.  Update the CHANGELOG.md with details of changes to the interface, this includes new environment\n    variables, exposed ports, useful file locations and container parameters.\n3.  Increase the version numbers in any examples files and the README.md to the new version that this\n    Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).\n4.  Keep PRs as tidy as possible. If need be, please use \n    `git reset --soft <hash>`, `git commit -m \"...\"` and `git push -f` to\n    compact your commits into a single one and rewrite the history of your branch.\n5.  One feature/change per PR\n6.  GITLAB issue number in commit comment\n7.  No changes to code not directly related to your change (e.g. no formatting changes or refactoring to existing code)\n8.  All tests in testsuite pass\n9.  Do a rebase on upstream master\n10. PR needs to be accompanied with tests that sufficiently test added/changed functionality\n"
  },
  {
    "path": "HOOK_DOCUMENTATION_TEMPLATE.md",
    "content": "# useYourHookName\n\nA hook that [...]\n\n### 💡 Why?\n\n- why this hook is necessary and what it does\n\n### Basic Usage:\n\n```jsx harmony\nimport { yourHook } from 'beautiful-react-hooks';\n\nconst YourExample = () => {\n  /* Your code goes here */\n\n  return null;\n};\n\n<YourExample />\n```\n\n### Use cases\n\ndescription of the use case\n\n```jsx harmony\nimport { yourHook } from 'beautiful-react-hooks';\n\nconst YourUseCase = () => {\n  /* Your code goes here */\n\n  return null;\n};\n\n<YourUseCase />\n```\n\n### Mastering the hooks\n\n#### ✅ When to use\n\n- When it's good to use\n\n#### 🛑 When not to use\n\n- When it's not good to use\n\n<!-- Types -->\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2019 Antonio Russo\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": "README.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"./logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    A collection of tailor-made React hooks to enhance your development process and make it faster.\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Hooks Playground 🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](./usage_example.png)\n\n🇬🇧 English | <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian Portuguese</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱 Polski </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.tr-TR.md\">🇹🇷 Türkçe</a>\n\n## 💡 Why?\n\nCustom React hooks allow developers to abstract the business logic of components into single, reusable functions.\\\nI have noticed that many of the hooks I have created and shared across projects involve callbacks, references, events, and dealing with the\ncomponent lifecycle.\\\nTherefore, I have created `beautiful-react-hooks`, a collection of useful [React hooks](https://beta.reactjs.org/reference/react) that may\nhelp other developers speed up their development process.\\\nMoreover, I have strived to create a concise and practical API that emphasizes code readability, while keeping the learning curve as low as\npossible, making it suitable for larger teams to use and share\nt\n**-- Please before using any hook, read its documentation! --**\n\n## ☕️ Features\n\n* Concise API\n* Small and lightweight\n* Easy to learn\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Hooks Playground 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 Install\n\nby using `npm`:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\nby using `yarn`:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## Basic usage\n\nimporting a hooks is as easy as the following straightforward line:\n\n```ts static\nimport useSomeHook from 'beautiful-react-hooks/useSomeHook'\n```\n\n## 🎨 Hooks\n\n* [useMutableState](docs/useMutableState.md)\n* [useInfiniteScroll](docs/useInfiniteScroll.md)\n* [useObservable](docs/useObservable.md)\n* [useEvent](docs/useEvent.md)\n* [useGlobalEvent](docs/useGlobalEvent.md)\n* [usePreviousValue](docs/usePreviousValue.md)\n* [useValueHistory](docs/useValueHistory.md)\n* [useValidatedState](docs/useValidatedState.md)\n* [useMediaQuery](docs/useMediaQuery.md)\n* [useOnlineState](docs/useOnlineState.md)\n* [useViewportSpy](docs/useViewportSpy.md)\n* [useViewportState](docs/useViewportState.md)\n* [useSpeechRecognition](docs/useSpeechRecognition.md) and [useSpeechSynthesis](docs/useSpeechSynthesis.md)\n* [useGeolocation](docs/useGeolocation.md), [useGeolocationState](docs/useGeolocationState.md)\n  and [useGeolocationEvents](docs/useGeolocationEvents.md)\n* [useDrag](docs/useDrag.md), [useDropZone](docs/useDropZone.md) and [useDragEvents](docs/useDragEvents.md)\n* [useMouse](docs/useMouse.md), [useMouseState](docs/useMouseState.md) and [useMouseEvents](docs/useMouseEvents.md)\n* [useTouch](docs/useTouch.md), [useTouchState](docs/useTouchState.md) and [useTouchEvents](docs/useTouchEvents.md)\n* [useLifecycle](docs/useLifecycle.md), [useDidMount](docs/useDidMount.md) and [useWillUnmount](docs/useWillUnmount.md)\n* [useWindowResize](docs/useWindowResize.md)\n* [useWindowScroll](docs/useWindowScroll.md)\n* [useRequestAnimationFrame](docs/useRequestAnimationFrame.md)\n* [useResizeObserver](docs/useResizeObserver.md)\n* [useTimeout](docs/useTimeout.md)\n* [useInterval](docs/useInterval.md)\n* [useDebouncedCallback](docs/useDebouncedCallback.md)\n* [useThrottledCallback](docs/useThrottledCallback.md)\n* [useLocalStorage](docs/useLocalStorage.md)\n* [useSessionStorage](docs/useSessionStorage.md)\n* [useDefaultedState](docs/useDefaultedState.md)\n* [useRenderInfo](docs/useRenderInfo.md)\n* [useSwipe](docs/useSwipe.md), [useHorizontalSwipe](docs/useHorizontalSwipe.md) and [useVerticalSwipe](docs/useVerticalSwipe.md)\n* [useSwipeEvents](docs/useSwipeEvents.md)\n* [useConditionalTimeout](docs/useConditionalTimeout.md)\n* [useCookie](docs/useCookie.md)\n* [useDarkMode](docs/useDarkMode.md)\n* [useUnmount](docs/useUnmount.md)\n* [useUpdateEffect](docs/useUpdateEffect.md)\n* [useIsFirstRender](docs/useIsFirstRender.md)\n* [useMutationObserver](docs/useMutationObserver.md)\n* [useAudio](docs/useAudio.md)\n* [useObjectState](docs/useObjectState.md)\n* [useToggle](docs/useToggle.md)\n* [useQueryParam](docs/useQueryParam.md)\n* [useQueryParams](docs/useQueryParams.md)\n* [useSearchQuery](docs/useSearchQuery.md)\n* [useURLSearchParams](docs/useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Hooks Playground 🌟\n    </a>\n  </p>\n</div>\n\n## Peer dependencies\n\nSome hooks are built using third-party libraries (such as rxjs, react-router-dom, redux). As a result, you will see these libraries listed\nas peer dependencies.\\\nUnless you are using these hooks directly, you need not install these dependencies.\n\n## Contributing\n\nContributions are very welcome and wanted.\n\nTo submit your custom hook, make sure you have thoroughly read and understood the [CONTRIBUTING](./CONTRIBUTING.md) guidelines.\n\n**Prior to submitting your pull request**: please take note of the following\n\n1. make sure to write tests for your code, run `npm test` and `npm build` before submitting your merge request.\n2. in case you're creating a custom hook, make sure you've added the documentation (*you may use\n   the [HOOK_DOCUMENTATION_TEMPLATE](./HOOK_DOCUMENTATION_TEMPLATE.md) to document your custom hook*).\n\n## Credits\n\nIcon made by [Freepik](https://www.flaticon.com/authors/freepik) from [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812)\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: ['@babel/react', '@babel/env']\n}\n"
  },
  {
    "path": "docs/Installation.md",
    "content": "# Getting started\n\nUsing `npm`:\n\n```bash\n$ npm i --save beautiful-react-hooks\n```\n\nUsing `yarn`:\n\n```bash \n$ yarn add beautiful-react-hooks\n```\n\nthen just import any hook described by the documentation in your React component file:\n\n```ts static\nimport useSomeHook from 'beautiful-react-hoks/useSomeHook'\n```\n\n**Please note**: always import your hook from the library as a single module to avoid importing unnecessary hooks and therefore unnecessary\ndependencies\n\n## Peer dependencies\n\nSome hooks are built on top of third-party libraries (rxjs, react-router-dom, redux), therefore you will notice those libraries listed as\npeer dependencies. You don't have to install these dependencies unless you directly use those hooks.\n\n## Working with Refs in TypeScript\n\nThe documentation of this module is written in JavaScript, so you will see a lot of this:\n\n```jsx static\nimport { ref } from 'react';\n\nconst myCustomHook = () => {\n  const ref = useRef()\n\n  /* your code */\n\n  return ref;\n}\n```\n\nIf you are in a TypeScript project, you should declare your ref as a `RefObject<T extends HTMLElement>`. For example:\n\n```ts static\nimport { ref } from 'react';\n\nconst myCustomHook = () => {\n  const ref = useRef<HTMLDivElement>(null);\n\n  /* your code */\n\n  return ref;\n}\n```\n\nSee [here](https://dev.to/wojciechmatuszewski/mutable-and-immutable-useref-semantics-with-react-typescript-30c9) for information on the\ndifference between a `MutableRefObject` and a `RefObject`.\n"
  },
  {
    "path": "docs/Introduction.md",
    "content": "# Introduction\n\n[![Build Status](https://travis-ci.org/beautifulinteractions/beautiful-react-hooks.svg?branch=master)](https://travis-ci.org/beautifulinteractions/beautiful-react-hooks)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n`beautiful-react-hooks` is a collection of tailor-made [React hooks](https://beta.reactjs.org/reference/react) to enhance your development\nprocess and make it faster.\n\n## 💡 Why?\n\nCustom React hooks allow developers to abstract the business logic of components into single, reusable functions.<br />\nI have noticed that many of the hooks I have created and shared across projects involve callbacks, references, events, and dealing with the\ncomponent lifecycle. <br />\nTherefore, I have created `beautiful-react-hooks`, a collection of useful [React hooks](https://beta.reactjs.org/reference/react) that may\nhelp other developers speed up their development process.<br/>\nMoreover, I have strived to create a concise and practical API that emphasizes code readability, while keeping the learning curve as low as\npossible, making it suitable for larger teams to use and share\n\n## ☕️ Features\n\n* Concise API\n* Small and lightweight\n* Easy to learn\n\n## Basic usage\n\nimporting a hooks is as easy as the following straightforward line:\n\n```ts static\nimport useSomeHook from 'beautiful-react-hooks/useSomeHook'\n```\n\n## Peer dependencies\n\nSome hooks are built using third-party libraries (such as rxjs, react-router-dom, redux). As a result, you will see these libraries listed\nas peer dependencies.\\\nUnless you are using these hooks directly, you need not install these dependencies.\n"
  },
  {
    "path": "docs/README.es-ES.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n     <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    Una colección de hermosos (y ojalá que útiles) hooks de React para acelerar tu desarrollo de componentes y hooks\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟Para probar clic aquí🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a> | 🇪🇸 Español\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian Portuguese</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱 Polski </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n\n## 💡 Por qué?\n\nReact custom hooks permite abstraer la lógica de negocio de los componentes en funciones únicas reutilizables.<br />\nHasta ahora hemos notado que la mayoría de los hooks que hemos creado y compartido en nuestros proyectos tienen un núcleo bastante similar,\nun núcleo que a menudo implica los mismos patrones de desarrollo (llamadas, referencias y ciclos de vida). <br />\nPor esta razón hemos tratado de resumir esa esencia en  `beautiful-react-hooks`:una colección de (*esperamos*) útiles Para que React hooks\nsirva otras empresas y profesionales ayudando a acelerar su proceso de desarrollo.<br /><br />\nAdemás, creamos un API conciso pero concreto teniendo en cuenta la legibilidad del código, centrándonos en mantener la curva de aprendizaje\nlo más baja posible para que pueda ser usada y compartida en equipos más grandes.\n\n**-- Por favor, antes de utilizar un hook, leer su documentación! --**\n\n## ☕️ Características\n\n* API Consistente.\n* Pequeña y ligera.\n* Fácil de aprender.\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Para probar clic aquí 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 Instalar\n\nUsando `npm`:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\nUsando `yarn`:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## 🎨 Hooks\n\n* [useMutableState](useMutableState.md)\n* [useInfiniteScroll](useInfiniteScroll.md)\n* [useObservable](useObservable.md)\n* [useEvent](useEvent.md)\n* [useGlobalEvent](useGlobalEvent.md)\n* [usePreviousValue](usePreviousValue.md)\n* [useValueHistory](useValueHistory.md)\n* [useValidatedState](useValidatedState.md)\n* [useMediaQuery](useMediaQuery.md)\n* [useOnlineState](useOnlineState.md)\n* [useViewportSpy](useViewportSpy.md)\n* [useViewportState](useViewportState.md)\n* [useSpeechRecognition](useSpeechRecognition.md) and [useSpeechSynthesis](useSpeechSynthesis.md)\n* [useGeolocation](useGeolocation.md), [useGeolocationState](useGeolocationState.md)\n  and [useGeolocationEvents](useGeolocationEvents.md)\n* [useDrag](useDrag.md), [useDropZone](useDropZone.md) and [useDragEvents](useDragEvents.md)\n* [useMouse](useMouse.md), [useMouseState](useMouseState.md) and [useMouseEvents](useMouseEvents.md)\n* [useTouch](useTouch.md), [useTouchState](useTouchState.md) and [useTouchEvents](useTouchEvents.md)\n* [useLifecycle](useLifecycle.md), [useDidMount](useDidMount.md) and [useWillUnmount](useWillUnmount.md)\n* [useWindowResize](useWindowResize.md)\n* [useWindowScroll](useWindowScroll.md)\n* [useRequestAnimationFrame](useRequestAnimationFrame.md)\n* [useResizeObserver](useResizeObserver.md)\n* [useTimeout](useTimeout.md)\n* [useInterval](useInterval.md)\n* [useDebouncedCallback](useDebouncedCallback.md)\n* [useThrottledCallback](useThrottledCallback.md)\n* [useLocalStorage](useLocalStorage.md)\n* [useSessionStorage](useSessionStorage.md)\n* [useDefaultedState](useDefaultedState.md)\n* [useRenderInfo](useRenderInfo.md)\n* [useSwipe](useSwipe.md), [useHorizontalSwipe](useHorizontalSwipe.md) and [useVerticalSwipe](useVerticalSwipe.md)\n* [useSwipeEvents](useSwipeEvents.md)\n* [useConditionalTimeout](useConditionalTimeout.md)\n* [useCookie](useCookie.md)\n* [useDarkMode](useDarkMode.md)\n* [useUpdateEffect](useUpdateEffect.md)\n* [useIsFirstRender](useIsFirstRender.md)\n* [useMutationObserver](useMutationObserver.md)\n* [useAudio](useAudio.md)\n* [useObjectState](useObjectState.md)\n* [useToggle](useToggle.md)\n* [useQueryParam](useQueryParam.md)\n* [useQueryParams](useQueryParams.md)\n* [useSearchQuery](useSearchQuery.md)\n* [useURLSearchParams](useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Para probar clic aquí🌟\n    </a>\n  </p>\n</div>\n\n## Contribuir\n\nLas contribuciones son muy bienvenidas y deseadas.\n\nPara presentar su custom hook, por favor asegúrese de leer nuestro [CONTRIBUTING](../CONTRIBUTING.md) guidelines.\n\n**Antes de enviar** un nuevo merge request, por favor asegúrese:\n\n1. Ha actualizado el package.json version e informó de sus cambios en el archivo [CHANGELOG](../CHANGELOG.md)\n2. Asegúrate de ejecutar `npm test` y `npm build` antes de enviar el merge request.\n3. Asegúrate de que has añadido la documentación de tu custom hook (* puedes usar\n   el [HOOK_DOCUMENTATION_TEMPLATE](../HOOK_DOCUMENTATION_TEMPLATE.md)  para documentar tu custom hook*).\n4. Asegúrate de que has actualizado el  `index.d.ts` el archivo de tus tipo de hook.\n\n### Herramientas utilizadas\n\n* [React](https://reactjs.org/)\n* [Mocha](https://mochajs.org/)\n* [Chai](https://www.chaijs.com/)\n* [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro)\n* [@testing-library/react-hooks](https://react-hooks-testing-library.com/)\n\n---\n\nIcon desde [Freepik](https://www.flaticon.com/authors/freepik) y [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812)\n"
  },
  {
    "path": "docs/README.it-IT.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    Una collezione di hooks leggeri (e si spera utili) per velocizzare lo sviluppo di hooks personalizzati e\n    componenti React\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Provali in azione qui 🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a> | 🇮🇹 Italiano\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian Portuguese</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱 Polski </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n\nIn un'applicazione React, gli hooks ci permettono di astrarre complesse logiche di business in singole funzioni riutilizzabili.<br />\nFino ad ora abbiamo notato che la maggior parte degli hooks che abbiamo creato e condiviso nei nostri progetti, hanno un\n_core_ piuttosto simile tra loro, un _core_ che coinvolge spesso gli stessi pattern di sviluppo (callback, referenze e cicli di vita).<br />\nPer queato motivo abbiamo cercato di semplificare e concentrare questo _core_ in  `beautiful-react-hooks`: una collezione di piccoli hooks\nriutilizzabili per aiutare altri sviluppatori (e società) a velocizzare i loro processi di sviluppo.<br /><br />\nAbbiamo cercato di creare una API che fosse sia concisa che coerente, concentrandoci sulla scalabilità e la leggibilità del codice,\nmantenendo la curva d'apprendimento il più bassa possible.\n\n**-- Prima di usare qualsiasi hook, leggi la documentazione! --**\n\n## ☕️ Features\n\n* API concisa e coerente\n* Piccole funzioni riutilizzabili\n* Facile da imparare\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Provali in azione qui 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 Installazione\n\nUsando `npm`:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\noppure usando `yarn`:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## 🎨 Hooks\n\n* [useMutableState](useMutableState.md)\n* [useInfiniteScroll](useInfiniteScroll.md)\n* [useObservable](useObservable.md)\n* [useEvent](useEvent.md)\n* [useGlobalEvent](useGlobalEvent.md)\n* [usePreviousValue](usePreviousValue.md)\n* [useValueHistory](useValueHistory.md)\n* [useValidatedState](useValidatedState.md)\n* [useMediaQuery](useMediaQuery.md)\n* [useOnlineState](useOnlineState.md)\n* [useViewportSpy](useViewportSpy.md)\n* [useViewportState](useViewportState.md)\n* [useSpeechRecognition](useSpeechRecognition.md) and [useSpeechSynthesis](useSpeechSynthesis.md)\n* [useGeolocation](useGeolocation.md), [useGeolocationState](useGeolocationState.md)\n  and [useGeolocationEvents](useGeolocationEvents.md)\n* [useDrag](useDrag.md), [useDropZone](useDropZone.md) and [useDragEvents](useDragEvents.md)\n* [useMouse](useMouse.md), [useMouseState](useMouseState.md) and [useMouseEvents](useMouseEvents.md)\n* [useTouch](useTouch.md), [useTouchState](useTouchState.md) and [useTouchEvents](useTouchEvents.md)\n* [useLifecycle](useLifecycle.md), [useDidMount](useDidMount.md) and [useWillUnmount](useWillUnmount.md)\n* [useWindowResize](useWindowResize.md)\n* [useWindowScroll](useWindowScroll.md)\n* [useRequestAnimationFrame](useRequestAnimationFrame.md)\n* [useResizeObserver](useResizeObserver.md)\n* [useTimeout](useTimeout.md)\n* [useInterval](useInterval.md)\n* [useDebouncedCallback](useDebouncedCallback.md)\n* [useThrottledCallback](useThrottledCallback.md)\n* [useLocalStorage](useLocalStorage.md)\n* [useSessionStorage](useSessionStorage.md)\n* [useDefaultedState](useDefaultedState.md)\n* [useRenderInfo](useRenderInfo.md)\n* [useSwipe](useSwipe.md), [useHorizontalSwipe](useHorizontalSwipe.md) and [useVerticalSwipe](useVerticalSwipe.md)\n* [useSwipeEvents](useSwipeEvents.md)\n* [useConditionalTimeout](useConditionalTimeout.md)\n* [useCookie](useCookie.md)\n* [useDarkMode](useDarkMode.md)\n* [useUpdateEffect](useUpdateEffect.md)\n* [useIsFirstRender](useIsFirstRender.md)\n* [useMutationObserver](useMutationObserver.md)\n* [useAudio](useAudio.md)\n* [useObjectState](useObjectState.md)\n* [useToggle](useToggle.md)\n* [useQueryParam](useQueryParam.md)\n* [useQueryParams](useQueryParams.md)\n* [useSearchQuery](useSearchQuery.md)\n* [useURLSearchParams](useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Provali in azione qui 🌟\n    </a>\n  </p>\n</div>\n\n## Contribuisci\n\nLa tua contribuzione è benvenuta!\n\nPer inviare il tuo custom hook, leggi le nostre [linee guida](../CONTRIBUTING.md) in materia di contribuzioni.\n\n**Prima di inviarci** la tua pull request, per favore sii sicuro che:\n\n1. Hai aggiornato la versione nel file package.json ed hai aggiunto i cambiamenti che hai fatto nel file [CHANGELOG](../CHANGELOG.md).\n2. Hai fatto partire i testi con `npm test` ed hai fatto una build locale con `npm build`.\n3. Hai aggiunto la documentazione del tuo custom hook (*puoi partire dal\n   template [HOOK_DOCUMENTATION_TEMPLATE](../HOOK_DOCUMENTATION_TEMPLATE.md), per scrivere la tua documentazione*).\n4. Hai aggiornato il file `index.d.ts` aggiungendo i tipi Typescript del tuo hook.\n\n### Tools utilizzati\n\n* [React](https://reactjs.org/)\n* [Mocha](https://mochajs.org/)\n* [Chai](https://www.chaijs.com/)\n* [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro)\n* [@testing-library/react-hooks](https://react-hooks-testing-library.com/)\n\n---\n\nIcona fatta dall'utente [Freepik](https://www.flaticon.com/authors/freepik)\nsu [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812)\n"
  },
  {
    "path": "docs/README.jp-JP.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    コンポーネントやフック開発を高速化するための、美しい（できれば便利な） React フックのコレクションです。\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 ライブプレイグラウンドはこちら 🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian Portuguese</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱 Polski </a>\n| 🇯🇵 日本語\n\n## 💡 なぜ?\n\nReact のカスタムフックは抽象的なコンポーネントのビジネスロジックを単一な再利用可能な関数とする事が出来ます。<br />\nこれまでのところ、私たちが作成し、内部で共有されているフックの大半はかなりの頻度でコールバック参照、イベントとコンポーネントのライフサイクルに関して類似する点がある事が分かっています。<br />\nこの理由から、私たちはそれらの知見を企業や専門家が開発プロセスをスピードアップするのに役立つ（*できれば*）便利な React フックのコレクションとして `beautiful-react-hooks` にまとめました。\n<br /><br />\nさらに、コードの読みやすさを考慮して、簡潔かつ具体的な API を作成しました。 より大きなチームで使用し、共有できるように、学習曲線を可能な限り低く抑える事が可能です。\n\n**-- フックを利用する前に、ドキュメントを確認して下さい！ --**\n\n## ☕️ 特徴\n\n* 簡潔な API\n* 軽量\n* 学習が容易\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 ライブプレイグラウンドはこちら 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 インストール\n\n`npm` を利用する場合:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\n`yarn` を利用する場合:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## 🎨 Hooks\n\n* [useMutableState](useMutableState.md)\n* [useInfiniteScroll](useInfiniteScroll.md)\n* [useObservable](useObservable.md)\n* [useEvent](useEvent.md)\n* [useGlobalEvent](useGlobalEvent.md)\n* [usePreviousValue](usePreviousValue.md)\n* [useValueHistory](useValueHistory.md)\n* [useValidatedState](useValidatedState.md)\n* [useMediaQuery](useMediaQuery.md)\n* [useOnlineState](useOnlineState.md)\n* [useViewportSpy](useViewportSpy.md)\n* [useViewportState](useViewportState.md)\n* [useSpeechRecognition](useSpeechRecognition.md) and [useSpeechSynthesis](useSpeechSynthesis.md)\n* [useGeolocation](useGeolocation.md), [useGeolocationState](useGeolocationState.md)\n  and [useGeolocationEvents](useGeolocationEvents.md)\n* [useDrag](useDrag.md), [useDropZone](useDropZone.md) and [useDragEvents](useDragEvents.md)\n* [useMouse](useMouse.md), [useMouseState](useMouseState.md) and [useMouseEvents](useMouseEvents.md)\n* [useTouch](useTouch.md), [useTouchState](useTouchState.md) and [useTouchEvents](useTouchEvents.md)\n* [useLifecycle](useLifecycle.md), [useDidMount](useDidMount.md) and [useWillUnmount](useWillUnmount.md)\n* [useWindowResize](useWindowResize.md)\n* [useWindowScroll](useWindowScroll.md)\n* [useRequestAnimationFrame](useRequestAnimationFrame.md)\n* [useResizeObserver](useResizeObserver.md)\n* [useTimeout](useTimeout.md)\n* [useInterval](useInterval.md)\n* [useDebouncedCallback](useDebouncedCallback.md)\n* [useThrottledCallback](useThrottledCallback.md)\n* [useLocalStorage](useLocalStorage.md)\n* [useSessionStorage](useSessionStorage.md)\n* [useDefaultedState](useDefaultedState.md)\n* [useRenderInfo](useRenderInfo.md)\n* [useSwipe](useSwipe.md), [useHorizontalSwipe](useHorizontalSwipe.md) and [useVerticalSwipe](useVerticalSwipe.md)\n* [useSwipeEvents](useSwipeEvents.md)\n* [useConditionalTimeout](useConditionalTimeout.md)\n* [useCookie](useCookie.md)\n* [useDarkMode](useDarkMode.md)\n* [useUpdateEffect](useUpdateEffect.md)\n* [useIsFirstRender](useIsFirstRender.md)\n* [useMutationObserver](useMutationObserver.md)\n* [useAudio](useAudio.md)\n* [useObjectState](useObjectState.md)\n* [useToggle](useToggle.md)\n* [useQueryParam](useQueryParam.md)\n* [useQueryParams](useQueryParams.md)\n* [useSearchQuery](useSearchQuery.md)\n* [useURLSearchParams](useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 ライブプレイグラウンドはこちら 🌟\n    </a>\n  </p>\n</div>\n\n## Peer dependencies\n\nいくつかのフックはサードパーティライブラリ(rxjs、react-router-dom、redux)の上に構築されているため、それらのライブラリが peer dependencies\nとしてリストされていることに気づくかもしれません。直接的にそれらのフックを使用しない限り、依存関係としてインストールする必要はありません。\n\n## コントリビューション\n\nこのリポジトリへの貢献は大歓迎ですし、必要としています。\n\nあなたが作成したカスタムフックの PR を送るにあたり、私たちの [CONTRIBUTING](../CONTRIBUTING.md) ガイドラインを必ず確認するようにしてください。\n\n**PR を送る前に**、下記を確認してください:\n\n1. コードのテストを必ず書くようにし、PR を送る前に `npm test` と `npm build` を実行して問題がない事を確認してください。\n2. カスタムフックを作成する場合には、ドキュメントに必ず追加するようにしてください。  \n   (*カスタムフックのドキュメントテンプレートを用意しています [HOOK_DOCUMENTATION_TEMPLATE](../HOOK_DOCUMENTATION_TEMPLATE.md)*).\n\n### 利用しているライブラリ\n\n* [React](https://reactjs.org/)\n* [Mocha](https://mochajs.org/)\n* [Chai](https://www.chaijs.com/)\n* [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro)\n* [@testing-library/react-hooks](https://react-hooks-testing-library.com/)\n\n---\n\nアイコンは [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812) で [Freepik](https://www.flaticon.com/authors/freepik) によって作成されました。\n"
  },
  {
    "path": "docs/README.pl-PL.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n   Zbiór pięknych (i mamy nadzieję, że użytecznych) hooków React, mających na celu przyspieszenie\ntworzenia spersonalizowanych hooków oraz komponentów.\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Wypróbuj je tutaj 🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a>\n|<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian Portuguese</a> |\n🇵🇱 Polski | <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n\n## 💡 Dlaczego?\n\nW aplikacji React hooki pozwalają na wyodrębnienie logiki biznesowej komponentów do pojedyńczych funkcji wielokrotnego użytku.<br />\nOdkryliśmy, że większość hooków, które stworzyliśmy i dzieliliśmy między naszymi wewnętrznymi projektami, miały zazwyczaj podobną istotę,\nobejmującą callbacki, eventy oraz cykle zycia komponentów. <br />\nZ tego powodu podjęliśmy próbę zebrania tej istoty pod postacią `beautiful-react-hooks` będących zbiorem (* mamy nadzieję *) przydatnych\nhooków React, mającym na celu pomoc innym firmom i specjalistom w przyspieszeniu procesu tworzenia aplikacji.<br /><br />\nPonadto, stworzyliśmy zwięzłe i konkretne API, mając na uwadze czytelność kodu oraz pragnąc utrzymać krzywą uczenia się na jak najniższym\npoziomie, tak, aby można je było wykorzystywać i dzielić się nim w większych zespołach.\n\n**-- Przeczytaj dokumentację kadego z hooków przed jego użyciem! --**\n\n## ☕️ Cechy\n\n* Zwarte API\n* Małe i lekkie\n* Łatwe do nauki\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Wypróbuj je tutaj 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 Instalacja\n\nużywając `npm`:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\nużywając `yarn`:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## 🎨 Hooki\n\n* [useMutableState](useMutableState.md)\n* [useInfiniteScroll](useInfiniteScroll.md)\n* [useObservable](useObservable.md)\n* [useEvent](useEvent.md)\n* [useGlobalEvent](useGlobalEvent.md)\n* [usePreviousValue](usePreviousValue.md)\n* [useValueHistory](useValueHistory.md)\n* [useValidatedState](useValidatedState.md)\n* [useMediaQuery](useMediaQuery.md)\n* [useOnlineState](useOnlineState.md)\n* [useViewportSpy](useViewportSpy.md)\n* [useViewportState](useViewportState.md)\n* [useSpeechRecognition](useSpeechRecognition.md) and [useSpeechSynthesis](useSpeechSynthesis.md)\n* [useGeolocation](useGeolocation.md), [useGeolocationState](useGeolocationState.md)\n  and [useGeolocationEvents](useGeolocationEvents.md)\n* [useDrag](useDrag.md), [useDropZone](useDropZone.md) and [useDragEvents](useDragEvents.md)\n* [useMouse](useMouse.md), [useMouseState](useMouseState.md) and [useMouseEvents](useMouseEvents.md)\n* [useTouch](useTouch.md), [useTouchState](useTouchState.md) and [useTouchEvents](useTouchEvents.md)\n* [useLifecycle](useLifecycle.md), [useDidMount](useDidMount.md) and [useWillUnmount](useWillUnmount.md)\n* [useWindowResize](useWindowResize.md)\n* [useWindowScroll](useWindowScroll.md)\n* [useRequestAnimationFrame](useRequestAnimationFrame.md)\n* [useResizeObserver](useResizeObserver.md)\n* [useTimeout](useTimeout.md)\n* [useInterval](useInterval.md)\n* [useDebouncedCallback](useDebouncedCallback.md)\n* [useThrottledCallback](useThrottledCallback.md)\n* [useLocalStorage](useLocalStorage.md)\n* [useSessionStorage](useSessionStorage.md)\n* [useDefaultedState](useDefaultedState.md)\n* [useRenderInfo](useRenderInfo.md)\n* [useSwipe](useSwipe.md), [useHorizontalSwipe](useHorizontalSwipe.md) and [useVerticalSwipe](useVerticalSwipe.md)\n* [useSwipeEvents](useSwipeEvents.md)\n* [useConditionalTimeout](useConditionalTimeout.md)\n* [useCookie](useCookie.md)\n* [useDarkMode](useDarkMode.md)\n* [useUpdateEffect](useUpdateEffect.md)\n* [useIsFirstRender](useIsFirstRender.md)\n* [useMutationObserver](useMutationObserver.md)\n* [useAudio](useAudio.md)\n* [useObjectState](useObjectState.md)\n* [useToggle](useToggle.md)\n* [useQueryParam](useQueryParam.md)\n* [useQueryParams](useQueryParams.md)\n* [useSearchQuery](useSearchQuery.md)\n* [useURLSearchParams](useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Wypróbuj je tutaj 🌟\n    </a>\n  </p>\n</div>\n\n## Współpraca\n\nWspółpraca jest bardzo mile widziana.\n\nPrzed dodaniem nowego hooka zapoznaj się koniecznie z zasadami projektowymi tutaj [CONTRIBUTING](../CONTRIBUTING.md)\n\n**Przed stworzeniem** nowego pull request, upewnij się, że:\n\n1. uaktualniłeś wersję pliku package.json oraz dodałeś zmiany w pliku [CHANGELOG](../CHANGELOG.md)\n2. użyłeś komend `npm test` oraz `npm build`.\n3. dodałeś dokumentację do twojego nowego hooka (*możesz użyć szablon [HOOK_DOCUMENTATION_TEMPLATE](../HOOK_DOCUMENTATION_TEMPLATE.md)*).\n4. uaktualniłeś plik `index.d.ts` dodając typy Typescript twojego hooka.\n\n### Użyte narzędzia\n\n* [React](https://reactjs.org/)\n* [Mocha](https://mochajs.org/)\n* [Chai](https://www.chaijs.com/)\n* [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro)\n* [@testing-library/react-hooks](https://react-hooks-testing-library.com/)\n\n---\n\nIkona wykonana przez [Freepik](https://www.flaticon.com/authors/freepik)\nna [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812)\n"
  },
  {
    "path": "docs/README.pt-BR.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    Uma coleção de React hooks lindos (e esperamos que úteis) para acelerar o desenvolvimento de seus componentes e hooks\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Playground aqui 🌟\n    </a>\n  </p>\n</div>\n\n![Exemplo de uso](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a> | 🇧🇷\nBrazilian Portuguese | <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱\nPolski </a> | <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n\n## 💡 Por quê?\n\nReact hooks permitem a abstrair a lógica de negócios dos componentes em funções únicas e reutilizáveis.<br />\nAté agora, descobrimos que a maioria dos hooks que criamos e, portanto, compartilhamos entre nossos projetos internos, muitas vezes têm uma\nessência semelhante que envolve referências de callback, eventos e ciclo de vida dos componentes. <br />\nPor este motivo, tentamos resumir esta essência em `beautiful-react-hooks`: uma coleção de React hooks úteis (*assim esperamos*)\npara possivelmente ajudar outras empresas e profissionais à agilizarem seus processos de desenvolvimento.<br /><br />\nAlém disso, criamos uma API simples porém sólida, tendo em mente a legibilidade do código, com o objetivo de manter a curva de aprendizado o\nmais baixa possível, para que possa ser usada e compartilhada em equipes maiores.\n\n**-- Por favor, antes de utilizar qualquer hook, leia a sua documentação! --**\n\n## ☕️ Recursos\n\n* API simples\n* Pequeno e leve\n* Fácil de aprender\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Playground aqui 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 Instalação\n\nutilizando `npm`:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\nutilizando `yarn`:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## 🎨 Hooks\n\n* [useMutableState](useMutableState.md)\n* [useInfiniteScroll](useInfiniteScroll.md)\n* [useObservable](useObservable.md)\n* [useEvent](useEvent.md)\n* [useGlobalEvent](useGlobalEvent.md)\n* [usePreviousValue](usePreviousValue.md)\n* [useValueHistory](useValueHistory.md)\n* [useValidatedState](useValidatedState.md)\n* [useMediaQuery](useMediaQuery.md)\n* [useOnlineState](useOnlineState.md)\n* [useViewportSpy](useViewportSpy.md)\n* [useViewportState](useViewportState.md)\n* [useSpeechRecognition](useSpeechRecognition.md) and [useSpeechSynthesis](useSpeechSynthesis.md)\n* [useGeolocation](useGeolocation.md), [useGeolocationState](useGeolocationState.md)\n  and [useGeolocationEvents](useGeolocationEvents.md)\n* [useDrag](useDrag.md), [useDropZone](useDropZone.md) and [useDragEvents](useDragEvents.md)\n* [useMouse](useMouse.md), [useMouseState](useMouseState.md) and [useMouseEvents](useMouseEvents.md)\n* [useTouch](useTouch.md), [useTouchState](useTouchState.md) and [useTouchEvents](useTouchEvents.md)\n* [useLifecycle](useLifecycle.md), [useDidMount](useDidMount.md) and [useWillUnmount](useWillUnmount.md)\n* [useWindowResize](useWindowResize.md)\n* [useWindowScroll](useWindowScroll.md)\n* [useRequestAnimationFrame](useRequestAnimationFrame.md)\n* [useResizeObserver](useResizeObserver.md)\n* [useTimeout](useTimeout.md)\n* [useInterval](useInterval.md)\n* [useDebouncedCallback](useDebouncedCallback.md)\n* [useThrottledCallback](useThrottledCallback.md)\n* [useLocalStorage](useLocalStorage.md)\n* [useSessionStorage](useSessionStorage.md)\n* [useDefaultedState](useDefaultedState.md)\n* [useRenderInfo](useRenderInfo.md)\n* [useSwipe](useSwipe.md), [useHorizontalSwipe](useHorizontalSwipe.md) and [useVerticalSwipe](useVerticalSwipe.md)\n* [useSwipeEvents](useSwipeEvents.md)\n* [useConditionalTimeout](useConditionalTimeout.md)\n* [useCookie](useCookie.md)\n* [useDarkMode](useDarkMode.md)\n* [useUpdateEffect](useUpdateEffect.md)\n* [useIsFirstRender](useIsFirstRender.md)\n* [useMutationObserver](useMutationObserver.md)\n* [useAudio](useAudio.md)\n* [useObjectState](useObjectState.md)\n* [useToggle](useToggle.md)\n* [useQueryParam](useQueryParam.md)\n* [useQueryParams](useQueryParams.md)\n* [useSearchQuery](useSearchQuery.md)\n* [useURLSearchParams](useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Playground aqui 🌟\n    </a>\n  </p>\n</div>\n\n## Contribuindo\n\nContribuições são muito bem-vindas e desejadas.\n\nPara enviar sua hook, por favor, certifique-se de ler o nosso arquivo [CONTRIBUTING](../CONTRIBUTING.md).\n\n**Antes de enviar** um novo merge request, por favor certifique-se:\n\n1. Você atualizou a versão no package.json e relatou suas alterações no arquivo [CHANGELOG](../CHANGELOG.md)\n2. Certifique-se de rodar `npm test` e `npm build` antes de enviar o merge request.\n3. Certifique-se de que você adicionou a documentação da sua hook (*você pode utilizar como base\n   o [HOOK_DOCUMENTATION_TEMPLATE](../HOOK_DOCUMENTATION_TEMPLATE.md) para documentar sua hook*).\n4. Certifique-se de que atualizou o arquivo `index.d.ts` com os tipos da sua hook.\n\n### Feito com\n\n* [React](https://reactjs.org/)\n* [Mocha](https://mochajs.org/)\n* [Chai](https://www.chaijs.com/)\n* [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro)\n* [@testing-library/react-hooks](https://react-hooks-testing-library.com/)\n\n---\n\nÍcone criado por [Freepik](https://www.flaticon.com/authors/freepik) / [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812)\n"
  },
  {
    "path": "docs/README.tr-TR.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    Geliştirme sürecinizi hızlandırmak ve daha verimli hale getirmek için özel olarak hazırlanmış React hooklar koleksiyonu.\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Bütün Özel React Hookları 🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a> | <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian Portuguese</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱 Polski </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n| 🇹🇷 Türkçe\n\n## 💡 Neden?\n\nÖzel React hooklar, geliştiricilere bileşenlerin iş mantığını tek, yeniden kullanılabilir işlevlere soyutlama imkanı sağlar.\nOluşturduğum ve projeler arasında paylaştığım birçok hookun geri çağrıları, referansları, etkinlikleri ve bileşen yaşam döngüsü ile ilgili olduğunu fark ettim.\\\nBu nedenle `beautiful-react-hooks`, adlı, diğer geliştiricilerin geliştirme süreçlerini hızlandırmalarına yardımcı olabilecek kullanışlı [React hooks](https://beta.reactjs.org/reference/react) koleksiyonunu oluşturdum.\nAyrıca, kod okunabilirliğini vurgulayan, öğrenme eğrisini mümkün olduğunca düşük tutarak daha büyük ekiplerin kullanımı ve paylaşımı için uygun hale getiren özlü ve pratik bir API oluşturmayı amaçladım.\n\n**-- Lütfen herhangi bir hook'u kullanmadan önce belgesini okuyun! --**\n\n## ☕️ Özellikler\n\n- Sade API\n- Hafif ve küçük\n- Öğrenmesi kolay\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Bütün Özel React Hookları 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 Kurulumu\n\n`npm` kullanıyorsanız:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\n`yarn` kullanıyorsanız:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## Temel kullanımı\n\nİstediğiniz özel hook'u aşağıdaki şekilde import ederek kolayca kullanabilirsin.:\n\n```ts static\nimport useSomeHook from \"beautiful-react-hooks/useSomeHook\";\n```\n\n## 🎨 Hooks\n\n- [useMutableState](docs/useMutableState.md)\n- [useInfiniteScroll](docs/useInfiniteScroll.md)\n- [useObservable](docs/useObservable.md)\n- [useEvent](docs/useEvent.md)\n- [useGlobalEvent](docs/useGlobalEvent.md)\n- [usePreviousValue](docs/usePreviousValue.md)\n- [useValueHistory](docs/useValueHistory.md)\n- [useValidatedState](docs/useValidatedState.md)\n- [useMediaQuery](docs/useMediaQuery.md)\n- [useOnlineState](docs/useOnlineState.md)\n- [useViewportSpy](docs/useViewportSpy.md)\n- [useViewportState](docs/useViewportState.md)\n- [useSpeechRecognition](docs/useSpeechRecognition.md) and [useSpeechSynthesis](docs/useSpeechSynthesis.md)\n- [useGeolocation](docs/useGeolocation.md), [useGeolocationState](docs/useGeolocationState.md)\n  and [useGeolocationEvents](docs/useGeolocationEvents.md)\n- [useDrag](docs/useDrag.md), [useDropZone](docs/useDropZone.md) and [useDragEvents](docs/useDragEvents.md)\n- [useMouse](docs/useMouse.md), [useMouseState](docs/useMouseState.md) and [useMouseEvents](docs/useMouseEvents.md)\n- [useTouch](docs/useTouch.md), [useTouchState](docs/useTouchState.md) and [useTouchEvents](docs/useTouchEvents.md)\n- [useLifecycle](docs/useLifecycle.md), [useDidMount](docs/useDidMount.md) and [useWillUnmount](docs/useWillUnmount.md)\n- [useWindowResize](docs/useWindowResize.md)\n- [useWindowScroll](docs/useWindowScroll.md)\n- [useRequestAnimationFrame](docs/useRequestAnimationFrame.md)\n- [useResizeObserver](docs/useResizeObserver.md)\n- [useTimeout](docs/useTimeout.md)\n- [useInterval](docs/useInterval.md)\n- [useDebouncedCallback](docs/useDebouncedCallback.md)\n- [useThrottledCallback](docs/useThrottledCallback.md)\n- [useLocalStorage](docs/useLocalStorage.md)\n- [useSessionStorage](docs/useSessionStorage.md)\n- [useDefaultedState](docs/useDefaultedState.md)\n- [useRenderInfo](docs/useRenderInfo.md)\n- [useSwipe](docs/useSwipe.md), [useHorizontalSwipe](docs/useHorizontalSwipe.md) and [useVerticalSwipe](docs/useVerticalSwipe.md)\n- [useSwipeEvents](docs/useSwipeEvents.md)\n- [useConditionalTimeout](docs/useConditionalTimeout.md)\n- [useCookie](docs/useCookie.md)\n- [useDarkMode](docs/useDarkMode.md)\n- [useUnmount](docs/useUnmount.md)\n- [useUpdateEffect](docs/useUpdateEffect.md)\n- [useIsFirstRender](docs/useIsFirstRender.md)\n- [useMutationObserver](docs/useMutationObserver.md)\n- [useAudio](docs/useAudio.md)\n- [useObjectState](docs/useObjectState.md)\n- [useToggle](docs/useToggle.md)\n- [useQueryParam](docs/useQueryParam.md)\n- [useQueryParams](docs/useQueryParams.md)\n- [useSearchQuery](docs/useSearchQuery.md)\n- [useURLSearchParams](docs/useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Bütün Özel React Hookları🌟\n    </a>\n  </p>\n</div>\n\n## Eş Bağımlılıklar\n\nBazı hooklar üçüncü taraf kütüphaneleri kullanarak oluşturulur (örneğin rxjs, react-router-dom, redux gibi). Bu nedenle, bu kütüphaneleri eş bağımlılıklar olarak listelenmiş olarak göreceksiniz.\\\nEğer bu hookları doğrudan kullanmıyorsanız, bu bağımlılıkları yüklemeniz gerekmez\n\n## Katkıda Bulunma\n\nKatkıda bulunmak hoş görülür ve istenir.\n\nÖzel hook'unuzu göndermeden önce [CONTRIBUTING](./CONTRIBUTING.md) yönergelerini tamamen okuduğunuzdan ve anladığınızdan emin olun.\n\n**Pull isteğini göndermeden önce**: Lütfen aşağıdakilere dikkat edin\n\n1. Kodunuz için testler yazmayı unutmayın ve çekme isteğinizi göndermeden önce `npm test` ve `npm build` komutlarını çalıştırın.\n2. Eğer özel bir hook oluşturuyorsanız, lütfen özel hook'unuzu belgelediğinizden emin olun (_Özel hook'unuzu belgelemek için [HOOK_DOCUMENTATION_TEMPLATE](./HOOK_DOCUMENTATION_TEMPLATE.md) bu dökümanı kullanabilirsiniz._).\n\n## Katkılar\n\nSimge [Freepik](https://www.flaticon.com/authors/freepik) tarafından [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812) adresinden oluşturuldu.\n"
  },
  {
    "path": "docs/README.uk-UA.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    Колекція красивих (також надіємось що корисних) Реакт хуків, для прискорення розробки ваших компонентів та хуків.\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Спробуйте їх у дії тут 🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.zh-CN.md\">🇨🇳 简体中文</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español </a> | 🇺🇦\nUkrainian | <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian\nPortuguese</a> | <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱 Polski </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n\n## 💡 Чому?\n\nКастомні Реакт хуки дозволяють абстрагувати бізнес логіку компонентів в окремі функції багаторазового використання.<br />\nДосі, ми зауважили, що більшість хуків які ми створили і після цього поширили між нашими внутрішніми проектами, досить часто мають\nаналогічну суть, що включають в себе виклик колбек функцій, подій та життєвих циклів компонентів.<br />\nЗ цієї причини, ми спробували реалізувати цю суть в `beautiful-react-hooks`: колекцію (*сподіваємось*) корисних Реакт хуків, для того щоб\nдопомогти іншим компаніям та професіоналам пришвидшити їхній процес розробки.<br /><br />\nКрім того, ми створили лаконічний, але конкретний API, з точки зору читабельності коду, маючи на меті тримати криву вивчення настільки\nнизькою, наскільки це можливо, тому це може бути використано та поширено у великих командах.\n\n**-- Будь-ласка, перед використанням будь-яких хуків, прочитайте їхню документацію! --**\n\n## ☕️ Особливості\n\n* Лаконічний API\n* Малий розмір та легкість\n* Простий у вивченні\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Спробуйте їх у дії тут 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 Встановлення\n\nВикористовуючи `npm`:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\nВикористовуючи `yarn`:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## 🎨 Хуки\n\n* [useMutableState](useMutableState.md)\n* [useInfiniteScroll](useInfiniteScroll.md)\n* [useObservable](useObservable.md)\n* [useEvent](useEvent.md)\n* [useGlobalEvent](useGlobalEvent.md)\n* [usePreviousValue](usePreviousValue.md)\n* [useValueHistory](useValueHistory.md)\n* [useValidatedState](useValidatedState.md)\n* [useMediaQuery](useMediaQuery.md)\n* [useOnlineState](useOnlineState.md)\n* [useViewportSpy](useViewportSpy.md)\n* [useViewportState](useViewportState.md)\n* [useSpeechRecognition](useSpeechRecognition.md) and [useSpeechSynthesis](useSpeechSynthesis.md)\n* [useGeolocation](useGeolocation.md), [useGeolocationState](useGeolocationState.md)\n  and [useGeolocationEvents](useGeolocationEvents.md)\n* [useDrag](useDrag.md), [useDropZone](useDropZone.md) and [useDragEvents](useDragEvents.md)\n* [useMouse](useMouse.md), [useMouseState](useMouseState.md) and [useMouseEvents](useMouseEvents.md)\n* [useTouch](useTouch.md), [useTouchState](useTouchState.md) and [useTouchEvents](useTouchEvents.md)\n* [useLifecycle](useLifecycle.md), [useDidMount](useDidMount.md) and [useWillUnmount](useWillUnmount.md)\n* [useWindowResize](useWindowResize.md)\n* [useWindowScroll](useWindowScroll.md)\n* [useRequestAnimationFrame](useRequestAnimationFrame.md)\n* [useResizeObserver](useResizeObserver.md)\n* [useTimeout](useTimeout.md)\n* [useInterval](useInterval.md)\n* [useDebouncedCallback](useDebouncedCallback.md)\n* [useThrottledCallback](useThrottledCallback.md)\n* [useLocalStorage](useLocalStorage.md)\n* [useSessionStorage](useSessionStorage.md)\n* [useDefaultedState](useDefaultedState.md)\n* [useRenderInfo](useRenderInfo.md)\n* [useSwipe](useSwipe.md), [useHorizontalSwipe](useHorizontalSwipe.md) and [useVerticalSwipe](useVerticalSwipe.md)\n* [useSwipeEvents](useSwipeEvents.md)\n* [useConditionalTimeout](useConditionalTimeout.md)\n* [useCookie](useCookie.md)\n* [useDarkMode](useDarkMode.md)\n* [useUpdateEffect](useUpdateEffect.md)\n* [useIsFirstRender](useIsFirstRender.md)\n* [useMutationObserver](useMutationObserver.md)\n* [useAudio](useAudio.md)\n* [useObjectState](useObjectState.md)\n* [useToggle](useToggle.md)\n* [useQueryParam](useQueryParam.md)\n* [useQueryParams](useQueryParams.md)\n* [useSearchQuery](useSearchQuery.md)\n* [useURLSearchParams](useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 Спробуйте їх у дії тут 🌟\n    </a>\n  </p>\n</div>\n\n## Внески\n\nВаші внески в проект дуже вітаються та потрібні.\n\nАле для подання ваших кастомних хуків, переконайтесь що ви ознайомились з нашим гайдом\nдля [ВНЕСКІВ](https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/CONTRIBUTING.md).\n\n**Перед поданням** нового merge реквесту, будь-ласка переконайтеся:\n\n1. Ви оновили версію package.json і повідомили про свої зміни\n   в [CHANGELOG](https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/CHANGELOG.md) файлі\n2. Переконайтеся, що ви запустили `npm test` і `npm build` перед поданням вашого merge реквесту.\n3. Переконайтеся що ви додали документацію ваших кастомних хуків(*ви також можете\n   використовувати [HOOK_DOCUMENTATION_TEMPLATE](https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/HOOK_DOCUMENTATION_TEMPLATE.md)\n   для документації кастомних хуків*).\n4. Переконайтеся що ви оновили `index.d.ts` файл з вашими типами хуків.\n\n### За сприяння\n\n* [React](https://reactjs.org/)\n* [Mocha](https://mochajs.org/)\n* [Chai](https://www.chaijs.com/)\n* [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro)\n* [@testing-library/react-hooks](https://react-hooks-testing-library.com/)\n\n---\n\nЗображення надано [Freepik](https://www.flaticon.com/authors/freepik) з [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812)\n"
  },
  {
    "path": "docs/README.zh-CN.md",
    "content": "![CI/CD](https://github.com/beautifulinteractions/beautiful-react-hooks/workflows/CI/CD/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/beautifulinteractions/beautiful-react-hooks/badge.svg?branch=master)](https://coveralls.io/github/beautifulinteractions/beautiful-react-hooks?branch=master)[![License:\nMIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![npm](https://img.shields.io/npm/v/beautiful-react-hooks)\n![GitHub stars](https://img.shields.io/github/stars/beautifulinteractions/beautiful-react-hooks?style=social)\n\n<div align=\"center\">\n  <p align=\"center\">\n    <img src=\"../logo.png\" alt=\"Beautiful React Hooks\" width=\"750px\" />\n  </p>\n</div>\n<br />\n<div>\n  <p align=\"center\">\n    可以显著为你提升组件开发和 hooks 开发效率的一系列漂亮（说不定也是才貌双全）的 React hooks。\n  </p>\n</div>\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 在线演示 🌟\n    </a>\n  </p>\n</div>\n\n![Usage example](../usage_example.png)\n\n<a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/\">🇬🇧 English</a> | 🇨🇳 简体中文\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.it-IT.md\">🇮🇹 Italiano</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.es-ES.md\"> 🇪🇸 Español </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.uk-UA.md\">🇺🇦 Ukrainian</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pt-BR.md\">🇧🇷 Brazilian Portuguese</a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.pl-PL.md\">🇵🇱 Polski </a>\n| <a href=\"https://github.com/beautifulinteractions/beautiful-react-hooks/blob/master/docs/README.jp-JP.md\">🇯🇵 日本語 </a>\n\n## 💡 为什么?\n\nReact hooks 让我们能把组件的业务逻辑抽象到一个可重用的函数里。<br />\n根据到目前为止的使用经验，我们发现：我们创建并在内部项目之间复用的大多数 hooks 通常都有一些共同的写法，涉及回调引用、事件或是组件生命周期。<br />\n发现这一点后，我们尝试把这些常用的写法抽出来放进 `beautiful-react-hooks` —— 一系列 _（说不定）_ 有用的 React hooks —— 来帮助其他公司和专家们加速他们的开发。<br /><br />\n此外，我们创建了简明而稳固的 API，时刻牢记代码可阅读性，专注于保持学习曲线越低越好，以便它们可以被更大的团队分享和使用。\n\n**-- 请在使用任何 hook 之前读完它的文档！ --**\n\n## ☕️ 功能\n\n- 简明的 API\n- 小巧轻量\n- 易于学习\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 在线演示 🌟\n    </a>\n  </p>\n</div>\n\n## 🕺 安装\n\n使用 `npm`:\n\n```bash\n$ npm install beautiful-react-hooks\n```\n\n使用 `yarn`:\n\n```bash\n$ yarn add beautiful-react-hooks\n```\n\n## 🎨 Hooks\n\n* [useMutableState](useMutableState.md)\n* [useInfiniteScroll](useInfiniteScroll.md)\n* [useObservable](useObservable.md)\n* [useEvent](useEvent.md)\n* [useGlobalEvent](useGlobalEvent.md)\n* [usePreviousValue](usePreviousValue.md)\n* [useValueHistory](useValueHistory.md)\n* [useValidatedState](useValidatedState.md)\n* [useMediaQuery](useMediaQuery.md)\n* [useOnlineState](useOnlineState.md)\n* [useViewportSpy](useViewportSpy.md)\n* [useViewportState](useViewportState.md)\n* [useSpeechRecognition](useSpeechRecognition.md) and [useSpeechSynthesis](useSpeechSynthesis.md)\n* [useGeolocation](useGeolocation.md), [useGeolocationState](useGeolocationState.md)\n  and [useGeolocationEvents](useGeolocationEvents.md)\n* [useDrag](useDrag.md), [useDropZone](useDropZone.md) and [useDragEvents](useDragEvents.md)\n* [useMouse](useMouse.md), [useMouseState](useMouseState.md) and [useMouseEvents](useMouseEvents.md)\n* [useTouch](useTouch.md), [useTouchState](useTouchState.md) and [useTouchEvents](useTouchEvents.md)\n* [useLifecycle](useLifecycle.md), [useDidMount](useDidMount.md) and [useWillUnmount](useWillUnmount.md)\n* [useWindowResize](useWindowResize.md)\n* [useWindowScroll](useWindowScroll.md)\n* [useRequestAnimationFrame](useRequestAnimationFrame.md)\n* [useResizeObserver](useResizeObserver.md)\n* [useTimeout](useTimeout.md)\n* [useInterval](useInterval.md)\n* [useDebouncedCallback](useDebouncedCallback.md)\n* [useThrottledCallback](useThrottledCallback.md)\n* [useLocalStorage](useLocalStorage.md)\n* [useSessionStorage](useSessionStorage.md)\n* [useDefaultedState](useDefaultedState.md)\n* [useRenderInfo](useRenderInfo.md)\n* [useSwipe](useSwipe.md), [useHorizontalSwipe](useHorizontalSwipe.md) and [useVerticalSwipe](useVerticalSwipe.md)\n* [useSwipeEvents](useSwipeEvents.md)\n* [useConditionalTimeout](useConditionalTimeout.md)\n* [useCookie](useCookie.md)\n* [useDarkMode](useDarkMode.md)\n* [useUpdateEffect](useUpdateEffect.md)\n* [useIsFirstRender](useIsFirstRender.md)\n* [useMutationObserver](useMutationObserver.md)\n* [useAudio](useAudio.md)\n* [useObjectState](useObjectState.md)\n* [useToggle](useToggle.md)\n* [useQueryParam](useQueryParam.md)\n* [useQueryParams](useQueryParams.md)\n* [useSearchQuery](useSearchQuery.md)\n* [useURLSearchParams](useURLSearchParams.md)\n\n<div>\n  <p align=\"center\">\n    <a href=\"https://antonioru.github.io/beautiful-react-hooks/\" target=\"_blank\">\n    🌟 在线演示 🌟\n    </a>\n  </p>\n</div>\n\n## 如何贡献\n\n我们非常欢迎而且期待着你的开源贡献。\n\n如果想要提交你的自定义 hook，请确保你阅读过这篇 [贡献](../CONTRIBUTING.md) 守则。\n\n在提交一个合并请求 **之前**，请确保:\n\n1. 你已经更新了 package.json 里的版本号，并将你的变更说明放进了 [CHANGELOG](../CHANGELOG.md) 文件里。\n2. 确保你执行过 `npm test` 和 `npm build` 再提交你的合并请求。\n3. 确保你已经写好了你添加的自定义 hook 的文档 _（你可以使用[HOOK 文档模板](../HOOK_DOCUMENTATION_TEMPLATE.md) 来写你的文档 ）_\n4. 确保你已经更新了 `index.d.ts` 文件，把你的 hook 的类型加进去了。\n\n### 项目依赖\n\n- [React](https://reactjs.org/)\n- [Mocha](https://mochajs.org/)\n- [Chai](https://www.chaijs.com/)\n- [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro)\n- [@testing-library/react-hooks](https://react-hooks-testing-library.com/)\n\n---\n\n图标的作者是 [Freepik](https://www.flaticon.com/authors/freepik) from [www.flaticon.com](https://www.flaticon.com/free-icon/hook_1081812)\n"
  },
  {
    "path": "docs/useAudio.md",
    "content": "# useAudio\n\nCreates an `<audio>` element, monitors its state and provides access to playback controls.\n\n### Why? 💡\n\n- A speedy approach to integrating the audio feature into your React component\n- Enhances the readability of components involving the audio feature\n\n### Basic Usage:\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Button, Typography } from 'antd';\nimport { PlayCircleFilled, PauseCircleFilled } from '@ant-design/icons';\n\nimport useAudio from 'beautiful-react-hooks/useAudio';\n\nconst UseAudioComponent = () => {\n  const [state, controls] = useAudio(\"https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3\", { autoPlay: true });\n  const code = JSON.stringify(state, null, '\\t');\n\n  const Actions = [\n    <Button onClick={controls.play} shape=\"round\" icon={<PlayCircleFilled />} />,\n    <Button onClick={controls.pause} shape=\"round\" icon={<PauseCircleFilled />} />,\n    <Button onClick={controls.mute}>\n      Mute\n    </Button>,\n    <Button onClick={() => controls.setVolume(state.volume + 0.1)}>Vol +1</Button>,\n    <Button onClick={() => controls.setVolume(state.volume - 0.1)}>Vol -1</Button>,\n    <Button onClick={() => controls.seek(state.currentTime + 10)}>+10 secs</Button>,\n    <Button onClick={() => controls.seek(state.currentTime - 10)}>-10 secs</Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useAudio\" actions={Actions}>\n      <Typography.Paragraph code>\n        <pre>\n          {code}\n        </pre>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<UseAudioComponent />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type MutableRefObject } from 'react';\n/**\n * The useAudio hook wraps the Audio API and provides a set of controls to manage the audio\n */\nexport declare const useAudio: (src: string, options?: UseAudioOptions) => [AudioState, Readonly<AudioControls>, MutableRefObject<HTMLAudioElement>];\ntype UseAudioPreloadType = 'auto' | 'metadata' | 'none';\n/**\n * The interface for the state of the useAudio hook\n */\nexport interface AudioState {\n    loop: boolean;\n    muted: boolean;\n    volume: number;\n    duration: number;\n    autoPlay: boolean;\n    isPlaying: boolean;\n    preload?: UseAudioPreloadType;\n    currentTime: number;\n    playbackRate: number;\n    isSrcLoading: boolean | undefined;\n}\n/**\n * The interface for the options of the useAudio hook\n */\nexport interface UseAudioOptions {\n    loop?: boolean;\n    muted?: boolean;\n    volume?: number;\n    autoPlay?: boolean;\n    preload?: UseAudioPreloadType;\n    playbackRate?: number;\n}\n/**\n * The interface for the controls of the useAudio hook\n */\nexport interface AudioControls {\n    play: () => void;\n    mute: () => void;\n    pause: () => void;\n    unmute: () => void;\n    seek: (time: number) => void;\n    onError: (onError: ((error: Error) => void)) => void;\n    setVolume: (volume: number) => void;\n}\nexport default useAudio;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useConditionalTimeout.md",
    "content": "# useConditionalTimeout\n\nAn asynchronous hook which takes in three parameters: a \"callback\", a \"delay time\" (in milliseconds), and a boolean value known as \"\ncondition\".\\\nIt then postpones the execution of the given callback by the specified delay time, only when the provided condition changes to `true`\n\n### 💡 Why?\n\n- To start a timeout only after a certain condition has been confirmed;\n- Handles the executing of the provided callback despite the component's re-rendering;\n- Terminates the timeout when the component unmounts (or not, depending on the specified options) and/or when the provided condition is\n  confirmed;\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Button, Space, Typography } from 'antd';\n\nimport useConditionalTimeout from 'beautiful-react-hooks/useConditionalTimeout';\n\nconst ConditionalDelayedContentComponent = () => {\n  const [condition, setCondition] = useState(false);\n  const [showContent, setShowContent] = useState(false);\n\n  useConditionalTimeout(() => {\n    setShowContent(true)\n  }, 2000, condition);\n\n  const Actions = [\n    <Button type=\"primary\" onClick={() => setCondition(true)} disabled={condition} loading={condition && !showContent}>\n      {condition ? 'Timer started' : 'Start the timer'}&hellip;\n    </Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useConditionalTimeout\" actions={Actions}>\n      <Space direction=\"vertical\">\n        <Typography.Paragraph>\n          Click on the following button to change the condition that triggers the 2 seconds timeout to true\n        </Typography.Paragraph>\n        <Typography.Paragraph>\n          After timeout is elapsed a content is displayed\n        </Typography.Paragraph>\n        {showContent && <div style={{ fontSize: '3rem' }}>🕰</div>}\n\n      </Space>\n    </DisplayDemo>)\n};\n\n<ConditionalDelayedContentComponent />\n```\n\n### State & clear method:\n\nThe hook will return the state of the timeout (either cleared or not cleared) and a function that may be used to clear it.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Button, Typography } from 'antd';\n\nimport useConditionalTimeout from 'beautiful-react-hooks/useConditionalTimeout';\n\nconst ConditionalDelayedContentComponent = () => {\n  const [condition, setCondition] = useState(false);\n  const [showContent, setShowContent] = useState(false);\n  const [isCleared, clearTimeoutRef] = useConditionalTimeout(() => {\n    setShowContent(true)\n  }, 5000, condition);\n\n  const Actions = [\n    <Button type=\"primary\" onClick={() => setCondition(true)} disabled={condition}>Start a 5 seconds timeout</Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useConditionalTimeout\" actions={Actions}>\n      <Typography.Paragraph>Content will show after 5 second starting from the following button click</Typography.Paragraph>\n      {showContent && <div style={{ fontSize: '3rem' }}>🕰</div>}\n      {!isCleared && !showContent && <Button onClick={clearTimeoutRef}>Cancel timeout</Button>}\n      {isCleared && <Typography.Paragraph>Cleared</Typography.Paragraph>}\n    </DisplayDemo>\n  )\n};\n\n<ConditionalDelayedContentComponent />\n```\n\n### Options:\n\nThe third parameter is an optional object of options\n\n#### cancelOnUnmount:\n\nDefines whether the timeout should be cleared on unmount.\n\n**default**: `true`\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Button } from 'antd';\nimport useConditionalTimeout from 'beautiful-react-hooks/useConditionalTimeout';\n\nconst ConditionalDelayedContentComponent = () => {\n  const [condition, setCondition] = useState(false);\n  const [showContent, setShowContent] = useState(false);\n  const options = { cancelOnUnmount: false };\n\n  useConditionalTimeout(() => {\n    setShowContent(true)\n  }, 5000, condition, options);\n\n  return (\n    <DisplayDemo title=\"useConditionalTimeout\">\n      <Button type=\"primary\" onClick={() => setCondition(true)}>Start a 5 seconds timeout</Button>\n      {showContent && <div style={{ fontSize: '3rem' }}>🕰</div>}\n    </DisplayDemo>)\n};\n\n<ConditionalDelayedContentComponent />\n```\n\n#### cancelOnConditionChange:\n\nDefines whether the timeout should be cleared when the condition changes.\n\nIn this example, clicking on the button will not trigger any action as there are two instances of useConditionalTimeout, and one of them\nwill modify the condition.\n\n**default**: `true`\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Button } from 'antd';\nimport useConditionalTimeout from 'beautiful-react-hooks/useConditionalTimeout';\n\nconst ConditionalDelayedContentComponent = () => {\n  const [condition, setCondition] = useState(false);\n  const [showContent, setShowContent] = useState(false);\n\n  useConditionalTimeout(() => {\n    setShowContent(true)\n  }, 5000, condition);\n\n  useConditionalTimeout(() => {\n    setCondition(false)\n  }, 2000, condition);\n\n  return (\n    <DisplayDemo title=\"useConditionalTimeout\">\n      <Button type=\"primary\" onClick={() => setCondition(true)}>Start a 5 seconds timeout</Button>\n      {showContent && <div style={{ fontSize: '3rem' }}>🕰</div>}\n    </DisplayDemo>)\n};\n\n<ConditionalDelayedContentComponent />\n```\n\n### Mastering the hooks\n\n#### ✅ When to use\n\n- If it is necessary to execute a callback after a specific duration and only when a specific condition has been verified.\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type GenericFunction } from './shared/types';\n/**\n * An async-utility hook that accepts a callback function and a delay time (in milliseconds), then delays the\n * execution of the given function by the defined time from when the condition verifies.\n */\ndeclare const useConditionalTimeout: <TCallback extends GenericFunction>(fn: TCallback, milliseconds: number, condition: boolean, options?: UseConditionalTimeoutOptios) => UseConditionalTimeoutReturn;\nexport interface UseConditionalTimeoutOptios {\n    cancelOnUnmount?: boolean;\n    cancelOnConditionChange?: boolean;\n}\nexport type UseConditionalTimeoutReturn = [boolean, () => void];\nexport default useConditionalTimeout;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useCookie.md",
    "content": "# useCookie\n\nA hook that facilitates the storage, updating, and deletion of values within\nthe [CookieStore](https://developer.mozilla.org/en-US/docs/Web/API/CookieStore).\n\n### 💡 Why?\n\n- A quick and safe way to access the `CookieStore` in your React components.\n- Improves readability of React components accessing the `CookieStore\n\n### Basic Usage:\n\n```jsx harmony\nimport { useCallback } from 'react';\nimport { Typography, Tag, Button } from 'antd';\n\nimport useCookie from 'beautiful-react-hooks/useCookie';\n\nconst UseCookieExample = () => {\n  const { onError, cookieValue, deleteCookie, updateCookie } = useCookie('cookie-key', {\n    secure: false,\n    path: '/',\n    defaultValue: 'default-value'\n  });\n\n  onError((error) => {\n    console.log(error)\n\n    alert(error.message)\n  })\n\n  const updateButtonClick = useCallback(() => {\n    updateCookie('new-cookie-value')\n  }, [])\n\n  const deleteButtonClick = useCallback(() => {\n    deleteCookie()\n  }, [])\n\n  const Actions = [\n    <Button type=\"primary\" onClick={updateButtonClick}>\n      Update the cookieStore\n    </Button>,\n    <Button onClick={deleteButtonClick}>\n      Clear the cookieStore\n    </Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useCookie\" actions={Actions}>\n      <Typography.Paragraph>\n        Click on the button to update or clear the cookieStore\n      </Typography.Paragraph>\n      <Tag color=\"blue\">\n        {cookieValue || 'no value'}\n      </Tag>\n    </DisplayDemo>\n  )\n};\n\n<UseCookieExample />\n```\n\n### Mastering the hooks\n\n#### ✅ When to use\n\n- When you need to CRUD values from the `CookieStore`\n\n#### 🛑 When not to use\n\n- in server-only components (during SSR)\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type CallbackSetter } from './shared/types';\ndeclare const useCookie: (key: string, options?: UseCookieOptions) => Readonly<UseCookieReturn>;\nexport declare enum CookieSameSite {\n    STRICT = \"strict\",\n    LAX = \"lax\",\n    NONE = \"none\"\n}\ninterface CookieStoreDeleteOptions {\n    name?: string;\n    domain?: string;\n    path?: string;\n}\ninterface CookieBase extends CookieStoreDeleteOptions {\n    sameSite?: CookieSameSite;\n}\nexport interface UseCookieOptions extends CookieBase {\n    defaultValue?: string;\n}\nexport interface UseCookieReturn {\n    cookieValue?: string;\n    updateCookie: (nextValue: string) => Promise<void>;\n    deleteCookie: () => Promise<void>;\n    onError: CallbackSetter<Error>;\n}\nexport default useCookie;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useDarkMode.md",
    "content": "# useDarkMode\n\nA hook that manages all the necessary operations to incorporate a toggle switch for dark and light modes on your website\n\n### 💡 Why?\n\n- Keep information about dark/light mode consistent and in sync across sessions using localStorage\n- Return the methods that allows you to change into dark/light mode\n- Safely read information about the dark/light mode from user's operating system using `prefers-color-scheme`\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography, Tag, Button } from 'antd';\n\nimport useDarkMode from 'beautiful-react-hooks/useDarkMode';\n\nconst UseDarkModeExample = () => {\n  const { toggle, enable, disable, isDarkMode } = useDarkMode();\n\n  const Actions = [\n    <Button type='primary' onClick={enable}>\n      Enable dark mode\n    </Button>,\n    <Button onClick={disable}>\n      Disable dark mode\n    </Button>,\n    <Button onClick={toggle}>\n      Toggle dark mode\n    </Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useDarkMode\" actions={Actions}>\n      <Typography.Paragraph>Click on the buttons to update isDarkMode flag</Typography.Paragraph>\n      <Typography.Paragraph>isDarkMode: <Tag>{isDarkMode ? 'true' : 'false'}</Tag></Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<UseDarkModeExample />\n```\n\n### Mastering the hooks\n\n#### 🛑 When not to use\n\n- in server-only components (during SSR)\n\n<!-- Types -->\n### Types\n    \n```typescript static\nexport declare const LOCAL_STORAGE_KEY = \"beautiful-react-hooks-is-dark-mode\";\ndeclare const useDarkMode: (defaultValue?: boolean, localStorageKey?: string) => Readonly<UseDarkModeReturn>;\nexport interface UseDarkModeReturn {\n    isDarkMode: boolean;\n    toggle: () => void;\n    enable: () => void;\n    disable: () => void;\n}\nexport default useDarkMode;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useDebouncedCallback.md",
    "content": "# useDebouncedCallback\n\nA hook that accepts a `function` parameter and produces a new memoized variant of that function which postpones its invocation by the\nspecified duration.\\\nIn case the duration is not specified, it will be set to the default value of 600ms.\\\n\nThis hook is built on top of the `lodash.debounce` function. For further details, kindly refer to\nthe [Lodash documentation](https://lodash.com/docs/#debounce).\n\n### Why? 💡\n\n- To take full control over frequency at which a function can execute, independent of the number of renders performed by the component\n\n### Basic Usage\n\n```jsx harmony\nimport { useEffect, useState } from 'react';\nimport { Typography, Alert, Space, Tag } from 'antd';\nimport useDebouncedCallback from 'beautiful-react-hooks/useDebouncedCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst DebouncedFnComponent = () => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useDebouncedCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  });\n\n  onWindowResize(onWindowResizeHandler);\n\n  useEffect(() => {\n    // do something\n    // don't forget to cancel debounced\n    return () => onWindowResizeHandler.cancel(); // or .flush()\n  });\n\n  return (\n    <DisplayDemo title=\"useDebounceCallback\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window and see the update taking effect after the designated delay\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{width}</Tag><br />\n          window height: <Tag color=\"green\">{height}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<DebouncedFnComponent />\n```\n\n### Dependencies\n\nSince `useDebouncedCallback` uses [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)\nunder the hood, you can possibly define the callback dependencies.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Alert, Space, Tag } from 'antd';\nimport useDebouncedCallback from 'beautiful-react-hooks/useDebouncedCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst DebouncedFnComponent = (props) => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useDebouncedCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  }, [setWidth, setHeight]);\n\n  onWindowResize(onWindowResizeHandler);\n\n  return (\n    <DisplayDemo title=\"useDebounceCallback\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window and see the update taking effect after the designated delay\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{width}</Tag><br />\n          window height: <Tag color=\"green\">{height}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<DebouncedFnComponent foo=\"bar\" />\n```\n\n### Debounce time\n\nA custom debounce time can be easily defined as follows (500ms)\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Alert, Space, Tag } from 'antd';\nimport useDebouncedCallback from 'beautiful-react-hooks/useDebouncedCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst DebouncedFnComponent = (props) => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useDebouncedCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  }, [setWidth, setHeight], 500);\n\n  onWindowResize(onWindowResizeHandler);\n\n  return (\n    <DisplayDemo title=\"useDebounceCallback\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window and see the update taking effect after the designated delay\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{width}</Tag><br />\n          window height: <Tag color=\"green\">{height}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<DebouncedFnComponent foo=\"bar\" />\n```\n\n### Options\n\nSince `useDebouncedCallback` uses [lodash.debounce](https://www.npmjs.com/package/lodash.debounce); under the hood, you can possibly define\nfew options to customise its behaviour.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Alert, Space, Tag } from 'antd';\nimport useDebouncedCallback from 'beautiful-react-hooks/useDebouncedCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst DebouncedFnComponent = () => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize()\n  const options = {\n    leading: false,\n    trailing: true,\n  };\n\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useDebouncedCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  }, [setWidth, setHeight], 500, options);\n\n  onWindowResize(onWindowResizeHandler);\n\n  return (\n    <DisplayDemo title=\"useDebounceCallback\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window and see the update taking effect after the designated delay\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{width}</Tag><br />\n          window height: <Tag color=\"green\">{height}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<DebouncedFnComponent />\n```\n\n#### ✅ Pro tip:\n\nTo deep understanding the differences between `throttle` and `debounce`, what they are and when to use them please\nread \"[Debouncing and Throttling Explained Through Examples](https://css-tricks.com/debouncing-throttling-explained-examples/)\"\nby [David Corbacho](https://twitter.com/dcorbacho)\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/// <reference types=\"lodash\" />\nimport { type DependencyList } from 'react';\nimport { type GenericFunction } from './shared/types';\nexport interface DebounceOptions {\n    leading?: boolean | undefined;\n    maxWait?: number | undefined;\n    trailing?: boolean | undefined;\n}\n/**\n * Accepts a function and returns a new debounced yet memoized version of that same function that delays\n * its invoking by the defined time.\n * If time is not defined, its default value will be 250ms.\n */\ndeclare const useDebouncedCallback: <TCallback extends GenericFunction>(fn: TCallback, dependencies?: DependencyList, wait?: number, options?: DebounceOptions) => import(\"lodash\").DebouncedFunc<TCallback>;\nexport default useDebouncedCallback;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useDefaultedState.md",
    "content": "# useDefaultedState\n\nA hook that functions similar to `useState`, with the added capability to receive a defaultValue and potentially an initialState.\\\nThis hook guarantees that the state returned is always set to defaultValue in the event of it being null or undefined.\n\n### Why? 💡\n\n- Avoids side-effects by ensuring a default state value\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography, Button } from 'antd';\nimport useDefaultedState from 'beautiful-react-hooks/useDefaultedState';\n\n/**\n * useDefaultedState example component\n */\nconst DefaultedStateExample = () => {\n  const placeholder = { name: 'John Doe' };\n  const data = { name: 'Antonio Rù' };\n  const [user, setUser] = useDefaultedState(placeholder, data);\n\n  const Actions = [\n    <Button type=\"primary\" onClick={() => setUser()}>Change to 'undefined'</Button>,\n  ]\n\n  return (\n    <DisplayDemo title=\"useDefaultedState\" actions={Actions}>\n      <Typography.Paragraph>The user name is: {user.name}</Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<DefaultedStateExample />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- If you require a secure state that must never be null or undefined\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Returns a safe state by making sure the given value is not null or undefined\n */\ndeclare const useDefaultedState: <TValue>(defaultValue: TValue, initialState?: TValue | undefined) => [TValue, (nextState: TValue) => void];\nexport default useDefaultedState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useDidMount.md",
    "content": "# useDidMount\n\nA hook that takes in a function to execute when the component has finished mounting.\n\n### Why? 💡\n\n- takes care of performing a callback when the component mounts\n- Is intended as a shortcut to `useEffect(onMount, [])`\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography } from 'antd';\nimport useDidMount from 'beautiful-react-hooks/useDidMount';\n\nconst ComponentDidMount = () => {\n  const [mounted, setIsMounted] = useState(false);\n\n  useDidMount(() => {\n    const timeout = setTimeout(() => {\n      setIsMounted(true);\n      clearTimeout(timeout);\n    }, 1000);\n  });\n\n  return (\n    <DisplayDemo title=\"useDidMount\">\n      {mounted && (<Typography.Paragraph>Component did mount!</Typography.Paragraph>)}\n    </DisplayDemo>\n  );\n};\n\n<ComponentDidMount />\n```\n\n### Callback setter syntax:\n\nif the first parameter is not provided, the returned function (*a callback setter*) can be used to set the `useDidMount` handler, as long as\nit is immediately invoked.\n\n**Please note**: the returned callback setter is meant to change the value of the callback reference only, it does not cause the component\nrerender nor should not be invoked asynchronously.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography } from 'antd';\nimport useDidMount from 'beautiful-react-hooks/useDidMount';\n\nconst ComponentDidMount = () => {\n  const [mounted, setIsMounted] = useState(false);\n  const onMount = useDidMount();\n\n  onMount(() => {\n    const timeout = setTimeout(() => {\n      setIsMounted(true);\n      clearTimeout(timeout);\n    }, 1000);\n  });\n\n  return (\n    <DisplayDemo title=\"useDidMount\">\n      {mounted && (<Typography.Paragraph>Component did mount!</Typography.Paragraph>)}\n    </DisplayDemo>\n  );\n};\n\n<ComponentDidMount />\n```\n\n#### ✅ Pro tip:\n\nWhen using a React function component you should not really think of it in terms of \"lifecycle\".\n\nThe `useDidMount` hook is indeed intended as a shortcut to  `useEffect(onMount, [])`.\n\nTo deep understanding `useEffect`, what it is and how it should be properly used, please read\n\"[A complete guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/)\"\nby [Dan Abramov](https://twitter.com/dan_abramov)\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When in need of performing a function after the component mounts\n\n#### 🛑 When not to use\n\n- You can't use it asynchronously since this will break the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n- If using the callback setter, it should not be used asynchronously but immediately invoked\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type GenericFunction, type Noop } from './shared/types';\n/**\n * Returns a callback setter for a function to be performed when the component did mount.\n */\ndeclare const useDidMount: <TCallback extends GenericFunction = Noop>(callback?: TCallback | undefined) => import(\"./shared/types\").CallbackSetter<undefined>;\nexport default useDidMount;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useDrag.md",
    "content": "# useDrag\n\nA hook that receives a reference to an HTML Element (using React's useRef) and enables it to be dragged.\\\nThe hook returns a boolean value indicating whether the element is currently being dragged or not.\n\n### Why? 💡\n\n- takes care of attaching drag-related event listeners to the specified target\n- takes care of emoving the listener when the component is unmounted.\n- allow to easily implement draggable business logic\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useDrag`\n\n```jsx harmony\nimport { useRef } from 'react';\nimport useDrag from 'beautiful-react-hooks/useDrag';\n\nconst MyComponent = () => {\n  const ref = useRef();\n  const isDragged = useDrag(ref);\n\n  return (\n    <DisplayDemo title=\"useDrag\">\n      <div ref={ref} style={{ padding: '20px 0', background: isDragged ? '#BE496E' : '#1D6C8B' }}>\n        Draggable item...\n        {isDragged && <span>is being dragged</span>}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Drag image:\n\n```jsx harmony\nimport { useRef } from 'react';\nimport useDrag from 'beautiful-react-hooks/useDrag';\n\nconst MyComponent = () => {\n  const ref = useRef();\n  const isDragged = useDrag(ref, {\n    dragImage: 'https://beautifulinteractions.com/img/logo-colorful.svg',\n    dragImageXOffset: 5,\n    dragImageYOffset: 5,\n  });\n\n  return (\n    <DisplayDemo title=\"useDrag\">\n      <div ref={ref} style={{ padding: '20px 0', background: isDragged ? '#BE496E' : '#1D6C8B' }}>\n        Draggable item...\n        {isDragged && <span>is being dragged</span>}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Data transfer:\n\n```jsx harmony\nimport { useRef } from 'react';\nimport useDrag from 'beautiful-react-hooks/useDrag';\n\nconst MyComponent = () => {\n  const ref = useRef();\n  const isDragged = useDrag(ref, {\n    transfer: { id: 'item-id', foo: 'bar' },\n    transferFormat: 'text/plain',\n  });\n\n  return (\n    <DisplayDemo title=\"useDrag\">\n      <div ref={ref} style={{ padding: '20px 0', background: isDragged ? '#BE496E' : '#1D6C8B' }}>\n        Draggable item...\n        {isDragged && <span>is being dragged</span>}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- If you require basic drag-related business logic\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nexport interface UseDragOptions {\n    dragImage?: string;\n    dragImageXOffset?: number;\n    dragImageYOffset?: number;\n    transfer?: string | number | Record<string, any>;\n    transferFormat?: string;\n}\ndeclare const useDrag: <TElement extends HTMLElement>(targetRef: RefObject<TElement>, options?: UseDragOptions) => boolean;\nexport default useDrag;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useDragEvents.md",
    "content": "# useDragEvents\n\nA hook that provides a collection of functions designed to simplify the management of drag-related events.\\\nIt takes a reference to target element where the events are to be attached.\\\nThis hook facilitates the handling of drag events, making it easier for developers to incorporate drag-and-drop functionality into their web\napplications.\n\n**Please note:** the returned callback setters should be invoked immediately in the function component's body, do not try to call this\nfunctions asynchronously.\n\n### Why? 💡\n\n- Takes care of attaching the drag-related event listeners to the specified target element\n- Automatically removes the event listeners when the component is unmounted\n- Enables the ability to abstract the handling of drag-related events\n\n### Basic Usage:\n\nProvide a DOM element ref as first parameter to `useDragEvents`\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useDragEvents from 'beautiful-react-hooks/useDragEvents';\n\nconst MyComponent = () => {\n  const ref = useRef();\n  const [isDragged, setIsDragged] = useState(false);\n  const { onDragStart, onDragEnd } = useDragEvents(ref);\n\n  onDragStart((event) => {\n    setIsDragged(true);\n  });\n\n  onDragEnd((event) => {\n    setIsDragged(false);\n  });\n\n  return (\n    <DisplayDemo title=\"useDragEvents\">\n      <div ref={ref} style={{ padding: '20px 0', background: '#1D6C8B' }}>\n        Draggable item...\n        {isDragged && <span>is being dragged</span>}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Draggable attribute:\n\nthe second parameter determines whether the target element should have the `draggable` attribute set. By default, this is set to `true`.\n\n**Please note**:\n\nThe following code is meant to be just as an example, **do not use this hooks to substitute the standard props approach**, please\nread [mastering the hook](#Mastering_the_hook) below.\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useDragEvents from 'beautiful-react-hooks/useDragEvents';\n\nconst MyComponent = () => {\n  const draggableRef = useRef();\n  const dropzoneRef = useRef();\n  const [droppedTimes, setDroopedTimes] = useState(0);\n  const [isDragged, setIsDragged] = useState(false);\n  const { onDragStart, onDragEnd } = useDragEvents(draggableRef);\n  const { onDrop, onDragOver } = useDragEvents(dropzoneRef, false);\n\n  onDragStart((event) => {\n    setIsDragged(true);\n  });\n\n  onDragEnd((event) => {\n    setIsDragged(false);\n  });\n\n  onDragOver((event) => {\n    event.preventDefault();\n  });\n\n  onDrop((event) => {\n    setDroopedTimes(1 + droppedTimes);\n  });\n\n  return (\n    <DisplayDemo title=\"useDragEvents\">\n      <div ref={draggableRef} style={{ padding: '20px 0', background: '#1D6C8B' }}>\n        Draggable item...\n        {isDragged && <span>is being dragged</span>}\n      </div>\n\n      <div ref={dropzoneRef} style={{ padding: '20px 0', marginTop: '20px', background: '#BE496E' }}>\n        Drop zone!\n        Dropped items: {droppedTimes}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- If in need to abstract some drag-n-drop related logic into a custom hooks\n\n#### 🛑 What not to do\n\n- Using the returned callback setter asynchronously won't have any effect and could introduce bugs into your code, so it should be avoided.\n- Standard drag handler props (like `onDragStart`) should not be replaced with useDragEvents callback setters.\n- useDragEvents is designed to be used for more complex hooks that require control over drag and drop.\n- Replacing classic props with useDragEvents handlers can lead to a loss in performance due to the lack of React SyntheticEvent support.\n- If you were already using a method similar to the following, it is recommended to continue doing so:\n\n```jsx harmony static noedit\nconst MyComponent = (props) => {\n  const { dragStartHandler } = props;\n\n  return (\n    <div onDragStart={dragStartHandler} />\n  );\n};\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nimport { type CallbackSetter } from './shared/types';\nexport interface UseDragEventsResult {\n    onDrag: CallbackSetter<DragEvent>;\n    onDrop: CallbackSetter<DragEvent>;\n    onDragEnter: CallbackSetter<DragEvent>;\n    onDragEnd: CallbackSetter<DragEvent>;\n    onDragExit: CallbackSetter<DragEvent>;\n    onDragLeave: CallbackSetter<DragEvent>;\n    onDragOver: CallbackSetter<DragEvent>;\n    onDragStart: CallbackSetter<DragEvent>;\n}\n/**\n * Returns an object of callback setters to handle the drag-related events.\n * It accepts a DOM ref representing the events target (where attach the events to).\n *\n * Returned callback setters: `onDrag`, `onDrop`, `onDragEnter`, `onDragEnd`, `onDragExit`, `onDragLeave`,\n * `onDragOver`, `onDragStart`;\n */\ndeclare const useDragEvents: <TElement extends HTMLElement>(targetRef: RefObject<TElement>, isDraggable?: boolean) => Readonly<UseDragEventsResult>;\nexport default useDragEvents;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useDropZone.md",
    "content": "# useDropZone\n\nA hook that receives an HTML Element ref and transforms it into a drop-zone capable of accepting data from a dragged object\n\n### Why? 💡\n\n- Handles the addition of drop-related event listeners to the specified target\n- Cleans up the listener upon component unmounting\n- Facilitates the implementation of drop-related business logic\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useDropZone`\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport useDrag from 'beautiful-react-hooks/useDrag';\nimport useDropZone from 'beautiful-react-hooks/useDropZone';\n\nconst MyComponent = () => {\n  const dragRef = useRef();\n  const dropRef = useRef();\n  const isDragged = useDrag(dragRef, { transfer: { data: 'foo' }, transferFormat: 'text' });\n  const { isOver, onDrop } = useDropZone(dropRef);\n  const [data, setData] = useState();\n\n  onDrop((event) => {\n    event.preventDefault();\n    const nextData = event.dataTransfer.getData('text');\n    setData(nextData);\n  });\n\n  return (\n    <DisplayDemo title=\"useDropZone\">\n      <div ref={dragRef} style={{ padding: '20px 0', background: isDragged ? '#BE496E' : '#1D6C8B' }}>\n        {!isDragged && <span>Drag to send data</span>}\n        {isDragged && <span>is being dragged</span>}\n      </div>\n      <div ref={dropRef} style={{ padding: '20px 0', marginTop: '4rem', background: isOver ? '#BE496E' : 'white' }}>\n        {!data && 'Drop here to receive data'}\n        {data && `Received: ${data}`}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- If in need to abstract some drag-n-drop related logic into a custom hooks\n\n#### 🛑 What not to do\n\n- Using the returned callback setter asynchronously won't have any effect and could introduce bugs into your code, so it should be avoided.\n- Standard drag handler props (like `onDragStart`) should not be replaced with useDragEvents callback setters.\n- useDragEvents is designed to be used for more complex hooks that require control over drag and drop.\n- Replacing classic props with useDragEvents handlers can lead to a loss in performance due to the lack of React SyntheticEvent support.\n- If you were already using a method similar to the following, it is recommended to continue doing so:\n\n```jsx harmony static noedit\nconst MyComponent = (props) => {\n  const { dragStartHandler } = props;\n\n  return (\n    <div onDragStart={dragStartHandler} />\n  );\n};\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nimport { type CallbackSetter } from './shared/types';\nexport interface UseDropZoneResult {\n    readonly isOver: boolean;\n    readonly onDrop: CallbackSetter<DragEvent>;\n}\ndeclare const useDropZone: <TElement extends HTMLElement>(targetRef: RefObject<TElement>) => Readonly<UseDropZoneResult>;\nexport default useDropZone;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useEvent.md",
    "content": "# useEvent\n\nA hook that allows you to specify an HTML element and an event name. It sets up a listener so that when that event happens on that element,\nyour code will be notified and can take action. Essentially, it lets you \"listen\" for events on a specific HTML element\n\n### Why? 💡\n\n- Automatically adds the event listener to the element, so you don't have to do it manually\n- Automatically removes the event listener when the component unmounts\n\n### Basic Usage:\n\n`useEvents` returns a callback setter for the defined event to be immediately invoked.\n\n**Please note**: the callback setter is only meant to change the callback reference, it does not cause the component rerender unless\ndifferently specified in the function's body. It's not invoked asynchronously\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport useEvent from 'beautiful-react-hooks/useEvent';\n\nconst TestComponent = () => {\n  const targetRef = useRef()\n  const [clicksNo, setClicksNo] = useState(0)\n  const onTargetClick = useEvent(targetRef, 'click');\n\n  onTargetClick((event) => {\n    setClicksNo(clicksNo + 1);\n  });\n\n  return (\n          <DisplayDemo title=\"useEvent\">\n            <div ref={targetRef}>\n              Click on this text to increase the number of clicks: {clicksNo}\n            </div>\n          </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n### Options:\n\nSince `useEvent` uses [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)\nunder the hood, it's possible to specify the listener characteristics by passing an options object as third parameter.\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport useEvent from 'beautiful-react-hooks/useEvent';\n\nconst TestComponent = () => {\n  const targetRef = useRef()\n  const [clicksNo, setClicksNo] = useState(0)\n  const onTargetClick = useEvent(targetRef, 'click', {\n    capture: true,\n    passive: true,\n    once: true\n  });\n\n  onTargetClick((event) => {\n    setClicksNo(clicksNo + 1);\n  });\n\n  return (\n          <DisplayDemo title=\"useEvent\">\n            <div ref={targetRef}>\n              Click on this text to increase the number of clicks: {clicksNo}\n            </div>\n          </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When in need of listening to a specific event from an HTMLElement\n\n#### 🛑 What not to do\n\n- When you can archive the same result by using a callback, **please remember listening/firing events directly to/from HTMLElement(s) in\n  React is considered an anti-pattern**\n- You can't use the returned callback setter asynchronously, it will not have any effect but changing the handler possibly leading to bugs\n  in your code\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\n/**\n * Accepts the reference to an HTML Element and an event name then performs the necessary operations to listen to the event\n * when fired from that HTML Element.\n */\ndeclare const useEvent: <TEvent extends Event, TElement extends HTMLElement = HTMLElement>(ref: RefObject<TElement>, eventName: string, options?: AddEventListenerOptions) => import(\"./shared/types\").CallbackSetter<TEvent>;\nexport default useEvent;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useGeolocation.md",
    "content": "# useGeolocation\n\nA hook that does the job of two - now that's efficiency! This nifty little function returns an array with two elements: the first being the\ngeolocation state from our trusty [useGeolocationState](./useGeolocationState) hook, and the second being an object of callback setters\nfrom [useGeolocationEvents](./useGeolocationEvents).\n\nIt is intended as a shortcut to those hooks.\n\n### Why? 💡\n\n- facilitates streamlined access to\n  the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API/Using_the_Geolocation_API), which allows for\n  geolocation tracking and position updates\n- manages the addition of geolocation event listeners, ensuring that events related to the user's location are properly handled.\n- automatically cleans up the event listener when the component is unmounted, preventing potential memory leaks and optimizing performance\n- enables the abstraction of geolocation-related events, allowing for more flexible and scalable code implementation\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useGeolocation from 'beautiful-react-hooks/useGeolocation';\n\nconst PositionReporter = () => {\n  const [geoState, { onChange }] = useGeolocation();\n\n  onChange(() => {\n    console.log('Position changed...');\n  });\n\n  return (\n          <DisplayDemo title=\"useGeolocation\">\n            <Typography.Title>The current position is:</Typography.Title>\n            {geoState.isRetrieving && (<Typography.Paragraph>Retrieving position...</Typography.Paragraph>)}\n            {geoState.isSupported && geoState.position && [\n              <Typography.Paragraph key={0}>Lat: {geoState.position.coords.latitude}</Typography.Paragraph>,\n              <Typography.Paragraph key={1}>Lng: {geoState.position.coords.longitude}</Typography.Paragraph>\n            ]}\n          </DisplayDemo>\n  );\n};\n\n<PositionReporter />\n```\n\n### Options:\n\nBefore using, please read about the [geolocation options](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions)\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useGeolocation from 'beautiful-react-hooks/useGeolocation';\n\nconst PositionReporter = () => {\n  const [geoState, { onChange }] = useGeolocation({\n    enableHighAccuracy: true,\n    timeout: 0xFFFFFFFF,\n    maximumAge: 0,\n  });\n\n  onChange(() => {\n    console.log('Position changed...');\n  });\n\n  return (\n          <DisplayDemo title=\"useGeolocation\">\n            <Typography.Title>The current position is:</Typography.Title>\n            {geoState.isRetrieving && (<Typography.Paragraph>Retrieving position...</Typography.Paragraph>)}\n            {geoState.isSupported && geoState.position && [\n              <Typography.Paragraph key={0}>Lat: {geoState.position.coords.latitude}</Typography.Paragraph>,\n              <Typography.Paragraph key={1}>Lng: {geoState.position.coords.longitude}</Typography.Paragraph>\n            ]}\n          </DisplayDemo>\n  );\n};\n\n<PositionReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- Use this hook when you require effortless access to the Geolocation API\n\n#### 🛑 What not to do\n\n- Do not utilize this hook to speculate the user's device capabilities.\n- Prior to accessing the geolocation state, ensure to verify the isSupported flag.\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type UseGeolocationStateResult } from './useGeolocationState';\nimport { type UseGeolocationEventsResult } from './useGeolocationEvents';\n/**\n * Returns an array where the first item is the geolocation state from the `useGeolocationState` hook and the\n * second one is the object of callback setters from the `useGeolocationEvents` hook.\n * It is intended as a shortcut to those hooks.\n */\ndeclare const useGeolocation: (options?: PositionOptions) => [UseGeolocationStateResult, UseGeolocationEventsResult];\nexport default useGeolocation;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useGeolocationEvents.md",
    "content": "# useGeolocationEvents\n\nA hook that returns an object of callback setters (functions to set the callback that will be performed once an event is fired)\nto handle geolocation-related events. So far, the supported methods are:\n\n- onChange, invoked when the position changes\n- onError, invoked when an error occurs while retrieving the position.\n\nThe returned object also contains the `isSupported boolean flag, reporting whether the geolocation API is supported.\n\n**Please note**: the returned callback setters should be invoked immediately in the function component's body. Do not try to call these\nfunctions asynchronously.\n\n### Why? 💡\n\n- Manages the addition of geolocation event listeners\n- Handles the cleaning of the listeners when the component unmounts\n- Enables the creation of abstractions for geolocation-related events\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography } from 'antd';\n\nimport useGeolocationEvents from 'beautiful-react-hooks/useGeolocationEvents';\n\nconst GeoReporter = () => {\n  const [position, setGeoPosition] = useState();\n  const [error, setError] = useState();\n  const { isSupported, onChange, onError } = useGeolocationEvents({ enableHighAccuracy: true });\n\n  onChange((geoPosition) => setGeoPosition(geoPosition));\n\n  onError((err) => setError(err));\n\n  return (\n          <DisplayDemo title=\"useGeolocationEvents\">\n            <Typography.Text>Geolocation supported: {isSupported ? 'yes' : 'no'}</Typography.Text>\n            {!error && position && (\n                    <Typography.Text>lat: {position.coords.latitude}, lng: {position.coords.longitude}</Typography.Text>\n            )}\n          </DisplayDemo>\n  );\n};\n\n<GeoReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- Use this hook when you need to abstract geolocation-related logic into a custom hook\n\n#### 🛑 What not to do\n\n- Do not use the returned callback setter asynchronously. Doing so will have no effect and may cause bugs in your code. Instead, be sure to\n  invoke the callback setters immediately in the function component's body\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type BRHGeolocationPosition, type BRHGeolocationPositionError } from './shared/types';\nexport interface UseGeolocationEventsResult {\n    isSupported: boolean;\n    onChange: (callback: (position: BRHGeolocationPosition) => void) => void;\n    onError: (callback: (error: BRHGeolocationPositionError) => void) => void;\n}\n/**\n * Returns a frozen object of callback setters to handle the geolocation events.<br/>\n * So far, the supported methods are: `onChange`, invoked when the position changes and `onError`, invoked when\n * an error occur while retrieving the position.<br/>\n * The returned object also contains the `isSupported` boolean flag reporting whether the geolocation API is supported.\n */\ndeclare const useGeolocationEvents: (options?: PositionOptions) => Readonly<UseGeolocationEventsResult>;\nexport default useGeolocationEvents;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useGeolocationState.md",
    "content": "# useGeolocationState\n\nA hook that returns an object comprising information on the response from\nthe [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API/Using_the_Geolocation_API). \\\nThis object properties are:\n\n- the `position` information, which is the actual response from the geolocation API\n- the `isSupported` boolean flag, indicating whether the geolocation API is supported or not\n- the `isRetrieving` boolean flag, indicating whether the hook is currently retrieving the position or not\n- the `onError` function, invoked when an error occurs while retrieving the position\n\nIt also accepts a [geolocation options object](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions) to be utilized as a\nparameter while utilizing the `Geolocation.getCurrentPosition()` method.\n\n### Why? 💡\n\n- facilitates streamlined access to\n  the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API/Using_the_Geolocation_API), which allows for\n  geolocation tracking and position updates\n- enables the abstraction of geolocation-related events, allowing for more flexible and scalable code implementation\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useGeolocationState from 'beautiful-react-hooks/useGeolocationState';\n\nconst PositionReporter = () => {\n  const { isSupported, isRetrieving, position, onError } = useGeolocationState();\n\n  onError((error) => {\n    alert(error.message);\n  });\n\n  return (\n          <DisplayDemo title=\"useGeolocationState\">\n            <Typography.Title>The current position is:</Typography.Title>\n            {geoState.isRetrieving && (<Typography.Paragraph>Retrieving position...</Typography.Paragraph>)}\n            {geoState.isSupported && geoState.position && [\n              <Typography.Paragraph key={0}>Lat: {geoState.position.coords.latitude}</Typography.Paragraph>,\n              <Typography.Paragraph key={1}>Lng: {geoState.position.coords.longitude}</Typography.Paragraph>\n            ]}\n          </DisplayDemo>\n  );\n};\n\n<PositionReporter />\n```\n\n### Options:\n\nRead more on the [geolocation options documentation](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions)\n\n```jsx harmony\nimport useGeolocationState from 'beautiful-react-hooks/useGeolocationState';\n\nconst PositionReporter = () => {\n  const { isSupported, isRetrieving, position, onError } = useGeolocationState({\n    enableHighAccuracy: true,\n    timeout: 0xFFFFFFFF,\n    maximumAge: 0,\n  });\n\n  onError((error) => {\n    alert(error.message);\n  });\n\n  return (\n          <DisplayDemo title=\"useGeolocationState\">\n            <Typography.Title>The current position is:</Typography.Title>\n            {geoState.isRetrieving && (<Typography.Paragraph>Retrieving position...</Typography.Paragraph>)}\n            {geoState.isSupported && geoState.position && [\n              <Typography.Paragraph key={0}>Lat: {geoState.position.coords.latitude}</Typography.Paragraph>,\n              <Typography.Paragraph key={1}>Lng: {geoState.position.coords.longitude}</Typography.Paragraph>\n            ]}\n          </DisplayDemo>\n  );\n};\n\n<PositionReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- Use this hook when you require effortless access to the Geolocation API\n\n#### 🛑 What not to do\n\n- Do not utilize this hook to speculate the user's device capabilities.\n- Prior to accessing the geolocation state, ensure to verify the isSupported flag.\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type BRHGeolocationPosition, type BRHGeolocationPositionError, type SomeCallback } from './shared/types';\nexport interface GeolocationState {\n    readonly isSupported: boolean;\n    readonly isRetrieving: boolean;\n    readonly position: BRHGeolocationPosition;\n}\nexport interface UseGeolocationStateResult extends GeolocationState {\n    onError: (callback: SomeCallback<BRHGeolocationPositionError>) => void;\n}\n/**\n * Returns a frozen object containing the `position` object, the `isSupported` boolean flag, reporting whether the\n * geolocation API is supported or not and the `isRetrieving` boolean flag reporting whether the hook is fetching the\n * current position.\n * The position is retrieved by using the\n * [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API/Using_the_Geolocation_API),\n * when supported.<br/><br />\n * It possibly accepts an object of [geolocation options]\n * (https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions) to be used as parameter when using the\n * `Geolocation.getCurrentPosition()` method.\n */\ndeclare const useGeolocationState: (options?: PositionOptions) => Readonly<UseGeolocationStateResult>;\nexport default useGeolocationState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useGlobalEvent.md",
    "content": "# useGlobalEvent\n\nA hook that streamlines event handling in your application, ensuring that event listeners are added and removed at the appropriate times,\nwithout requiring you to manage them manually.\\\nSimply provide the name of the event you want to attach to the `window` object, and the hook will take care of the rest.\n\n### Why? 💡\n\n- Simplifies the process of adding a listener for a specific event to the `window` object.\n- Automates the removal of the listener when the component is unmounted.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Alert, Tag, Space } from 'antd';\nimport useGlobalEvent from 'beautiful-react-hooks/useGlobalEvent';\n\nconst TestComponent = () => {\n  const [windowWidth, setWindowWidth] = useState(window.innerWidth);\n  const onWindowResize = useGlobalEvent('resize');\n\n  onWindowResize((event) => {\n    setWindowWidth(window.innerWidth);\n  });\n\n  return (\n    <DisplayDemo title=\"useGlobalEvent\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window to update the state\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{windowWidth}</Tag><br />\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n### Options:\n\nSince `useGlobalEvent` uses [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)\nunder the hood, it's possible to specify the listener characteristics by passing an options object as second parameter.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Alert, Tag, Space } from 'antd';\nimport useGlobalEvent from 'beautiful-react-hooks/useGlobalEvent';\n\nconst TestComponent = () => {\n  const [windowWidth, setWindowWidth] = useState(window.innerWidth);\n  const options = { capture: true, passive: true, once: true };\n  const onWindowResize = useGlobalEvent('resize', options);\n\n  onWindowResize((event) => {\n    setWindowWidth(window.innerWidth);\n  });\n\n  return (\n    <DisplayDemo title=\"useGlobalEvent\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window to update the state\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{windowWidth}</Tag><br />\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- To capture a specific event from the `window` global object.\n\n#### 🛑 What not to do\n\n- Avoid using the returned callback setter asynchronously, as it will only change the handler and may cause bugs in your code.\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type CallbackSetter } from './shared/types';\n/**\n * Accepts an event name then returns a callback setter for a function to be performed when the event triggers.\n */\ndeclare const useGlobalEvent: <TEvent extends Event>(eventName: keyof WindowEventMap, opts?: AddEventListenerOptions) => CallbackSetter<TEvent>;\nexport default useGlobalEvent;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useHorizontalSwipe.md",
    "content": "# useHorizontalSwipe\n\nReturns the state of the horizontal swipe gesture both on mobile or desktop.<br/>\nIt is intended as a shortcut to [useSwipe](./useSwipe.md).\n"
  },
  {
    "path": "docs/useInfiniteScroll.md",
    "content": "# useInfiniteScroll\n\nA hook that accepts an HTML Element reference and returns a function that facilitates handling infinite scroll for that specific element.\n\n### Why? 💡\n\n- adds the required event listeners for infinite scrolling to the defined target\n- takes care of cleaning up the event listener when the component is unmounted, reducing the risk of memory leaks in your application\n- simplifies the implementation of infinite scroll business logic by providing an intuitive and easy-to-use interface\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useInfiniteScroll`\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport { Alert, List, Typography } from 'antd';\nimport useInfiniteScroll from 'beautiful-react-hooks/useInfiniteScroll';\n\nconst generateRandomNo = () => Math.floor(Math.random() * 11)\nconst initialData = Array.from({ length: 40 }).map(generateRandomNo)\n\n/**\n * Fake fetch, resolves an array of random numbers\n * @param items\n * @returns {Promise<unknown>}\n */\nconst fetchMock = (items = 10) => new Promise((resolve) => {\n  setTimeout(() => {\n    const data = Array.from({ length: items }).map(generateRandomNo)\n    resolve(data)\n  }, 1000)\n})\n\n/**\n * Uses fetchMock to mimic an inifinite loading\n * @returns {JSX.Element}\n * @constructor\n */\nconst TestComponent = () => {\n  const targetElementRef = useRef();\n  const onInfiniteScroll = useInfiniteScroll(targetElementRef);\n  const [isFetching, setIsFetching] = useState(false)\n  const [data, setData] = useState(initialData)\n\n  onInfiniteScroll(() => {\n    if (!isFetching) {\n      setIsFetching(true)\n\n      fetchMock()\n              .then((next) => setData([...data, ...next]))\n              .finally(() => setIsFetching(false))\n    }\n  })\n\n  return (\n          <DisplayDemo title=\"useInfiniteScroll\">\n            <div style={{ maxHeight: 250, overflow: 'scroll' }} ref={targetElementRef}>\n              <div style={{ height: 500, position: 'relative' }}>\n                <Alert type=\"info\" message=\"Scroll to load more content\" />\n                <List\n                        bordered\n                        dataSource={data}\n                        renderItem={(_, item) => (\n                                <List.Item>\n                                  <Typography.Text mark>mock item no: {item}</Typography.Text>\n                                </List.Item>\n                        )}\n                />\n                {isFetching && (\n                        <div style={{ opacity: 0.6, textAlign: 'center', marginBottom: 20 }}>\n                          Loading next data...\n                        </div>\n                )}\n              </div>\n            </div>\n          </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- Use this hook to abstract your own infinite scroll business logic and streamline the implementation of this functionality in your\n  application\n\n#### 🛑 What not to do\n\n- Avoid using this hook to debounce or throttle your functions. If you're implementing a pagination-like infinite scroll, it's best to\n  handle this debounce/throttle functionality yourself, to ensure that your application behaves exactly as you intend.\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\n/**\n * Accepts an HTML Element ref, then returns a function that allows you to handle the infinite\n * scroll for that specific element.\n */\ndeclare const useInfiniteScroll: <TElement extends HTMLElement>(ref: RefObject<TElement>, delay?: number) => import(\"./shared/types\").CallbackSetter<unknown>;\nexport default useInfiniteScroll;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useInterval.md",
    "content": "# useInterval\n\nA hook that facilitates the utilization of the `setInterval` function in React function components. This hook receives a callback function\nand a delay duration as inputs, and subsequently, executes the given function at regular intervals with the specified delay time between\neach invocation\n\n### Why? 💡\n\n- Ensures that the given callback is executed reliably, even when the component re-renders;\n- Automatically cancels the interval when the component unmounts (although this behavior can be modified by adjusting the options);\n- Provides information about the current state of the interval (whether it has been cleared or not);\n- Offers a method to cancel the set interval, which can trigger a re-render of the component if desired.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Typography } from 'antd';\n\nimport useInterval from 'beautiful-react-hooks/useInterval';\n\nconst DelayedContentComponent = () => {\n  const [seconds, setSeconds] = useState(0);\n\n  // repeat the function each 1000ms\n  useInterval(() => {\n    setSeconds(1 + seconds);\n  }, 1000);\n\n  return (\n    <DisplayDemo title=\"useInterval\">\n      <Typography.Text>Rendering since <Tag color=\"green\">{seconds}</Tag>seconds</Typography.Text>\n    </DisplayDemo>\n  );\n};\n\n<DelayedContentComponent />\n```\n\n### State & clear method:\n\nThe hook returns information about the timeout's state (whether it has been cleared or not, represented by a boolean flag), and also offers\na method to potentially clear it.\n\n**Note**: Invoking this method to programmatically clear the timeout may trigger the component re-rendering.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Typography, Button } from 'antd';\nimport useInterval from 'beautiful-react-hooks/useInterval';\n\nconst DelayedContentComponent = () => {\n  const [seconds, setSeconds] = useState(0);\n  const [isCleared, clearInterval] = useInterval(() => {\n    setSeconds(1 + seconds);\n  }, 1000);\n\n  return (\n    <DisplayDemo>\n      <Typography.Paragraph>Rendering since <Tag color=\"green\">{seconds}</Tag>seconds</Typography.Paragraph>\n      {!isCleared && <Button onClick={clearInterval} type=\"primary\">Stop the counter</Button>}\n      {isCleared && <Typography.Paragraph mark>Interval cleared!</Typography.Paragraph>}\n    </DisplayDemo>\n  );\n};\n\n<DelayedContentComponent />\n```\n\n### Options:\n\nIt is possible to provide an options object as the last parameter of the hook.\n\n#### cancelOnUnmount:\n\nDefines whether the timeout should be cleared on unmount.\n\n**default**: `true`\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Typography, Button } from 'antd';\nimport useInterval from 'beautiful-react-hooks/useInterval';\n\nconst DelayedContentComponent = () => {\n  const [seconds, setSeconds] = useState(0);\n  const options = { cancelOnUnmount: false };\n\n  useInterval(() => setSeconds(1 + seconds), 1000, options);\n\n  return (\n    <DisplayDemo>\n      <Typography.Paragraph>Rendering since <Tag color=\"green\">{seconds}</Tag>seconds</Typography.Paragraph>\n      <Typography.Paragraph mark>It won't be cleared at unmount</Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<DelayedContentComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to perform a function on a regular interval (e.g., every x number of milliseconds), regardless of whether the component\n  re-renders.\n\n#### 🛑 When not to use\n\n- When attempting to use it asynchronously, since doing so would violate the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type GenericFunction } from './shared/types';\nexport interface UseIntervalOptions {\n    cancelOnUnmount?: boolean;\n}\n/**\n * An async-utility hook that accepts a callback function and a delay time (in milliseconds), then repeats the\n * execution of the given function by the defined milliseconds.\n */\ndeclare const useInterval: <TCallback extends GenericFunction>(fn: TCallback, milliseconds: number, options?: UseIntervalOptions) => [boolean, () => void];\nexport default useInterval;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useIsFirstRender.md",
    "content": "# useIsFirstRender\n\nA hook that returns a boolean value indicating whether it's the first render or not.\n\nThis hook can be used to conditionally execute logic or render components based on whether it's the first time the component is being\nrendered or if it's being re-rendered due to a state or prop change.\n\n### 💡 Why?\n\n- A useful tool for managing component rendering behavior and enables you to write more efficient and flexible code\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState, useCallback } from 'react';\nimport { Button, Typography } from 'antd';\nimport useIsFirstRender from 'beautiful-react-hooks/useIsFirstRender';\n\nconst UseIsFirstRenderExample = () => {\n  const [data, setData] = useState(0)\n  const isFirstRender = useIsFirstRender();\n\n  const setNewDate = useCallback(() => setData(Date.now()), []);\n\n  return (\n    <DisplayDemo title=\"useIsFirstRender\">\n      <Typography.Paragraph>Click on the button to update isFirstRender flag</Typography.Paragraph>\n      <Typography.Paragraph>isFirstRender: {isFirstRender ? 'yes' : 'no'}</Typography.Paragraph>\n      <Button type='primary' onClick={setNewDate}>\n        Update data\n      </Button>\n    </DisplayDemo>\n  );\n};\n\n<UseIsFirstRenderExample />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\ndeclare const useIsFirstRender: () => boolean;\nexport default useIsFirstRender;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useLifecycle.md",
    "content": "# useLifecycle\n\nA hook that facilitates performing specific functions during the lifecycle of a component.\n\nIt accepts two functions as arguments. The first function will be executed after the component has mounted, which means that the component\nhas been initialized and rendered on the screen. The second function will be executed right before the component unmounts, which happens\nwhen the component is removed from the screen or destroyed.\n\nUsing this hook allows for greater control and customization of a component's behavior.\n\n### Why? 💡\n\n- Provides a wrapper for \"lifecycle hooks\" including `useDidMount` and `useWillUnmount`.\n- Serves as a shorthand for `useEffect(onMount, [])` and `useEffect(() => () => willUnmount, [])`.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useCallback } from 'react';\nimport { Alert } from 'antd';\nimport useLifecycle from 'beautiful-react-hooks/useLifecycle';\n\n/**\n * useDidMount example component\n */\nconst LifeCycleComponent = () => {\n  const onMount = useCallback(() => {\n    console.log('Component did mount');\n  }, []);\n\n  const onUnmount = useCallback(() => {\n    console.log('Component will unmount');\n  }, []);\n\n  useLifecycle(onMount, onUnmount);\n\n  return (\n    <DisplayDemo title=\"useLifecycle\">\n      <Alert icon message=\"Please check the javascript console to read mount/unmount messages\" />\n    </DisplayDemo>\n  );\n};\n\n<LifeCycleComponent />\n```\n\n### Callback setter syntax:\n\nIf you don't provide any parameters, you can use the returned callback setters to set the `useDidMount` and `useWillUnmount` handlers.\nHowever, you must immediately invoke them to make it work.\n\n**Note**: It's important to keep in mind that the callback setters are intended to modify the value of the callback reference only. They do\nnot cause the component to rerender, and you should not invoke them asynchronously. This ensures that the behavior of your code remains\npredictable and that your project runs smoothly.\n\n```jsx harmony\nimport { Alert } from 'antd';\nimport useLifecycle from 'beautiful-react-hooks/useLifecycle';\n\nconst ComponentDidMount = () => {\n  const { onDidMount, onWillUnmount } = useLifecycle();\n\n  onDidMount(() => {\n    console.log('Component did mount');\n  });\n\n  onWillUnmount(() => {\n    console.log('Component will unmount');\n  });\n\n  return (\n    <DisplayDemo title=\"useLifecycle\">\n      <Alert icon message=\"Please check the javascript console to read mount/unmount messages\" />\n    </DisplayDemo>\n  );\n};\n\n<ComponentDidMount />\n```\n\n#### ✅ Pro tip:\n\nWhen using a React function component you should not really think of it in terms of \"lifecycle\".\n\nTo deep understanding `useEffect`, what it is and how it should be properly used, please read\n\"[A complete guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/)\"\nby [Dan Abramov](https://twitter.com/dan_abramov)\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to execute a function after the component has mounted\n- When you need to execute a function immediately before the component unmounts\n- When you require a shortcut to the component lifecycle\n\n#### 🛑 When not to use\n\n- If you need to use it asynchronously, as this violates the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n- If you're using the callback setters, you must not use them asynchronously, but instead, immediately invoke them.\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type GenericFunction } from './shared/types';\n/**\n * Returns an object wrapping lifecycle hooks such as `useDidMount` or `useWillUnmount`.\n * It is intended as a shortcut to those hooks.\n */\ndeclare const useLifecycle: <TMount extends GenericFunction = GenericFunction, TUnmount extends GenericFunction = GenericFunction>(mount?: TMount | undefined, unmount?: TUnmount | undefined) => {\n    onDidMount: import(\"./shared/types\").CallbackSetter<undefined>;\n    onWillUnmount: import(\"./shared/types\").CallbackSetter<undefined>;\n};\nexport default useLifecycle;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useLocalStorage.md",
    "content": "# useLocalStorage\n\nA hook that enables effortless storage and retrieval of values in the\nbrowser's [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).\n\n### 💡 Why?\n\n- A fast and efficient method to implement the `localStorage` functionality in your React components\n\n### Basic Usage:\n\n```jsx harmony\nimport React, { useCallback } from 'react';\nimport { Button, Tag, Typography } from 'antd';\nimport useLocalStorage from 'beautiful-react-hooks/useLocalStorage';\n\nconst NotificationBadgeExample = ({ notifications }) => {\n  const [notificationCount, setNotificationCount] = useLocalStorage('demo-notification-count', notifications);\n\n  const clearNotifications = useCallback(() => {\n    setNotificationCount(0);\n  }, [notificationCount]);\n\n  const Actions = [\n    <Button type=\"primary\" onClick={clearNotifications}>\n      You've got {notificationCount} new messages\n    </Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useLocalStorage\" actions={Actions}>\n      <Typography.Paragraph>\n        Click on the following button to clear data from the <Tag>demo-notification-count</Tag> local storage key.\n      </Typography.Paragraph>\n    </DisplayDemo>\n  )\n};\n\n<NotificationBadgeExample notifications={100} />\n```\n\n### Interface\n\n```typescript\ntype SetValue<TValue> = (value: TValue | ((previousValue: TValue) => TValue)) => void\n\ndeclare const useLocalStorage: <TValue>(storageKey: string, defaultValue?: any) => [TValue, SetValue<TValue>]\n```\n\n### Mastering the hooks\n\n#### ✅ When to use\n\n- When you need to get/set values from and to the `localStorage`\n\n#### 🛑 When not to use\n\n- Do not use this hook as a state manager, the `localStorage` is meant to be used for small pieces of data\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Save a value on local storage\n */\ndeclare const useLocalStorage: <TValue>(storageKey: string, defaultValue?: any) => [TValue | null, (value: TValue | ((previousValue: TValue) => TValue)) => void];\nexport default useLocalStorage;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useLongPress.md",
    "content": "# useLongPress\n\nA hook that facilitates the implementation of a long press functionality on a given target, supporting both mouse and touch events.\n\n### Why? 💡\n\n- Provides an easy way to add long-press functionality to a specific target element\n- Automatically adds mouse event listeners to the specified target element\n- Automatically removes the listeners when the component unmounts\n- Enables abstractions on mouse-related and touch-related events\n\n### Basic Usage:\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Space, Typography, Alert } from 'antd';\nimport useLongPress from 'beautiful-react-hooks/useLongPress';\n\nconst MyComponent = () => {\n  const [coordinates, setCoordinates] = useState([0, 0]);\n  const ref = useRef();\n  const [longPressCount, setLongPressCount] = useState(0)\n  const { isLongPressing, onLongPressStart, onLongPressEnd } = useLongPress(ref);\n\n  onLongPressStart(() => {\n    setLongPressCount(() => {\n      return longPressCount + 1\n    });\n  });\n\n  onLongPressEnd(() => {\n    setLongPressCount(() => {\n      return longPressCount + 1\n    });\n  })\n\n  return (\n    <DisplayDemo title=\"useLongPress\">\n      <div ref={ref}>\n        <Space direction=\"vertical\">\n          <Alert message=\"Long press this box to get information on the long press event\" type=\"info\" showIcon />\n          <Tag color={isLongPressing ? 'green' : 'red'}>isLongPressing: {isLongPressing ? 'yes' : 'no'}</Tag>\n          {!!longPressCount && (\n            <Typography.Paragraph>\n              Long press events count:\n              <Tag color=\"green\">{longPressCount}</Tag>\n            </Typography.Paragraph>\n          )}\n        </Space>\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Press duration:\n\nYou can specify the duration of the long press by passing a number as the second argument to the hook.\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Space, Typography, Alert } from 'antd';\nimport useLongPress from 'beautiful-react-hooks/useLongPress';\n\nconst MyComponent = () => {\n  const [coordinates, setCoordinates] = useState([0, 0]);\n  const ref = useRef();\n  const { isLongPressing } = useLongPress(ref, 1000);\n\n  return (\n    <DisplayDemo title=\"useLongPress\">\n      <div ref={ref}>\n        <Space direction=\"vertical\">\n          <Alert message=\"Long press this box to get information on the long press event\" type=\"info\" showIcon />\n          <Tag color={isLongPressing ? 'green' : 'red'}>isLongPressing: {isLongPressing ? 'yes' : 'no'}</Tag>\n        </Space>\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n<!-- Types -->\n"
  },
  {
    "path": "docs/useMediaQuery.md",
    "content": "# useMediaQuery\n\nA hook that takes in a media query string and utilizes the [matchMedia](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)\nAPI to check whether it corresponds to the present document.\n\nAdditionally, it tracks changes in the document to detect when it no longer corresponds to the provided media query.\n\nThe hook returns the validity status of the media query provided.\n\n```jsx harmony\nimport { Tag, Typography, Space, Alert } from 'antd';\nimport useMediaQuery from 'beautiful-react-hooks/useMediaQuery';\n\nconst MediaQueryReporter = () => {\n  const isSmall = useMediaQuery('(max-width: 48rem)');\n  const isLarge = useMediaQuery('(min-width: 48rem)');\n\n  return (\n    <DisplayDemo title=\"useMediaQuery\">\n      <Space direction=\"vertical\">\n        <Alert type=\"info\" message=\"Resize the browser window to see the changes\" showIcon />\n        <Typography.Paragraph>Small view? <Tag color={isSmall ? 'green' : 'red'}>{isSmall ? 'yes' : 'no'}</Tag></Typography.Paragraph>\n        <Typography.Paragraph>Large view? <Tag color={isLarge ? 'green' : 'red'}>{isLarge ? 'yes' : 'no'}</Tag></Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<MediaQueryReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- If a component needs to display a different layout or behavior on various media types\n- Conditionally render sub-components based on a specified media query\n\n#### 🛑 When not to use\n\n- Avoid using this hook to identify the user's device, use agent detection instead\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Accepts a media query string then uses the\n * [window.matchMedia](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) API to determine if it\n * matches with the current document.<br />\n * It also monitor the document changes to detect when it matches or stops matching the media query.<br />\n * Returns the validity state of the given media query.\n *\n */\ndeclare const useMediaQuery: (mediaQuery: string) => boolean;\nexport default useMediaQuery;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useMouse.md",
    "content": "# `useMouse`\n\nA hook that combines the functionalities of [useMouseState](./useMouseState.md) and [useMouseEvents](./useMouseEvents.md), returning an\narray where the first item is the mouse state and the second item is a wrapper of all the handler-setters.\n\n`useMouse` is intended as a shortcut to avoid the need for using both `useMouse`State and `useMouse`Events separately.\n\n### Why? 💡\n\n- Provides an easy way to obtain the mouse position\n- Automatically adds mouse event listeners either globally or to the specified target element\n- Automatically removes the listeners when the component unmounts\n- Enables abstractions on mouse-related events\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to ``useMouse``\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useMouse from 'beautiful-react-hooks/useMouse';\n\nconst MouseReporter = () => {\n  const ref = useRef();\n  const [showCoords, setShowCoords] = useState(false);\n  const [position, { onMouseEnter, onMouseLeave }] = useMouse(ref);\n\n  onMouseEnter(() => setShowCoords(true));\n  onMouseLeave(() => setShowCoords(false));\n\n  return (\n          <DisplayDemo title=\"useMediaQuery\">\n            <div ref={ref}>\n              <Space direction=\"vertical\">\n                <Alert message=\"Move mouse over this box to get its current coordinates\" type=\"info\" showIcon />\n                <Tag color=\"green\">ClientX: {position.clientX}</Tag>\n                <Tag color=\"green\">ClientY: {position.clientY}</Tag>\n              </Space>\n            </div>\n          </DisplayDemo>\n  );\n};\n\n<MouseReporter />\n```\n\n### Global events\n\nIf no ref is provided to `useMouse` it will use the window global object assign the events to\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useMouse from 'beautiful-react-hooks/useMouse';\n\nconst MouseReporter = () => {\n  const [mouseDown, setMouseDown] = useState(false);\n  const [position, { onMouseDown, onMouseUp }] = useMouse();\n\n  onMouseDown(() => setMouseDown(true));\n  onMouseUp(() => setMouseDown(false));\n\n  return (\n          <DisplayDemo title=\"useMouse\">\n            <Space direction=\"vertical\">\n              <Alert message=\"Move mouse around to get its current global coordinates\" type=\"info\" showIcon />\n              <Tag color=\"green\">ClientX: {position.clientX}</Tag>\n              <Tag color=\"green\">ClientY: {position.clientY}</Tag>\n            </Space>\n          </DisplayDemo>\n  );\n};\n\n<MouseReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- use `useMouse` to obtain the current mouse position.\n- use `useMouse` to abstract custom mouse-related logic into a hook.\n\n#### 🛑 What not to do\n\n- Do not use the returned callback setters asynchronously, as doing so will have no effect and may result in bugs in your code.\n- Avoid using `useMouse` callback setters to replace standard mouse handler props.\n- `useMouse`  is designed to be used for abstracting more complex hooks that need to control the mouse, such as a drag-and-drop hook.\n- Using `useMouse` handlers instead of the classic props approach will result in decreased performance due to the loss of the React\n  SyntheticEvent performance boost. If you were using a classic props approach before, continue to do so.\n\n```jsx harmony static noedit\nconst MyComponent = (props) => {\n  const { mouseDownHandler } = props;\n\n  return (\n          <div onMouseDown={mouseDownHandler} />\n  );\n};\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\n/**\n * Returns an array where the first item is the mouse state from the `useMouseState` hook and the second item\n * is the object of callback setters from the `useMouseEvents` hook.\n * It is intended as a shortcut to those hooks.\n */\ndeclare const useMouse: <TElement extends HTMLElement>(targetRef?: RefObject<TElement> | undefined) => ({\n    clientX: number;\n    clientY: number;\n    screenX: number;\n    screenY: number;\n} | Readonly<{\n    onMouseDown: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseEnter: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseLeave: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseMove: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseOut: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseOver: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseUp: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n}>)[];\nexport default useMouse;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useMouseEvents.md",
    "content": "# useMouseEvents\n\nA hook that provides an easy way to manage mouse events by returning a set of callback setters. The returned setters allow control over\nvarious mouse events including `onMouseDown`, `onMouseEnter`, `onMouseLeave`, `onMouseMove`, `onMouseOut`, `onMouseOver`, and `onMouseUp`.\n\nThe hook optionally accepts a reference to a DOM element to target the desired event(s) to. If no target is provided, the events will be\nattached globally to the document object.\n\nIt is important to note that the returned callback setters should be immediately invoked within the component's body, and should not be\ncalled asynchronously.\n\n### Why? 💡\n\n- handles the addition of mouse event listeners either globally or to a specified target.\n- takes care of cleaning up the listeners when the component is unmounted.\n- enables the implementation of abstractions on mouse-related events.\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useMouseEvents`\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useMouseEvents from 'beautiful-react-hooks/useMouseEvents';\n\nconst MyComponent = () => {\n  const [coordinates, setCoordinates] = useState([0, 0]);\n  const ref = useRef();\n  const { onMouseMove, onMouseLeave } = useMouseEvents(ref);\n\n  onMouseMove((event) => {\n    const nextCoords = [event.clientX, event.clientY];\n    setCoordinates(nextCoords);\n  });\n\n  onMouseLeave(() => {\n    setCoordinates([0, 0]);\n  });\n\n  return (\n    <DisplayDemo title=\"useMouseEvent\">\n      <div ref={ref}>\n        <Space direction=\"vertical\">\n          <Alert message=\"Move mouse over this box to get its current coordinates\" type=\"info\" showIcon />\n          <Tag color=\"green\">ClientX: {coordinates[0]}</Tag>\n          <Tag color=\"green\">ClientY: {coordinates[1]}</Tag>\n        </Space>\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Global events\n\nIf no ref is provided to `useMouseEvents` it will use the window global object assign the events to\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useMouseEvents from 'beautiful-react-hooks/useMouseEvents';\n\nconst MyComponent = () => {\n  const [coordinates, setCoordinates] = useState([0, 0]);\n  const { onMouseMove } = useMouseEvents();\n\n  onMouseMove((event) => {\n    const nextCoords = [event.clientX, event.clientY];\n    setCoordinates(nextCoords);\n  });\n\n  return (\n    <DisplayDemo title=\"useMouseEvent\">\n      <Space direction=\"vertical\">\n        <Alert message=\"Move mouse around to get its current global coordinates\" type=\"info\" showIcon />\n        <Tag color=\"green\">ClientX: {coordinates[0]}</Tag>\n        <Tag color=\"green\">ClientY: {coordinates[1]}</Tag>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to abstract mouse-related logics into custom hooks(s)\n\n#### 🛑 What not to do\n\n- Do not use the returned callback setters asynchronously, as doing so will have no effect and may result in bugs in your code.\n- Avoid using `useMouseEvents` callback setters to replace standard mouse handler props.\n- `useMouseEvents`  is designed to be used for abstracting more complex hooks that need to control the mouse, such as a drag-and-drop hook.\n- Using `useMouseEvents` handlers instead of the classic props approach will result in decreased performance due to the loss of the React\n  SyntheticEvent performance boost. If you were using a classic props approach before, continue to do so.\n\n```jsx harmony static noedit\nconst MyComponent = (props) => {\n  const { mouseDownHandler } = props;\n\n  return (\n    <div onMouseDown={mouseDownHandler} />\n  );\n};\n```\n\n<!-- Types -->\n\n### Types\n\n```typescript static\nimport { type RefObject } from 'react';\n/**\n * Returns a frozen object of callback setters to handle the mouse events.<br/>\n * It accepts a DOM ref representing the events target. <br/>\n * If a target is not provided the events will be globally attached to the document object.\n * <br/>\n * ### Shall the `useMouseEvents` callbacks replace the standard mouse handler props?\n *\n * **They shall not!**<br />\n * **useMouseEvents is meant to be used to abstract more complex hooks that need to control mouse**, for instance:\n * a drag n drop hook.<br />\n * Using useMouseEvents handlers instead of the classic props approach it's just as bad as it sounds since you'll\n * lose the React SyntheticEvent performance boost.<br />\n * If you were doing something like the following:\n */\ndeclare const useMouseEvents: <TElement extends HTMLElement>(targetRef?: RefObject<TElement> | undefined, passive?: boolean) => Readonly<{\n    onMouseDown: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseEnter: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseLeave: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseMove: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseOut: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseOver: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n    onMouseUp: import(\"./shared/types\").CallbackSetter<MouseEvent>;\n}>;\nexport default useMouseEvents;\n\n```\n\n<!-- Types:end -->\n"
  },
  {
    "path": "docs/useMouseState.md",
    "content": "# useMouseState\n\nA hook that returns relevant properties from the current mouse position, such as clientX and clientY. To ensure that events are attached to\nthe intended target, please provide a DOM reference to the hook. If no target is specified, the events will be attached to the\nthe `document` object globally.\n\n### Why? 💡\n\n- Allows to quickly get the mouse position\n- Manages the addition of mouse event listeners either globally or to a defined target\n- Ensures the listener is cleaned up when the component unmounts\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useMouseState`\n\n```jsx harmony\nimport { useRef } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useMouseState from 'beautiful-react-hooks/useMouseState';\n\nconst MouseReporter = () => {\n  const ref = useRef();\n  const { clientX, clientY } = useMouseState(ref);\n\n  return (\n    <DisplayDemo title=\"useMediaQuery\">\n      <div ref={ref}>\n        <Space direction=\"vertical\">\n          <Alert message=\"Move mouse over this box to get its current coordinates\" type=\"info\" showIcon />\n          <Tag color=\"green\">ClientX: {clientX}</Tag>\n          <Tag color=\"green\">ClientY: {clientY}</Tag>\n        </Space>\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<MouseReporter />\n```\n\n### Global events\n\nAttach the mouse events globally by simply not providing any dom reference to the `useMouseState` hook\n\n```jsx harmony\nimport { Tag, Space, Alert } from 'antd';\nimport useMouseState from 'beautiful-react-hooks/useMouseState';\n\nconst MouseReporter = () => {\n  const { clientX, clientY } = useMouseState();\n\n  return (\n    <DisplayDemo title=\"useMouseState\">\n      <Space direction=\"vertical\">\n        <Alert message=\"Move mouse around to get its current global coordinates\" type=\"info\" showIcon />\n        <Tag color=\"green\">ClientX: {clientX}</Tag>\n        <Tag color=\"green\">ClientY: {clientY}</Tag>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<MouseReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to abstract mouse-related logics into custom hooks(s)\n- When you need to quickly get the current mouse position\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\n/**\n * Returns the current state (position) of the mouse pointer.\n * It possibly accepts a DOM ref representing the mouse target.\n * If a target is not provided the state will be caught globally.\n */\ndeclare const useMouseState: <TElement extends HTMLElement>(targetRef?: RefObject<TElement> | undefined) => {\n    clientX: number;\n    clientY: number;\n    screenX: number;\n    screenY: number;\n};\nexport default useMouseState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useMutableState.md",
    "content": "# useMutableState\n\nThis hook provides mutable states that trigger the component to re-render. It offers similar functionality to Svelte's reactivity, enabling\ndevelopers to write more efficient and concise code.\n\n### Why? 💡\n\n- Improves code streamlining by providing a reactive state that can be used to trigger a rerender\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography, Space, Button, Tag } from 'antd';\nimport useMutableState from 'beautiful-react-hooks/useMutableState';\n\nconst TestComponent = () => {\n  const counter = useMutableState({ value: 0 });\n\n  return (\n    <DisplayDemo title=\"useMutableState\">\n      <Typography.Paragraph>\n        Counter: <Tag color=\"green\">{counter.value}</Tag>\n      </Typography.Paragraph>\n      <Space>\n        <Button type=\"primary\" onClick={() => counter.value += 1}>increase</Button>\n        <Button type=\"primary\" onClick={() => counter.value -= 1}>decrease</Button>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n<!-- Types -->\n"
  },
  {
    "path": "docs/useMutationObserver.md",
    "content": "# useMutationObserver\n\nA hook that employs the [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) API to monitor changes made to\nthe Document Object Model (DOM) tree.\n\nThis hook enables asynchronous observation of changes to a specified HTML Element. It automatically handles the clean-up of the observation\nprocess when the associated component is unmounted.\n\n### Why? 💡\n\n- allows for real-time monitoring of changes to the DOM, without requiring constant polling or manual inspection of the element.\n- provides more granular control over the types of changes being observed, allowing developers to selectively listen for specific events\n  such as attribute modifications, node insertions or removals, and so on.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Typography } from 'antd';\nimport useMutationObserver from 'beautiful-react-hooks/useMutationObserver';\n\nconst UseMutationObserverExample = () => {\n  const ref = useRef();\n  const [content, setContent] = useState('Hello world');\n  const [mutationCount, setMutationCount] = useState(0);\n\n  const incrementMutationCount = () =>\n    setMutationCount((prev) => prev + 1);\n\n  useMutationObserver(ref, incrementMutationCount);\n\n  return (\n    <DisplayDemo title=\"useMutationObserver\">\n      <div style={{ width: '100%' }} ref={ref}>\n        <div\n          style={{\n            resize: 'both',\n            overflow: 'auto',\n            background: '#FF934F',\n            maxWidth: '100%',\n            padding: 20,\n            border: '1px solid black',\n            borderRadius: 6,\n            marginBottom: 20,\n          }}\n        >\n          <Typography.Paragraph>Resize me</Typography.Paragraph>\n        </div>\n      </div>\n      <Typography.Paragraph>Mutations: <Tag color=\"green\">{mutationCount}</Tag></Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<UseMutationObserverExample />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\ndeclare const useMutationObserver: <TElement extends HTMLElement>(ref: RefObject<TElement>, callback: MutationCallback, options?: MutationObserverInit) => void;\nexport default useMutationObserver;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useObjectState.md",
    "content": "# useObjectState\n\nA hook has been developed to emulate the behavior of the now deprecated class Component.setState method. This hook aims to facilitate the\nmigration process of legacy class components to the new function components paradigm.\n\n### Why? 💡\n\n- Automates the process of destructing the previous state and replacing it with a new one, alleviating the burden of manually handling these\n  operations in function components\n- Allow developers to seamlessly transition their codebase from class components to function components without needing to restructure the\n  existing codebase\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport { Button, Typography } from 'antd';\nimport useObjectState from 'beautiful-react-hooks/useObjectState';\n\nconst UseObjectStateComponent = () => {\n  const [state, setState] = useObjectState({ count: 0, title: 'Test title' })\n\n  const reset = () => setState({ count: 0 })\n\n  const increment = () => setState({ count: state.count + 1 })\n\n  const decrement = () => setState({ count: state.count - 1 })\n\n  const Actions = [\n    <Button onClick={increment}>\n      Increment counter\n    </Button>,\n    <Button onClick={decrement}>\n      Decrement counter\n    </Button>,\n    <Button onClick={reset}>\n      Reset counter\n    </Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useObjectState\" actions={Actions}>\n      <Typography.Paragraph>State:</Typography.Paragraph>\n      <pre>{JSON.stringify(state, null, '\\t')}</pre>\n    </DisplayDemo>\n  );\n};\n\n<UseObjectStateComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When required to migrate legacy class components to the new function components paradigm\n\n#### 🛑 What not to do\n\n- Don't use this hook in place of `useReducer`.\n\n<!-- Types -->\n### Types\n    \n```typescript static\ndeclare const useObjectState: <TState>(initialState: TState) => [TState, (state: Partial<TState>) => void];\nexport default useObjectState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useObservable.md",
    "content": "# useObservable\n\nA hook that enables reactivity in your components through the utilization of `RxJs` library.\n\n### Why? 💡\n\n- Modify your data using default `RxJs` operators within pipes, providing a cleaner and more concise way of handling asynchronous data\n- Combine data from multiple sources into a single observable stream using various `RxJs` operators, allowing you to create more structured\n  and organized code\n\n### Basic Usage:\n\nMimics the behaviour of [useInterval](./useInterval.md) with `RxJs`\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Typography } from 'antd';\nimport { interval } from 'rxjs';\nimport useObservable from 'beautiful-react-hooks/useObservable';\n\nconst interval$ = interval(1000); // create an interval pipe\n\nconst ObservableInterval = () => {\n  const [seconds, setSeconds] = useState(0);\n\n  useObservable(interval$, setSeconds);\n\n  return (\n    <DisplayDemo title=\"useObservable\">\n      <Typography.Text>Rendering since <Tag color=\"green\">{seconds}</Tag>seconds</Typography.Text>\n    </DisplayDemo>\n  );\n};\n\n<ObservableInterval />\n```\n\nMimics the behaviour of [useGeolocationState](./useGeolocation.md) with `RxJs`\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Observable } from 'rxjs';\nimport { Typography } from 'antd';\nimport useObservable from 'beautiful-react-hooks/useObservable';\n\nconst position$ = new Observable(subscriber => {\n  const watcherRef = navigator.geolocation.watchPosition(\n    position => subscriber.next(position),\n    error => subscriber.error(error),\n  );\n\n  return () => {\n    navigator.geolocation.clearWatch(watcherRef);\n  }\n});\n\nconst ObservableGeolocation = () => {\n  const [position, setPosition] = useState({});\n  const { coords } = position;\n\n  useObservable(position$, setPosition);\n\n  return (\n    <DisplayDemo title=\"useObservable\">\n      <Typography.Title>Current position:</Typography.Title>\n      {position.coords && [\n        <Typography.Paragraph key={0}>Lat: {position.coords.latitude}</Typography.Paragraph>,\n        <Typography.Paragraph key={1}>Lng: {position.coords.longitude}</Typography.Paragraph>\n      ]}\n    </DisplayDemo>\n  );\n};\n\n<ObservableGeolocation />\n```\n\n###### Handle resize event\n\n```jsx harmony\nimport { useState } from 'react';\nimport { fromEvent } from 'rxjs';\nimport { Typography, Tag } from 'antd';\nimport useObservable from 'beautiful-react-hooks/useObservable';\n\nconst resize$ = fromEvent(window, 'resize');\n\nconst ObservableResize = () => {\n  const [event, setEvent] = useState({});\n\n  useObservable(resize$, setEvent);\n  const { target } = event;\n\n  return (\n    <DisplayDemo title=\"useObservable\">\n      <Typography.Title>Resize your window</Typography.Title>\n      <Typography.Paragraph>\n        width: <Tag color=\"green\">{target && target.innerWidth || 0}</Tag>\n      </Typography.Paragraph>\n      <Typography.Paragraph>\n        height: <Tag color=\"green\">{target && target.innerHeight || 0}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<ObservableResize />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- when you need to display and manipulate data using reactive programming techniques. `RxJs` pipes can be used for filtering, sorting,\n  mapping, and other transformations.\n\n#### 🛑 When not to use\n\n- Don't use this hook as a state manager\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type Observable, type Observer } from 'rxjs';\n/**\n * Hook, which helps you combine rxjs flow and setState in your component\n */\ndeclare const useObservable: <T, F extends Partial<Observer<T>> | ((value: T) => void)>(observable: Observable<T>, setter: F) => void;\nexport default useObservable;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useOnlineState.md",
    "content": "# useOnlineState\n\nA hook is available in this library that utilizes\nthe [Navigator online API](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine)  to determine the connectivity status of\nthe user's browser.\n\nThis hook returns a boolean value which indicates whether the browser is currently online or offline.\n\nThe primary use case for this hook is to facilitate re-rendering of a component when the browser's connectivity status changes. By using\nthis hook, your component can respond dynamically to changes in connectivity and update its behavior accordingly\n\n### Why? 💡\n\n- Your component requires network connectivity to function correctly and should behave differently when offline\n- You need to trigger some functionality when the user's connectivity status changes, such as syncing data with a server when the user comes\n  back online\n\n### Basic Usage:\n\n```jsx harmony\nimport { Tag, Typography } from 'antd';\nimport useOnlineState from 'beautiful-react-hooks/useOnlineState';\n\nconst ConnectionTest = () => {\n  const isOnline = useOnlineState();\n\n  return (\n          <DisplayDemo title=\"useOnlineState\">\n            <Typography.Paragraph>\n              Connection status: <Tag color=\"green\">{isOnline ? 'online' : 'offline'}</Tag>\n            </Typography.Paragraph>\n          </DisplayDemo>\n  );\n};\n\n<ConnectionTest />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Uses the [Navigator online API](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine) to define\n * whether the browser is connected or not.\n */\ndeclare const useOnlineState: () => boolean;\nexport default useOnlineState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/usePreviousValue.md",
    "content": "# usePreviousValue\n\nA hook that receives a variable, which can be either a prop or a state, and outputs its previous value from the last render cycle\n\n### Why? 💡\n\n- Enables monitoring of changes to component state/props\n- Facilitates informed decisions on when to trigger component updates\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useInterval from 'beautiful-react-hooks/useInterval';\nimport usePreviousValue from 'beautiful-react-hooks/usePreviousValue';\n\nconst TestComponent = () => {\n  const [seconds, setSeconds] = useState(0);\n  const prevSeconds = usePreviousValue(seconds);\n\n  useInterval(() => setSeconds(1 + seconds), 1000);\n\n  return (\n    <DisplayDemo title=\"usePreviousValue\">\n      <Typography.Paragraph>\n        {seconds}s\n      </Typography.Paragraph>\n      <Typography.Paragraph>\n        The previous value of the state 'seconds' was: <Tag color=\"green\">{prevSeconds}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * On each render returns the previous value of the given variable/constant.\n */\ndeclare const usePreviousValue: <TValue>(value?: TValue | undefined) => TValue | undefined;\nexport default usePreviousValue;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useQueryParam.md",
    "content": "# useQueryParam\n\nA hook built on top of React Router v5 that facilitate access and manipulation of query parameters.\n\n### Why? 💡\n\n- Facilitates editing the query string in the URL for the current location\n- Functions similarly to the useState hook\n- Does not rely on version 6 of the useSearchParams function from react-router-dom, ensuring compatibility with older versions\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport { HashRouter as Router } from 'react-router-dom'\nimport { Typography, Tag, Input } from 'antd';\nimport useQueryParam from 'beautiful-react-hooks/useQueryParam';\n\nconst ExampleComponent = () => {\n  // second parameter is optional\n  const [param, setValue] = useQueryParam('foo', {\n    initialValue: 'bar',\n    replaceState: false,\n  })\n\n  return (\n    <DisplayDemo title=\"useQueryParam\">\n      <Typography.Paragraph>\n        Current value of 'foo' param is <Tag color=\"green\">{param}</Tag><\n      /Typography.Paragraph>\n      <Input value={param} onChange={(e) => setValue(e.targt.value)} />\n    </DisplayDemo>\n  );\n};\n\n<Router>\n  <ExampleComponent />\n</Router>\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nexport interface UseQueryParamOptions<TValue extends string> {\n    initialValue?: TValue;\n    replaceState?: boolean;\n}\n/**\n * Ease the process of modify the query string in the URL for the current location.\n */\ndeclare const useQueryParam: <TValue extends string>(key: string, options?: UseQueryParamOptions<TValue>) => [TValue, (nextValue?: TValue | undefined) => void];\nexport default useQueryParam;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useQueryParams.md",
    "content": "# useQueryParams\n\nVery similar to `useQueryParam` (mind the final 's'), it eases the process of manipulate a query string with multiple values.\n\n### Why? 💡\n\n- Ease the process of manipulate a query string (with multiple values) in the URL for the current location.\n- Works similar to the useState hook\n- it's NOT built on top of version 6 of react-router-dom's useSearchParams, it is therefore compatible with older version\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport { HashRouter as Router } from 'react-router-dom'\nimport { Button, Typography, Input } from 'antd'\nimport useQueryParams from 'beautiful-react-hooks/useQueryParams';\n\nconst ExampleComponent = () => {\n  // second parameter is optional\n  const [foos, setFoos] = useQueryParams('foo[]', {\n    initialValue: [1, 2, 3],\n    replaceState: false,\n  })\n\n  const onClick = () => setFoos([4, 5, 6])\n\n  const Actions = [\n    <Button onClick={onClick} type=\"primary\">\n      Change to param to [4,5,6]\n    </Button>\n  ]\n\n  return (\n    <DisplayDemo actions={Actions}>\n      <Typography.Paragraph>\n        Current value of 'foo[]' param is '{foos.join(',')}'\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<Router>\n  <ExampleComponent />\n</Router>\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nexport interface UseQueryParamsOptions<TValue extends string[]> {\n    initialValue?: TValue;\n    replaceState?: boolean;\n}\n/**\n * Very similar to `useQueryParams`, it eases the process of manipulate a query string that handles multiple values\n */\ndeclare const useQueryParams: <TValue extends string[]>(key: string, options?: UseQueryParamsOptions<TValue>) => [TValue, (nextValue?: TValue | undefined) => void];\nexport default useQueryParams;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useRenderInfo.md",
    "content": "# useRenderInfo\n\nA hook that prints the number of renders for a given component, along with a timestamp of the most recent render and the time elapsed since\nthe last render.\n\n### Why? 💡\n\n- Easily display information on components render\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useInterval from 'beautiful-react-hooks/useInterval';\nimport useRenderInfo from 'beautiful-react-hooks/useRenderInfo';\n\nconst RenderInfo = () => {\n  const [seconds, setSeconds] = React.useState(0);\n\n  // repeat the function each 1000ms\n  useInterval(() => {\n    setSeconds(1 + seconds);\n  }, 1000);\n\n  useRenderInfo('Module');\n\n  return (\n    <DisplayDemo title=\"useRenderInfo\">\n      <Typography.Paragraph>Check the console!</Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<RenderInfo />\n```\n\n### Custom logs:\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useInterval from 'beautiful-react-hooks/useInterval';\nimport useRenderInfo from 'beautiful-react-hooks/useRenderInfo';\n\nconst RenderInfo = () => {\n  const [seconds, setSeconds] = React.useState(0);\n  const info = useRenderInfo();\n\n  // repeat the function each 1000ms\n  useInterval(() => {\n    setSeconds(1 + seconds);\n  }, 1000);\n\n  return (\n    <DisplayDemo title=\"useRenderInfo\">\n      <Typography.Paragraph>{info.sinceLast} seconds passed from the last render!</Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<RenderInfo />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When debugging a component\n\n#### 🛑 What not to do\n\n- In production build, you don't want useless logs in console :)\n\n<!-- Types -->\n### Types\n    \n```typescript static\nexport interface RenderInfo {\n    readonly module: string;\n    renders: number;\n    timestamp: null | number;\n    sinceLast: null | number | '[now]';\n}\n/**\n * useRenderInfo\n * @param moduleName\n * @param log\n * @returns {{renders: number, module: *, timestamp: null}}\n */\ndeclare const useRenderInfo: (moduleName?: string, log?: boolean) => RenderInfo;\nexport default useRenderInfo;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useRequestAnimationFrame.md",
    "content": "# useRequestAnimationFrame\n\nA hook that facilitates the execution of javascript animations.\n\nUpon usage, this hook initiates a recurring call to the provided function, using the\nbuilt-in [window.requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) function under the\nhood.\n\nThe provided function received two arguments: the current progress of the animation and a next function that must be executed to sustain the\nanimation.\n\nThe animation loop will terminate once the progress value reaches 100, although any other value can be specified using the `finishAt`\noption.\n\n### Why? 💡\n\n- Easily manage requestAnimationFrame within a React component\n\n### Basic Usage\n\n```jsx harmony\nimport { useRef } from 'react';\nimport { Alert } from 'antd';\nimport useRequestAnimationFrame from 'beautiful-react-hooks/useRequestAnimationFrame';\n\nconst AnimationExample = () => {\n  const ref = useRef();\n\n  useRequestAnimationFrame((progress, next) => {\n    ref.current.style.transform = `translateX(${progress}px)`;\n    next();\n  });\n\n  return (\n    <DisplayDemo title=\"useRequestAnimationFrame\">\n      <div ref={ref}>\n        <Alert color=\"primary\" message=\"Animating content\" />\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<AnimationExample />\n```\n\n### Options\n\nThe animation can be fine-tuned using an options object as the second argument.\n\nPlease note that setting `options.finishAt` to a value of `-1` will result in an infinite animation.\n\n```jsx harmony\nimport { useRef } from 'react';\nimport { Alert } from 'antd';\nimport useRequestAnimationFrame from 'beautiful-react-hooks/useRequestAnimationFrame';\n\nconst AnimationExample = () => {\n  const ref = useRef();\n  const options = { increment: 0.5, startAt: 0, finishAt: -1 };\n\n  useRequestAnimationFrame((progress, next) => {\n    ref.current.style.transform = `rotate(${progress}deg)`;\n    next();\n  }, options);\n\n  return (\n    <DisplayDemo title=\"useRequestAnimationFrame\">\n      <div ref={ref}>\n        <Alert color=\"primary\" message=\"Animating content\" />\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<AnimationExample />\n```\n\n### onFinish callback\n\nThe hook returns an function to possibly set a callback when the animation finishes:\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Alert, Typography } from 'antd';\nimport useRequestAnimationFrame from 'beautiful-react-hooks/useRequestAnimationFrame';\n\nconst AnimationExample = () => {\n  const ref = useRef();\n  const [isFinished, setIsFinished] = useState(false);\n  const onFinish = useRequestAnimationFrame((progress, next) => {\n    ref.current.style.transform = `translateX(${progress}px)`;\n    next();\n  });\n\n  onFinish(() => setIsFinished(true));\n\n  return (\n    <DisplayDemo title=\"useRequestAnimationFrame\">\n      <div ref={ref}>\n        <Alert color=\"primary\" message=\"Animating content\" />\n      </div>\n      {isFinished && <Typography.Paragraph>Animation completed!</Typography.Paragraph>}\n    </DisplayDemo>\n  );\n};\n\n<AnimationExample />\n```\n\n#### ✅ Pro tip:\n\nControl the speed of your animation by changing the increment value\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When in need to perform requestAnimationFrame without re-rendering the component on each frame\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type CallbackSetter, type GenericFunction } from './shared/types';\nexport interface UseRequestAnimationFrameOpts {\n    increment?: number;\n    startAt?: number;\n    finishAt?: number;\n}\n/**\n * Takes care of running an animating function, provided as the first argument, while keeping track of its progress.\n */\ndeclare const useRequestAnimationFrame: <T extends GenericFunction>(func: T, options?: UseRequestAnimationFrameOpts) => CallbackSetter<void>;\nexport default useRequestAnimationFrame;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useResizeObserver.md",
    "content": "# useResizeObserver\n\nA hook that utilizes the [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)  to monitor changes in the size\nof the supplied element and yields DOMRect data.\n\n### Why? 💡\n\n- Monitors variations asynchronously in the DOM Rect of the specified HTML Element.\n- Automatically disposes of the observer once the component unmounts.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useRef } from 'react';\nimport { Input } from 'antd';\nimport useResizeObserver from 'beautiful-react-hooks/useResizeObserver';\n\nconst ResizeObserverExample = () => {\n  const ref = useRef();\n  const DOMRect = useResizeObserver(ref);\n\n  return (\n    <DisplayDemo title=\"useResizeObserver\">\n      <div ref={ref}>\n        <Input.TextArea value=\"Resize me\" />\n      </div>\n      {DOMRect && (\n        <ul style={{ margin: '20px 0 10px 0', textAlign: 'left', padding: 0 }}>\n          <li>Box width: {DOMRect.width}</li>\n          <li>Box height: {DOMRect.height}</li>\n          <li>Box left: {DOMRect.left}</li>\n          <li>Box right: {DOMRect.right}</li>\n          <li>Box top: {DOMRect.top}</li>\n          <li>Box bottom: {DOMRect.bottom}</li>\n        </ul>\n      )}\n    </DisplayDemo>\n  );\n};\n\n<ResizeObserverExample />\n```\n\n### Debounce timout:\n\nThis hook employs a debounced callback to prevent extra-renders. By default, the timeout for the callback is set to 250ms. However, it's\npossible to supersede the default timeout by passing a numeric value to useResizeObserver, in lieu of the HTMLElement reference.\n\n```jsx harmony\nimport { useRef } from 'react';\nimport useResizeObserver from 'beautiful-react-hooks/useResizeObserver';\n\nconst ResizeObserverExample = () => {\n  const ref = useRef();\n  const DOMRect = useResizeObserver(ref, 1000);\n\n  return (\n    <DisplayDemo title=\"useResizeObserver\">\n      <div ref={ref}>\n        <Input.TextArea value=\"Resize me\" />\n      </div>\n      {DOMRect && (\n        <ul style={{ margin: '20px 0 10px 0', textAlign: 'left', padding: 0 }}>\n          <li>Box width: {DOMRect.width}</li>\n          <li>Box height: {DOMRect.height}</li>\n          <li>Box left: {DOMRect.left}</li>\n          <li>Box right: {DOMRect.right}</li>\n          <li>Box top: {DOMRect.top}</li>\n          <li>Box bottom: {DOMRect.bottom}</li>\n        </ul>\n      )}\n    </DisplayDemo>\n  );\n};\n\n<ResizeObserverExample />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nexport type DOMRectValues = Pick<DOMRectReadOnly, 'bottom' | 'height' | 'left' | 'right' | 'top' | 'width'>;\n/**\n * Uses the ResizeObserver API to observe changes within the given HTML Element DOM Rect.\n * @param elementRef\n * @param debounceTimeout\n * @returns {undefined}\n */\ndeclare const useResizeObserver: <TElement extends HTMLElement>(elementRef: RefObject<TElement>, debounceTimeout?: number) => DOMRectValues | undefined;\nexport default useResizeObserver;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useSearchQuery.md",
    "content": "# useSearchQuery\n\nA hook built on top of React Router v5 that facilitate access and manipulation of the 'search' query parameter.\n\n### Why? 💡\n\n- Facilitates editing the 'search' query string in the URL for the current location\n- Functions similarly to the useState hook\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport { HashRouter as Router } from 'react-router-dom'\nimport { Input, Typography, Tag } from 'antd'\nimport useSearchQuery from 'beautiful-react-hooks/useSearchQuery';\n\nconst ExampleComponent = () => {\n  const [searchValue, setSearch] = useSearchQuery('initial-value')\n\n  return (\n    <DisplayDemo title=\"useSearchQuery\">\n      <Typography.Paragraph>\n        Current value of search param is <Tag color=\"green\">{searchValue}</Tag>\n      </Typography.Paragraph>\n      <Input value={searchValue} onChange={(e, nextValue) => setSearch(nextValue)} />\n    </DisplayDemo>\n  );\n};\n\n<Router>\n  <ExampleComponent />\n</Router>\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Ease the process of modify the 'search' query string in the URL for the current location.\n * It's just a shortcut/wrapper around useQueryParam\n */\ndeclare const useSearchQuery: <TSearchKey extends string>(initialValue?: TSearchKey | undefined, replaceState?: boolean) => [TSearchKey, (nextValue?: TSearchKey | undefined) => void];\nexport default useSearchQuery;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useSessionStorage.md",
    "content": "# useSessionStorage\n\nA hook that enables effortless storage and retrieval of values in the\nbrowser's [Session Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage).\n\n### 💡 Why?\n\n- A fast and efficient method to implement the `sessionStorage` functionality in your React components\n\n### Basic Usage:\n\n```jsx harmony\nimport React, { useCallback } from 'react';\nimport { Pill, Paragraph, Icon } from 'antd';\nimport useSessionStorage from 'beautiful-react-hooks/useSessionStorage';\n\nconst NotificationBadgeExample = ({ notifications }) => {\n  const [notificationCount, setNotificationCount] = useSessionStorage('demo-notification-count', notifications);\n\n  const clearNotifications = useCallback(() => {\n    setNotificationCount(0);\n  }, [notificationCount]);\n\n  const Actions = [\n    <Button type=\"primary\" onClick={clearNotifications}>\n      You've got {notificationCount} new messages\n    </Button>\n  ]\n\n  return (\n    <DisplayDemo title=\"useSessionStorage\" actions={Actions}>\n      <Typography.Paragraph>\n        Click on the following button to clear data from the <Tag>demo-notification-count</Tag> session storage key.\n      </Typography.Paragraph>\n    </DisplayDemo>\n  )\n};\n\n<NotificationBadgeExample notifications={100} />\n```\n\n### Interface\n\n```typescript\ntype SetValue<TValue> = (value: TValue | ((previousValue: TValue) => TValue)) => void\n\ndeclare const useSessionStorage: <TValue>(storageKey: string, defaultValue?: any) => [TValue, SetValue<TValue>]\n```\n\n### Mastering the hooks\n\n#### ✅ When to use\n\n- When you need to get/set values from and to the `sessionStorage`\n\n#### 🛑 When not to use\n\n- Do not use this hook as a state manager, the `sessionStorage` is meant to be used for small pieces of data\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Save a value on session storage\n */\ndeclare const useSessionStorage: <TValue>(storageKey: string, defaultValue?: any) => [TValue | null, (value: TValue | ((previousValue: TValue) => TValue)) => void];\nexport default useSessionStorage;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useSpeechRecognition.md",
    "content": "# useSpeechSynthesis\n\nA hook that provides an interface for using the [Web_Speech_API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API) to\nrecognize and transcribe speech in a user's browser.\n\n### Why? 💡\n\n- Abstracts the implementation details of the Web Speech API into a single reusable function.\n\n### Basic Usage:\n\n```jsx harmony\nimport { Button, Space, Tag, Typography, Input } from 'antd';\nimport useSpeechRecognition from 'beautiful-react-hooks/useSpeechRecognition';\n\nconst SpeechSynthesisDemo = () => {\n  const [name, setName] = React.useState('Antonio');\n  const { startRecording, transcript, stopRecording, isRecording, isSupported } = useSpeechRecognition();\n\n  return (\n    <DisplayDemo title=\"useSpeechSynthesis\">\n      <Space direction=\"vertical\">\n        <Typography.Paragraph>\n          Supported: <Tag color={isSupported ? 'green' : 'red'}>{isSupported ? 'Yes' : 'No'}</Tag>\n        </Typography.Paragraph>\n        <Button onClick={!isRecording ? startRecording : stopRecording} type=\"primary\">\n          {isRecording ? 'Stop' : 'Start'} recording\n        </Button>\n        <Typography.Paragraph>\n          {transcript}\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<SpeechSynthesisDemo />\n```\n\n<!-- Types -->\n"
  },
  {
    "path": "docs/useSpeechSynthesis.md",
    "content": "# useSpeechSynthesis\n\nA hook that allows you to integrate text-to-speech functionality (with varying voices) within your React component by leveraging\nthe [Web_Speech_API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API).\n\n### Why? 💡\n\n- Abstracts the implementation details of the Web Speech API into a single reusable function.\n\n### Basic Usage:\n\n```jsx harmony\nimport { Button, Space, Input } from 'antd';\nimport useSpeechSynthesis from 'beautiful-react-hooks/useSpeechSynthesis';\n\nconst SpeechSynthesisDemo = () => {\n  const [name, setName] = React.useState('Antonio');\n  const { speak } = useSpeechSynthesis(`Hello, ${name}`);\n\n  return (\n          <DisplayDemo title=\"useSpeechSynthesis\">\n            <Space direction=\"vertical\">\n              <Input value={name} onChange={(_, v) => setName(v)} placeholder=\"Name\" fluid />\n              <Button onClick={speak} type=\"primary\">Say hello...</Button>\n            </Space>\n          </DisplayDemo>\n  );\n};\n\n<SpeechSynthesisDemo />\n```\n\n### Different voices:\n\n`useSpeechSynthesis` receives an optional options object as second parameter to possibly define a custom voice.\n\n```jsx harmony\nimport { Button, Input, Space, Select } from 'antd';\nimport useSystemVoices from 'beautiful-react-hooks/useSystemVoices';\nimport useSpeechSynthesis from 'beautiful-react-hooks/useSpeechSynthesis';\n\nconst VoiceSelector = ({ onVoiceChange }) => {\n  const [current, setVoice] = React.useState(0);\n  const voices = useSystemVoices();\n  const options = voices.map(({ name }, index) => ({ label: name, value: index }));\n\n  React.useEffect(() => {\n    onVoiceChange(voices[current]);\n  }, [current]);\n\n  return (\n          <Select options={options} onChange={setVoice} value={current} />\n  );\n};\n\nconst SpeechSynthesisDemo = () => {\n  const [voice, setVoice] = React.useState();\n  const [name, setName] = React.useState('my friend');\n  const { speak } = useSpeechSynthesis(`Hello, ${name}`, { voice });\n\n  return (\n          <DisplayDemo title=\"useSpeechSynthesis\">\n            <Space direction=\"vertical\">\n              <Input value={name} onChange={(e, next) => setName(next)} placeholder=\"Your name\" />\n              <VoiceSelector onVoiceChange={setVoice} />\n              <Button type=\"primary\" onClick={speak}>Greet!</Button>\n            </Space>\n          </DisplayDemo>\n  );\n};\n\n<SpeechSynthesisDemo />\n```\n\n### Different pitch, volume and rate:\n\n`useSpeechSynthesis` receives an optional options object as second parameter to possibly define a custom `rate` and `pitch`\n\n```jsx harmony\nimport { Button, Input, Space } from 'antd';\nimport useSpeechSynthesis from 'beautiful-react-hooks/useSpeechSynthesis';\n\nconst SpeechSynthesisDemo = () => {\n  const [name, setName] = React.useState('Antonio');\n  const { speak } = useSpeechSynthesis(`Hello, ${name}`, { rate: 1.2, pitch: 1.2, volume: 1.2 });\n\n  return (\n          <DisplayDemo title=\"useSpeechSynthesis\">\n            <Space direction=\"vertical\">\n              <Input value={name} onChange={(e, next) => setName(next)} placeholder=\"Your name\" />\n              <Button type=\"primary\" onClick={speak}>Greet!</Button>\n            </Space>\n          </DisplayDemo>\n  );\n};\n\n<SpeechSynthesisDemo />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you want to incorporate text-to-speech functionality in your React application by utilizing\n  the [Web_Speech_API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API)\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * The options that can be passed to the hook\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance\n */\nexport interface UseSpeechSynthesisOptions {\n    rate?: number;\n    pitch?: number;\n    volume?: number;\n    voice?: SpeechSynthesisVoice;\n}\n/**\n * The result of the hook\n */\nexport interface SpeechSynthesisResult {\n    readonly speak: () => void;\n    readonly speechSynthUtterance: SpeechSynthesisUtterance;\n}\n/**\n * Enables the possibility to perform a text-to-speech (with different voices) operation in your\n * React component by using the Web_Speech_API\n */\ndeclare const useSpeechSynthesis: (text: string, options?: UseSpeechSynthesisOptions) => Readonly<SpeechSynthesisResult>;\nexport default useSpeechSynthesis;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useSwipe.md",
    "content": "# useSwipe\n\nA hook that provides access to the current state of swipe gestures, regardless of whether the user is on a mobile or desktop device\n\n### Why? 💡\n\n- facilitates the retrieval of the most recent swipe data\n- registers global or target-specific listeners for both mouse and touch events\n- automatically removes listeners upon unmounting of the component\n- enables abstraction of swipe-related logic\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useSwipe`\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useSwipe from 'beautiful-react-hooks/useSwipe';\n\nconst SwipeReporter = () => {\n  const ref = useRef();\n  const swipeState = useSwipe(ref);\n  const showDetail = swipeState.count > 0 || swipeState.swiping;\n\n  return (\n    <DisplayDemo title=\"useSwipe\">\n      <div ref={ref} style={{ padding: 20, background: '#A1B5D8' }}>\n        Swipe me!\n        {showDetail && (\n          <div>\n            <p>Swipe information:</p>\n            <p>Is swiping: {swipeState.swiping ? 'yes' : 'no'}</p>\n            <p>Direction: {swipeState.direction}</p>\n            <p>Alpha-x: {swipeState.alphaX}, Alpha-y: {swipeState.alphaY} </p>\n            <p>Swipe count: {swipeState.count}</p>\n          </div>\n        )}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<SwipeReporter />\n```\n\n### Global events\n\nTo register global listeners, simply invoke the hook without passing any arguments\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useSwipe from 'beautiful-react-hooks/useSwipe';\n\nconst SwipeReporter = () => {\n  const swipeState = useSwipe();\n  const showDetail = swipeState.count > 0 || swipeState.swiping;\n\n  return (\n    <DisplayDemo title=\"useSwipe\">\n      <div style={{ padding: 20, background: '#A1B5D8' }}>\n        Swipe everywehere you want!\n        {showDetail && (\n          <div>\n            <p>Swipe information:</p>\n            <p>Is swiping: {swipeState.swiping ? 'yes' : 'no'}</p>\n            <p>Direction: {swipeState.direction}</p>\n            <p>Alpha-x: {swipeState.alphaX}, Alpha-y: {swipeState.alphaY} </p>\n            <p>Swipe count: {swipeState.count}</p>\n          </div>\n        )}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<SwipeReporter />\n```\n\n### Options\n\n* **direction**: defines the swiping direction, can be `horizontal`, `vertical`, `both`. _default: \"both\"_.\n* **threshold**: defines the minimum amount of pixel \"to move\" to start swiping. _default: 15_.\n* **preventDefault**: prevents the default behaviour of the mouse/touch events. _default: true_.\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useSwipe from 'beautiful-react-hooks/useSwipe';\n\nconst SwipeReporter = () => {\n  const ref = useRef();\n  const options = { direction: 'horizontal', threshold: 10, preventDefault: true };\n  const swipeState = useSwipe(ref, options);\n  const showDetail = swipeState.count > 0 || swipeState.swiping;\n\n  return (\n    <DisplayDemo title=\"useSwipe\">\n      <div ref={ref} style={{ padding: 20, background: '#A1B5D8' }}>\n        Swipe me, horizontally...\n        {showDetail && (\n          <div>\n            <p>Swipe information:</p>\n            <p>Is swiping: {swipeState.swiping ? 'yes' : 'no'}</p>\n            <p>Direction: {swipeState.direction}</p>\n            <p>Alpha-x: {swipeState.alphaX}, Alpha-y: {swipeState.alphaY} </p>\n            <p>Swipe count: {swipeState.count}</p>\n          </div>\n        )}\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<SwipeReporter />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nimport { type Direction } from './shared/swipeUtils';\n/**\n * The options that can be passed to the hook\n */\nexport interface UseSwipeOptions {\n    direction?: 'both' | 'horizontal' | 'vertical';\n    threshold?: number;\n    preventDefault?: boolean;\n    passive?: boolean;\n}\n/**\n * The result of the hook\n */\nexport interface SwipeState {\n    swiping: boolean;\n    direction?: Direction;\n    alphaX: number;\n    alphaY: number;\n    count: number;\n}\n/**\n * useSwipe hook\n */\ndeclare const useSwipe: <TElement extends HTMLElement>(targetRef?: RefObject<TElement> | undefined, options?: UseSwipeOptions) => SwipeState;\nexport default useSwipe;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useSwipeEvents.md",
    "content": "# useSwipeEvents\n\nA hook that provides a set of callback setters to manage swipe events. It can optionally receive a DOM ref to specify the target element for\nthe event(s). If no target is provided, the events will be attached globally to the `document` object.\n\nAvailable callback setters: `onSwipeLeft`, `onSwipeRight`, `onSwipeUp`, `onSwipeDown`,  `onSwipeStart`,  `onSwipeMove`,  `onSwipeEnd`;\n\n### Why? 💡\n\n- simplifies the handling of swipe gestures by adding mouse and touch listeners for swipe events globally or to a defined target.\n- handles the cleanup of listeners when the component unmounts, avoiding memory leaks and unwanted behaviors.\n- enables the creation of abstractions on swipe-related events, allowing you to focus on implementing your desired functionality without\n  worrying about the details of swipe detection.\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useSwipeEvents`\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useSwipeEvents from 'beautiful-react-hooks/useSwipeEvents';\n\nconst SwipeReporter = () => {\n  const ref = useRef();\n  const { onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeMove, onSwipeDown } = useSwipeEvents(ref);\n  const [lastSwipeInfo, setLastSwipeInfo] = useState();\n\n  onSwipeLeft(setLastSwipeInfo);\n  onSwipeRight(setLastSwipeInfo);\n  onSwipeUp(setLastSwipeInfo);\n  onSwipeDown(setLastSwipeInfo);\n\n  onSwipeMove(console.log);\n\n  return (\n    <DisplayDemo title=\"useSwipeEvents\">\n      <div ref={ref} style={{ padding: 20, background: '#CF7A95' }}>\n        Swipe me!\n      </div>\n      {lastSwipeInfo && (<>\n        <p>Last swipe direction: {lastSwipeInfo.direction}</p>\n        <p>Alpha-x: {lastSwipeInfo.alphaX}, Alpha-y: {lastSwipeInfo.alphaY} </p>\n      </>)}\n    </DisplayDemo>\n  );\n};\n\n<SwipeReporter />\n```\n\n### Global events\n\nAvoid providing any argument to `useMouseEvents` to attach the events globally\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useSwipeEvents from 'beautiful-react-hooks/useSwipeEvents';\n\nconst SwipeReporter = () => {\n  const { onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown } = useSwipeEvents();\n  const [lastSwipeInfo, setLastSwipeInfo] = useState();\n\n  onSwipeLeft(setLastSwipeInfo);\n  onSwipeRight(setLastSwipeInfo);\n  onSwipeUp(setLastSwipeInfo);\n  onSwipeDown(setLastSwipeInfo);\n\n  return (\n    <DisplayDemo title=\"useSwipeEvents\">\n      <div style={{ padding: 20, background: '#CF7A95' }}>\n        Swipe around!\n      </div>\n      {lastSwipeInfo && (<>\n        <p>Last swipe direction: {lastSwipeInfo.direction}</p>\n        <p>Alpha-x: {lastSwipeInfo.alphaX}, Alpha-y: {lastSwipeInfo.alphaY} </p>\n      </>)}\n    </DisplayDemo>\n  );\n};\n\n<SwipeReporter />\n```\n\n### Options\n\n* **threshold**: defines the minimum amount of pixel \"to move\" to start swiping. _default: 15_.\n* **preventDefault**: prevents the default behaviour of the mouse/touch events. _default: true_.\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport useSwipeEvents from 'beautiful-react-hooks/useSwipeEvents';\n\nconst SwipeReporter = () => {\n  const ref = useRef();\n  const options = { threshold: 25, preventDefault: false, usePassiveEvents: true };\n  const { onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown } = useSwipeEvents(ref, options);\n  const [lastSwipeInfo, setLastSwipeInfo] = useState();\n\n  onSwipeLeft(setLastSwipeInfo);\n  onSwipeRight(setLastSwipeInfo);\n  onSwipeUp(setLastSwipeInfo);\n  onSwipeDown(setLastSwipeInfo);\n\n  return (\n    <DisplayDemo title=\"useSwipeEvents\">\n      <div ref={ref} style={{ padding: 20, background: '#CF7A95' }}>\n        Swipe me!\n      </div>\n      {lastSwipeInfo && (<>\n        <p>Last swipe direction: {lastSwipeInfo.direction}</p>\n        <p>Alpha-x: {lastSwipeInfo.alphaX}, Alpha-y: {lastSwipeInfo.alphaY} </p>\n      </>)}\n    </DisplayDemo>\n  );\n};\n\n<SwipeReporter />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nimport { type CallbackSetter } from './shared/types';\n/**\n * The swipe event state interface\n */\nexport interface SwipeEventState {\n    clientX?: number;\n    clientY?: number;\n    direction: 'right' | 'left' | 'up' | 'down';\n    alphaX: number;\n    alphaY: number;\n}\n/**\n * The result of the hook\n */\ninterface UseSwipeEventsReturn {\n    onSwipeLeft: CallbackSetter<SwipeEventState>;\n    onSwipeRight: CallbackSetter<SwipeEventState>;\n    onSwipeUp: CallbackSetter<SwipeEventState>;\n    onSwipeDown: CallbackSetter<SwipeEventState>;\n    onSwipeMove: CallbackSetter<SwipeEventState>;\n    onSwipeStart: CallbackSetter<SwipeEventState>;\n    onSwipeEnd: CallbackSetter<SwipeEventState>;\n}\nexport interface UseSwipeEventsOpts {\n    threshold?: number;\n    preventDefault?: boolean;\n    passive?: boolean;\n}\n/**\n * useSwipeEvents\n * @param ref\n * @param options\n */\ndeclare const useSwipeEvents: <TElement extends HTMLElement>(ref?: RefObject<TElement> | undefined, options?: UseSwipeEventsOpts) => Readonly<UseSwipeEventsReturn>;\nexport default useSwipeEvents;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useSystemVoices.md",
    "content": "# useSystemVoices\n\nA hook that returns all the available voices on the system.\n\n**Note:** it's important to note that the purpose of this hook is to maintain backward compatibility with a previous version of the library\nthat utilized a non-stable version of the Web Speech API. In that version, voices were returned asynchronously.\n\nIf you are currently using a version of the library that does not require this hook, you can simply run:\n\n```typescript static  \nconst voices = window.speechSynthesis.getVoices()\n```\n\n### Why? 💡\n\n- At the moment, the `window.speechSynthesis.getVoices` function returns all the available system voices, but since  \n  it does it\n  asynchronously [the returning value is an empty array until a second call is performed](https://w3c.github.io/speech-api/speechapi-errata.html)\n  this hook manage the side-effect of correctly retrieve all the available system voices.\n\n### Basic Usage:\n\n```jsx harmony\nimport { List, Typography } from 'antd';\nimport useSystemVoices from 'beautiful-react-hooks/useSystemVoices';\n\nconst SpeechSynthesisDemo = () => {\n  const voices = useSystemVoices();\n\n  return (\n          <DisplayDemo title=\"useSystemVoices\">\n            <Typography.Title>System voices</Typography.Title>\n            <List condensed>\n              {voices.map(({ name, lang }) => <List.Item key={name}>{name} - <small>{lang}</small></List.Item>)}\n            </List>\n          </DisplayDemo>\n  );\n};\n\n<SpeechSynthesisDemo />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Returns all the available voices on the system.\n * This hook is here to backward compatibility with the previous version of the library that was using\n * a different non-stable version of the Web Speech API.\n */\ndeclare const useSystemVoices: () => SpeechSynthesisVoice[];\nexport default useSystemVoices;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useThrottledCallback.md",
    "content": "# useThrottledCallback\n\nA hook that takes in a function as an argument and returns a new memoized version of the function that limits its invocation to once per\nspecified time interval, measured in milliseconds. By default, the time interval is set to 250ms if not defined.\n\n### Why? 💡\n\n- Manages the frequency of function execution, irrespective of the number of times a component is rendered.\n\n## Basic Usage\n\n```jsx harmony\nimport { useEffect, useState } from 'react';\nimport { Space, Alert, Typography, Tag } from 'antd';\nimport useThrottledCallback from 'beautiful-react-hooks/useThrottledCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst ThrottledFnComponent = () => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useThrottledCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  });\n\n  onWindowResize(onWindowResizeHandler);\n\n  useEffect(() => {\n    // do something\n    // don't forget to cancel debounced\n    return () => onWindowResizeHandler.cancel(); // or .flush()\n  });\n\n  return (\n    <DisplayDemo title=\"useThrottledCallback\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window and see the update taking effect after the designated delay\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{width}</Tag><br />\n          window height: <Tag color=\"green\">{height}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<ThrottledFnComponent />\n```\n\n## Dependencies\n\nSince `useThrottledCallback` uses [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)\nunder the hood, you can possibly define the callback dependencies.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Space, Alert, Typography, Tag } from 'antd';\nimport useThrottledCallback from 'beautiful-react-hooks/useThrottledCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst ThrottledFnComponent = (props) => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useThrottledCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  }, [setWidth, setHeight]);\n\n  onWindowResize(onWindowResizeHandler);\n\n  return (\n    <DisplayDemo>\n      <p>window width: {width}</p>\n      <p>window height: {height}</p>\n    </DisplayDemo>\n  );\n};\n\n<ThrottledFnComponent foo=\"bar\" />\n```\n\n### Throttled time\n\nA custom throttled time can be easily defined as follows (500ms)\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Space, Alert, Typography, Tag } from 'antd';\nimport useThrottledCallback from 'beautiful-react-hooks/useThrottledCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst ThrottledFnComponent = (props) => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useThrottledCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  }, [setWidth, setHeight], 500);\n\n  onWindowResize(onWindowResizeHandler);\n\n  return (\n    <DisplayDemo title=\"useThrottledCallback\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window and see the update taking effect after the designated delay\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{width}</Tag><br />\n          window height: <Tag color=\"green\">{height}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<ThrottledFnComponent foo=\"bar\" />\n```\n\n## Options\n\nSince `useThrottledCallback` uses [lodash.throttle](https://www.npmjs.com/package/lodash.throttle)\nunder the hood, you can possibly define few options to customise its behaviour.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Space, Alert, Typography, Tag } from 'antd';\nimport useThrottledCallback from 'beautiful-react-hooks/useThrottledCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst ThrottledFnComponent = () => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n  const options = {\n    leading: false,\n    trailing: true,\n  };\n\n  // there's no need to use `useCallback` since the returned function \n  // is already memoized\n  const onWindowResizeHandler = useThrottledCallback(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  }, [setWidth, setHeight], 500, options);\n\n  onWindowResize(onWindowResizeHandler);\n\n  return (\n    <DisplayDemo title=\"useThrottledCallback\">\n      <Space direction=\"vertical\" size=\"middle\">\n        <Alert type=\"info\" message=\"Resize the browser window and see the update taking effect after the designated delay\" showIcon />\n\n        <Typography.Paragraph>\n          window width: <Tag color=\"green\">{width}</Tag><br />\n          window height: <Tag color=\"green\">{height}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<ThrottledFnComponent />\n```\n\n#### ✅ Pro tip:\n\nTo deep understanding the differences between `throttle` and `debounce`, what they are and when to use them please\nread \"[Debouncing and Throttling Explained Through Examples](https://css-tricks.com/debouncing-throttling-explained-examples/)\"\nby [David Corbacho](https://twitter.com/dcorbacho)\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/// <reference types=\"lodash\" />\nimport { type DependencyList } from 'react';\nimport { type GenericFunction } from './shared/types';\ninterface ThrottleSettings {\n    leading?: boolean | undefined;\n    trailing?: boolean | undefined;\n}\n/**\n * Accepts a function and returns a new throttled yet memoized version of that same function that waits the defined time\n * before allowing the next execution.\n * If time is not defined, its default value will be 250ms.\n */\ndeclare const useThrottledCallback: <TCallback extends GenericFunction>(fn: TCallback, dependencies?: DependencyList, wait?: number, options?: ThrottleSettings) => import(\"lodash\").DebouncedFunc<TCallback>;\nexport default useThrottledCallback;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useTimeout.md",
    "content": "# useTimeout\n\nA hook that facilitates the utilization of the `setTimeout` function in React function components. This hook receives a callback function\nand a delay duration as inputs, and subsequently, executes the given function at after the specified delay time.\n\n### 💡 Why?\n\n- Ensures that the given callback is executed reliably, even when the component re-renders;\n- Automatically cancels the timeout when the component unmounts (although this behavior can be modified by adjusting the options);\n- Provides information about the current state of the timeout (whether it has been cleared or not);\n- Offers a method to cancel the timeout, which can trigger a re-render of the component if desired.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography } from 'antd'\nimport useTimeout from 'beautiful-react-hooks/useTimeout';\n\nconst DelayedContentComponent = () => {\n  const [showContent, setShowContent] = useState(false);\n\n  // delay the function by 2000ms\n  useTimeout(() => {\n    setShowContent(true);\n  }, 2000);\n\n  return (\n    <DisplayDemo title=\"useTimeout\">\n      <Typography.Paragraph>Content will show in 2 seconds...</Typography.Paragraph>\n      {showContent && <div style={{ fontSize: '3rem' }}>🕰</div>}\n    </DisplayDemo>\n  );\n};\n\n<DelayedContentComponent />\n```\n\n### State & clear method:\n\nThe hook returns the state of the timeout (a boolean, cleared/not cleared) and a method to possibly clear it.\n\n**Note:** programmatically clearing the timeout will cause the component re-render.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Button } from 'antd'\nimport useTimeout from 'beautiful-react-hooks/useTimeout';\n\nconst DelayedContentComponent = () => {\n  const [showContent, setShowContent] = useState(false);\n  const [isCleared, clearTimeoutRef] = useTimeout(() => {\n    setShowContent(true);\n  }, 5000);\n\n  return (\n    <DisplayDemo title=\"useTimeout\">\n      <Typography.Paragraph>Content will show in 5 seconds...</Typography.Paragraph>\n      {showContent && <div style={{ fontSize: '3rem' }}>🕰</div>}\n      {!isCleared && <Button type=\"primary\" onClick={clearTimeoutRef}>Press here to cancel timeout</Button>}\n      {isCleared && <Typography.Paragraph>Cleared</Typography.Paragraph>}\n    </DisplayDemo>\n  );\n};\n\n<DelayedContentComponent />\n```\n\n### Options:\n\n`useTimeout` might accept an options object provided as eventual parameter.\n\n#### cancelOnUnmount:\n\nDefines whether the timeout should be cleared on unmount.\n\n**default**: `true`\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography } from 'antd';\nimport useTimeout from 'beautiful-react-hooks/useTimeout';\n\nconst DelayedContentComponent = () => {\n  const [showContent, setShowContent] = useState(false);\n  const options = { cancelOnUnmount: false };\n\n  useTimeout(() => setShowContent(true), 3000, options);\n\n  return (\n    <DisplayDemo title=\"useTimeout\">\n      <Typography.Paragraph>Content will show in 3 seconds but not be cleared on unmount</Typography.Paragraph>\n      {showContent && <div style={{ fontSize: '3rem' }}>🕰</div>}\n    </DisplayDemo>\n  );\n};\n\n<DelayedContentComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- when there is a requirement to execute a function after a specific number of milliseconds, without being affected by component re-renders\n\n#### 🛑 When not to use\n\n- Avoid using this hook for asynchronous operations since it violates the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type GenericFunction } from './shared/types';\nexport interface UseTimeoutOptions {\n    cancelOnUnmount?: boolean;\n}\n/**\n * An async-utility hook that accepts a callback function and a delay time (in milliseconds), then delays the\n * execution of the given function by the defined time.\n */\ndeclare const useTimeout: <TCallback extends GenericFunction>(fn: TCallback, milliseconds: number, options?: UseTimeoutOptions) => [boolean, () => void];\nexport default useTimeout;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useToggle.md",
    "content": "# useToggle\n\nA hook that encapsulates the business logic of dealing with boolean values.\n\nProvides a higher-level interface for dealing with boolean logic in React function component.\n\n### Why? 💡\n\n- Having multiple boolean states in an application often leads to code redundancy. This hook consolidates the implementation details of a\n  singular boolean state, promoting code reusability and reducing code bloat.\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography, Tag, Button } from 'antd'\nimport useToggle from 'beautiful-react-hooks/useToggle'\n\nconst ComponentWillUnmount = () => {\n  const [value, toggleValue] = useToggle()\n  const tagColor = value ? 'green' : 'red'\n\n  return (\n          <DisplayDemo title=\"useToggle\">\n            <Typography.Paragraph>\n              Toggle is <Tag color={tagColor}>{value ? 'on' : 'off'}</Tag>\n            </Typography.Paragraph>\n            <Button type=\"primary\" onClick={toggleValue}>toggle value</Button>\n          </DisplayDemo>\n  );\n};\n\n<ComponentWillUnmount />\n```\n\n### Initial state\n\n```jsx harmony\nimport { Button, Typography, Tag } from 'antd'\nimport useToggle from 'beautiful-react-hooks/useToggle'\n\nconst ComponentWillUnmount = () => {\n  const [value, toggleValue] = useToggle(true)\n  const tagColor = value ? 'green' : 'red'\n\n  return (\n          <DisplayDemo title=\"useToggle\">\n            <Typography.Paragraph>\n              Toggle is <Tag color={tagColor}>{value ? 'on' : 'off'}</Tag>\n            </Typography.Paragraph>\n            <Button type=\"primary\" onClick={toggleValue}>toggle value</Button>\n          </DisplayDemo>\n  );\n};\n\n<ComponentWillUnmount />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * A quick and simple utility for toggle states\n */\ndeclare const useToggle: (initialState?: boolean) => [boolean, () => void];\nexport default useToggle;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useTouch.md",
    "content": "# useTouch\n\nA hook that combines the functionalities of [useTouchState](./useTouchState.md) and [useTouchEvents](./useTouchEvents.md), returning an\narray where the first item is the mouse state and the second item is a wrapper of all the handler-setters.\n\n`useTouch` is intended as a shortcut to avoid the need for using both `useTouch`State and `useTouch`Events separately.\n\n### Why? 💡\n\n- Provides an easy way to obtain the mouse position\n- Automatically adds mouse event listeners either globally or to the specified target element\n- Automatically removes the listeners when the component unmounts\n- Enables abstractions on mouse-related events\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useTouch`\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useTouch from 'beautiful-react-hooks/useTouch';\n\nconst TouchReporter = () => {\n  const ref = useRef();\n  const [showCoords, setShowCoords] = useState(false);\n  const [touches, { onTouchStart, onTouchEnd }] = useTouch(ref);\n\n  onTouchStart(() => setShowCoords(true));\n  onTouchEnd(() => setShowCoords(false));\n\n  return (\n          <DisplayDemo>\n            <div ref={ref}>\n              <Space direction=\"vertical\">\n                <Alert message=\"Swipe this box to get the event coordinates\" type=\"info\" showIcon />\n                {showCoords && touches.length > 0 && ([\n                  <Tag color=\"green\">Touch X: {touches[0].clientX}</Tag>,\n                  <Tag color=\"green\">Touch Y: {touches[0].clientY}</Tag>\n                ])}\n              </Space>\n            </div>\n          </DisplayDemo>\n  );\n};\n\n<TouchReporter />\n```\n\n### Global events\n\nIf no ref is provided to `useTouch` it will use the window global object assign the events to\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useTouch from 'beautiful-react-hooks/useTouch';\n\nconst TouchReporter = () => {\n  const [showCoords, setShowCoords] = useState(false);\n  const [touches, { onTouchStart, onTouchEnd }] = useTouch();\n\n  onTouchStart(() => setShowCoords(true));\n  onTouchEnd(() => setShowCoords(false));\n\n  return (\n          <DisplayDemo>\n            <Space direction=\"vertical\">\n              <Alert message=\"Swipe this box to display the event coordinates\" type=\"info\" showIcon />\n              {touches.length > 0 && ([\n                <Tag color=\"green\">Touch X: {touches[0].clientX}</Tag>,\n                <Tag color=\"green\">Touch Y: {touches[0].clientY}</Tag>\n              ])}\n            </Space>\n          </DisplayDemo>\n  );\n};\n\n<TouchReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to abstract touch-related logics into custom hooks(s)\n\n#### 🛑 What not to do\n\n- Do not use the returned callback setters asynchronously, as doing so will have no effect and may result in bugs in your code.\n- Avoid using `useTouch` callback setters to replace standard mouse handler props.\n- `useTouch`  is designed to be used for abstracting more complex hooks that need to control the mouse, such as a drag-and-drop hook.\n- Using `useTouch` handlers instead of the classic props approach will result in decreased performance due to the loss of the React\n  SyntheticEvent performance boost. If you were using a classic props approach before, continue to do so.\n\n```jsx harmony static noedit\nconst MyComponent = (props) => {\n  const { mouseDownHandler } = props;\n\n  return (\n          <div onMouseDown={mouseDownHandler} />\n  );\n};\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nimport { type UseTouchEventsReturn } from './useTouchEvents';\n/**\n * Returns an array where the first item is the touch state from the `useTouchState` hook and the second item\n * is the object of callback setters from the `useTouchEvents` hook.\n * It is intended as a shortcut to those hooks.\n */\ndeclare const useTouch: <TElement extends HTMLElement>(targetRef?: RefObject<TElement> | undefined) => [TouchList, Readonly<UseTouchEventsReturn>];\nexport default useTouch;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useTouchEvents.md",
    "content": "# useTouchEvents\n\nA hook that provides an easy way to manage touch events by returning a set of callback setters. The returned setters allow control over\nvarious mouse events including `onTouchStart`, `onTouchMove`, `onTouchEnd`;\n\nThe hook optionally accepts a reference to a DOM element to target the desired event(s) to. If no target is provided, the events will be\nattached globally to the document object.\n\nIt is important to note that the returned callback setters should be immediately invoked within the component's body, and should not be\ncalled asynchronously.\n\n### Why? 💡\n\n- handles the addition of touch event listeners either globally or to a specified target.\n- takes care of cleaning up the listeners when the component is unmounted.\n- enables the implementation of abstractions on touch-related events.\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useTouchEvents`\n\n```jsx harmony\nimport { useRef, useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useTouchEvents from 'beautiful-react-hooks/useTouchEvents';\n\nconst MyComponent = () => {\n  const [touching, setTouching] = useState(false);\n  const [coordinates, setCoordinates] = useState([0, 0]);\n  const ref = useRef();\n  const { onTouchStart, onTouchMove, onTouchEnd } = useTouchEvents(ref);\n\n  onTouchStart((event) => {\n    setTouching(true);\n  });\n\n  onTouchMove((event) => {\n    if (touching) {\n      const { clientX, clientY } = event.touches[0];\n\n      setCoordinates([clientX, clientY]);\n    }\n  });\n\n  onTouchEnd(() => {\n    setTouching(false);\n  });\n\n  return (\n          <DisplayDemo title=\"useTouchEvents\">\n            <div ref={ref}>\n              <Space direction=\"vertical\">\n                <Alert message=\"Touch this box to get the event coordinates\" type=\"info\" showIcon />\n                <Tag color=\"green\">Is touching: {touching ? 'no' : 'yes'}</Tag>\n                <Tag color=\"green\">Touch X: {coordinates[0]}</Tag>\n                <Tag color=\"green\">Touch Y: {coordinates[1]}</Tag>\n              </Space>\n            </div>\n          </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Global events\n\nIf no ref is provided to `useTouchEvents` it will use the window global object assign the events to\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useTouchEvents from 'beautiful-react-hooks/useTouchEvents';\n\nconst MyComponent = () => {\n  const [coordinates, setCoordinates] = useState([0, 0]);\n  const { onTouchMove } = useTouchEvents();\n\n  onTouchMove((event) => {\n    const { clientX, clientY } = event.touches[0];\n\n    setCoordinates([clientX, clientY]);\n  });\n\n  return (\n          <DisplayDemo title=\"useTouchEvents\">\n            <Space direction=\"vertical\">\n              <Alert message=\"Swipe this box to get the event coordinates\" type=\"info\" showIcon />\n              <Tag color=\"green\">Touch X: {coordinates[0]}</Tag>\n              <Tag color=\"green\">Touch Y: {coordinates[1]}</Tag>\n            </Space>\n          </DisplayDemo>\n  );\n};\n\n<MyComponent />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to abstract touch-related logics into custom hooks(s)\n\n#### 🛑 What not to do\n\n- Do not use the returned callback setters asynchronously, as doing so will have no effect and may result in bugs in your code.\n- Avoid using `useTouchEvents` callback setters to replace standard mouse handler props.\n- `useTouchEvents`  is designed to be used for abstracting more complex hooks that need to control the mouse, such as a drag-and-drop hook.\n- Using `useTouchEvents` handlers instead of the classic props approach will result in decreased performance due to the loss of the React\n  SyntheticEvent performance boost. If you were using a classic props approach before, continue to do so.\n\n```jsx harmony static noedit\nconst MyComponent = (props) => {\n  const { mouseDownHandler } = props;\n\n  return (\n          <div onMouseDown={mouseDownHandler} />\n  );\n};\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\nimport { type CallbackSetter } from './shared/types';\n/**\n * Returns a frozen object of callback setters to handle the touch events.<br/>\n * It accepts a DOM ref representing the events target. <br/>\n * If a target is not provided the events will be globally attached to the document object.\n * <br/>\n * ### Shall the `useTouchEvents` callbacks replace the standard mouse handler props?\n *\n * **They shall not!**<br />\n * **useTouchEvents is meant to be used to abstract more complex hooks that need to control mouse**, for instance:\n * a drag n drop hook.<br />\n * Using useTouchEvents handlers instead of the classic props approach it's just as bad as it sounds since you'll\n * lose the React SyntheticEvent performance boost.<br />\n * If you were doing something like the following:\n *\n */\ndeclare const useTouchEvents: <TElement extends HTMLElement>(targetRef?: RefObject<TElement> | undefined, passive?: boolean) => Readonly<UseTouchEventsReturn>;\n/**\n * The return object of the `useTouchEvents` hook.\n */\nexport interface UseTouchEventsReturn {\n    onTouchStart: CallbackSetter<TouchEvent>;\n    onTouchEnd: CallbackSetter<TouchEvent>;\n    onTouchCancel: CallbackSetter<TouchEvent>;\n    onTouchMove: CallbackSetter<TouchEvent>;\n}\nexport default useTouchEvents;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useTouchState.md",
    "content": "# useTouchState\n\nA hook that returns relevant properties from the last touch event, such as clientX and clientY. To ensure that events are attached to the\nintended target, please provide a DOM reference to the hook. If no target is specified, the events will be attached to the the `document`\nobject globally.\n\n### Why? 💡\n\n- Allows to quickly get relevant information on the last touch event\n- Manages the addition of event listeners either globally or to a defined target\n- Ensures the listener is cleaned up when the component unmounts\n\n### Basic Usage:\n\nProvide a DOM ref as first parameter to `useTouchState`\n\n```jsx harmony\nimport { useRef } from 'react';\nimport { Tag, Space, Alert } from 'antd';\nimport useTouchState from 'beautiful-react-hooks/useTouchState';\n\nconst TouchReporter = () => {\n  const ref = useRef();\n  const touches = useTouchState(ref);\n  const lastTouch = touches[0];\n\n  return (\n    <DisplayDemo title=\"useTouchState\">\n      <div ref={ref}>\n        <Space direction=\"vertical\">\n          <Alert message=\"Touch this box to get the event coordinates\" type=\"info\" showIcon />\n          {touches.length > 0 && lastTouch && (\n            <>\n              <Tag color=\"green\">Touch X: {lastTouch.clientX}</Tag>\n              <Tag color=\"green\">Touch Y: {lastTouch.clientY}</Tag>\n            </>\n          )}\n          {touches.length === 0 && (\n            <Alert message=\"Use a touch device for this example\" type=\"error\" showIcon />\n          )}\n        </Space>\n      </div>\n    </DisplayDemo>\n  );\n};\n\n<TouchReporter />\n```\n\n### Global events\n\nAttach the touch events globally by simply not providing any dom reference to the `useTouchState` hook\n\n```jsx harmony\nimport useTouchState from 'beautiful-react-hooks/useTouchState';\nimport { Tag, Space, Alert } from 'antd';\n\nconst TouchReporter = () => {\n  const touches = useTouchState();\n  const lastTouch = touches[0];\n\n  return (\n    <DisplayDemo title=\"useTouchState\">\n      <Space direction=\"vertical\">\n        <Alert message=\"Touch this box to get the event coordinates\" type=\"info\" showIcon />\n        {touches.length > 0 && lastTouch && (\n          <>\n            <Tag color=\"green\">Touch X: {lastTouch.clientX}</Tag>\n            <Tag color=\"green\">Touch Y: {lastTouch.clientY}</Tag>\n          </>\n        )}\n        {touches.length === 0 && (\n          <Alert message=\"Use a touch device for this example\" type=\"error\" showIcon />\n        )}\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<TouchReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to abstract touch-related logics into custom hooks(s)\n- When you need to quickly get the last touch position\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\n/**\n * Returns the current touches from the touch move event.\n * It possibly accepts a DOM ref representing the mouse target.\n * If a target is not provided the state will be caught globally.\n */\ndeclare const useTouchState: <TElement extends HTMLElement>(targetRef?: RefObject<TElement> | undefined) => TouchList;\nexport default useTouchState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useURLSearchParams.md",
    "content": "# useURLSearchParams\n\nA hook that encapsulates the functionality of retrieving an always updated URLSearchParams object.\n\n### Why? 💡\n\n- simplify the process of obtaining an always up-to-date instance of the URLSearchParams object\n- This hook is not based on the useSearchParams hook from version **6** of the `react-router-dom` library. Therefore, it is compatible with\n  earlier versions of `react-router-dom`\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState, useRef } from 'react';\nimport { HashRouter as Router, useHistory } from 'react-router-dom'\nimport { Button, Input } from 'antd'\nimport useURLSearchParams from 'beautiful-react-hooks/useURLSearchParams'\nimport useDidMount from 'beautiful-react-hooks/useDidMount'\n\nconst ExampleComponent = () => {\n  const history = useHistory()\n  const params = useURLSearchParams()\n  const onMount = useDidMount()\n\n  onMount(() => {\n    params.set('foo', 'value')\n\n    history.replace({\n      search: params.toString(),\n    })\n  })\n\n  return (\n    <DisplayDemo title=\"useURLSearchParams\">\n      <p>Current value of 'foo' param is '{params.get('foo')}'</p>\n      <p>Change the value of the foo param to see how this hook works</p>\n    </DisplayDemo>\n  );\n};\n\n<Router>\n  <ExampleComponent />\n</Router>\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Wraps the business logic of retrieve always updated URLSearchParams\n */\ndeclare const useURLSearchParams: () => URLSearchParams;\nexport default useURLSearchParams;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useUnmount.md",
    "content": "# useUnmount\n\nA hook that takes in a function to execute right when the component unmounts.\n\n### Why? 💡\n\n- takes care of performing a callback when the component unmounts\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useUnmount from 'beautiful-react-hooks/useUnmount';\n\nconst ComponentUnmount = () => {\n  useUnmount(() => {\n    console.log('Component did unmount');\n  });\n\n  return (\n    <DisplayDemo title=\"useUnmount\">\n      <Typography.Paragraph>Check the javascript console complete moving from this page</Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<ComponentUnmount />;\n```\n\n### Callback setter syntax:\n\nIf the first parameter is omitted, you can use the returned function (a callback setter) to set the useWillUnmount handler. However, you\nmust immediately invoke the callback setter.\n\nImportant: The callback setter only changes the value of the callback reference and does not trigger a component rerender. Also, avoid\ninvoking it asynchronously\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useUnmount from 'beautiful-react-hooks/useUnmount';\n\nconst ComponentUnmount = () => {\n  const onUnmount = useUnmount();\n\n  onUnmount(() => {\n    console.log('Component did unmount');\n  });\n\n  return (\n    <DisplayDemo title=\"useUnmount\">\n      <Typography.Paragraph>\n        Check the javascript console complete moving from this page\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<ComponentUnmount />;\n```\n\n#### ✅ Pro tip:\n\nWhen using a React function component you should not really think of it in terms of \"lifecycle\".\n\nThe `useUnmount` hook is indeed intended as a shortcut to `useEffect(() => () => Unmount, [])`.\n\nTo deep understanding `useEffect`, what it is and how it should be properly used, please read\n\"[A complete guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/)\"\nby [Dan Abramov](https://twitter.com/dan_abramov)\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to perform a function after the component has mounted\n\n#### 🛑 When not to use\n\n- Avoid using this hook asynchronously since it would violate the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n- If you're using the callback setter, make sure to invoke it immediately instead of asynchronously\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type GenericFunction } from './shared/types';\n/**\n * Returns a callback setter for a callback to be performed when the component did unmount.\n */\ndeclare const useUnmount: <TCallback extends GenericFunction>(callback?: TCallback | undefined) => import(\"./shared/types\").CallbackSetter<undefined>;\nexport default useUnmount;\n\n```\n\n<!-- Types:end -->\n"
  },
  {
    "path": "docs/useUpdateEffect.md",
    "content": "# useUpdateEffect\n\nA hook that modifies the behavior of the `useEffect` hook by skipping the initial render. This hook is particularly useful in cases where\nthe effect should only run after the first update of the component, but not during the initial mount.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState, useEffect, useCallback } from 'react';\nimport { Alert, Space, Button } from 'antd';\nimport useUpdateEffect from 'beautiful-react-hooks/useUpdateEffect';\n\nconst UseUpdateEffectExample = () => {\n  const [data, setData] = useState(0)\n\n  useEffect(() => {\n    console.log('Normal useEffect', { data })\n  }, [data])\n\n  useUpdateEffect(() => {\n    console.log('Update useEffect only', { data })\n  }, [data])\n\n  const setNewDate = useCallback(() => setData(Date.now()), []);\n\n  return (\n    <DisplayDemo title=\"useUpdateEffect\">\n      <Space direction=\"vertical\">\n        <Alert type=\"info\" message=\"Open a console to see result and try to click update date button\" showIcon />\n        <Button type='primary' onClick={setNewDate}>\n          Update data\n        </Button>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<UseUpdateEffectExample />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type DependencyList, type EffectCallback } from 'react';\n/**\n * A hook that runs an effect after the first render.\n * @param callback\n * @param deps\n */\ndeclare const useUpdateEffect: (callback: EffectCallback, deps?: DependencyList) => void;\nexport default useUpdateEffect;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useValidatedState.md",
    "content": "# useValidatedState\n\nThis hook is similar to useState but accepts a validator function as first parameter and the initial state value as second, then returns the\nstate array where the third parameter is result of the validation.\n\n### Why? 💡\n\n- You want to have information on a state validation.\n\n### Basic Usage:\n\n```jsx harmony\nimport { Input, Space, Typography } from 'antd';\nimport useValidatedState from 'beautiful-react-hooks/useValidatedState';\n\nconst passwordValidator = (password) => password.length > 3;\n\nconst ValidatedField = () => {\n  const [password, setPassword, validation] = useValidatedState(passwordValidator, 'sk8');\n\n  return (\n    <DisplayDemo title=\"useValidatedState\">\n      <Space direction=\"vertical\">\n        <Input\n          value={password}\n          onChange={(e) => setPassword(e.target.value)}\n          status={!validation.valid && 'error'}\n          placeholder=\"Insert password\"\n        />\n        <Typography.Paragraph>\n          {validation.valid ? 'Password is valid' : 'Password is too short'}\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<ValidatedField />\n```\n\n### Mastering the hook\n\n#### ✅ good to know:\n\n- useValidatedState does not re-render your component twice to save the validation state.\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Returns a state that changes only if the next value pass its validator\n */\ndeclare const useValidatedState: <TValue, TValidator extends Validator<TValue>>(validator: TValidator, initialValue?: TValue | undefined) => [TValue, (nextValue: TValue) => void, ValidationResult];\nexport type Validator<TValue> = (value: TValue) => boolean;\nexport interface ValidationResult {\n    changed: boolean;\n    valid?: boolean;\n}\nexport default useValidatedState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useValueHistory.md",
    "content": "# useValueHistory\n\nA hook that takes a variable, which can be a prop or a state, and returns an array of its previous values. This hook is useful for tracking\nchanges in a variable across multiple renders and allows developers to compare the current value with its previous values.\n\nOverall, the \"usePrevious\" hook is a helpful tool for debugging and improving the performance of React components that rely on the history\nof a specific variable\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Tag, Typography } from 'antd';\nimport useValueHistory from 'beautiful-react-hooks/useValueHistory';\nimport useInterval from 'beautiful-react-hooks/useInterval';\n\nconst TestComponent = () => {\n  const [count, setCount] = useState(0);\n  const countHistory = useValueHistory(count);\n\n  useInterval(() => setCount(1 + count), 500);\n\n  return (\n    <DisplayDemo title={useValueHistory}>\n      <Typography.Paragraph>Count: <Tag color=\"blue\">{count}</Tag></Typography.Paragraph>\n      <Typography.Paragraph>The history of the `count` state is:</Typography.Paragraph>\n      <Tag color=\"green\">\n        {countHistory.join(', ')}\n      </Tag>\n    </DisplayDemo>\n  );\n};\n\n<TestComponent />\n```\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Accepts a variable (possibly a prop or a state) and returns its history (changes through updates).\n */\ndeclare const useValueHistory: <TValue = unknown>(value: TValue, distinct?: boolean) => TValue[];\nexport default useValueHistory;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useVerticalSwipe.md",
    "content": "# useVerticalSwipe\n\nReturns the state of the vertical swipe gesture both on mobile or desktop.<br/>\nIt is intended as a shortcut to [useSwipe](./useSwipe.md).\n"
  },
  {
    "path": "docs/useViewportSpy.md",
    "content": "# useViewportSpy\n\nA hook that uses the [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) API to tell whether the\nprovided DOM Element is visible within the viewport.\n\n### Why? 💡\n\n- Asynchronously observes changes in the intersection of the given element with the document\n- Can be used to perform animation when the component appear into the viewport\n\n### Basic Usage:\n\n```jsx harmony\nimport { useRef } from 'react';\nimport { Space, Typography, Tag } from 'antd';\nimport useViewportSpy from 'beautiful-react-hooks/useViewportSpy';\n\nconst ViewportSpyComponent = () => {\n  const ref = useRef();\n  const isVisible = useViewportSpy(ref);\n\n  return (\n    <DisplayDemo>\n      <Space direction=\"vertical\">\n        <div ref={ref} style={{ padding: 20, background: '#FF6B6C', borderRadius: 5 }}>\n          Observed element\n        </div>\n        <Typography.Paragraph>\n          is the observed element in viewport?\n          <Tag color={isVisible ? 'green' : 'red'}>{isVisible ? 'yes' : 'no'}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<ViewportSpyComponent />\n```\n\n### Options\n\nPass [IntersectionObserver options](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver) as second\nparameter to customize the behavior of the hook\n\n```jsx harmony\nimport { useRef } from 'react';\nimport { Space, Typography, Tag } from 'antd';\nimport useViewportSpy from 'beautiful-react-hooks/useViewportSpy';\n\nconst ViewportSpyComponent = () => {\n  const ref = useRef();\n  const isVisible = useViewportSpy(ref, { threshold: 0.6 });\n\n  return (\n    <DisplayDemo>\n      <Space direction=\"vertical\">\n        <div ref={ref} style={{ padding: 20, background: '#FF6B6C', borderRadius: 5 }}>\n          Observed element\n        </div>\n        <Typography.Paragraph>\n          is the observed element in viewport?\n          <Tag color={isVisible ? 'green' : 'red'}>{isVisible ? 'yes' : 'no'}</Tag>\n        </Typography.Paragraph>\n      </Space>\n    </DisplayDemo>\n  );\n};\n\n<ViewportSpyComponent />\n```\n\n#### ✅ Pro tip:\n\nThis hook can be used to perform animations when a component/element enters or exit the viewport. To deeply\nunderstand [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver)\nplease read [Using the Intersection Observer API to Trigger Animations and Transitions](https://alligator.io/js/intersection-observer)\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type RefObject } from 'react';\n/**\n * Uses the IntersectionObserverMock API to tell whether the given DOM Element (from useRef) is visible within the\n * viewport.\n */\ndeclare const useViewportSpy: <TElement extends HTMLElement>(ref: RefObject<TElement>, options?: IntersectionObserverInit) => boolean | undefined;\nexport default useViewportSpy;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useViewportState.md",
    "content": "# useViewportState\n\nA hook that returns relevant information on the current viewport state.\n\nIt's built on top of [useWindowResize](./useWindowResize.md) and [useWindowScroll](./useWindowScroll.md).\n\n### Why? 💡\n\n- takes care of adding the listener for the window resize event.\n- takes care of removing the listener when the component will unmount\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useViewportState from 'beautiful-react-hooks/useViewportState';\n\nconst WindowSizeReporter = () => {\n  const { width, height, scrollX, scrollY } = useViewportState();\n\n  return (\n    <DisplayDemo title=\"useViewportState\">\n      <Typography.Title>Window current properties</Typography.Title>\n      <Typography.Paragraph>width: <Tag color=\"green\">{width}</Tag></Typography.Paragraph>\n      <Typography.Paragraph>height: <Tag color=\"green\">{height}</Tag></Typography.Paragraph>\n      <Typography.Paragraph>horizontal scroll: <Tag color=\"green\">{scrollX}</Tag></Typography.Paragraph>\n      <Typography.Paragraph>vertical scroll: <Tag color=\"green\">{scrollY}</Tag></Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<WindowSizeReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When in need of reading common information about the current viewport\n\n<!-- Types -->\n### Types\n    \n```typescript static\nexport interface ViewportState {\n    width: number;\n    height: number;\n    scrollX: number;\n    scrollY: number;\n}\n/**\n * Returns updated information on the current viewport state\n */\ndeclare const useViewportState: (debounceBy?: number) => ViewportState;\nexport default useViewportState;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useWillUnmount.md",
    "content": "# useWillUnmount\n\nA hook that takes in a function to execute right before the component unmounts.\n\n### Why? 💡\n\n- takes care of performing a callback before the component unmounts\n\n### Basic Usage:\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useWillUnmount from 'beautiful-react-hooks/useWillUnmount';\n\nconst ComponentWillUnmount = () => {\n  useWillUnmount(() => {\n    console.log('Component will unmount');\n  });\n\n  return (\n    <DisplayDemo title=\"useWillUnmount\">\n      <Typography.Paragraph>Check the javascript console after moving from this page</Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<ComponentWillUnmount />\n```\n\n### Callback setter syntax:\n\nIf the first parameter is omitted, you can use the returned function (a callback setter) to set the useWillUnmount handler. However, you\nmust immediately invoke the callback setter.\n\nImportant: The callback setter only changes the value of the callback reference and does not trigger a component rerender. Also, avoid\ninvoking it asynchronously\n\n```jsx harmony\nimport { Typography } from 'antd';\nimport useWillUnmount from 'beautiful-react-hooks/useWillUnmount';\n\nconst ComponentWillUnmount = () => {\n  const onUnmount = useWillUnmount();\n\n  onUnmount(() => {\n    console.log('Component will unmount');\n  });\n\n  return (\n    <DisplayDemo title=\"useWillUnmount\">\n      <Typography.Paragraph>Check the javascript console after moving from this page</Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<ComponentWillUnmount />\n```\n\n#### ✅ Pro tip:\n\nWhen using a React function component you should not really think of it in terms of \"lifecycle\".\n\nThe `useWillUnmount` hook is indeed intended as a shortcut to `useLayoutEffect(() => () => willUnmount, [])`.\n\nTo deep understanding `useLayoutEffect`, what it is and how it should be properly used, please read\n\"[A complete guide to useLayoutEffect](https://react.dev/reference/react/useLayoutEffect)\"\nby React Team\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When you need to perform a function before the component has mounted\n\n#### 🛑 When not to use\n\n- Avoid using this hook asynchronously since it would violate the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n- If you're using the callback setter, make sure to invoke it immediately instead of asynchronously\n\n<!-- Types -->\n### Types\n    \n```typescript static\nimport { type GenericFunction } from './shared/types';\n/**\n * Returns a callback setter for a callback to be performed when the component will unmount.\n */\ndeclare const useWillUnmount: <TCallback extends GenericFunction>(callback?: TCallback | undefined) => import(\"./shared/types\").CallbackSetter<undefined>;\nexport default useWillUnmount;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useWindowResize.md",
    "content": "# useWindowResize\n\nA hook that receives a callback function to execute on the window's resize event.\n\nIt's built on top of [useGlobalEvent](./useGlobalEvent.md).\n\n### Why? 💡\n\n- Simplifies the process of adding a listener for a specific event to the `window` object.\n- Automates the removal of the listener when the component is unmounted.\n\n### Basic Usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst WindowSizeReporter = () => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n\n  useWindowResize((event) => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  });\n\n  return (\n    <DisplayDemo title=\"useWindowResize\">\n      <Typography.Paragraph>\n        current window width: <Tag color=\"green\">{width}</Tag>\n      </Typography.Paragraph>\n      <Typography.Paragraph>\n        current window height: <Tag color=\"green\">{height}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<WindowSizeReporter />\n```\n\n### Callback setter syntax:\n\nif the first parameter is not provided, the returned function (*a callback setter*) can be used to set the `useWindowResize` handler, as\nlong as it is immediately invoked.\n\n**Please note**: the returned callback setter is meant to change the value of the callback reference only, it does not cause the component\nrerender nor should not be invoked asynchronously.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst WindowSizeReporter = () => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n\n  onWindowResize(() => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  });\n\n  return (\n    <DisplayDemo title=\"useWindowResize\">\n      <Typography.Paragraph>\n        current window width: <Tag color=\"green\">{width}</Tag>\n      </Typography.Paragraph>\n      <Typography.Paragraph>\n        current window height: <Tag color=\"green\">{height}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<WindowSizeReporter />\n```\n\n#### ✅ Pro tip:\n\nif you're using a `setState` function in your `useWindowResize` callback, you probably want to optimise your component performances by\npreventing too many useless renders, please take into account using\n[useThrottledCallback](useThrottledCallback.md).\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useThrottledCallback from 'beautiful-react-hooks/useThrottledCallback';\nimport useWindowResize from 'beautiful-react-hooks/useWindowResize';\n\nconst WindowSizeReporter = () => {\n  const [width, setWidth] = useState(window.innerWidth);\n  const [height, setHeight] = useState(window.innerHeight);\n  const onWindowResize = useWindowResize();\n\n  onWindowResize(useThrottledCallback((event) => {\n    setWidth(window.innerWidth);\n    setHeight(window.innerHeight);\n  }));\n\n  return (\n    <DisplayDemo title=\"useWindowResize\">\n      <Typography.Paragraph>\n        current window width: <Tag color=\"green\">{width}</Tag>\n      </Typography.Paragraph>\n      <Typography.Paragraph>\n        current window height: <Tag color=\"green\">{height}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<WindowSizeReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When in need of performing a function during the window resize, for example: to keep track of the window size\n\n#### 🛑 When not to use\n\n- Avoid using this hook asynchronously since it would violate the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n- If you're using the callback setter, make sure to invoke it immediately instead of asynchronously\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Returns a function that accepts a callback to be performed when the window resize.\n */\ndeclare const useWindowResize: () => import(\"./shared/types\").CallbackSetter<UIEvent>;\nexport default useWindowResize;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/useWindowScroll.md",
    "content": "# useWindowScroll\n\nA hook that receives a callback function to execute on the window's scroll event.\n\nIt's built on top of [useGlobalEvent](./useGlobalEvent.md).\n\n### Why? 💡\n\n- Simplifies the process of adding a listener for a specific event to the `window` object.\n- Automates the removal of the listener when the component is unmounted.\n\n### Basic usage:\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useWindowScroll from 'beautiful-react-hooks/useWindowScroll';\n\nconst WindowScrollReporter = () => {\n  const [scrollY, setScrollY] = useState(window.scrollY);\n  const onWindowScroll = useWindowScroll();\n\n  onWindowScroll((event) => {\n    setScrollY(window.scrollY);\n  });\n\n  return (\n    <DisplayDemo>\n      <Typography.Paragraph>\n        current window vertical scroll: <Tag color=\"green\">{scrollY}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<WindowScrollReporter />\n```\n\n### Callback setter syntax:\n\nif the first parameter is not provided, the returned function (*a callback setter*) can be used to set the `useWindowScroll` handler, as\nlong as it is immediately invoked.\n\n**Please note**: the returned callback setter is meant to change the value of the callback reference only, it does not cause the component\nrerender nor should not be invoked asynchronously.\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useWindowScroll from 'beautiful-react-hooks/useWindowScroll';\n\nconst WindowScrollReporter = () => {\n  const [scrollY, setScrollY] = useState(window.scrollY);\n  const onScroll = useWindowScroll();\n\n  onScroll(() => {\n    setScrollY(window.scrollY);\n  });\n\n  return (\n    <DisplayDemo>\n      <Typography.Paragraph>\n        current window vertical scroll: <Tag color=\"green\">{scrollY}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<WindowScrollReporter />\n```\n\n#### ✅ Pro tip:\n\nif you're using a `setState` function in your `useWindowScroll` callback, you probably want to optimise your component performances by\npreventing too many useless renders, please take into account using\n[useThrottledCallback](useThrottledCallback.md).\n\n```jsx harmony\nimport { useState } from 'react';\nimport { Typography, Tag } from 'antd';\nimport useThrottledCallback from 'beautiful-react-hooks/useThrottledCallback'\nimport useWindowScroll from 'beautiful-react-hooks/useWindowScroll';\n\nconst WindowScrollReporter = () => {\n  const [scrollY, setScrollY] = useState(window.scrollY);\n  const onWindowScroll = useWindowScroll();\n\n  onWindowScroll(useThrottledCallback((event) => {\n    setScrollY(window.scrollY);\n  }));\n\n  return (\n    <DisplayDemo>\n      <Typography.Paragraph>\n        current window vertical scroll: <Tag color=\"green\">{scrollY}</Tag>\n      </Typography.Paragraph>\n    </DisplayDemo>\n  );\n};\n\n<WindowScrollReporter />\n```\n\n### Mastering the hook\n\n#### ✅ When to use\n\n- When in need of performing a function during the window scroll, for example: to keep track of the window scroll position\n\n#### 🛑 When not to use\n\n- Avoid using this hook asynchronously since it would violate the [rules of hooks](https://reactjs.org/docs/hooks-rules.html)\n- If you're using the callback setter, make sure to invoke it immediately instead of asynchronously\n\n<!-- Types -->\n### Types\n    \n```typescript static\n/**\n * Returns a function that accepts a callback to be performed when the window scrolls.\n */\ndeclare const useWindowScroll: () => import(\"./shared/types\").CallbackSetter<UIEvent>;\nexport default useWindowScroll;\n\n```\n<!-- Types:end -->"
  },
  {
    "path": "docs/utils/_CustomLogo.js",
    "content": "import React from 'react'\nimport PropTypes from 'prop-types'\nimport Styled from 'rsg-components/Styled'\nimport logo from './_doc-logo.png'\n\nconst styles = ({ fontFamily, color }) => ({\n  logo: {\n    display: 'block'\n  },\n  image: {\n    width: '100%'\n  }\n})\n\nconst LogoRenderer = ({ classes }) => (\n  <h1 className={classes.logo}>\n    <img className={classes.image} src={logo} alt=\"Beautiful React Hooks\" />\n  </h1>\n)\n\nLogoRenderer.propTypes = {\n  classes: PropTypes.object.isRequired,\n  children: PropTypes.node\n}\n\nexport default Styled(styles)(LogoRenderer)\n"
  },
  {
    "path": "docs/utils/_EmptyComponent.js",
    "content": "export default () => null;\n"
  },
  {
    "path": "docs/utils/_custom.css",
    "content": "@import url('https://fonts.googleapis.com/css?family=Ubuntu:300,300i,400,400i,500,500i,700,700i&display=swap');\n@import '~antd/dist/reset.css';\n\nbody {\n  font-family: 'Ubuntu', sans-serif;\n}\n"
  },
  {
    "path": "docs/utils/_setup.js",
    "content": "const React = require('react')\nconst { Card } = require('antd')\n\nconst DisplayDemo = window.DisplayDemo = (props) => (\n  React.createElement(Card, { bordered: true, hoverable: true, ...props }, props.children)\n)\n"
  },
  {
    "path": "docs/utils/_styleguidist.theme.js",
    "content": "module.exports = {\n  // https://github.com/styleguidist/react-styleguidist/blob/master/src/client/styles/theme.ts\n  theme: {\n    color: {\n      base: '#2D3142',\n      text: '#2D3142',\n      link: '#1D6C8B',\n      linkHover: '#317995'\n    },\n    baseColor: '#2D3142',\n    fontFamily: {\n      base: '\"Ubuntu\", \"sans-serif\", light',\n    },\n  },\n  styles: {\n    SectionHeading: {\n      wrapper: {\n        display: 'none',\n      },\n    },\n    Code: {\n      code: {\n        fontFamily: '\\'Ubuntu Mono\\', sans-serif',\n        backgroundColor: '#CF7A95',\n        color: '#fff',\n        fontWeight: '400',\n        padding: '0 5px',\n      },\n    },\n    Para: {\n      para: {\n        fontFamily: '\\'Ubuntu\\', sans-serif',\n      },\n    },\n    StyleGuide: {\n      sidebar: {\n        border: 0,\n        width: '16rem',\n        background: 'white',\n        boxShadow: '0 0 20px 0 rgba(20, 20, 20, 0.1)',\n      },\n      content: {\n        maxWidth: '960px',\n      },\n      root: {\n        background: '#FBFAF9',\n      },\n      hasSidebar: {\n        paddingLeft: '16rem',\n      }\n    },\n    Playground: {\n      preview: {\n        padding: 0,\n        border: 'none',\n        background: 'transparent',\n        //borderRadius: '6px',\n        // boxShadow: '0 0px 10px 0 rgba(93, 100, 148, 0.05)',\n      },\n    },\n  },\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"beautiful-react-hooks\",\n  \"version\": \"5.1.0\",\n  \"description\": \"A collection of beautiful (and hopefully useful) React hooks to speed-up your components and hooks development\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"lint\": \"eslint src/ --ext .ts\",\n    \"build-types\": \"tsc --project ./tsconfig.types.json\",\n    \"build-cjs\": \"tsc --project ./tsconfig.cjs.json\",\n    \"build-esm\": \"tsc --project ./tsconfig.esm.json\",\n    \"build\": \"npx del-cli dist && npm run build-cjs && npm run build-esm && npm run build-types && echo 'Successfully built'\",\n    \"build-doc\": \"npx del-cli dist-ghpages && node scripts/generate-doc-append-types.js && npx styleguidist build\",\n    \"test\": \"nyc mocha --recursive --exit \\\"./test/**/*.spec.+(js|jsx)\\\"\",\n    \"test:watch\": \"npm run test -- --watch\",\n    \"start\": \"npx styleguidist server\",\n    \"semantic-release\": \"semantic-release\"\n  },\n  \"browserslist\": [\n    \">1%\",\n    \"last 1 version\",\n    \"Firefox ESR\",\n    \"not dead\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/antonioru/beautiful-react-hooks.git\"\n  },\n  \"author\": {\n    \"name\": \"Antonio Russo\",\n    \"email\": \"antonio@beautifulinteractions.com\"\n  },\n  \"keywords\": [\n    \"react\",\n    \"react-hooks\"\n  ],\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/antonioru/beautiful-react-hooks/issues\"\n  },\n  \"homepage\": \"https://antonioru.github.io/beautiful-react-hooks/\",\n  \"dependencies\": {\n    \"lodash.debounce\": \"^4.0.8\",\n    \"lodash.throttle\": \"^4.1.1\"\n  },\n  \"peerDependencies\": {\n    \"react\": \">=18.2.0 <20.0.0\",\n    \"react-dom\": \">=18.2.0 <20.0.0\",\n    \"react-router-dom\": \">=5.0.0\",\n    \"rxjs\": \">=7.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ant-design/icons\": \"5.0.1\",\n    \"@babel/core\": \"7.21.0\",\n    \"@babel/preset-env\": \"7.20.2\",\n    \"@babel/preset-react\": \"7.18.6\",\n    \"@babel/register\": \"^7.21.0\",\n    \"@semantic-release/changelog\": \"6.0.2\",\n    \"@semantic-release/commit-analyzer\": \"9.0.2\",\n    \"@semantic-release/exec\": \"6.0.3\",\n    \"@semantic-release/git\": \"10.0.1\",\n    \"@semantic-release/github\": \"8.0.7\",\n    \"@semantic-release/npm\": \"9.0.2\",\n    \"@testing-library/react\": \"14.0.0\",\n    \"@testing-library/react-hooks\": \"6.0.0\",\n    \"@types/lodash.debounce\": \"4.0.7\",\n    \"@types/lodash.throttle\": \"4.1.7\",\n    \"@types/react-router-dom\": \"5.3.3\",\n    \"antd\": \"5.3.1\",\n    \"babel-loader\": \"^9.1.2\",\n    \"babel-plugin-istanbul\": \"^6.1.1\",\n    \"babel-plugin-transform-require-ignore\": \"^0.1.1\",\n    \"chai\": \"^4.3.7\",\n    \"css-loader\": \"^6.7.3\",\n    \"eslint\": \"8.36.0\",\n    \"eslint-config-standard-with-typescript\": \"34.0.0\",\n    \"eslint-plugin-import\": \"2.27.5\",\n    \"eslint-plugin-n\": \"15.6.1\",\n    \"eslint-plugin-promise\": \"6.1.1\",\n    \"eslint-plugin-react\": \"7.32.2\",\n    \"glob\": \"^9.2.1\",\n    \"husky\": \"^8.0.3\",\n    \"jsdoc-to-markdown\": \"^8.0.0\",\n    \"jsdom\": \"^21.1.1\",\n    \"jsdom-global\": \"^3.0.2\",\n    \"mocha\": \"10.2.0\",\n    \"mock-local-storage\": \"1.1.23\",\n    \"mutation-observer\": \"1.0.3\",\n    \"nyc\": \"^15.1.0\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\",\n    \"react-router-dom\": \"5.3.4\",\n    \"react-styleguidist\": \"13.1.1\",\n    \"regenerator-runtime\": \"0.13.11\",\n    \"rxjs\": \"7.8.0\",\n    \"semantic-release\": \"^20.1.1\",\n    \"sinon\": \"^15.0.2\",\n    \"style-loader\": \"^3.3.1\",\n    \"ts-loader\": \"9.4.2\",\n    \"typescript\": \"5.8.3\",\n    \"url-loader\": \"^4.1.1\",\n    \"webpack\": \"5.76.1\"\n  },\n  \"exports\": {\n    \"./useWindowScroll\": {\n      \"import\": \"./dist/esm/useWindowScroll.js\",\n      \"require\": \"./dist/useWindowScroll.js\",\n      \"types\": \"./dist/useWindowScroll.d.ts\"\n    },\n    \"./useWindowResize\": {\n      \"import\": \"./dist/esm/useWindowResize.js\",\n      \"require\": \"./dist/useWindowResize.js\",\n      \"types\": \"./dist/useWindowResize.d.ts\"\n    },\n    \"./useWillUnmount\": {\n      \"import\": \"./dist/esm/useWillUnmount.js\",\n      \"require\": \"./dist/useWillUnmount.js\",\n      \"types\": \"./dist/useWillUnmount.d.ts\"\n    },\n    \"./useViewportState\": {\n      \"import\": \"./dist/esm/useViewportState.js\",\n      \"require\": \"./dist/useViewportState.js\",\n      \"types\": \"./dist/useViewportState.d.ts\"\n    },\n    \"./useViewportSpy\": {\n      \"import\": \"./dist/esm/useViewportSpy.js\",\n      \"require\": \"./dist/useViewportSpy.js\",\n      \"types\": \"./dist/useViewportSpy.d.ts\"\n    },\n    \"./useVerticalSwipe\": {\n      \"import\": \"./dist/esm/useVerticalSwipe.js\",\n      \"require\": \"./dist/useVerticalSwipe.js\",\n      \"types\": \"./dist/useVerticalSwipe.d.ts\"\n    },\n    \"./useValueHistory\": {\n      \"import\": \"./dist/esm/useValueHistory.js\",\n      \"require\": \"./dist/useValueHistory.js\",\n      \"types\": \"./dist/useValueHistory.d.ts\"\n    },\n    \"./useValidatedState\": {\n      \"import\": \"./dist/esm/useValidatedState.js\",\n      \"require\": \"./dist/useValidatedState.js\",\n      \"types\": \"./dist/useValidatedState.d.ts\"\n    },\n    \"./useUpdateEffect\": {\n      \"import\": \"./dist/esm/useUpdateEffect.js\",\n      \"require\": \"./dist/useUpdateEffect.js\",\n      \"types\": \"./dist/useUpdateEffect.d.ts\"\n    },\n    \"./useUnmount\": {\n      \"import\": \"./dist/esm/useUnmount.js\",\n      \"require\": \"./dist/useUnmount.js\",\n      \"types\": \"./dist/useUnmount.d.ts\"\n    },\n    \"./useURLSearchParams\": {\n      \"import\": \"./dist/esm/useURLSearchParams.js\",\n      \"require\": \"./dist/useURLSearchParams.js\",\n      \"types\": \"./dist/useURLSearchParams.d.ts\"\n    },\n    \"./useTouchState\": {\n      \"import\": \"./dist/esm/useTouchState.js\",\n      \"require\": \"./dist/useTouchState.js\",\n      \"types\": \"./dist/useTouchState.d.ts\"\n    },\n    \"./useTouchEvents\": {\n      \"import\": \"./dist/esm/useTouchEvents.js\",\n      \"require\": \"./dist/useTouchEvents.js\",\n      \"types\": \"./dist/useTouchEvents.d.ts\"\n    },\n    \"./useTouch\": {\n      \"import\": \"./dist/esm/useTouch.js\",\n      \"require\": \"./dist/useTouch.js\",\n      \"types\": \"./dist/useTouch.d.ts\"\n    },\n    \"./useToggle\": {\n      \"import\": \"./dist/esm/useToggle.js\",\n      \"require\": \"./dist/useToggle.js\",\n      \"types\": \"./dist/useToggle.d.ts\"\n    },\n    \"./useTimeout\": {\n      \"import\": \"./dist/esm/useTimeout.js\",\n      \"require\": \"./dist/useTimeout.js\",\n      \"types\": \"./dist/useTimeout.d.ts\"\n    },\n    \"./useThrottledCallback\": {\n      \"import\": \"./dist/esm/useThrottledCallback.js\",\n      \"require\": \"./dist/useThrottledCallback.js\",\n      \"types\": \"./dist/useThrottledCallback.d.ts\"\n    },\n    \"./useSystemVoices\": {\n      \"import\": \"./dist/esm/useSystemVoices.js\",\n      \"require\": \"./dist/useSystemVoices.js\",\n      \"types\": \"./dist/useSystemVoices.d.ts\"\n    },\n    \"./useSwipeEvents\": {\n      \"import\": \"./dist/esm/useSwipeEvents.js\",\n      \"require\": \"./dist/useSwipeEvents.js\",\n      \"types\": \"./dist/useSwipeEvents.d.ts\"\n    },\n    \"./useSwipe\": {\n      \"import\": \"./dist/esm/useSwipe.js\",\n      \"require\": \"./dist/useSwipe.js\",\n      \"types\": \"./dist/useSwipe.d.ts\"\n    },\n    \"./useSpeechSynthesis\": {\n      \"import\": \"./dist/esm/useSpeechSynthesis.js\",\n      \"require\": \"./dist/useSpeechSynthesis.js\",\n      \"types\": \"./dist/useSpeechSynthesis.d.ts\"\n    },\n    \"./useSpeechRecognition\": {\n      \"import\": \"./dist/esm/useSpeechRecognition.js\",\n      \"require\": \"./dist/useSpeechRecognition.js\",\n      \"types\": \"./dist/useSpeechRecognition.d.ts\"\n    },\n    \"./useSessionStorage\": {\n      \"import\": \"./dist/esm/useSessionStorage.js\",\n      \"require\": \"./dist/useSessionStorage.js\",\n      \"types\": \"./dist/useSessionStorage.d.ts\"\n    },\n    \"./useSearchQuery\": {\n      \"import\": \"./dist/esm/useSearchQuery.js\",\n      \"require\": \"./dist/useSearchQuery.js\",\n      \"types\": \"./dist/useSearchQuery.d.ts\"\n    },\n    \"./useResizeObserver\": {\n      \"import\": \"./dist/esm/useResizeObserver.js\",\n      \"require\": \"./dist/useResizeObserver.js\",\n      \"types\": \"./dist/useResizeObserver.d.ts\"\n    },\n    \"./useRequestAnimationFrame\": {\n      \"import\": \"./dist/esm/useRequestAnimationFrame.js\",\n      \"require\": \"./dist/useRequestAnimationFrame.js\",\n      \"types\": \"./dist/useRequestAnimationFrame.d.ts\"\n    },\n    \"./useRenderInfo\": {\n      \"import\": \"./dist/esm/useRenderInfo.js\",\n      \"require\": \"./dist/useRenderInfo.js\",\n      \"types\": \"./dist/useRenderInfo.d.ts\"\n    },\n    \"./useQueryParams\": {\n      \"import\": \"./dist/esm/useQueryParams.js\",\n      \"require\": \"./dist/useQueryParams.js\",\n      \"types\": \"./dist/useQueryParams.d.ts\"\n    },\n    \"./useQueryParam\": {\n      \"import\": \"./dist/esm/useQueryParam.js\",\n      \"require\": \"./dist/useQueryParam.js\",\n      \"types\": \"./dist/useQueryParam.d.ts\"\n    },\n    \"./usePreviousValue\": {\n      \"import\": \"./dist/esm/usePreviousValue.js\",\n      \"require\": \"./dist/usePreviousValue.js\",\n      \"types\": \"./dist/usePreviousValue.d.ts\"\n    },\n    \"./useOnlineState\": {\n      \"import\": \"./dist/esm/useOnlineState.js\",\n      \"require\": \"./dist/useOnlineState.js\",\n      \"types\": \"./dist/useOnlineState.d.ts\"\n    },\n    \"./useObservable\": {\n      \"import\": \"./dist/esm/useObservable.js\",\n      \"require\": \"./dist/useObservable.js\",\n      \"types\": \"./dist/useObservable.d.ts\"\n    },\n    \"./useObjectState\": {\n      \"import\": \"./dist/esm/useObjectState.js\",\n      \"require\": \"./dist/useObjectState.js\",\n      \"types\": \"./dist/useObjectState.d.ts\"\n    },\n    \"./useMutationObserver\": {\n      \"import\": \"./dist/esm/useMutationObserver.js\",\n      \"require\": \"./dist/useMutationObserver.js\",\n      \"types\": \"./dist/useMutationObserver.d.ts\"\n    },\n    \"./useMutableState\": {\n      \"import\": \"./dist/esm/useMutableState.js\",\n      \"require\": \"./dist/useMutableState.js\",\n      \"types\": \"./dist/useMutableState.d.ts\"\n    },\n    \"./useMouseState\": {\n      \"import\": \"./dist/esm/useMouseState.js\",\n      \"require\": \"./dist/useMouseState.js\",\n      \"types\": \"./dist/useMouseState.d.ts\"\n    },\n    \"./useMouseEvents\": {\n      \"import\": \"./dist/esm/useMouseEvents.js\",\n      \"require\": \"./dist/useMouseEvents.js\",\n      \"types\": \"./dist/useMouseEvents.d.ts\"\n    },\n    \"./useMouse\": {\n      \"import\": \"./dist/esm/useMouse.js\",\n      \"require\": \"./dist/useMouse.js\",\n      \"types\": \"./dist/useMouse.d.ts\"\n    },\n    \"./useMediaQuery\": {\n      \"import\": \"./dist/esm/useMediaQuery.js\",\n      \"require\": \"./dist/useMediaQuery.js\",\n      \"types\": \"./dist/useMediaQuery.d.ts\"\n    },\n    \"./useLongPress\": {\n      \"import\": \"./dist/esm/useLongPress.js\",\n      \"require\": \"./dist/useLongPress.js\",\n      \"types\": \"./dist/useLongPress.d.ts\"\n    },\n    \"./useLocalStorage\": {\n      \"import\": \"./dist/esm/useLocalStorage.js\",\n      \"require\": \"./dist/useLocalStorage.js\",\n      \"types\": \"./dist/useLocalStorage.d.ts\"\n    },\n    \"./useLifecycle\": {\n      \"import\": \"./dist/esm/useLifecycle.js\",\n      \"require\": \"./dist/useLifecycle.js\",\n      \"types\": \"./dist/useLifecycle.d.ts\"\n    },\n    \"./useIsFirstRender\": {\n      \"import\": \"./dist/esm/useIsFirstRender.js\",\n      \"require\": \"./dist/useIsFirstRender.js\",\n      \"types\": \"./dist/useIsFirstRender.d.ts\"\n    },\n    \"./useInterval\": {\n      \"import\": \"./dist/esm/useInterval.js\",\n      \"require\": \"./dist/useInterval.js\",\n      \"types\": \"./dist/useInterval.d.ts\"\n    },\n    \"./useInfiniteScroll\": {\n      \"import\": \"./dist/esm/useInfiniteScroll.js\",\n      \"require\": \"./dist/useInfiniteScroll.js\",\n      \"types\": \"./dist/useInfiniteScroll.d.ts\"\n    },\n    \"./useHorizontalSwipe\": {\n      \"import\": \"./dist/esm/useHorizontalSwipe.js\",\n      \"require\": \"./dist/useHorizontalSwipe.js\",\n      \"types\": \"./dist/useHorizontalSwipe.d.ts\"\n    },\n    \"./useGlobalEvent\": {\n      \"import\": \"./dist/esm/useGlobalEvent.js\",\n      \"require\": \"./dist/useGlobalEvent.js\",\n      \"types\": \"./dist/useGlobalEvent.d.ts\"\n    },\n    \"./useGeolocationState\": {\n      \"import\": \"./dist/esm/useGeolocationState.js\",\n      \"require\": \"./dist/useGeolocationState.js\",\n      \"types\": \"./dist/useGeolocationState.d.ts\"\n    },\n    \"./useGeolocationEvents\": {\n      \"import\": \"./dist/esm/useGeolocationEvents.js\",\n      \"require\": \"./dist/useGeolocationEvents.js\",\n      \"types\": \"./dist/useGeolocationEvents.d.ts\"\n    },\n    \"./useGeolocation\": {\n      \"import\": \"./dist/esm/useGeolocation.js\",\n      \"require\": \"./dist/useGeolocation.js\",\n      \"types\": \"./dist/useGeolocation.d.ts\"\n    },\n    \"./useEvent\": {\n      \"import\": \"./dist/esm/useEvent.js\",\n      \"require\": \"./dist/useEvent.js\",\n      \"types\": \"./dist/useEvent.d.ts\"\n    },\n    \"./useDropZone\": {\n      \"import\": \"./dist/esm/useDropZone.js\",\n      \"require\": \"./dist/useDropZone.js\",\n      \"types\": \"./dist/useDropZone.d.ts\"\n    },\n    \"./useDragEvents\": {\n      \"import\": \"./dist/esm/useDragEvents.js\",\n      \"require\": \"./dist/useDragEvents.js\",\n      \"types\": \"./dist/useDragEvents.d.ts\"\n    },\n    \"./useDrag\": {\n      \"import\": \"./dist/esm/useDrag.js\",\n      \"require\": \"./dist/useDrag.js\",\n      \"types\": \"./dist/useDrag.d.ts\"\n    },\n    \"./useDidMount\": {\n      \"import\": \"./dist/esm/useDidMount.js\",\n      \"require\": \"./dist/useDidMount.js\",\n      \"types\": \"./dist/useDidMount.d.ts\"\n    },\n    \"./useDefaultedState\": {\n      \"import\": \"./dist/esm/useDefaultedState.js\",\n      \"require\": \"./dist/useDefaultedState.js\",\n      \"types\": \"./dist/useDefaultedState.d.ts\"\n    },\n    \"./useDebouncedCallback\": {\n      \"import\": \"./dist/esm/useDebouncedCallback.js\",\n      \"require\": \"./dist/useDebouncedCallback.js\",\n      \"types\": \"./dist/useDebouncedCallback.d.ts\"\n    },\n    \"./useDarkMode\": {\n      \"import\": \"./dist/esm/useDarkMode.js\",\n      \"require\": \"./dist/useDarkMode.js\",\n      \"types\": \"./dist/useDarkMode.d.ts\"\n    },\n    \"./useCookie\": {\n      \"import\": \"./dist/esm/useCookie.js\",\n      \"require\": \"./dist/useCookie.js\",\n      \"types\": \"./dist/useCookie.d.ts\"\n    },\n    \"./useConditionalTimeout\": {\n      \"import\": \"./dist/esm/useConditionalTimeout.js\",\n      \"require\": \"./dist/useConditionalTimeout.js\",\n      \"types\": \"./dist/useConditionalTimeout.d.ts\"\n    },\n    \"./useAudio\": {\n      \"import\": \"./dist/esm/useAudio.js\",\n      \"require\": \"./dist/useAudio.js\",\n      \"types\": \"./dist/useAudio.d.ts\"\n    }\n  }\n}"
  },
  {
    "path": "scripts/commit-version.sh",
    "content": "#!/bin/bash\n\ncd ..\ngit add package.json\ngit commit -m \"chore(release): Updates package.json version to $1 [skip ci]\"\ngit push origin master\n"
  },
  {
    "path": "scripts/generate-doc-append-types.js",
    "content": "const fs = require('fs/promises')\nconst path = require('path')\nconst { globSync } = require('glob')\n\nconst docsPath = path.join(__dirname, '..', 'docs')\nconst distPath = path.join(__dirname, '..', 'dist')\nconst docFiles = globSync(`${docsPath}/*.md`)\n  .map((file) => file.replace(`${docsPath}/`, '').replace('.md', ''))\n  .filter((file) => file.startsWith('use'))\n\ndocFiles.forEach(async (hook) => {\n  const docPath = path.join(docsPath, `${hook}.md`)\n  const typeFile = path.join(distPath, `${hook}.d.ts`)\n\n  const declarations = await fs.readFile(typeFile, { encoding: 'utf8' })\n  const document = await fs.readFile(docPath, { encoding: 'utf8' })\n\n  if (document.match(/<!-- Types -->/g)) {\n    const cleared = emptyOldTypes(document).trim()\n    const nextDocument = cleared.replace('<!-- Types -->', template(declarations)).trim()\n\n    fs.writeFile(docPath, nextDocument, { encoding: 'utf8' }).then(() => {\n      console.log(`Updated \"${hook}\" types`)\n    })\n  }\n})\n\nconst template = (content) => `<!-- Types -->\n### Types\n    \n\\`\\`\\`typescript static\n${content}\n\\`\\`\\`\n<!-- Types:end -->\n`\n\nconst emptyOldTypes = (content) => {\n  const regex = /<!-- Types -->[\\s\\S]*<!-- Types:end -->/g\n\n  return `${content.replace(regex, '\\n').replace(/<!-- Types -->/g, '').trim()}\n\n<!-- Types -->\n`\n}\n"
  },
  {
    "path": "scripts/generate-exports.js",
    "content": "'use strict'\n\nconst fs = require('fs')\nconst path = require('path')\nconst { globSync } = require('glob')\n\nconst srcPath = path.join(__dirname, '..', 'src')\nconst pkgPath = path.join(__dirname, '..', 'package.json')\n\nconst srcFiles = globSync(`${srcPath}/*.ts`)\n  .map((file) => file.replace(`${srcPath}/`, '').replace('.ts', ''))\n  .filter((file) => file !== 'index')\n\nconst exportsObj = srcFiles.reduce((acc, file) => ({\n  ...acc,\n  [`./${file}`]: {\n    import: `./esm/${file}.js`,\n    require: `./${file}.js`,\n    types: `./${file}.d.ts`\n  }\n}), {})\n\nconst packageJsonText = fs.readFileSync(pkgPath)\nconst packageJson = JSON.parse(packageJsonText)\n\nconst nextPackageJson = { ...packageJson, exports: exportsObj }\n\nconsole.log('\\nUPDATING EXPORTS: ', Object.keys(exportsObj))\n\nfs.writeFileSync(pkgPath, JSON.stringify(nextPackageJson, null, 2))\n"
  },
  {
    "path": "scripts/update-version.js",
    "content": "'use strict'\n\nconst fs = require('fs')\nconst path = require('path')\n\nconst nextVersion = process.argv[2]\nconst pkgPath = path.join(__dirname, '..', 'package.json')\n\nconst packageJsonText = fs.readFileSync(pkgPath)\nconst packageJson = JSON.parse(packageJsonText)\n\nconst nextPackageJson = { ...packageJson, version: nextVersion }\n\nconsole.log('\\nUPDATING PACKAGE JSON VERSION TO: ', nextVersion)\n\nfs.writeFileSync(pkgPath, JSON.stringify(nextPackageJson, null, 2))\n"
  },
  {
    "path": "src/factory/createHandlerSetter.ts",
    "content": "import { type RefObject, useRef } from 'react'\nimport { type CallbackSetter, type SomeCallback } from '../shared/types.ts'\n\n/**\n * Returns an array where the first item is the [ref](https://reactjs.org/docs/hooks-reference.html#useref) to a\n * callback function and the second one is a reference to a function for can change the first ref.\n *\n * Although it looks quite similar to [useState](https://reactjs.org/docs/hooks-reference.html#usestate),\n * in this case the setter just makes sure the given callback is indeed a new function.\n * **Setting a callback ref does not force your component to re-render.**\n *\n * `createHandlerSetter` is meant to be used internally to abstracting other hooks.\n * Don't use this function to abstract hooks outside this library as it changes quite often\n */\nconst createHandlerSetter = <TArgs, TResult = void>(callback?: SomeCallback<TArgs, TResult>) => {\n  const handlerRef = useRef(callback)\n\n  const setHandler = useRef((nextCallback: SomeCallback<TArgs, TResult>) => {\n    if (typeof nextCallback !== 'function') {\n      throw new Error('the argument supplied to the \\'setHandler\\' function should be of type function')\n    }\n\n    handlerRef.current = nextCallback\n  })\n\n  return [handlerRef, setHandler.current] as [RefObject<SomeCallback<TArgs, TResult>>, CallbackSetter<TArgs>]\n}\n\nexport default createHandlerSetter\n"
  },
  {
    "path": "src/factory/createStorageHook.ts",
    "content": "import { useCallback, useState } from 'react'\nimport safelyParseJson from '../shared/safelyParseJson.ts'\nimport isClient from '../shared/isClient.ts'\nimport isAPISupported from '../shared/isAPISupported.ts'\nimport isDevelopment from '../shared/isDevelopment.ts'\nimport noop from '../shared/noop.ts'\nimport warnOnce from '../shared/warnOnce.ts'\n\n/**\n * A utility to quickly create hooks to access both Session Storage and Local Storage\n */\nconst createStorageHook = (type: 'session' | 'local') => {\n  type SetValue<TValue> = (value: TValue | ((previousValue: TValue) => TValue)) => void\n  const storageName: `${typeof type}Storage` = `${type}Storage`\n\n  if (isClient && !isAPISupported(storageName)) {\n    warnOnce(`${storageName} is not supported`)\n  }\n\n  /**\n   * the hook\n   */\n  return function useStorageCreatedHook<TValue> (storageKey: string, defaultValue?: any): [TValue | null, SetValue<TValue>] {\n    if (!isClient) {\n      if (isDevelopment) {\n        warnOnce(`Please be aware that ${storageName} could not be available during SSR`)\n      }\n      return [JSON.stringify(defaultValue) as unknown as TValue, noop]\n    }\n    const storage = (window)[storageName]\n\n    const safelySetStorage = useCallback((valueToStore: string) => {\n      try {\n        storage.setItem(storageKey, valueToStore)\n        // eslint-disable-next-line no-empty\n      } catch (e) {\n      }\n    }, [storage, storageKey])\n\n    const [storedValue, setStoredValue] = useState<TValue | null>(\n      () => {\n        let valueToStore: string\n        try {\n          valueToStore = storage.getItem(storageKey) ?? JSON.stringify(defaultValue)\n        } catch (e) {\n          valueToStore = JSON.stringify(defaultValue)\n        }\n\n        safelySetStorage(valueToStore)\n        return safelyParseJson(valueToStore)\n      }\n    )\n\n    const setValue: SetValue<TValue> = useCallback(\n      (value: TValue) => {\n        setStoredValue((current: TValue) => {\n          const valueToStore = value instanceof Function ? value(current) : value\n          safelySetStorage(JSON.stringify(valueToStore))\n          return valueToStore\n        })\n      },\n      [safelySetStorage]\n    )\n\n    return [storedValue, setValue]\n  }\n}\n\nexport default createStorageHook\n"
  },
  {
    "path": "src/shared/geolocationUtils.ts",
    "content": "import { type BRHGeolocationPosition } from './types.ts'\n\nexport const geoStandardOptions: PositionOptions = Object.freeze({\n  enableHighAccuracy: false,\n  timeout: 0xFFFFFFFF,\n  maximumAge: 0\n})\n\n/**\n * Checks if two position are equals\n */\nexport const isSamePosition = (current: BRHGeolocationPosition, next: BRHGeolocationPosition): boolean => {\n  if (!current || !next || !next.coords) return false\n  if (current.timestamp && next.timestamp && current.timestamp !== next.timestamp) return false\n\n  return (\n    (current.coords.latitude === next.coords.latitude) &&\n    (current.coords.longitude === next.coords.longitude) &&\n    (current.coords.altitude === next.coords.altitude) &&\n    (current.coords.accuracy === next.coords.accuracy) &&\n    (current.coords.altitudeAccuracy === next.coords.altitudeAccuracy) &&\n    (current.coords.heading === next.coords.heading) &&\n    (current.coords.speed === next.coords.speed)\n  )\n}\n\n/**\n * Given a position object returns only its properties\n */\nexport const makePositionObj = (position: BRHGeolocationPosition) => (!position\n  ? null\n  : ({\n      timestamp: position.timestamp,\n      coords: {\n        latitude: position.coords.latitude,\n        longitude: position.coords.longitude,\n        altitude: position.coords.altitude,\n        accuracy: position.coords.accuracy,\n        altitudeAccuracy: position.coords.altitudeAccuracy,\n        heading: position.coords.heading,\n        speed: position.coords.speed\n      }\n    }))\n"
  },
  {
    "path": "src/shared/isAPISupported.ts",
    "content": "/**\n * Exports a boolean value reporting whether the given API is supported or not\n */\nconst isApiSupported = (api: string): boolean => (typeof window !== 'undefined' ? api in window : false)\n\nexport default isApiSupported\n"
  },
  {
    "path": "src/shared/isClient.ts",
    "content": "/**\n * Exports a boolean value reporting whether is client side or server side by checking on the window object\n */\nconst isClient = !!(\n  typeof window !== 'undefined' && window.document && window.document.createElement\n)\n\nexport default isClient\n"
  },
  {
    "path": "src/shared/isDevelopment.ts",
    "content": "const isDevelopment = (\n  typeof process !== 'undefined' && typeof process.env !== 'undefined' && (!process.env.NODE_ENV || process.env.NODE_ENV === 'development')\n)\n\nexport default isDevelopment\n"
  },
  {
    "path": "src/shared/isFunction.ts",
    "content": "type SomeFunction = (...args: any[]) => any\n\nconst isFunction = (functionToCheck: unknown): functionToCheck is SomeFunction => (\n  typeof functionToCheck === 'function' &&\n  !!functionToCheck.constructor &&\n  !!functionToCheck.call &&\n  !!functionToCheck.apply\n)\n\nexport default isFunction\n"
  },
  {
    "path": "src/shared/noop.ts",
    "content": "import { type Noop } from './types.ts'\n\n/* eslint-disable-next-line @typescript-eslint/no-unused-vars */\nconst noop: Noop = (...args: any[]) => undefined\n\nnoop.noop = true\n\nexport default noop\n"
  },
  {
    "path": "src/shared/safeHasOwnProperty.ts",
    "content": "const safeHasOwnProperty = (obj: any, prop: string): boolean => (obj ? Object.prototype.hasOwnProperty.call(obj, prop) : false)\n\nexport default safeHasOwnProperty\n"
  },
  {
    "path": "src/shared/safelyParseJson.ts",
    "content": "/**\n * Safely parse JSON string to object or null\n * @param parseString\n */\nconst safelyParseJson = <T = any>(parseString: string): T | null => {\n  try {\n    return JSON.parse(parseString)\n  } catch (e) {\n    return null\n  }\n}\n\nexport default safelyParseJson\n"
  },
  {
    "path": "src/shared/swipeUtils.ts",
    "content": "/**\n * Takes a mouse or a touch events and returns clientX and clientY values\n * @param event\n * @return {[undefined, undefined]}\n */\nexport const getPointerCoordinates = (event: TouchEvent | MouseEvent): [number, number] => {\n  if ((event as TouchEvent).touches) {\n    const { clientX, clientY } = (event as TouchEvent).touches[0]\n    return [clientX, clientY]\n  }\n\n  const { clientX, clientY } = event as MouseEvent\n\n  return [clientX, clientY]\n}\n\nexport const getHorizontalDirection = (alpha: number) => (alpha < 0 ? 'right' : 'left')\n\nexport const getVerticalDirection = (alpha: number) => (alpha < 0 ? 'down' : 'up')\n\nexport type Direction = 'right' | 'left' | 'down' | 'up'\n\nexport const getDirection = (currentPoint: [number, number], startingPoint: [number, number], alpha: [number, number]): Direction => {\n  const alphaX = startingPoint[0] - currentPoint[0]\n  const alphaY = startingPoint[1] - currentPoint[1]\n  if (Math.abs(alphaX) > Math.abs(alphaY)) {\n    return getHorizontalDirection(alpha[0])\n  }\n\n  return getVerticalDirection(alpha[1])\n}\n"
  },
  {
    "path": "src/shared/types.ts",
    "content": "export interface Noop {\n  noop: true\n\n  (...args: any[]): any\n}\n\n/**\n * Represent a generic function.\n * Used internally to improve code readability\n */\nexport type GenericFunction = (...args: any[]) => any\n\n/**\n * Typed generic callback function, used mostly internally\n * to defined callback setters\n */\nexport type SomeCallback<TArgs, TResult = void> = (...args: TArgs[]) => TResult\n\n/**\n * A callback setter is generally used to set the value of\n * a callback that will be used to perform updates\n */\nexport type CallbackSetter<TArgs> = (nextCallback: SomeCallback<TArgs>) => void\n\n/**\n * This type is used internally to avoid using directly GeolocationPosition\n * as that type is not always compatible with all typescript versions\n */\nexport interface BRHGeolocationPosition {\n  readonly timestamp: number\n  readonly coords: {\n    readonly accuracy: number\n    readonly altitude: number | null\n    readonly altitudeAccuracy: number | null\n    readonly heading: number | null\n    readonly latitude: number\n    readonly longitude: number\n    readonly speed: number | null\n  }\n}\n\n/**\n * This type is used internally to avoid using directly GeolocationPositionError\n * as that type is not always compatible with all typescript versions\n */\nexport interface BRHGeolocationPositionError {\n  readonly code: number\n  readonly message: string\n  readonly PERMISSION_DENIED: number\n  readonly POSITION_UNAVAILABLE: number\n  readonly TIMEOUT: number\n}\n"
  },
  {
    "path": "src/shared/warnOnce.ts",
    "content": "const cache = new Map()\n\n/**\n * A tiny wrapper around console.warn that makes sure the message is only displayed once.\n * Used mainly to avoid polluting server side logs\n * @param message\n */\nconst warnOnce = (message: string) => {\n  if (cache.has(message)) return\n\n  cache.set(message, true)\n\n  // eslint-disable-next-line no-console\n  console.warn(message)\n}\n\nexport default warnOnce\n"
  },
  {
    "path": "src/useAudio.ts",
    "content": "import { type MutableRefObject, useCallback, useEffect, useRef } from 'react'\nimport noop from './shared/noop.ts'\nimport isClient from './shared/isClient.ts'\nimport useObjectState from './useObjectState.ts'\nimport isDevelopment from './shared/isDevelopment.ts'\nimport isAPISupported from './shared/isAPISupported.ts'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\n/**\n * The default options for the useAudio hook\n */\nconst defaultOptions: Required<UseAudioOptions> = {\n  volume: 1,\n  loop: false,\n  muted: false,\n  playbackRate: 1,\n  autoPlay: false,\n  preload: 'auto'\n}\n\n/**\n * The default state for the useAudio hook\n */\nconst defaultState: AudioState = {\n  duration: 0,\n  currentTime: 0,\n  isPlaying: false,\n  isSrcLoading: undefined,\n  ...defaultOptions\n}\n\n/**\n * The error event code to message mapper\n */\nconst errorEventCodeToMessageMapper: Record<number, string> = {\n  3: 'MEDIA_ERR_DECODE - error occurred when decoding',\n  4: 'MEDIA_ERR_SRC_NOT_SUPPORTED - audio not supported',\n  2: 'MEDIA_ERR_NETWORK - error occurred when downloading',\n  1: 'MEDIA_ERR_ABORTED - fetching process aborted by user',\n  0: 'UNKNOWN_ERROR - unknown error'\n}\n\n/**\n * The hook not supported controls\n */\nconst hookNotSupportedControls: AudioControls = Object.freeze({\n  seek: noop,\n  play: noop,\n  mute: noop,\n  pause: noop,\n  unmute: noop,\n  onError: noop,\n  setVolume: noop\n})\n\n/**\n * Checks if the ref element exists and calls the callback with it\n * @param ref\n * @param callback\n */\nconst checkIfRefElementExists = <TElement>(ref: MutableRefObject<TElement>, callback: (element: TElement) => unknown) => () => {\n  const element = ref.current\n\n  if (!element) {\n    return undefined\n  }\n\n  return callback(element)\n}\n\n/**\n * The useAudio hook wraps the Audio API and provides a set of controls to manage the audio\n */\nexport const useAudio = (src: string, options?: UseAudioOptions) => {\n  const hookNotSupportedResponse = [\n    defaultState,\n    hookNotSupportedControls,\n    useRef<HTMLAudioElement | null>(null)\n  ]\n\n  if (!isClient) {\n    if (!isDevelopment) {\n      warnOnce('Please be aware that useAudio hook could not be available during SSR')\n    }\n\n    return hookNotSupportedResponse as [AudioState, Readonly<AudioControls>, MutableRefObject<HTMLAudioElement>]\n  }\n\n  if (!isAPISupported('Audio')) {\n    warnOnce('The current device does not support the \\'Audio\\' API, you should avoid using useAudio hook')\n\n    return hookNotSupportedResponse as [AudioState, Readonly<AudioControls>, MutableRefObject<HTMLAudioElement>]\n  }\n\n  const audioRef = useRef<HTMLAudioElement>(new Audio(src))\n  const [onErrorRef, setOnErrorRef] = createHandlerSetter<Error>()\n\n  const [state, setState] = useObjectState<AudioState>(defaultState)\n\n  const onError = (error: Error) => {\n    if (onErrorRef.current != null) {\n      onErrorRef.current(error)\n    }\n  }\n\n  const play = useCallback(\n    checkIfRefElementExists(audioRef, async (element) => {\n      await element\n        .play()\n        .then(() => {\n          setState({\n            isPlaying: true\n          })\n        })\n        .catch(onError)\n    }),\n    []\n  )\n\n  const pause = useCallback(\n    checkIfRefElementExists(audioRef, (element) => {\n      element.pause()\n\n      setState({\n        isPlaying: false\n      })\n    }),\n    []\n  )\n\n  const mute = useCallback(\n    checkIfRefElementExists(audioRef, (element) => {\n      // eslint-disable-next-line no-param-reassign\n      element.muted = true\n\n      setState({\n        muted: true\n      })\n    }),\n    []\n  )\n\n  const unmute = useCallback(\n    checkIfRefElementExists(audioRef, (element) => {\n      // eslint-disable-next-line no-param-reassign\n      element.muted = false\n\n      setState({\n        muted: false\n      })\n    }),\n    []\n  )\n\n  const seek = useCallback(\n    (time: number) => checkIfRefElementExists(audioRef, (element) => {\n      const newTime = time >= 0 ? Math.min(time, element.duration) : Math.max(time, 0)\n\n      // eslint-disable-next-line no-param-reassign\n      element.currentTime = newTime\n\n      setState({\n        currentTime: newTime\n      })\n    })(),\n    []\n  )\n\n  const setVolume = useCallback(\n    (volume: number) => checkIfRefElementExists(audioRef, (element) => {\n      const newVolume = volume >= 0 ? Math.min(volume, 1) : Math.max(volume, 0)\n\n      // eslint-disable-next-line no-param-reassign\n      element.volume = newVolume\n\n      setState({\n        volume: newVolume\n      })\n    })(),\n    []\n  )\n\n  const onLoadedData = checkIfRefElementExists(audioRef, (element) => {\n    setState({\n      isSrcLoading: false,\n      duration: element.duration,\n      currentTime: element.currentTime\n    })\n  })\n\n  const onTimeUpdate = checkIfRefElementExists(audioRef, (element) => {\n    setState({\n      currentTime: element.currentTime\n    })\n  })\n\n  const errorEventCallback = () => {\n    const element = audioRef.current\n    const errorCode = element.error?.code\n    const errorMessage = (element.error?.message ?? errorEventCodeToMessageMapper[errorCode ?? 0]) || 'UNKNOWN'\n\n    onError(new Error(errorMessage))\n  }\n\n  useEffect(() => {\n    const element = audioRef.current\n\n    if (element) {\n      const mergedOptions = { ...defaultOptions, ...options }\n\n      element.loop = mergedOptions.loop\n      element.muted = mergedOptions.muted\n      element.volume = mergedOptions.volume\n      element.preload = mergedOptions.preload\n      element.autoplay = mergedOptions.autoPlay\n      element.playbackRate = mergedOptions.playbackRate\n\n      setState({\n        ...mergedOptions,\n        isSrcLoading: true\n      })\n\n      element.addEventListener('loadeddata', onLoadedData)\n      element.addEventListener('timeupdate', onTimeUpdate)\n      element.addEventListener('error', errorEventCallback)\n    }\n\n    return () => {\n      if (element) {\n        element.removeEventListener('loadeddata', onLoadedData)\n        element.removeEventListener('timeupdate', onTimeUpdate)\n        element.removeEventListener('error', errorEventCallback)\n      }\n      pause()\n    }\n  }, [])\n\n  useEffect(() => {\n    if (state.isSrcLoading === false && state.autoPlay) {\n      play()\n    }\n  }, [state.isSrcLoading, state.autoPlay])\n\n  const controls = Object.freeze<AudioControls>({\n    seek,\n    play,\n    mute,\n    pause,\n    unmute,\n    setVolume,\n    onError: setOnErrorRef\n  })\n\n  return [state, controls, audioRef] as [AudioState, Readonly<AudioControls>, MutableRefObject<HTMLAudioElement>]\n}\n\ntype UseAudioPreloadType = 'auto' | 'metadata' | 'none';\n\n/**\n * The interface for the state of the useAudio hook\n */\nexport interface AudioState {\n  loop: boolean\n  muted: boolean\n  volume: number\n  duration: number\n  autoPlay: boolean\n  isPlaying: boolean\n  preload?: UseAudioPreloadType\n  currentTime: number\n  playbackRate: number\n  isSrcLoading: boolean | undefined\n}\n\n/**\n * The interface for the options of the useAudio hook\n */\nexport interface UseAudioOptions {\n  loop?: boolean\n  muted?: boolean\n  volume?: number\n  autoPlay?: boolean\n  preload?: UseAudioPreloadType\n  playbackRate?: number\n}\n\n/**\n * The interface for the controls of the useAudio hook\n */\nexport interface AudioControls {\n  play: () => void\n  mute: () => void\n  pause: () => void\n  unmute: () => void\n  seek: (time: number) => void\n  onError: (onError: ((error: Error) => void)) => void\n  setVolume: (volume: number) => void\n}\n\nexport default useAudio\n"
  },
  {
    "path": "src/useConditionalTimeout.ts",
    "content": "import { useCallback, useEffect, useRef, useState } from 'react'\nimport isFunction from './shared/isFunction.ts'\nimport { type GenericFunction } from './shared/types.ts'\nimport usePreviousValue from './usePreviousValue.ts'\n\n/**\n * An async-utility hook that accepts a callback function and a delay time (in milliseconds), then delays the\n * execution of the given function by the defined time from when the condition verifies.\n */\nconst useConditionalTimeout = <TCallback extends GenericFunction>\n  (fn: TCallback, milliseconds: number, condition: boolean, options: UseConditionalTimeoutOptios = defaultOptions) => {\n  const opts = { ...defaultOptions, ...(options || {}) }\n  const timeout = useRef<any>()\n  const callback = useRef(fn)\n  const [isCleared, setIsCleared] = useState(false)\n  const prevCondition = usePreviousValue(condition)\n\n  // the clear method\n  const clear = useCallback(() => {\n    if (timeout.current) {\n      clearTimeout(timeout.current)\n      setIsCleared(true)\n    }\n  }, [])\n\n  // if the provided function changes, change its reference\n  useEffect(() => {\n    if (isFunction(fn)) {\n      callback.current = fn\n    }\n  }, [fn])\n\n  // when the milliseconds change, reset the timeout\n  useEffect(() => {\n    if (condition && typeof milliseconds === 'number') {\n      timeout.current = setTimeout(() => {\n        callback.current()\n      }, milliseconds)\n    }\n  }, [condition, milliseconds])\n\n  // when the condition change, clear the timeout\n  useEffect(() => {\n    if (prevCondition && condition !== prevCondition && opts.cancelOnConditionChange) {\n      clear()\n    }\n  }, [condition, options])\n\n  // when component unmount clear the timeout\n  useEffect(() => () => {\n    if (opts.cancelOnUnmount) {\n      clear()\n    }\n  }, [])\n\n  return [isCleared, clear] as UseConditionalTimeoutReturn\n}\n\nexport interface UseConditionalTimeoutOptios {\n  cancelOnUnmount?: boolean\n  cancelOnConditionChange?: boolean\n}\n\nconst defaultOptions: UseConditionalTimeoutOptios = {\n  cancelOnUnmount: true,\n  cancelOnConditionChange: true\n}\n\nexport type UseConditionalTimeoutReturn = [boolean, () => void]\n\nexport default useConditionalTimeout\n"
  },
  {
    "path": "src/useCookie.ts",
    "content": "import { useCallback, useEffect, useState } from 'react'\nimport noop from './shared/noop.ts'\nimport isClient from './shared/isClient.ts'\nimport isDevelopment from './shared/isDevelopment.ts'\nimport isAPISupported from './shared/isAPISupported.ts'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport warnOnce from './shared/warnOnce.ts'\nimport { type CallbackSetter } from './shared/types.ts'\n\nconst useCookie = (key: string, options?: UseCookieOptions) => {\n  const hookNotSupportedResponse = Object.freeze<UseCookieReturn>({\n    onError: noop,\n    updateCookie: noop,\n    deleteCookie: noop,\n    cookieValue: options?.defaultValue\n  })\n\n  if (!isClient) {\n    if (!isDevelopment) {\n      warnOnce('Please be aware that cookieStore could not be available during SSR')\n    }\n\n    return hookNotSupportedResponse\n  }\n\n  if (!isAPISupported('cookieStore')) {\n    warnOnce('The current device does not support the \\'cookieStore\\' API, you should avoid using useCookie')\n\n    return hookNotSupportedResponse\n  }\n\n  const [cookieValue, setCookieValue] = useState<string>()\n  const [onErrorRef, setOnErrorRef] = createHandlerSetter<Error>()\n\n  const cookieStoreObject = (window as any).cookieStore as CookieStore\n\n  const onError = (err: Error) => {\n    if (onErrorRef.current != null) {\n      onErrorRef.current(err)\n    }\n  }\n\n  useEffect(() => {\n    const getInitialValue = async () => {\n      try {\n        const getFunctionResult = await cookieStoreObject.get(key)\n\n        if (getFunctionResult?.value) {\n          setCookieValue(getFunctionResult.value)\n          return\n        }\n\n        await cookieStoreObject.set({\n          name: key,\n          value: options?.defaultValue,\n          ...options\n        })\n        setCookieValue(options?.defaultValue)\n        return\n      } catch (err) {\n        onError(err)\n      }\n    }\n\n    getInitialValue().catch(onError)\n  }, [])\n\n  const updateCookie = useCallback(\n    async (newValue: string) => {\n      await cookieStoreObject\n        .set({ name: key, value: newValue, ...options })\n        .then(() => {\n          setCookieValue(newValue)\n        })\n        .catch(onError)\n    },\n    []\n  )\n\n  const deleteCookie = useCallback(\n    async () => {\n      await cookieStoreObject\n        .delete({ name: key, ...options })\n        .then(() => {\n          setCookieValue(undefined)\n        })\n        .catch(onError)\n    },\n    []\n  )\n\n  return Object.freeze<UseCookieReturn>({\n    cookieValue,\n    updateCookie,\n    deleteCookie,\n    onError: setOnErrorRef\n  })\n}\n\nexport enum CookieSameSite {\n  STRICT = 'strict',\n  LAX = 'lax',\n  NONE = 'none',\n}\n\ninterface CookieStoreDeleteOptions {\n  name?: string\n  domain?: string\n  path?: string\n}\n\ninterface CookieBase extends CookieStoreDeleteOptions {\n  sameSite?: CookieSameSite\n}\n\ninterface CookieBaseWithNameAndValue extends CookieBase {\n  name?: string\n  value?: string\n}\n\nexport interface UseCookieOptions extends CookieBase {\n  defaultValue?: string\n}\n\ninterface CookieStore {\n  get: (key: string) => Promise<CookieBaseWithNameAndValue>\n  set: (options: CookieBaseWithNameAndValue) => Promise<void>\n  delete: (options: CookieStoreDeleteOptions) => Promise<void>\n}\n\nexport interface UseCookieReturn {\n  cookieValue?: string\n  updateCookie: (nextValue: string) => Promise<void>\n  deleteCookie: () => Promise<void>\n  onError: CallbackSetter<Error>\n}\n\nexport default useCookie\n"
  },
  {
    "path": "src/useDarkMode.ts",
    "content": "import { useCallback } from 'react'\nimport useMediaQuery from './useMediaQuery.ts'\nimport useUpdateEffect from './useUpdateEffect.ts'\nimport useLocalStorage from './useLocalStorage.ts'\nimport noop from './shared/noop.ts'\nimport isClient from './shared/isClient.ts'\nimport isDevelopment from './shared/isDevelopment.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\nconst COLOR_SCHEME_QUERY = '(prefers-color-scheme: dark)'\nexport const LOCAL_STORAGE_KEY = 'beautiful-react-hooks-is-dark-mode'\n\nconst useDarkMode = (defaultValue?: boolean, localStorageKey: string = LOCAL_STORAGE_KEY) => {\n  if (!isClient) {\n    if (!isDevelopment) {\n      warnOnce('Please be aware that useDarkMode hook could not be available during SSR')\n    }\n\n    return Object.freeze<UseDarkModeReturn>({\n      toggle: noop,\n      enable: noop,\n      disable: noop,\n      isDarkMode: defaultValue ?? false\n    })\n  }\n\n  const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY)\n  const [isDarkMode, setIsDarkMode] = useLocalStorage<boolean>(\n    localStorageKey,\n    defaultValue ?? isDarkOS ?? false\n  )\n\n  useUpdateEffect(() => {\n    setIsDarkMode(isDarkOS)\n  }, [isDarkOS])\n\n  const enable = useCallback(() => {\n    setIsDarkMode(true)\n  }, [])\n\n  const disable = useCallback(() => {\n    setIsDarkMode(false)\n  }, [])\n\n  const toggle = useCallback(() => {\n    setIsDarkMode((prev) => !prev)\n  }, [setIsDarkMode])\n\n  return Object.freeze<UseDarkModeReturn>({\n    toggle,\n    enable,\n    disable,\n    isDarkMode: isDarkMode ?? false\n  })\n}\n\nexport interface UseDarkModeReturn {\n  isDarkMode: boolean\n  toggle: () => void\n  enable: () => void\n  disable: () => void\n}\n\nexport default useDarkMode\n"
  },
  {
    "path": "src/useDebouncedCallback.ts",
    "content": "import { type DependencyList, useCallback, useEffect, useRef } from 'react'\nimport debounce from 'lodash.debounce'\nimport { type GenericFunction } from './shared/types.ts'\nimport useWillUnmount from './useWillUnmount.ts'\n\nexport interface DebounceOptions {\n  leading?: boolean | undefined\n  maxWait?: number | undefined\n  trailing?: boolean | undefined\n}\n\nconst defaultOptions: DebounceOptions = {\n  leading: false,\n  trailing: true\n}\n\n/**\n * Accepts a function and returns a new debounced yet memoized version of that same function that delays\n * its invoking by the defined time.\n * If time is not defined, its default value will be 250ms.\n */\nconst useDebouncedCallback = <TCallback extends GenericFunction>\n  (fn: TCallback, dependencies: DependencyList = [], wait: number = 600, options: DebounceOptions = defaultOptions) => {\n  const debounced = useRef(debounce<TCallback>(fn, wait, options))\n\n  useEffect(() => {\n    debounced.current = debounce(fn, wait, options)\n  }, [fn, wait, options, ...dependencies])\n\n  useWillUnmount(() => {\n    debounced.current?.cancel()\n  })\n\n  return useCallback((...args: Parameters<TCallback>) => debounced.current(...args), [...dependencies])\n}\n\nexport default useDebouncedCallback\n"
  },
  {
    "path": "src/useDefaultedState.ts",
    "content": "import { useCallback, useState } from 'react'\n\nconst maybeState = <TValue>(state: TValue, defaultValue?: TValue) => (state ?? defaultValue) as TValue\n\n/**\n * Returns a safe state by making sure the given value is not null or undefined\n */\nconst useDefaultedState = <TValue>(defaultValue: TValue, initialState?: TValue) => {\n  const [state, setState] = useState<TValue>(maybeState(initialState, defaultValue) as TValue)\n\n  const setStateSafe = useCallback((nextState: TValue) => {\n    setState(maybeState(nextState, defaultValue))\n  }, [setState])\n\n  return [maybeState(state, defaultValue), setStateSafe] as [TValue, typeof setStateSafe]\n}\n\nexport default useDefaultedState\n"
  },
  {
    "path": "src/useDidMount.ts",
    "content": "import { useEffect, useRef } from 'react'\nimport isFunction from './shared/isFunction.ts'\nimport { type GenericFunction, type Noop } from './shared/types.ts'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\n\n/**\n * Returns a callback setter for a function to be performed when the component did mount.\n */\nconst useDidMount = <TCallback extends GenericFunction = Noop>(callback?: TCallback) => {\n  const mountRef = useRef(false)\n  const [handler, setHandler] = createHandlerSetter<undefined>(callback)\n\n  useEffect(() => {\n    if (isFunction(handler?.current) && !mountRef.current) {\n      handler.current()\n      mountRef.current = true\n    }\n  }, [])\n\n  return setHandler\n}\n\nexport default useDidMount\n"
  },
  {
    "path": "src/useDrag.ts",
    "content": "import { type RefObject, useState } from 'react'\nimport useDragEvents from './useDragEvents.ts'\n\nexport interface UseDragOptions {\n  dragImage?: string\n  dragImageXOffset?: number\n  dragImageYOffset?: number\n  transfer?: string | number | Record<string, any>\n  transferFormat?: string\n}\n\nconst defaultOptions: UseDragOptions = {\n  dragImageXOffset: 0,\n  dragImageYOffset: 0,\n  transferFormat: 'text'\n}\n\nconst useDrag = <TElement extends HTMLElement>(targetRef: RefObject<TElement>, options = defaultOptions) => {\n  const { onDragStart, onDragEnd } = useDragEvents<TElement>(targetRef, true)\n  const [isDragging, setIsDragging] = useState(false)\n  const opts: UseDragOptions = { ...defaultOptions, ...(options || {}) }\n\n  onDragStart((event: DragEvent) => {\n    setIsDragging(true)\n\n    if (opts.dragImage && event.dataTransfer) {\n      const img = new Image()\n      img.src = opts.dragImage\n      event.dataTransfer.setDragImage(img, opts.dragImageXOffset ?? 0, opts.dragImageYOffset ?? 0)\n    }\n\n    if (opts.transfer && event.dataTransfer) {\n      const data = typeof opts.transfer === 'object' ? JSON.stringify(opts.transfer) : `${opts.transfer}`\n      event.dataTransfer.setData(opts.transferFormat ?? 'text', data)\n    }\n  })\n\n  onDragEnd(() => {\n    setIsDragging(false)\n  })\n\n  return isDragging\n}\n\nexport default useDrag\n"
  },
  {
    "path": "src/useDragEvents.ts",
    "content": "import { type RefObject, useEffect } from 'react'\nimport safeHasOwnProperty from './shared/safeHasOwnProperty.ts'\nimport useEvent from './useEvent.ts'\nimport { type CallbackSetter } from './shared/types.ts'\n\nexport interface UseDragEventsResult {\n  onDrag: CallbackSetter<DragEvent>\n  onDrop: CallbackSetter<DragEvent>\n  onDragEnter: CallbackSetter<DragEvent>\n  onDragEnd: CallbackSetter<DragEvent>\n  onDragExit: CallbackSetter<DragEvent>\n  onDragLeave: CallbackSetter<DragEvent>\n  onDragOver: CallbackSetter<DragEvent>\n  onDragStart: CallbackSetter<DragEvent>\n}\n\n/**\n * Returns an object of callback setters to handle the drag-related events.\n * It accepts a DOM ref representing the events target (where attach the events to).\n *\n * Returned callback setters: `onDrag`, `onDrop`, `onDragEnter`, `onDragEnd`, `onDragExit`, `onDragLeave`,\n * `onDragOver`, `onDragStart`;\n */\nconst useDragEvents = <TElement extends HTMLElement>(targetRef: RefObject<TElement>, isDraggable: boolean = true) => {\n  const onDrag = useEvent<DragEvent, TElement>(targetRef, 'drag')\n  const onDrop = useEvent<DragEvent, TElement>(targetRef, 'drop')\n  const onDragEnter = useEvent<DragEvent, TElement>(targetRef, 'dragenter')\n  const onDragEnd = useEvent<DragEvent, TElement>(targetRef, 'dragend')\n  const onDragExit = useEvent<DragEvent, TElement>(targetRef, 'dragexit')\n  const onDragLeave = useEvent<DragEvent, TElement>(targetRef, 'dragleave')\n  const onDragOver = useEvent<DragEvent, TElement>(targetRef, 'dragover')\n  const onDragStart = useEvent<DragEvent, TElement>(targetRef, 'dragstart')\n\n  if (targetRef !== null && !safeHasOwnProperty(targetRef, 'current')) {\n    throw new Error('Unable to assign any drag event to the given ref')\n  }\n\n  useEffect(() => {\n    if (isDraggable && targetRef.current && !targetRef.current.hasAttribute('draggable')) {\n      targetRef.current.setAttribute('draggable', String(true))\n    }\n  }, [])\n\n  return Object.freeze<UseDragEventsResult>({\n    onDrag,\n    onDrop,\n    onDragEnter,\n    onDragEnd,\n    onDragExit,\n    onDragLeave,\n    onDragOver,\n    onDragStart\n  })\n}\n\nexport default useDragEvents\n"
  },
  {
    "path": "src/useDropZone.ts",
    "content": "import { type RefObject, useState } from 'react'\nimport useDragEvents from './useDragEvents.ts'\nimport { type CallbackSetter } from './shared/types.ts'\n\nexport interface UseDropZoneResult {\n  readonly isOver: boolean\n  readonly onDrop: CallbackSetter<DragEvent>\n}\n\nconst useDropZone = <TElement extends HTMLElement>(targetRef: RefObject<TElement>) => {\n  const { onDrop, onDragOver, onDragLeave } = useDragEvents<TElement>(targetRef, false)\n  const [isOver, setIsOver] = useState(false)\n\n  onDragOver((event: DragEvent) => {\n    event.preventDefault()\n    setIsOver(true)\n  })\n\n  onDragLeave(() => {\n    setIsOver(false)\n  })\n\n  return Object.freeze<UseDropZoneResult>({\n    isOver,\n    onDrop\n  })\n}\n\nexport default useDropZone\n"
  },
  {
    "path": "src/useEvent.ts",
    "content": "import { type RefObject, useEffect } from 'react'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport safeHasOwnProperty from './shared/safeHasOwnProperty.ts'\n\n/**\n * Accepts the reference to an HTML Element and an event name then performs the necessary operations to listen to the event\n * when fired from that HTML Element.\n */\nconst useEvent = <TEvent extends Event, TElement extends HTMLElement = HTMLElement>\n  (target: RefObject<TElement>, eventName: string, options?: AddEventListenerOptions) => {\n  const [handler, setHandler] = createHandlerSetter<TEvent>()\n\n  if (!!target && !safeHasOwnProperty(target, 'current')) {\n    throw new Error('Unable to assign any scroll event to the given ref')\n  }\n\n  useEffect(() => {\n    const cb: EventListenerOrEventListenerObject = (event: TEvent) => {\n      if (handler.current) {\n        handler.current(event)\n      }\n    }\n\n    if (target.current?.addEventListener && handler.current) {\n      target.current.addEventListener(eventName, cb, options)\n    }\n\n    return () => {\n      if (target.current?.addEventListener && handler.current) {\n        target.current.removeEventListener(eventName, cb, options)\n      }\n    }\n  }, [eventName, target.current, options])\n\n  return setHandler\n}\n\nexport default useEvent\n"
  },
  {
    "path": "src/useGeolocation.ts",
    "content": "import useGeolocationState, { type UseGeolocationStateResult } from './useGeolocationState.ts'\nimport useGeolocationEvents, { type UseGeolocationEventsResult } from './useGeolocationEvents.ts'\nimport { geoStandardOptions } from './shared/geolocationUtils.ts'\n\n/**\n * Returns an array where the first item is the geolocation state from the `useGeolocationState` hook and the\n * second one is the object of callback setters from the `useGeolocationEvents` hook.\n * It is intended as a shortcut to those hooks.\n */\nconst useGeolocation = (options: PositionOptions = geoStandardOptions) => {\n  const state = useGeolocationState(options)\n  const events = useGeolocationEvents(options)\n\n  return [state, events] as [UseGeolocationStateResult, UseGeolocationEventsResult]\n}\n\nexport default useGeolocation\n"
  },
  {
    "path": "src/useGeolocationEvents.ts",
    "content": "import { useEffect, useMemo, useRef } from 'react'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport { geoStandardOptions } from './shared/geolocationUtils.ts'\nimport { type BRHGeolocationPosition, type BRHGeolocationPositionError } from './shared/types.ts'\n\nexport interface UseGeolocationEventsResult {\n  isSupported: boolean\n  onChange: (callback: (position: BRHGeolocationPosition) => void) => void\n  onError: (callback: (error: BRHGeolocationPositionError) => void) => void\n}\n\n/**\n * Returns a frozen object of callback setters to handle the geolocation events.<br/>\n * So far, the supported methods are: `onChange`, invoked when the position changes and `onError`, invoked when\n * an error occur while retrieving the position.<br/>\n * The returned object also contains the `isSupported` boolean flag reporting whether the geolocation API is supported.\n */\nconst useGeolocationEvents = (options: PositionOptions = geoStandardOptions) => {\n  const watchId = useRef<number>()\n  const [onChangeRef, setOnChangeRef] = createHandlerSetter<BRHGeolocationPosition>()\n  const [onErrorRef, setOnErrorRef] = createHandlerSetter<BRHGeolocationPositionError>()\n  const isSupported = useMemo(() => typeof window !== 'undefined' && 'geolocation' in window.navigator, [])\n\n  if (!isSupported) {\n    throw new Error('The Geolocation API is not supported')\n  }\n\n  useEffect(() => {\n    const onSuccess = (successEvent: BRHGeolocationPosition) => {\n      if (onChangeRef.current) {\n        onChangeRef.current(successEvent)\n      }\n    }\n    const onError = (err: BRHGeolocationPositionError) => {\n      if (onErrorRef.current) {\n        onErrorRef.current(err)\n      }\n    }\n\n    if (isSupported) {\n      watchId.current = window.navigator.geolocation.watchPosition(onSuccess, onError, options)\n    }\n\n    return () => {\n      if (isSupported && watchId.current) {\n        window.navigator.geolocation.clearWatch(watchId.current)\n      }\n    }\n  }, [])\n\n  return Object.freeze<UseGeolocationEventsResult>({\n    isSupported,\n    onChange: setOnChangeRef,\n    onError: setOnErrorRef\n  })\n}\n\nexport default useGeolocationEvents\n"
  },
  {
    "path": "src/useGeolocationState.ts",
    "content": "import { useCallback, useEffect, useState } from 'react'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport useGeolocationEvents from './useGeolocationEvents.ts'\nimport { type BRHGeolocationPosition, type BRHGeolocationPositionError, type SomeCallback } from './shared/types.ts'\nimport { geoStandardOptions, isSamePosition, makePositionObj } from './shared/geolocationUtils.ts'\n\nexport interface GeolocationState {\n  readonly isSupported: boolean\n  readonly isRetrieving: boolean\n  readonly position: BRHGeolocationPosition\n}\n\nexport interface UseGeolocationStateResult extends GeolocationState {\n  onError: (callback: SomeCallback<BRHGeolocationPositionError>) => void\n}\n\n/**\n * Returns a frozen object containing the `position` object, the `isSupported` boolean flag, reporting whether the\n * geolocation API is supported or not and the `isRetrieving` boolean flag reporting whether the hook is fetching the\n * current position.\n * The position is retrieved by using the\n * [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API/Using_the_Geolocation_API),\n * when supported.<br/><br />\n * It possibly accepts an object of [geolocation options]\n * (https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions) to be used as parameter when using the\n * `Geolocation.getCurrentPosition()` method.\n */\nconst useGeolocationState = (options: PositionOptions = geoStandardOptions) => {\n  const [isRetrieving, setRetrieving] = useState<boolean>(false)\n  const [position, setPosition] = useState<BRHGeolocationPosition | null>(null)\n  const { isSupported, onChange, onError: setOnGeolocationEventsErrorRef } = useGeolocationEvents(options)\n  const [onCurrentPositionErrorRef, setOnCurrentPositionErrorRef] = createHandlerSetter<BRHGeolocationPositionError>()\n\n  const savePosition = useCallback(() => {\n    if (position === null) {\n      setRetrieving(true)\n      navigator.geolocation.getCurrentPosition((nextPosition) => {\n        if (!position || !isSamePosition(position, nextPosition)) {\n          setPosition(makePositionObj(nextPosition))\n          setRetrieving(false)\n        }\n      }, (err: BRHGeolocationPositionError) => {\n        if (onCurrentPositionErrorRef.current) {\n          onCurrentPositionErrorRef.current(err)\n        }\n      })\n    }\n  }, [position])\n\n  useEffect(savePosition, [position])\n  onChange(savePosition)\n\n  const onError = (callback: SomeCallback<BRHGeolocationPositionError, void>) => {\n    setOnCurrentPositionErrorRef(callback)\n    setOnGeolocationEventsErrorRef(callback)\n  }\n\n  return Object.freeze<UseGeolocationStateResult>({\n    onError,\n    isSupported,\n    isRetrieving,\n    position: position as BRHGeolocationPosition\n  })\n}\n\nexport default useGeolocationState\n"
  },
  {
    "path": "src/useGlobalEvent.ts",
    "content": "import { type RefObject } from 'react'\nimport useEvent from './useEvent.ts'\nimport isClient from './shared/isClient.ts'\nimport { type CallbackSetter } from './shared/types.ts'\nimport noop from './shared/noop.ts'\n\n/**\n * Accepts an event name then returns a callback setter for a function to be performed when the event triggers.\n */\nconst useGlobalEvent = <TEvent extends Event>(eventName: keyof WindowEventMap, opts?: AddEventListenerOptions) => {\n  if (!isClient) {\n    return noop as CallbackSetter<TEvent>\n  }\n\n  const target = { current: window } as unknown as RefObject<HTMLElement> // that's a bit of a hack but it works\n  return useEvent<TEvent>(target, eventName, opts)\n}\n\nexport default useGlobalEvent\n"
  },
  {
    "path": "src/useHorizontalSwipe.ts",
    "content": "import { type RefObject } from 'react'\nimport useSwipe, { type UseSwipeOptions } from './useSwipe.ts'\n\nconst defaultOptions: UseSwipeOptions = {\n  threshold: 15,\n  preventDefault: true\n}\n\n/**\n * A shortcut to useSwipe (with horizontal options)\n */\nconst useHorizontalSwipe = <TElement extends HTMLElement>(ref?: RefObject<TElement>, options: UseSwipeOptions = defaultOptions) => {\n  const opts: UseSwipeOptions = { ...defaultOptions, ...(options || {}), ...{ direction: 'horizontal' } }\n\n  return useSwipe<TElement>(ref, opts)\n}\n\nexport default useHorizontalSwipe\n"
  },
  {
    "path": "src/useInfiniteScroll.ts",
    "content": "import { type RefObject, useRef } from 'react'\nimport useEvent from './useEvent.ts'\nimport isFunction from './shared/isFunction.ts'\nimport safeHasOwnProperty from './shared/safeHasOwnProperty.ts'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\n\n/**\n * Accepts an HTML Element ref, then returns a function that allows you to handle the infinite\n * scroll for that specific element.\n */\nconst useInfiniteScroll = <TElement extends HTMLElement>(ref: RefObject<TElement>, delay = 300) => {\n  const onScroll = useEvent<UIEvent, TElement>(ref, 'scroll', { passive: true })\n  const [onScrollEnd, setOnScrollEnd] = createHandlerSetter<unknown>()\n  const timeoutRef = useRef<NodeJS.Timeout>()\n\n  if (ref && !safeHasOwnProperty(ref, 'current')) {\n    throw new Error('Unable to assign any scroll event to the given ref')\n  }\n\n  onScroll((event: UIEvent) => {\n    const { target } = event\n    const el = target as HTMLDivElement\n    if (el) {\n      const isBottom = Math.abs(el.scrollHeight - el.clientHeight - el.scrollTop) < 1\n\n      // event.preventDefault()\n      event.stopPropagation()\n\n      if (isBottom && isFunction(onScrollEnd?.current)) {\n        clearTimeout(timeoutRef.current)\n\n        timeoutRef.current = setTimeout(() => {\n          if (onScrollEnd.current && isFunction(onScrollEnd.current)) {\n            onScrollEnd.current()\n          }\n          clearTimeout(timeoutRef.current)\n        }, delay)\n      }\n    }\n  })\n\n  return setOnScrollEnd\n}\n\nexport default useInfiniteScroll\n"
  },
  {
    "path": "src/useInterval.ts",
    "content": "import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport isFunction from './shared/isFunction.ts'\nimport { type GenericFunction } from './shared/types.ts'\n\nexport interface UseIntervalOptions {\n  cancelOnUnmount?: boolean\n}\n\nconst defaultOptions: UseIntervalOptions = {\n  cancelOnUnmount: true\n}\n\n/**\n * An async-utility hook that accepts a callback function and a delay time (in milliseconds), then repeats the\n * execution of the given function by the defined milliseconds.\n */\nconst useInterval = <TCallback extends GenericFunction>\n  (fn: TCallback, milliseconds: number, options: UseIntervalOptions = defaultOptions) => {\n  const opts = { ...defaultOptions, ...(options || {}) }\n  const timeout = useRef<NodeJS.Timeout>()\n  const callback = useRef<TCallback>(fn)\n  const [isCleared, setIsCleared] = useState<boolean>(false)\n\n  // the clear method\n  const clear = useCallback(() => {\n    if (timeout.current) {\n      setIsCleared(true)\n      clearInterval(timeout.current)\n    }\n  }, [])\n\n  // if the provided function changes, change its reference\n  useEffect(() => {\n    if (isFunction(fn)) {\n      callback.current = fn\n    }\n  }, [fn])\n\n  // when the milliseconds change, reset the timeout\n  useEffect(() => {\n    if (typeof milliseconds === 'number') {\n      timeout.current = setInterval(() => {\n        callback.current()\n      }, milliseconds)\n    }\n\n    // cleanup previous interval\n    return clear\n  }, [milliseconds])\n\n  // when component unmount clear the timeout\n  useEffect(() => () => {\n    if (opts.cancelOnUnmount) {\n      clear()\n    }\n  }, [])\n\n  return [isCleared, clear] as [boolean, () => void]\n}\n\nexport default useInterval\n"
  },
  {
    "path": "src/useIsFirstRender.ts",
    "content": "import { useRef } from 'react'\n\nconst useIsFirstRender = () => {\n  const isFirstRenderRef = useRef(true)\n\n  if (isFirstRenderRef.current) {\n    isFirstRenderRef.current = false\n\n    return true\n  }\n\n  return isFirstRenderRef.current\n}\n\nexport default useIsFirstRender\n"
  },
  {
    "path": "src/useLifecycle.ts",
    "content": "import useDidMount from './useDidMount.ts'\nimport useWillUnmount from './useWillUnmount.ts'\nimport { type GenericFunction } from './shared/types.ts'\n\n/**\n * Returns an object wrapping lifecycle hooks such as `useDidMount` or `useWillUnmount`.\n * It is intended as a shortcut to those hooks.\n */\nconst useLifecycle = <TMount extends GenericFunction = GenericFunction, TUnmount extends GenericFunction = GenericFunction>\n  (mount?: TMount, unmount?: TUnmount) => {\n  const onDidMount = useDidMount<TMount>(mount)\n  const onWillUnmount = useWillUnmount<TUnmount>(unmount)\n\n  return { onDidMount, onWillUnmount }\n}\n\nexport default useLifecycle\n"
  },
  {
    "path": "src/useLocalStorage.ts",
    "content": "import createStorageHook from './factory/createStorageHook.ts'\n\n/**\n * Save a value on local storage\n */\nconst useLocalStorage = createStorageHook('local')\n\nexport default useLocalStorage\n"
  },
  {
    "path": "src/useLongPress.ts",
    "content": "import { type RefObject, useCallback, useState } from 'react'\nimport useMouseEvents from './useMouseEvents.ts'\nimport useConditionalTimeout from './useConditionalTimeout.ts'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport useTouchEvents from './useTouchEvents.ts'\nimport { type CallbackSetter } from './shared/types.ts'\n\n/**\n * A hook that facilitates the implementation of the long press functionality on a given target, supporting both mouse and touch events.\n */\nconst useLongPress = <TElement extends HTMLElement>(target: RefObject<TElement>, duration = 500) => {\n  const { onMouseDown, onMouseUp, onMouseLeave } = useMouseEvents<TElement>(target, false)\n  const { onTouchStart, onTouchEnd } = useTouchEvents(target, false)\n  const [isLongPressing, setIsLongPressing] = useState(false)\n  const [timerOn, startTimer] = useState(false)\n  const [onLongPressStart, setOnLongPressStart] = createHandlerSetter<void>()\n  const [onLongPressEnd, setOnLongPressEnd] = createHandlerSetter<void>()\n\n  const longPressStart = useCallback((event: MouseEvent | TouchEvent) => {\n    event.preventDefault()\n    startTimer(true)\n  }, [])\n\n  const longPressStop = useCallback((event: MouseEvent | TouchEvent) => {\n    if (!isLongPressing) return\n    clearTimeout()\n    setIsLongPressing(false)\n    startTimer(false)\n    event.preventDefault()\n\n    if (onLongPressEnd?.current) {\n      onLongPressEnd.current()\n    }\n  }, [isLongPressing])\n\n  const [, clearTimeout] = useConditionalTimeout(() => {\n    setIsLongPressing(true)\n\n    if (onLongPressStart?.current) {\n      onLongPressStart.current()\n    }\n  }, duration, timerOn)\n\n  onMouseDown(longPressStart)\n  onMouseLeave(longPressStop)\n  onMouseUp(longPressStop)\n\n  onTouchStart(longPressStart)\n  onTouchEnd(longPressStop)\n\n  return Object.freeze<UseLongPressResult>({\n    isLongPressing,\n    onLongPressStart: setOnLongPressStart,\n    onLongPressEnd: setOnLongPressEnd\n  })\n}\n\nexport interface UseLongPressResult {\n  isLongPressing: boolean\n  onLongPressStart: CallbackSetter<void>\n  onLongPressEnd: CallbackSetter<void>\n}\n\nexport default useLongPress\n"
  },
  {
    "path": "src/useMediaQuery.ts",
    "content": "import { useEffect, useState } from 'react'\nimport isClient from './shared/isClient.ts'\nimport isAPISupported from './shared/isAPISupported.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\nconst errorMessage = 'matchMedia is not supported, this could happen both because window.matchMedia is not supported by' +\n  ' your current browser or you\\'re using the useMediaQuery hook whilst server side rendering.'\n\n/**\n * Accepts a media query string then uses the\n * [window.matchMedia](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) API to determine if it\n * matches with the current document.<br />\n * It also monitor the document changes to detect when it matches or stops matching the media query.<br />\n * Returns the validity state of the given media query.\n *\n */\nconst useMediaQuery = (mediaQuery: string) => {\n  if (!isClient || !isAPISupported('matchMedia')) {\n    warnOnce(errorMessage)\n    return false\n  }\n\n  const [isVerified, setIsVerified] = useState(!!window.matchMedia(mediaQuery).matches)\n\n  useEffect(() => {\n    const mediaQueryList = window.matchMedia(mediaQuery)\n    const documentChangeHandler = () => { setIsVerified(!!mediaQueryList.matches) }\n\n    try {\n      mediaQueryList.addEventListener('change', documentChangeHandler)\n    } catch (e) {\n      // Safari isn't supporting mediaQueryList.addEventListener\n      mediaQueryList.addListener(documentChangeHandler)\n    }\n\n    documentChangeHandler()\n    return () => {\n      try {\n        mediaQueryList.removeEventListener('change', documentChangeHandler)\n      } catch (e) {\n        // Safari isn't supporting mediaQueryList.removeEventListener\n        mediaQueryList.removeListener(documentChangeHandler)\n      }\n    }\n  }, [mediaQuery])\n\n  return isVerified\n}\n\nexport default useMediaQuery\n"
  },
  {
    "path": "src/useMouse.ts",
    "content": "import { type RefObject } from 'react'\nimport useMouseEvents from './useMouseEvents.ts'\nimport useMouseState from './useMouseState.ts'\n\n/**\n * Returns an array where the first item is the mouse state from the `useMouseState` hook and the second item\n * is the object of callback setters from the `useMouseEvents` hook.\n * It is intended as a shortcut to those hooks.\n */\nconst useMouse = <TElement extends HTMLElement>(targetRef?: RefObject<TElement>) => {\n  const state = useMouseState<TElement>(targetRef)\n  const events = useMouseEvents<TElement>(targetRef)\n\n  return [state, events]\n}\n\nexport default useMouse\n"
  },
  {
    "path": "src/useMouseEvents.ts",
    "content": "import { type RefObject } from 'react'\nimport useEvent from './useEvent.ts'\n\n/**\n * Returns a frozen object of callback setters to handle the mouse events.<br/>\n * It accepts a DOM ref representing the events target. <br/>\n * If a target is not provided the events will be globally attached to the document object.\n * <br/>\n * ### Shall the `useMouseEvents` callbacks replace the standard mouse handler props?\n *\n * **They shall not!**<br />\n * **useMouseEvents is meant to be used to abstract more complex hooks that need to control mouse**, for instance:\n * a drag n drop hook.<br />\n * Using useMouseEvents handlers instead of the classic props approach it's just as bad as it sounds since you'll\n * lose the React SyntheticEvent performance boost.<br />\n * If you were doing something like the following:\n */\nconst useMouseEvents = <TElement extends HTMLElement>(targetRef?: RefObject<TElement>, passive?: boolean) => {\n  const target = targetRef ?? { current: window.document } as unknown as RefObject<TElement>\n  const onMouseDown = useEvent<MouseEvent, TElement>(target, 'mousedown', { passive })\n  const onMouseEnter = useEvent<MouseEvent, TElement>(target, 'mouseenter', { passive })\n  const onMouseLeave = useEvent<MouseEvent, TElement>(target, 'mouseleave', { passive })\n  const onMouseMove = useEvent<MouseEvent, TElement>(target, 'mousemove', { passive })\n  const onMouseOut = useEvent<MouseEvent, TElement>(target, 'mouseout', { passive })\n  const onMouseOver = useEvent<MouseEvent, TElement>(target, 'mouseover', { passive })\n  const onMouseUp = useEvent<MouseEvent, TElement>(target, 'mouseup', { passive })\n\n  return Object.freeze({\n    onMouseDown,\n    onMouseEnter,\n    onMouseLeave,\n    onMouseMove,\n    onMouseOut,\n    onMouseOver,\n    onMouseUp\n  })\n}\n\nexport default useMouseEvents\n"
  },
  {
    "path": "src/useMouseState.ts",
    "content": "import { type RefObject, useState } from 'react'\nimport useMouseEvents from './useMouseEvents.ts'\n\nconst createStateObject = (event: MouseEvent) => ({\n  clientX: event.clientX,\n  clientY: event.clientY,\n  screenX: event.screenX,\n  screenY: event.screenY\n})\n\n/**\n * Returns the current state (position) of the mouse pointer.\n * It possibly accepts a DOM ref representing the mouse target.\n * If a target is not provided the state will be caught globally.\n */\nconst useMouseState = <TElement extends HTMLElement>(targetRef?: RefObject<TElement>) => {\n  const [state, setState] = useState({ clientX: 0, clientY: 0, screenX: 0, screenY: 0 })\n  const { onMouseMove } = useMouseEvents<TElement>(targetRef)\n\n  onMouseMove((event: MouseEvent) => {\n    const nextState = createStateObject(event)\n    setState(nextState)\n  })\n\n  return state\n}\n\nexport default useMouseState\n"
  },
  {
    "path": "src/useMutableState.ts",
    "content": "import { useMemo, useState } from 'react'\n\n/**\n * Returns a reactive value that can be used as a state.\n */\nconst useMutableState = <TValue, TProxied extends Record<string | symbol, TValue>>(initialState: TProxied) => {\n  if (typeof initialState !== 'object' || initialState === null) throw new Error('The initial state must be an object')\n\n  const [, setState] = useState(0)\n\n  return useMemo<TProxied>(() => new Proxy(initialState, {\n    set: (target, prop: keyof TProxied, value: TProxied[keyof TProxied]) => {\n      if (target && target[prop] !== value) {\n        target[prop] = value\n        setState((state) => (state + 1))\n      }\n      return true\n    }\n  }), [])\n}\n\nexport default useMutableState\n"
  },
  {
    "path": "src/useMutationObserver.ts",
    "content": "import { type RefObject, useEffect } from 'react'\n\nimport isClient from './shared/isClient.ts'\nimport isApiSupported from './shared/isAPISupported.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\n// eslint-disable-next-line max-len\nconst errorMessage = 'MutationObserver is not supported, this could happen both because window. MutationObserver is not supported by your current browser or you\\'re using the useMutationObserver hook whilst server side rendering.'\n\nconst defaultOptions: MutationObserverInit = {\n  attributes: true,\n  characterData: true,\n  childList: true,\n  subtree: true\n}\n\nconst useMutationObserver = <TElement extends HTMLElement>(\n  ref: RefObject<TElement>,\n  callback: MutationCallback,\n  options: MutationObserverInit = defaultOptions\n) => {\n  const isSupported = isClient && isApiSupported('MutationObserver')\n\n  if (!isSupported) {\n    warnOnce(errorMessage)\n    return\n  }\n\n  // eslint-disable-next-line consistent-return\n  useEffect(() => {\n    if (ref.current) {\n      const observer = new MutationObserver(callback)\n      observer.observe(ref.current, options)\n\n      return () => { observer.disconnect() }\n    }\n  }, [callback, options])\n}\n\nexport default useMutationObserver\n"
  },
  {
    "path": "src/useObjectState.ts",
    "content": "import { useCallback, useReducer } from 'react'\n\nconst reducer = <TState>(\n  previousState: TState,\n  updatedState: Partial<TState>\n) => ({\n    ...previousState,\n    ...updatedState\n  })\n\nconst useObjectState = <TState>(\n  initialState: TState\n): [TState, (state: Partial<TState>) => void] => {\n  const [state, dispatch] = useReducer(\n    (previousState: TState, updatedState: Partial<TState>) => reducer(previousState, updatedState),\n    initialState\n  )\n\n  const setState = useCallback((updatedState: Partial<TState>): void => { dispatch(updatedState) }, [dispatch])\n\n  return [state, setState]\n}\n\nexport default useObjectState\n"
  },
  {
    "path": "src/useObservable.ts",
    "content": "import { useEffect } from 'react'\nimport { type Observable, type Observer } from 'rxjs'\n\n/**\n * Hook, which helps you combine rxjs flow and setState in your component\n */\nconst useObservable = <T, F extends Partial<Observer<T>> | ((value: T) => void)>(observable: Observable<T>, setter: F) => {\n  useEffect(() => {\n    const subscription = observable.subscribe(setter)\n\n    return () => {\n      subscription.unsubscribe()\n    }\n  }, [observable, setter])\n}\n\nexport default useObservable\n"
  },
  {
    "path": "src/useOnlineState.ts",
    "content": "import { useState } from 'react'\nimport useGlobalEvent from './useGlobalEvent.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\n/**\n * Uses the [Navigator online API](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine) to define\n * whether the browser is connected or not.\n */\nconst useOnlineState = () => {\n  /**\n   * If the browser doesn't support the `navigator.onLine` state, the hook will always return true\n   * assuming the app is already online.\n   */\n  const isSupported = typeof window !== 'undefined' && 'ononline' in window\n  const [isOnline, setIsOnline] = useState(isSupported ? navigator.onLine : true)\n  const whenOnline = useGlobalEvent('online', { capture: true })\n  const whenOffline = useGlobalEvent('offline', { capture: true })\n\n  if (!isSupported) {\n    warnOnce('The current device does not support the \\'online/offline\\' events, you should avoid using useOnlineState')\n    return isOnline\n  }\n\n  whenOnline(() => {\n    setIsOnline(true)\n  })\n\n  whenOffline(() => {\n    setIsOnline(false)\n  })\n\n  return isOnline\n}\n\nexport default useOnlineState\n"
  },
  {
    "path": "src/usePreviousValue.ts",
    "content": "import { useEffect, useRef } from 'react'\n\n/**\n * On each render returns the previous value of the given variable/constant.\n */\nconst usePreviousValue = <TValue>(value?: TValue): TValue | undefined => {\n  const prevValue = useRef<TValue>()\n\n  useEffect(() => {\n    prevValue.current = value\n\n    return () => {\n      prevValue.current = undefined\n    }\n  })\n\n  return prevValue.current\n}\n\nexport default usePreviousValue\n"
  },
  {
    "path": "src/useQueryParam.ts",
    "content": "import { useCallback, useRef } from 'react'\nimport { useHistory } from 'react-router-dom'\nimport useDidMount from './useDidMount.ts'\nimport useURLSearchParams from './useURLSearchParams.ts'\n\nexport interface UseQueryParamOptions<TValue extends string> {\n  initialValue?: TValue\n  replaceState?: boolean\n}\n\n/**\n * Ease the process of modify the query string in the URL for the current location.\n */\nconst useQueryParam = <TValue extends string>(key: string, options: UseQueryParamOptions<TValue> = {}) => {\n  const history = useHistory()\n  const params = useURLSearchParams()\n  const initialisedRef = useRef(false)\n  const onMount = useDidMount()\n\n  const setParam = useCallback((nextValue?: TValue) => {\n    if (!nextValue) {\n      params.delete(key)\n    } else {\n      params.set(key, nextValue)\n    }\n\n    if (options.replaceState) {\n      history.replace({ search: params.toString() })\n      return\n    }\n\n    history.push({ search: params.toString() })\n  }, [options.replaceState, history])\n\n  onMount(() => {\n    if (!params.has(key)) {\n      initialisedRef.current = true\n      setParam(options.initialValue)\n    }\n  })\n\n  return [initialisedRef.current ? params.get(key) : options.initialValue, setParam] as [TValue, (nextValue?: TValue) => void]\n}\n\nexport default useQueryParam\n"
  },
  {
    "path": "src/useQueryParams.ts",
    "content": "import { useHistory } from 'react-router-dom'\nimport { useCallback, useRef } from 'react'\nimport useDidMount from './useDidMount.ts'\nimport useURLSearchParams from './useURLSearchParams.ts'\n\nexport interface UseQueryParamsOptions<TValue extends string[]> {\n  initialValue?: TValue\n  replaceState?: boolean\n}\n\n/**\n * Very similar to `useQueryParams`, it eases the process of manipulate a query string that handles multiple values\n */\nconst useQueryParams = <TValue extends string[]>(key: string, options: UseQueryParamsOptions<TValue> = {}) => {\n  const history = useHistory()\n  const params = useURLSearchParams()\n  const initialisedRef = useRef(false)\n  const onMount = useDidMount()\n\n  const setParam = useCallback((nextValue?: TValue) => {\n    params.delete(key)\n\n    if (nextValue) {\n      nextValue.forEach((value) => {\n        params.append(key, value)\n      })\n    }\n\n    if (options.replaceState) {\n      history.replace({ search: params.toString() })\n      return\n    }\n\n    history.push({ search: params.toString() })\n  }, [options.replaceState, history])\n\n  onMount(() => {\n    if (!params.has(key)) {\n      setParam(options.initialValue)\n      initialisedRef.current = true\n    }\n  })\n\n  return [initialisedRef.current ? params.getAll(key) : options.initialValue, setParam] as [TValue, (nextValue?: TValue) => void]\n}\n\nexport default useQueryParams\n"
  },
  {
    "path": "src/useRenderInfo.ts",
    "content": "import { useRef } from 'react'\n\nexport interface RenderInfo {\n  readonly module: string\n  renders: number\n  timestamp: null | number\n  sinceLast: null | number | '[now]'\n}\n\nconst getInitial = (moduleName: string): RenderInfo => ({\n  module: moduleName,\n  renders: 0,\n  timestamp: null,\n  sinceLast: null\n})\n\n/**\n * useRenderInfo\n * @param moduleName\n * @param log\n * @returns {{renders: number, module: *, timestamp: null}}\n */\nconst useRenderInfo = (moduleName: string = 'Unknown component', log: boolean = true) => {\n  const { current: info } = useRef(getInitial(moduleName))\n  const now = +Date.now()\n\n  info.renders += 1\n  info.sinceLast = info.timestamp ? (now - info.timestamp) / 1000 : '[now]'\n  info.timestamp = now\n\n  if (log) {\n    console.group(`${moduleName} info`)\n    console.log(`Render no: ${info.renders}${info.renders > 1 ? `, ${info.sinceLast}s since last render` : ''}`)\n    console.dir(info)\n    console.groupEnd()\n  }\n\n  return info\n}\n\nexport default useRenderInfo\n"
  },
  {
    "path": "src/useRequestAnimationFrame.ts",
    "content": "import { useCallback, useRef } from 'react'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport isClient from './shared/isClient.ts'\nimport isAPISupported from './shared/isAPISupported.ts'\nimport { type CallbackSetter, type GenericFunction } from './shared/types.ts'\nimport noop from './shared/noop.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\nexport interface UseRequestAnimationFrameOpts {\n  increment?: number\n  startAt?: number\n  finishAt?: number\n}\n\nconst defaultOptions = { increment: 1, startAt: 0, finishAt: 100 }\n\nconst errorMessage = 'requestAnimationFrame is not supported, this could happen both because ' +\n  'window.requestAnimationFrame is not supported by your current browser version or you\\'re using the ' +\n  'useRequestAnimationFrame hook whilst server side rendering.'\n\n/**\n * Takes care of running an animating function, provided as the first argument, while keeping track of its progress.\n */\nconst useRequestAnimationFrame = <T extends GenericFunction>(func: T, options: UseRequestAnimationFrameOpts = defaultOptions) => {\n  if (!isClient || !isAPISupported('requestAnimationFrame')) {\n    warnOnce(errorMessage)\n    return noop as CallbackSetter<void>\n  }\n\n  const opts = { ...defaultOptions, ...options }\n  const progress = useRef(opts.startAt)\n  const [onFinish, setOnFinish] = createHandlerSetter<undefined>()\n\n  // eslint-disable-next-line @typescript-eslint/no-use-before-define\n  const next = () => window.requestAnimationFrame(step)\n\n  const step = useCallback(() => {\n    if (progress.current <= opts.finishAt || opts.finishAt === -1) {\n      func(progress.current, next)\n      progress.current += opts.increment\n    } else if (onFinish.current) {\n      onFinish.current()\n    }\n  }, [func, opts.finishAt, opts.increment, progress.current, onFinish])\n\n  if (progress.current <= opts.startAt) {\n    next()\n  }\n\n  return setOnFinish\n}\n\nexport default useRequestAnimationFrame\n"
  },
  {
    "path": "src/useResizeObserver.ts",
    "content": "import debounce from 'lodash.debounce'\nimport { type RefObject, useEffect, useRef, useState } from 'react'\n\nimport isClient from './shared/isClient.ts'\nimport isFunction from './shared/isFunction.ts'\nimport isApiSupported from './shared/isAPISupported.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\n// eslint-disable-next-line max-len\nconst errorMessage = 'ResizeObserver is not supported, this could happen both because window. ResizeObserver is not supported by your current browser or you\\'re using the useResizeObserver hook whilst server side rendering.'\n\nexport type DOMRectValues = Pick<DOMRectReadOnly, 'bottom' | 'height' | 'left' | 'right' | 'top' | 'width'>\n\n/**\n * Uses the ResizeObserver API to observe changes within the given HTML Element DOM Rect.\n * @param elementRef\n * @param debounceTimeout\n * @returns {undefined}\n */\nconst useResizeObserver = <TElement extends HTMLElement>\n  (elementRef: RefObject<TElement>, debounceTimeout: number = 100): DOMRectValues | undefined => {\n  const isSupported = isApiSupported('ResizeObserver')\n  const observerRef = useRef<ResizeObserver | null>(null)\n  const [DOMRect, setDOMRect] = useState<DOMRectValues>()\n\n  if (isClient && !isSupported) {\n    warnOnce(errorMessage)\n    return undefined\n  }\n\n  // creates the observer reference on mount\n  useEffect(() => {\n    if (isSupported) {\n      const fn = debounce((entries) => {\n        const { bottom, height, left, right, top, width } = entries[0].contentRect\n\n        setDOMRect({ bottom, height, left, right, top, width })\n      }, debounceTimeout)\n\n      observerRef.current = new ResizeObserver(fn)\n\n      return () => {\n        fn.cancel()\n        if (observerRef.current && isFunction(observerRef?.current?.disconnect)) {\n          observerRef.current.disconnect()\n        }\n      }\n    }\n\n    return () => {\n    }\n  }, [])\n\n  // observes on the provided element ref\n  useEffect(() => {\n    if (isSupported && elementRef.current) {\n      if (observerRef.current && isFunction(observerRef?.current?.observe)) {\n        observerRef.current.observe(elementRef.current)\n      }\n    }\n  }, [elementRef.current])\n\n  return DOMRect\n}\n\nexport default useResizeObserver\n"
  },
  {
    "path": "src/useSearchQuery.ts",
    "content": "import useQueryParam from './useQueryParam.ts'\n\n/**\n * Ease the process of modify the 'search' query string in the URL for the current location.\n * It's just a shortcut/wrapper around useQueryParam\n */\nconst useSearchQuery = <TSearchKey extends string>(initialValue?: TSearchKey, replaceState = false) => useQueryParam<TSearchKey>('search', {\n  initialValue,\n  replaceState\n})\n\nexport default useSearchQuery\n"
  },
  {
    "path": "src/useSessionStorage.ts",
    "content": "import createStorageHook from './factory/createStorageHook.ts'\n\n/**\n * Save a value on session storage\n */\nconst useSessionStorage = createStorageHook('session')\n\nexport default useSessionStorage\n"
  },
  {
    "path": "src/useSpeechRecognition.ts",
    "content": "import { useCallback, useEffect, useMemo, useState } from 'react'\n\ndeclare global {\n  interface SpeechRecognitionEvent extends Event {\n    results: SpeechRecognitionResultList\n  }\n\n  interface SpeechRecognitionPolyfill {\n    start: () => void\n    stop: () => void\n    abort: () => void\n    addEventListener: (event: string, callback: (event: SpeechRecognitionEvent) => void) => void\n    removeEventListener: (event: string, callback: (event: SpeechRecognitionEvent) => void) => void\n\n    // eslint-disable-next-line @typescript-eslint/no-misused-new\n    new(): SpeechRecognitionPolyfill\n  }\n\n  interface Window {\n    SpeechRecognition?: SpeechRecognitionPolyfill\n    webkitSpeechRecognition?: SpeechRecognitionPolyfill\n  }\n}\n\nconst SpeechRecognition = window.SpeechRecognition ?? window.webkitSpeechRecognition\n\n/**\n * A hook that provides an interface for using the Web Speech API to recognize and transcribe speech in a user's browser.\n */\nconst useSpeechRecognition = () => {\n  const spInstance = useMemo(() => SpeechRecognition ? new SpeechRecognition() : null, [])\n  const [isRecording, setIsRecording] = useState(false)\n  const [transcript, setTranscript] = useState('')\n  const isSupported = !!spInstance\n\n  useEffect(() => {\n    const getResults = (event: SpeechRecognitionEvent) => {\n      const nextTranscript = event.results[0][0].transcript\n      setTranscript(nextTranscript)\n    }\n\n    if (spInstance && isSupported) {\n      spInstance.addEventListener('result', getResults)\n    }\n    return () => {\n      if (spInstance && isSupported) {\n        spInstance.stop()\n        spInstance.abort()\n        spInstance.removeEventListener('result', getResults)\n      }\n    }\n  }, [spInstance])\n\n  const startRecording = useCallback(() => {\n    if (spInstance && isSupported) {\n      spInstance.start()\n      setIsRecording(true)\n    }\n  }, [spInstance])\n\n  const stopRecording = useCallback(() => {\n    if (spInstance && isSupported) {\n      spInstance.stop()\n      setIsRecording(false)\n    }\n  }, [spInstance])\n\n  return Object.freeze<UseSpeechRecognitionResult>({\n    isSupported,\n    transcript,\n    isRecording,\n    startRecording,\n    stopRecording\n  })\n}\n\nexport interface UseSpeechRecognitionResult {\n  isSupported: boolean\n  transcript: string\n  isRecording: boolean\n  startRecording: () => void\n  stopRecording: () => void\n}\n\nexport default useSpeechRecognition\n"
  },
  {
    "path": "src/useSpeechSynthesis.ts",
    "content": "import { useCallback, useEffect, useMemo } from 'react'\n\n/**\n * The options that can be passed to the hook\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance\n */\nexport interface UseSpeechSynthesisOptions {\n  rate?: number\n  pitch?: number\n  volume?: number\n  voice?: SpeechSynthesisVoice\n}\n\n/**\n * The result of the hook\n */\nexport interface SpeechSynthesisResult {\n  readonly speak: () => void\n  readonly speechSynthUtterance: SpeechSynthesisUtterance\n}\n\nconst defaultOptions: UseSpeechSynthesisOptions = { rate: 1, pitch: 1, volume: 1 }\n\n/**\n * Enables the possibility to perform a text-to-speech (with different voices) operation in your\n * React component by using the Web_Speech_API\n */\nconst useSpeechSynthesis = (text: string, options: UseSpeechSynthesisOptions = defaultOptions) => {\n  const utter: SpeechSynthesisUtterance = useMemo(() => new SpeechSynthesisUtterance(text), [text])\n  const voiceOptions = { ...defaultOptions, ...options }\n  utter.voice = voiceOptions.voice!\n\n  useEffect(() => {\n    utter.pitch = voiceOptions.pitch!\n  }, [voiceOptions.pitch])\n\n  useEffect(() => {\n    utter.rate = voiceOptions.rate!\n  }, [voiceOptions.rate])\n\n  useEffect(() => {\n    utter.volume = voiceOptions.volume!\n  }, [voiceOptions.volume])\n\n  const speak = useCallback(\n    () => {\n      speechSynthesis.speak(utter)\n    },\n    [text, voiceOptions.pitch, voiceOptions.rate, voiceOptions.voice, voiceOptions.volume]\n  )\n\n  return Object.freeze<SpeechSynthesisResult>({\n    speak,\n    speechSynthUtterance: utter\n  })\n}\n\nexport default useSpeechSynthesis\n"
  },
  {
    "path": "src/useSwipe.ts",
    "content": "import { type RefObject, useRef, useState } from 'react'\nimport { type Direction, getDirection, getHorizontalDirection, getPointerCoordinates, getVerticalDirection } from './shared/swipeUtils.ts'\nimport useMouseEvents from './useMouseEvents.ts'\nimport useTouchEvents from './useTouchEvents.ts'\n\n/**\n * The options that can be passed to the hook\n */\nexport interface UseSwipeOptions {\n  direction?: 'both' | 'horizontal' | 'vertical'\n  threshold?: number\n  preventDefault?: boolean\n  passive?: boolean\n}\n\n/**\n * The result of the hook\n */\nexport interface SwipeState {\n  swiping: boolean\n  direction?: Direction\n  alphaX: number\n  alphaY: number\n  count: number\n}\n\nconst initialState: SwipeState = { swiping: false, direction: undefined, alphaX: 0, alphaY: 0, count: 0 }\n\nconst defaultOptions: UseSwipeOptions = {\n  direction: 'both',\n  threshold: 10,\n  preventDefault: true,\n  passive: undefined\n}\n\nconst isEqual = (prev: SwipeState, next: SwipeState): boolean => (\n  prev.swiping === next.swiping &&\n  prev.direction === next.direction &&\n  prev.count === next.count &&\n  prev.alphaX === next.alphaX &&\n  prev.alphaY === next.alphaY\n)\n\n/**\n * useSwipe hook\n */\nconst useSwipe = <TElement extends HTMLElement>\n  (targetRef: RefObject<TElement> | undefined = undefined, options: UseSwipeOptions = defaultOptions) => {\n  const [state, setState] = useState(initialState)\n  const startingPointRef = useRef<[number, number]>([-1, -1])\n  const isDraggingRef = useRef(false)\n  const opts: NonNullable<UseSwipeOptions> = { ...defaultOptions, ...(options || {}) }\n  const { onMouseDown, onMouseMove, onMouseLeave, onMouseUp } = useMouseEvents<TElement>(targetRef, opts.passive)\n  const { onTouchStart, onTouchMove, onTouchEnd, onTouchCancel } = useTouchEvents<TElement>(targetRef, opts.passive)\n\n  const startSwipe = (event: MouseEvent | TouchEvent) => {\n    const [clientX, clientY] = getPointerCoordinates(event)\n    startingPointRef.current = [clientX, clientY]\n\n    if (opts.preventDefault) {\n      event.preventDefault()\n      event.stopPropagation()\n    }\n  }\n\n  const continueSwipe = (event: MouseEvent | TouchEvent) => {\n    const [clientX, clientY] = getPointerCoordinates(event)\n\n    if (opts.preventDefault) {\n      event.preventDefault()\n      event.stopPropagation()\n    }\n\n    if (isDraggingRef.current || (startingPointRef.current[0] !== -1 && startingPointRef.current[1] !== -1)) {\n      const alpha: [number, number] = [startingPointRef.current[0] - clientX, startingPointRef.current[1] - clientY]\n\n      if (opts.direction === 'both' && (Math.abs(alpha[0]) > opts.threshold! || Math.abs(alpha[1]) > opts.threshold!)) {\n        isDraggingRef.current = true\n\n        const nextState: SwipeState = {\n          alphaX: alpha[0],\n          alphaY: alpha[1],\n          count: state.count,\n          swiping: true,\n          direction: getDirection([clientX, clientY], startingPointRef.current, alpha)\n        }\n\n        if (!isEqual(nextState, state)) {\n          setState(nextState)\n        }\n      }\n\n      if (opts.direction === 'horizontal' && Math.abs(alpha[0]) > opts.threshold!) {\n        isDraggingRef.current = true\n\n        const nextState: SwipeState = {\n          alphaX: alpha[0],\n          alphaY: 0,\n          count: state.count,\n          swiping: true,\n          direction: getHorizontalDirection(alpha[0])\n        }\n\n        if (!isEqual(nextState, state)) {\n          setState(nextState)\n        }\n      }\n\n      if (opts.direction === 'vertical' && Math.abs(alpha[1]) > opts.threshold!) {\n        isDraggingRef.current = true\n\n        const nextState: SwipeState = {\n          alphaY: alpha[1],\n          alphaX: 0,\n          count: state.count,\n          swiping: true,\n          direction: getVerticalDirection(alpha[1])\n        }\n\n        if (!isEqual(nextState, state)) {\n          setState(nextState)\n        }\n      }\n    }\n  }\n\n  const endSwipe = (event: MouseEvent | TouchEvent) => {\n    if (isDraggingRef.current) {\n      if (opts.preventDefault) {\n        event.preventDefault()\n        event.stopPropagation()\n      }\n\n      setState((prevState) => ({\n        ...prevState,\n        swiping: false,\n        count: state.count + 1\n      }))\n    }\n\n    startingPointRef.current = [-1, -1]\n    isDraggingRef.current = false\n  }\n\n  onMouseDown(startSwipe)\n  onTouchStart(startSwipe)\n\n  onMouseMove(continueSwipe)\n  onTouchMove(continueSwipe)\n\n  onMouseUp(endSwipe)\n  onTouchEnd(endSwipe)\n\n  onMouseLeave(endSwipe)\n  onTouchCancel(endSwipe)\n\n  return state\n}\n\nexport default useSwipe\n"
  },
  {
    "path": "src/useSwipeEvents.ts",
    "content": "import { type RefObject, useEffect, useRef, useState } from 'react'\nimport isFunction from './shared/isFunction.ts'\nimport useMouseEvents from './useMouseEvents.ts'\nimport useTouchEvents from './useTouchEvents.ts'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\nimport { getDirection, getPointerCoordinates } from './shared/swipeUtils.ts'\nimport { type CallbackSetter } from './shared/types.ts'\n\n/**\n * The swipe event state interface\n */\nexport interface SwipeEventState {\n  clientX?: number\n  clientY?: number\n  direction: 'right' | 'left' | 'up' | 'down'\n  alphaX: number\n  alphaY: number\n}\n\n/**\n * The result of the hook\n */\ninterface UseSwipeEventsReturn {\n  onSwipeLeft: CallbackSetter<SwipeEventState>\n  onSwipeRight: CallbackSetter<SwipeEventState>\n  onSwipeUp: CallbackSetter<SwipeEventState>\n  onSwipeDown: CallbackSetter<SwipeEventState>\n  onSwipeMove: CallbackSetter<SwipeEventState>\n  onSwipeStart: CallbackSetter<SwipeEventState>\n  onSwipeEnd: CallbackSetter<SwipeEventState>\n}\n\nexport interface UseSwipeEventsOpts {\n  threshold?: number\n  preventDefault?: boolean\n  passive?: boolean\n}\n\nconst defaultOptions: UseSwipeEventsOpts = {\n  threshold: 15,\n  preventDefault: true,\n  passive: undefined\n}\n/* eslint-disable @typescript-eslint/default-param-last */\n\n/**\n * Very similar to useSwipe but doesn't cause re-rendering during swipe.\n * Internal usage only.\n */\nconst useSwipeStateInternal = <TElement extends HTMLElement>(\n  targetRef: RefObject<TElement> | undefined = undefined,\n  options: UseSwipeEventsOpts = defaultOptions,\n  onSwipeStart?: (...args: any[]) => any,\n  onSwipeMove?: (...args: any[]) => any,\n  onSwipeEnd?: (...args: any[]) => any) => {\n  const startingPointRef = useRef<[number, number]>([-1, -1])\n  const directionRef = useRef<'right' | 'left' | 'up' | 'down' | null>(null)\n  const isDraggingRef = useRef(false)\n  const alphaRef = useRef<number[]>([])\n  const opts = { ...defaultOptions, ...(options || {}) }\n  const { onMouseDown, onMouseMove, onMouseLeave, onMouseUp } = useMouseEvents<TElement>(targetRef, opts.passive)\n  const { onTouchStart, onTouchMove, onTouchEnd, onTouchCancel } = useTouchEvents<TElement>(targetRef, opts.passive)\n  const [state, setState] = useState<SwipeEventState>()\n\n  const startSwipe = (event: MouseEvent | TouchEvent) => {\n    const [clientX, clientY] = getPointerCoordinates(event)\n    startingPointRef.current = [clientX, clientY]\n    directionRef.current = null\n\n    if (onSwipeStart) {\n      onSwipeStart({ clientX, clientY })\n    }\n\n    if (opts.preventDefault) {\n      event.preventDefault()\n      event.stopPropagation()\n    }\n  }\n\n  const continueSwipe = (event: MouseEvent | TouchEvent) => {\n    const [clientX, clientY] = getPointerCoordinates(event)\n\n    if (opts.preventDefault) {\n      event.preventDefault()\n      event.stopPropagation()\n    }\n\n    if (startingPointRef.current[0] !== -1 && startingPointRef.current[1] !== -1) {\n      const alpha: [number, number] = [startingPointRef.current[0] - clientX, startingPointRef.current[1] - clientY]\n\n      if (Math.abs(alpha[0]) > opts.threshold! || Math.abs(alpha[1]) > opts.threshold!) {\n        isDraggingRef.current = true\n        directionRef.current = getDirection([clientX, clientY], startingPointRef.current, alpha)\n        alphaRef.current = alpha\n\n        if (onSwipeMove) {\n          onSwipeMove({\n            clientX,\n            clientY,\n            direction: directionRef.current,\n            alphaX: alphaRef.current[0],\n            alphaY: alphaRef.current[1]\n          })\n        }\n      }\n    }\n  }\n\n  const endSwipe = (event: MouseEvent | TouchEvent) => {\n    if (isDraggingRef.current && directionRef.current) {\n      if (opts.preventDefault) {\n        event.preventDefault()\n        event.stopPropagation()\n      }\n\n      setState({\n        direction: directionRef.current,\n        alphaX: alphaRef.current[0],\n        alphaY: alphaRef.current[1]\n      })\n\n      if (onSwipeEnd) {\n        onSwipeEnd({\n          direction: directionRef.current,\n          alphaX: alphaRef.current[0],\n          alphaY: alphaRef.current[1]\n        })\n      }\n    }\n\n    startingPointRef.current = [-1, -1]\n    isDraggingRef.current = false\n    directionRef.current = null\n  }\n\n  onMouseDown(startSwipe)\n  onTouchStart(startSwipe)\n\n  onMouseMove(continueSwipe)\n  onTouchMove(continueSwipe)\n\n  onMouseUp(endSwipe)\n  onTouchEnd(endSwipe)\n\n  onMouseLeave(endSwipe)\n  onTouchCancel(endSwipe)\n\n  return state\n}\n\n/**\n * useSwipeEvents\n * @param ref\n * @param options\n */\n// eslint-disable-next-line max-len\nconst useSwipeEvents = <TElement extends HTMLElement>(ref: RefObject<TElement> | undefined = undefined, options: UseSwipeEventsOpts = defaultOptions) => {\n  const opts = { ...defaultOptions, ...(options || {}) }\n  const [onSwipeLeft, setOnSwipeLeft] = createHandlerSetter<SwipeEventState>()\n  const [onSwipeRight, setOnSwipeRight] = createHandlerSetter<SwipeEventState>()\n  const [onSwipeUp, setOnSwipeUp] = createHandlerSetter<SwipeEventState>()\n  const [onSwipeDown, setOnSwipeDown] = createHandlerSetter<SwipeEventState>()\n  const [onSwipeStart, setOnSwipeStart] = createHandlerSetter<SwipeEventState>()\n  const [onSwipeMove, setOnSwipeMove] = createHandlerSetter<SwipeEventState>()\n  const [onSwipeEnd, setOnSwipeEnd] = createHandlerSetter<SwipeEventState>()\n  const state = useSwipeStateInternal<TElement>(ref, opts, onSwipeStart.current!, onSwipeMove.current!, onSwipeEnd.current!)\n\n  const fnMap = {\n    right: onSwipeRight,\n    left: onSwipeLeft,\n    up: onSwipeUp,\n    down: onSwipeDown\n  }\n\n  useEffect(() => {\n    if (state?.direction) {\n      const cb = fnMap[state.direction].current\n\n      if (isFunction(cb)) {\n        cb(state)\n      }\n    }\n  }, [state])\n\n  return Object.freeze<UseSwipeEventsReturn>({\n    onSwipeLeft: setOnSwipeLeft,\n    onSwipeRight: setOnSwipeRight,\n    onSwipeUp: setOnSwipeUp,\n    onSwipeDown: setOnSwipeDown,\n    onSwipeMove: setOnSwipeMove,\n    onSwipeStart: setOnSwipeStart,\n    onSwipeEnd: setOnSwipeEnd\n  })\n}\n\nexport default useSwipeEvents\n"
  },
  {
    "path": "src/useSystemVoices.ts",
    "content": "/**\n * Returns all the available voices on the system.\n * This hook is here to backward compatibility with the previous version of the library that was using\n * a different non-stable version of the Web Speech API.\n */\nconst useSystemVoices = () => window.speechSynthesis.getVoices()\n\nexport default useSystemVoices\n"
  },
  {
    "path": "src/useThrottledCallback.ts",
    "content": "import { type DependencyList, useCallback, useEffect, useRef } from 'react'\nimport throttle from 'lodash.throttle'\nimport { type GenericFunction } from './shared/types.ts'\nimport useWillUnmount from './useWillUnmount.ts'\n\ninterface ThrottleSettings {\n  leading?: boolean | undefined\n  trailing?: boolean | undefined\n}\n\nconst defaultOptions: ThrottleSettings = {\n  leading: false,\n  trailing: true\n}\n\n/**\n * Accepts a function and returns a new throttled yet memoized version of that same function that waits the defined time\n * before allowing the next execution.\n * If time is not defined, its default value will be 250ms.\n */\nconst useThrottledCallback = <TCallback extends GenericFunction>\n  (fn: TCallback, dependencies: DependencyList = [], wait: number = 600, options: ThrottleSettings = defaultOptions) => {\n  const throttled = useRef(throttle<TCallback>(fn, wait, options))\n\n  useEffect(() => {\n    throttled.current = throttle(fn, wait, options)\n  }, [fn, wait, options, ...dependencies])\n\n  useWillUnmount(() => {\n    throttled.current?.cancel()\n  })\n\n  return useCallback((...args: Parameters<TCallback>) => throttled.current(...args), [...dependencies])\n}\n\nexport default useThrottledCallback\n"
  },
  {
    "path": "src/useTimeout.ts",
    "content": "import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport isFunction from './shared/isFunction.ts'\nimport { type GenericFunction } from './shared/types.ts'\n\nexport interface UseTimeoutOptions {\n  cancelOnUnmount?: boolean\n}\n\nconst defaultOptions = {\n  cancelOnUnmount: true\n}\n\n/**\n * An async-utility hook that accepts a callback function and a delay time (in milliseconds), then delays the\n * execution of the given function by the defined time.\n */\nconst useTimeout = <TCallback extends GenericFunction>\n  (fn: TCallback, milliseconds: number, options: UseTimeoutOptions = defaultOptions): [boolean, () => void] => {\n  const opts = { ...defaultOptions, ...(options || {}) }\n  const timeout = useRef<NodeJS.Timeout>()\n  const callback = useRef<TCallback>(fn)\n  const [isCleared, setIsCleared] = useState<boolean>(false)\n\n  // the clear method\n  const clear = useCallback(() => {\n    if (timeout.current) {\n      clearTimeout(timeout.current)\n      setIsCleared(true)\n    }\n  }, [])\n\n  // if the provided function changes, change its reference\n  useEffect(() => {\n    if (isFunction(fn)) {\n      callback.current = fn\n    }\n  }, [fn])\n\n  // when the milliseconds change, reset the timeout\n  useEffect(() => {\n    if (typeof milliseconds === 'number') {\n      timeout.current = setTimeout(() => {\n        callback.current()\n      }, milliseconds)\n    }\n    return clear\n  }, [milliseconds])\n\n  // when component unmount clear the timeout\n  useEffect(() => () => {\n    if (opts.cancelOnUnmount) {\n      clear()\n    }\n  }, [])\n\n  return [isCleared, clear] as [boolean, () => void]\n}\n\nexport default useTimeout\n"
  },
  {
    "path": "src/useToggle.ts",
    "content": "import { useCallback, useState } from 'react'\n\n/**\n * A quick and simple utility for toggle states\n */\nconst useToggle = (initialState = false): [boolean, () => void] => {\n  const [value, setValue] = useState(initialState)\n\n  const toggleState = useCallback(() => {\n    setValue(!value)\n  }, [value])\n\n  return [value, toggleState]\n}\n\nexport default useToggle\n"
  },
  {
    "path": "src/useTouch.ts",
    "content": "import { type RefObject } from 'react'\nimport useTouchEvents, { type UseTouchEventsReturn } from './useTouchEvents.ts'\nimport useTouchState from './useTouchState.ts'\n\n/**\n * Returns an array where the first item is the touch state from the `useTouchState` hook and the second item\n * is the object of callback setters from the `useTouchEvents` hook.\n * It is intended as a shortcut to those hooks.\n */\nconst useTouch = <TElement extends HTMLElement>(targetRef: RefObject<TElement> | undefined = undefined) => {\n  const state = useTouchState<TElement>(targetRef)\n  const events = useTouchEvents<TElement>(targetRef)\n\n  return [state, events] as [TouchList, Readonly<UseTouchEventsReturn>]\n}\n\nexport default useTouch\n"
  },
  {
    "path": "src/useTouchEvents.ts",
    "content": "import { type RefObject } from 'react'\nimport useEvent from './useEvent.ts'\nimport { type CallbackSetter } from './shared/types.ts'\n\n/**\n * Returns a frozen object of callback setters to handle the touch events.<br/>\n * It accepts a DOM ref representing the events target. <br/>\n * If a target is not provided the events will be globally attached to the document object.\n * <br/>\n * ### Shall the `useTouchEvents` callbacks replace the standard mouse handler props?\n *\n * **They shall not!**<br />\n * **useTouchEvents is meant to be used to abstract more complex hooks that need to control mouse**, for instance:\n * a drag n drop hook.<br />\n * Using useTouchEvents handlers instead of the classic props approach it's just as bad as it sounds since you'll\n * lose the React SyntheticEvent performance boost.<br />\n * If you were doing something like the following:\n *\n */\nconst useTouchEvents = <TElement extends HTMLElement>(targetRef?: RefObject<TElement>, passive?: boolean) => {\n  const target = targetRef ?? { current: window.document } as unknown as RefObject<TElement> // hackish but works\n  const onTouchStart = useEvent<TouchEvent, TElement>(target, 'touchstart', { passive })\n  const onTouchEnd = useEvent<TouchEvent, TElement>(target, 'touchend', { passive })\n  const onTouchCancel = useEvent<TouchEvent, TElement>(target, 'touchcancel', { passive })\n  const onTouchMove = useEvent<TouchEvent, TElement>(target, 'touchmove', { passive })\n\n  return Object.freeze<UseTouchEventsReturn>({\n    onTouchStart,\n    onTouchEnd,\n    onTouchCancel,\n    onTouchMove\n  })\n}\n\n/**\n * The return object of the `useTouchEvents` hook.\n */\nexport interface UseTouchEventsReturn {\n  onTouchStart: CallbackSetter<TouchEvent>\n  onTouchEnd: CallbackSetter<TouchEvent>\n  onTouchCancel: CallbackSetter<TouchEvent>\n  onTouchMove: CallbackSetter<TouchEvent>\n}\n\nexport default useTouchEvents\n"
  },
  {
    "path": "src/useTouchState.ts",
    "content": "import { type RefObject, useState } from 'react'\nimport useTouchEvents from './useTouchEvents.ts'\n\n/**\n * Returns the current touches from the touch move event.\n * It possibly accepts a DOM ref representing the mouse target.\n * If a target is not provided the state will be caught globally.\n */\nconst useTouchState = <TElement extends HTMLElement>(targetRef?: RefObject<TElement>) => {\n  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n  const [state, setState] = useState<TouchList>({ length: 0 } as TouchList)\n  const { onTouchStart, onTouchMove } = useTouchEvents<TElement>(targetRef)\n\n  onTouchStart((event: TouchEvent) => {\n    setState(event.touches)\n  })\n\n  onTouchMove((event: TouchEvent) => {\n    setState(event.touches)\n  })\n\n  return state\n}\n\nexport default useTouchState\n"
  },
  {
    "path": "src/useURLSearchParams.ts",
    "content": "import { useMemo } from 'react'\nimport { useLocation } from 'react-router-dom'\n\n/**\n * Wraps the business logic of retrieve always updated URLSearchParams\n */\nconst useURLSearchParams = () => {\n  const { search } = useLocation()\n\n  return useMemo(() => new URLSearchParams(search), [search])\n}\n\nexport default useURLSearchParams\n"
  },
  {
    "path": "src/useUnmount.ts",
    "content": "import { useEffect, useRef } from \"react\";\nimport isFunction from \"./shared/isFunction.ts\";\nimport { type GenericFunction } from \"./shared/types.ts\";\nimport createHandlerSetter from \"./factory/createHandlerSetter.ts\";\n\n/**\n * Returns a callback setter for a callback to be performed when the component did unmount.\n */\nconst useUnmount = <TCallback extends GenericFunction>(\n  callback?: TCallback\n) => {\n  const mountRef = useRef(false);\n  const [handler, setHandler] = createHandlerSetter<undefined>(callback);\n\n  useEffect(() => {\n    mountRef.current = true;\n\n    return () => {\n      if (isFunction(handler?.current) && mountRef.current) {\n        handler.current();\n      }\n    };\n  }, []);\n\n  return setHandler;\n};\n\nexport default useUnmount;\n"
  },
  {
    "path": "src/useUpdateEffect.ts",
    "content": "import { type DependencyList, type EffectCallback, useEffect } from 'react'\nimport useIsFirstRender from './useIsFirstRender.ts'\n\n/**\n * A hook that runs an effect after the first render.\n * @param callback\n * @param deps\n */\nconst useUpdateEffect = (callback: EffectCallback, deps?: DependencyList) => {\n  const isFirstRender = useIsFirstRender()\n\n  useEffect(() => {\n    if (!isFirstRender) {\n      return callback()\n    }\n\n    return undefined\n  }, deps)\n}\n\nexport default useUpdateEffect\n"
  },
  {
    "path": "src/useValidatedState.ts",
    "content": "import { useCallback, useRef, useState } from 'react'\n\n/**\n * Returns a state that changes only if the next value pass its validator\n */\nconst useValidatedState = <TValue, TValidator extends Validator<TValue>>(validator: TValidator, initialValue?: TValue) => {\n  const [state, setState] = useState<TValue | undefined>(initialValue)\n  const validation = useRef<ValidationResult>({ changed: false })\n\n  const onChange = useCallback((nextValue: TValue) => {\n    setState(nextValue)\n    validation.current = { changed: true, valid: validator(nextValue) }\n  }, [validator])\n\n  return [state, onChange, validation.current] as [TValue, (nextValue: TValue) => void, ValidationResult]\n}\n\nexport type Validator<TValue> = (value: TValue) => boolean\n\nexport interface ValidationResult {\n  changed: boolean\n  valid?: boolean\n}\n\nexport default useValidatedState\n"
  },
  {
    "path": "src/useValueHistory.ts",
    "content": "import { useEffect, useRef } from 'react'\n\nconst distinctValues = <T>(value: T, current: number, array: T[]): boolean => array.indexOf(value) === current\n\n/**\n * Accepts a variable (possibly a prop or a state) and returns its history (changes through updates).\n */\nconst useValueHistory = <TValue = unknown>(value: TValue, distinct = false) => {\n  const history = useRef<TValue[]>([])\n\n  // quite simple\n  useEffect(() => {\n    history.current.push(value)\n\n    if (distinct) {\n      history.current = history.current.filter(distinctValues)\n    }\n  }, [value])\n\n  return history.current\n}\n\nexport default useValueHistory\n"
  },
  {
    "path": "src/useVerticalSwipe.ts",
    "content": "import { type RefObject } from 'react'\nimport useSwipe, { type UseSwipeOptions } from './useSwipe.ts'\n\nconst defaultOptions: UseSwipeOptions = {\n  threshold: 15,\n  preventDefault: true\n}\n\n/**\n * A shortcut to useSwipe (with vertical options)\n * @param ref\n * @param options\n * @return {{alpha: number, count: number, swiping: boolean, direction: null}}\n */\nconst useVerticalSwipe = <TElement extends HTMLElement>(ref?: RefObject<TElement>, options: UseSwipeOptions = defaultOptions) => {\n  const opts: UseSwipeOptions = { ...defaultOptions, ...(options || {}), ...{ direction: 'vertical' } }\n\n  return useSwipe<TElement>(ref, opts)\n}\n\nexport default useVerticalSwipe\n"
  },
  {
    "path": "src/useViewportSpy.ts",
    "content": "import { type RefObject, useLayoutEffect, useState } from 'react'\nimport isClient from './shared/isClient.ts'\nimport isApiSupported from './shared/isAPISupported.ts'\nimport isDevelopment from './shared/isDevelopment.ts'\nimport warnOnce from './shared/warnOnce.ts'\n\nconst defaultOptions: IntersectionObserverInit = {\n  rootMargin: '0px',\n  threshold: 0\n}\n\nconst errorMessage = 'IntersectionObserver is not supported, this could happen both because' +\n  ' window.IntersectionObserver is not supported by' +\n  ' your current browser or you\\'re using the useViewportSpy hook whilst server side rendering.' +\n  ' This message is displayed only in development mode'\n\n/**\n * Uses the IntersectionObserverMock API to tell whether the given DOM Element (from useRef) is visible within the\n * viewport.\n */\nconst useViewportSpy = <TElement extends HTMLElement>(ref: RefObject<TElement>, options: IntersectionObserverInit = defaultOptions) => {\n  if (!isClient || !isApiSupported('IntersectionObserver')) {\n    if (isDevelopment) {\n      warnOnce(errorMessage)\n    }\n    return false\n  }\n\n  const [isVisible, setIsVisible] = useState<boolean>()\n\n  useLayoutEffect(() => {\n    const observer = new window.IntersectionObserver((entries) => {\n      entries.forEach((item) => {\n        const nextValue = item.isIntersecting\n        setIsVisible(nextValue)\n      })\n    }, options)\n\n    if (ref.current) {\n      observer.observe(ref.current)\n    }\n\n    return () => {\n      observer.disconnect()\n    }\n  }, [ref])\n\n  return isVisible\n}\n\nexport default useViewportSpy\n"
  },
  {
    "path": "src/useViewportState.ts",
    "content": "import { useState } from 'react'\nimport useWindowScroll from './useWindowScroll.ts'\nimport useWindowResize from './useWindowResize.ts'\nimport useThrottledCallback from './useThrottledCallback.ts'\nimport useDidMount from './useDidMount.ts'\n\nexport interface ViewportState {\n  width: number\n  height: number\n  scrollX: number\n  scrollY: number\n}\n\n/**\n * Returns updated information on the current viewport state\n */\nconst useViewportState = (debounceBy: number = 250) => {\n  const [viewport, setViewport] = useState<ViewportState>({ width: 0, height: 0, scrollY: 0, scrollX: 0 })\n  const onScroll = useWindowScroll()\n  const onResize = useWindowResize()\n  const onMount = useDidMount()\n\n  const saveInfo = useThrottledCallback(() => {\n    setViewport({\n      width: window.innerWidth,\n      height: window.innerHeight,\n      scrollX: window.scrollX,\n      scrollY: window.scrollY\n    })\n  }, [setViewport], debounceBy)\n\n  onScroll(saveInfo)\n  onResize(saveInfo)\n  onMount(saveInfo)\n\n  return viewport\n}\n\nexport default useViewportState\n"
  },
  {
    "path": "src/useWillUnmount.ts",
    "content": "import { useLayoutEffect, useRef } from 'react'\nimport isFunction from './shared/isFunction.ts'\nimport { type GenericFunction } from './shared/types.ts'\nimport createHandlerSetter from './factory/createHandlerSetter.ts'\n\n/**\n * Returns a callback setter for a callback to be performed when the component will unmount.\n */\nconst useWillUnmount = <TCallback extends GenericFunction>(callback?: TCallback) => {\n  const mountRef = useRef(false)\n  const [handler, setHandler] = createHandlerSetter<undefined>(callback)\n\n  useLayoutEffect(() => {\n    mountRef.current = true\n\n    return () => {\n      if (isFunction(handler?.current) && mountRef.current) {\n        handler.current()\n      }\n    }\n  }, [])\n\n  return setHandler\n}\n\nexport default useWillUnmount\n"
  },
  {
    "path": "src/useWindowResize.ts",
    "content": "import useGlobalEvent from './useGlobalEvent.ts'\n\n/**\n * Returns a function that accepts a callback to be performed when the window resize.\n */\nconst useWindowResize = () => useGlobalEvent<UIEvent>('resize')\n\nexport default useWindowResize\n"
  },
  {
    "path": "src/useWindowScroll.ts",
    "content": "import useGlobalEvent from './useGlobalEvent.ts'\n\n/**\n * Returns a function that accepts a callback to be performed when the window scrolls.\n */\nconst useWindowScroll = () => useGlobalEvent<UIEvent>('scroll')\n\nexport default useWindowScroll\n"
  },
  {
    "path": "styleguide.config.js",
    "content": "const { globSync } = require('glob')\nconst path = require('path')\nconst theme = require('./docs/utils/_styleguidist.theme.js')\n\nconst srcPath = path.resolve(__dirname, 'src')\nconst docsPath = path.resolve(__dirname, 'docs')\n\nconst getHooksDocFiles = () => globSync(path.join(__dirname, 'docs', '[use]*.md')).map((filePath) => {\n  const [filename] = filePath.match(/use[a-zA-Z]*/, 'gm')\n\n  return ({\n    name: filename, content: `./docs/${filename}.md`\n  })\n})\n\nmodule.exports = {\n  title: 'beautiful-react-hooks - documentation',\n  pagePerSection: true,\n  exampleMode: 'expand',\n  skipComponentsWithoutExample: true,\n  styleguideDir: 'dist-ghpages',\n  ribbon: {\n    url: 'https://github.com/antonioru/beautiful-react-hooks', text: 'Fork me on GitHub'\n  },\n  sections: [{ name: 'Introduction', content: './docs/Introduction.md', sectionDepth: 1 }, {\n    name: 'Installation',\n    content: './docs/Installation.md',\n    sectionDepth: 1\n  }, ...getHooksDocFiles()],\n  require: [path.join(docsPath, 'utils', '_setup.js'), path.join(docsPath, 'utils', '_custom.css')],\n  webpackConfig () {\n    return {\n      resolve: {\n        alias: { 'beautiful-react-hooks': srcPath }\n      },\n      module: {\n        rules: [{\n          test: /\\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'\n        }, {\n          test: /\\.tsx?$/, use: 'ts-loader', exclude: /node_modules/\n        }, {\n          test: /\\.css$/i, use: ['style-loader', 'css-loader']\n        }, {\n          test: /\\.png$/, loader: 'url-loader'\n        }]\n      }\n    }\n  },\n  styleguideComponents: {\n    LogoRenderer: path.join(docsPath, 'utils', '_CustomLogo'),\n    PathlineRenderer: path.join(docsPath, 'utils', '_EmptyComponent'),\n    ToolbarButtonRenderer: path.join(docsPath, 'utils', '_EmptyComponent')\n  },\n  ...theme\n}\n"
  },
  {
    "path": "test/_setup.js",
    "content": "const chai = require('chai')\nconst sinon = require('sinon')\nconst { createMemoryHistory } = require('history')\n\nglobal.history = createMemoryHistory()\n\n// shortcuts:\nglobal.expect = chai.expect\nglobal.should = chai.should()\nglobal.sinon = sinon\n\n// because of a bug in one of the project dependency `wait-for-expect`, the following line must be placed here.\n// to know more: https://github.com/testing-library/dom-testing-library/issues/194\nwindow.Date = Date\n"
  },
  {
    "path": "test/geolocationUtils.spec.js",
    "content": "import { geoStandardOptions, isSamePosition, makePositionObj } from '../dist/shared/geolocationUtils'\nimport { positionMock } from './mocks/GeoLocationApi.mock'\nimport assertFunction from './utils/assertFunction'\n\ndescribe('geolocation utils', () => {\n  assertFunction(isSamePosition)\n  assertFunction(makePositionObj)\n\n  it('geoStandardOptions should be a frozen object defining standard geolocation options', () => {\n    expect(geoStandardOptions).to.be.an('object').that.has.all.deep.keys('enableHighAccuracy', 'timeout', 'maximumAge')\n    expect(geoStandardOptions).to.be.frozen\n  })\n\n  it('isSamePosition should return false if nothing is provided', () => {\n    const result = isSamePosition()\n\n    expect(result).to.be.false\n  })\n\n  it('isSamePosition should return false if invalid objects are provided', () => {\n    expect(isSamePosition(null, {})).to.be.false\n    expect(isSamePosition(null, null)).to.be.false\n    expect(isSamePosition(positionMock, { current: false })).to.be.false\n  })\n\n  it('isSamePosition should return false if the provided objects have different timestamp', () => {\n    expect(isSamePosition(positionMock, { ...positionMock, timestamp: 200 })).to.be.false\n  })\n\n  it('isSamePosition should return false if the provided objects are different', () => {\n    const positionMock2 = { ...positionMock }\n    positionMock2.coords = { ...positionMock.coords }\n    positionMock2.coords.altitudeAccuracy = 60\n\n    expect(isSamePosition(positionMock, positionMock2)).to.be.false\n  })\n\n  it('isSamePosition should return true if the provided objects are equal', () => {\n    const positionMock2 = { ...positionMock }\n\n    expect(isSamePosition(positionMock, positionMock2)).to.be.true\n  })\n\n  it('makePositionObj should return null if nothing is provided', () => {\n    const result = makePositionObj()\n\n    expect(result).to.be.null\n  })\n\n  it('makePositionObj should remove unwanted property from a position object', () => {\n    const pos = {\n      ...positionMock, foo: 'bar', bar: 'foo'\n    }\n\n    const result = makePositionObj(pos)\n\n    expect(result).to.be.deep.equal(positionMock)\n  })\n})\n"
  },
  {
    "path": "test/isAPISupported.spec.js",
    "content": "import isAPISupported from '../dist/shared/isAPISupported'\nimport assertFunction from './utils/assertFunction'\n\ndescribe('isAPISupported utility', () => {\n  assertFunction(isAPISupported)\n\n  it('should return true if an API is supported', () => {\n    const result = isAPISupported('addEventListener')\n\n    expect(result).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/isClient.spec.js",
    "content": "import isClient from '../dist/shared/isClient'\n\ndescribe('isClient utility', () => {\n  it('should be a boolean', () => expect(isClient).to.be.a('boolean'))\n  it('should return true during tests', () => expect(isClient).to.be.true)\n})\n"
  },
  {
    "path": "test/mocks/AudioApi.mock.js",
    "content": "class AudioApiMock extends window.Audio {\n  src;\n  state;\n  duration;\n  playing;\n  constructor() {\n    super();\n\n    this.src = \"\";\n    this.duration = NaN;\n    this.playing = false;\n    this.state = \"STOPPED\";\n  }\n  play = () => {\n    this.playing = true;\n    this.state = \"PLAYING\";\n\n    return super.play();\n  };\n  pause = () => {\n    this.playing = false;\n    this.state = \"PAUSED\";\n\n    return super.pause();\n  };\n}\n\nexport default AudioApiMock;\n"
  },
  {
    "path": "test/mocks/CookieStoreApi.mock.js",
    "content": "const createCookieStoreApiMock = () => {\n  const store = {};\n\n  const getItem = (key) => {\n    return Promise.resolve({ name: key, value: store[key] });\n  }\n\n  const deleteItem = (key) => {\n    delete store[key];\n\n    return Promise.resolve();\n  }\n\n  const setItem = ({ name, value }) => {\n    store[name] = value;\n\n    return Promise.resolve();\n  }\n\n  return {\n    get: getItem,\n    set: setItem,\n    delete: deleteItem,\n  }\n}\n\nexport default createCookieStoreApiMock();\n\n"
  },
  {
    "path": "test/mocks/GeoLocationApi.mock.js",
    "content": "export const watchPositionSpy = sinon.spy()\nexport const getCurrentPosition = sinon.spy()\n\nexport const positionMock = {\n  timestamp: 1,\n  coords: {\n    latitude: 1,\n    longitude: 1,\n    altitude: 1,\n    accuracy: 1,\n    altitudeAccuracy: 10,\n    heading: 10,\n    speed: 0\n  }\n}\n\nconst GeoLocationApiMock = {\n  listeners: {},\n  getCurrentPosition(fn) {\n    this.listeners.gcp = fn\n    this.listeners.gcp(positionMock)\n    getCurrentPosition(positionMock)\n  },\n  watchPosition(success, error, options) {\n    watchPositionSpy(options)\n\n    this.listeners.s = success\n    this.listeners.e = error\n  },\n  clearWatch() {\n    this.listeners = {}\n  }\n}\n\nexport default GeoLocationApiMock\n\n"
  },
  {
    "path": "test/mocks/IntersectionObserver.mock.js",
    "content": "class IntersectionObserverMock {\n  constructor(fn) {\n    this.connected = true\n    this.fn = fn\n\n    IntersectionObserverMock.instances.push(this)\n  }\n\n  observe() {\n    if (this.connected) {\n      this.fn([{ isIntersecting: true }])\n    }\n  }\n\n  disconnect() {\n    this.connected = false\n  }\n}\n\nIntersectionObserverMock.instances = []\nIntersectionObserverMock.simulateObservation = () => {\n  IntersectionObserverMock.instances.forEach((item) => item.observe())\n}\n\nexport default IntersectionObserverMock\n\n"
  },
  {
    "path": "test/mocks/MatchMediaQueryList.mock.js",
    "content": "const matchMediaQueryListMock = {\n  listeners: {},\n  matches: true,\n  addEventListener(cb) {\n    this.listeners.cb = cb\n  },\n  removeListener() {\n    delete this.listeners.cb\n  }\n}\n\nexport default matchMediaQueryListMock;\n"
  },
  {
    "path": "test/mocks/ResizeObserver.mock.js",
    "content": "class ResizeObserverMock {\n  constructor(fn) {\n    this.fn = fn\n    ResizeObserverMock.instances.push(this)\n  }\n\n  observe() {\n    this.fn([{\n      contentRect: { bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0 }\n    }])\n  }\n\n  unobserve() {\n    ResizeObserverMock.instances = []\n  }\n}\n\nResizeObserverMock.instances = []\n\nResizeObserverMock.simulateResize = () => {\n  ResizeObserverMock.instances.forEach((target) => {\n    target.fn([{\n      contentRect: { bottom: 10, height: 10, left: 10, right: 10, top: 10, width: 10 }\n    }])\n  })\n}\n\nexport default ResizeObserverMock\n"
  },
  {
    "path": "test/mocks/SpeechSynthesis.mock.js",
    "content": "export default {\n  getVoices() {\n    return []\n  }\n}\n\n"
  },
  {
    "path": "test/mocks/SpeechSynthesisUtterance.mock.js",
    "content": "export default class SpeechSynthesisUtteranceMock {\n  constructor(text) {\n    this.text = text\n    this.voice = {}\n    this.pitch = 0\n    this.rate = 0\n    this.volume = 0\n  }\n}\n"
  },
  {
    "path": "test/safeHasOwnProperty.spec.js",
    "content": "import safeHasOwnProperty from '../dist/shared/safeHasOwnProperty'\nimport assertFunction from './utils/assertFunction'\n\ndescribe('safeHasOwnProperty utility', () => {\n  assertFunction(safeHasOwnProperty)\n\n  it('should return false if nothing is provided', () => {\n    const result = safeHasOwnProperty()\n\n    expect(result).to.be.false\n  })\n\n  it('should return true if the given object has the defined property', () => {\n    const result = safeHasOwnProperty({ foo: 'bar' }, 'foo')\n\n    expect(result).to.be.true\n  })\n\n  it('should return false if the given object does not have the defined property', () => {\n    const result = safeHasOwnProperty({ foo: 'bar' }, 'bar')\n\n    expect(result).to.be.false\n  })\n})\n"
  },
  {
    "path": "test/useAudio.spec.js",
    "content": "import {\n  cleanup,\n  renderHook,\n} from \"@testing-library/react-hooks\";\n\nimport useAudio from \"../dist/useAudio\";\nimport assertHook from \"./utils/assertHook\";\n\nimport AudioMock from \"./mocks/AudioApi.mock\";\n\nconst validAudioUrl =\n  \"https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3\";\n\ndescribe(\"useAudio\", () => {\n  const originalAudio = global.Audio;\n\n  before(() => {\n    global.Audio = window.Audio = AudioMock;\n  });\n\n  beforeEach(() => {\n    cleanup();\n  });\n\n  after(() => {\n    global.Audio = window.Audio = originalAudio;\n  });\n\n  assertHook(useAudio);\n\n  describe(\"when the Audio API is not supported\", () => {\n    beforeEach(() => {\n      delete global.Audio;\n      delete window.Audio;\n    });\n\n    afterEach(() => {\n      global.Audio = window.Audio = originalAudio;\n      sinon.restore();\n    });\n\n    it(\"should not play anything\", async () => {\n      const warnSpy = sinon.spy(console, \"warn\");\n\n      const { result } = renderHook(() => useAudio(validAudioUrl));\n\n      const [state, controls, audio] = result.current;\n\n      expect(warnSpy.called).to.be.true;\n      expect(audio.current).to.be.null;\n      expect(controls)\n        .to.be.an(\"object\")\n        .that.has.all.deep.keys(\n          \"play\",\n          \"mute\",\n          \"pause\",\n          \"unmute\",\n          \"seek\",\n          \"onError\",\n          \"setVolume\"\n        );\n      expect(state)\n        .to.be.an(\"object\")\n        .that.has.all.deep.keys(\n          \"loop\",\n          \"muted\",\n          \"playbackRate\",\n          \"volume\",\n          \"currentTime\",\n          \"duration\",\n          \"isPlaying\",\n          \"autoPlay\",\n          \"isSrcLoading\",\n          \"preload\"\n        );\n    });\n  });\n\n  it(\"should return state, controls and audioRef\", async () => {\n    const { result } = renderHook(() => useAudio(validAudioUrl));\n\n    const [state, controls, audio] = result.current;\n\n    expect(audio.current).to.not.be.undefined;\n    expect(controls)\n      .to.be.an(\"object\")\n      .that.has.all.deep.keys(\n        \"play\",\n        \"mute\",\n        \"pause\",\n        \"unmute\",\n        \"seek\",\n        \"onError\",\n        \"setVolume\"\n      );\n    expect(state)\n      .to.be.an(\"object\")\n      .that.has.all.deep.keys(\n        \"loop\",\n        \"muted\",\n        \"playbackRate\",\n        \"volume\",\n        \"currentTime\",\n        \"duration\",\n        \"isPlaying\",\n        \"autoPlay\",\n        \"isSrcLoading\",\n        \"preload\"\n      );\n  });\n});\n"
  },
  {
    "path": "test/useConditionalTimeout.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { act, cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useConditionalTimeout from '../dist/useConditionalTimeout'\nimport promiseDelay from './utils/promiseDelay'\nimport assertHook from './utils/assertHook'\n\ndescribe('useConditionalTimeout', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  afterEach(() => {\n    sinon.restore()\n  })\n\n  assertHook(useConditionalTimeout)\n\n  it('should return an array, the first item is the timeout state whilst the second its clearing method', () => {\n    const { result } = renderHook(() => useConditionalTimeout(() => null, 1000, true))\n\n    expect(result.current).to.be.an('array')\n    expect(result.current[0]).to.be.an('boolean')\n    expect(result.current[1]).to.be.a('function')\n  })\n\n  it('should delay the execution of the delayed function only if the condition is verified', async () => {\n    const delay = 50\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      useConditionalTimeout(spy, delay, true)\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    await promiseDelay(10 + delay)\n\n    expect(spy.called).to.be.true\n  })\n\n  it('should not delay the execution of the delayed function if the condition is false', async () => {\n    const delay = 50\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      useConditionalTimeout(spy, delay, false)\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    await promiseDelay(10 + delay)\n\n    expect(spy.called).to.be.false\n  })\n\n  it('should allow to define whether the timeout should be cleared on unmount', async () => {\n    const delay = 50\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      useConditionalTimeout(spy, delay, true, { cancelOnUnmount: false })\n\n      return <div />\n    }\n\n    const { rerender } = render(<TestComponent />)\n    rerender(null)\n\n    await promiseDelay(10 + delay)\n\n    expect(spy.called).to.be.true\n  })\n\n  /*it('should allow to define whether the timeout should be cleared on condition change', async () => {\n   const delay = 50;\n   const spy = sinon.spy();\n\n   const TestComponent = () => {\n   const [condition, setCondition] = useState(true);\n   useConditionalTimeout(spy, delay, condition);\n   useConditionalTimeout(() => setCondition(false), (delay - 10), true);\n   return <div />;\n   };\n\n   render(<TestComponent />);\n\n   await promiseDelay(10 + delay);\n\n   expect(spy.called).to.be.false;\n   });*/\n\n  it('even if the provided options is null, it should keep working', () => {\n    const { result } = renderHook(() => useConditionalTimeout(() => null, 1000, true, null))\n\n    expect(result.current).to.be.an('array')\n  })\n\n  it('should allow to clear the created timeout', () => {\n    const spy = sinon.spy()\n    const delay = 100\n    const { result, error } = renderHook(() => useConditionalTimeout(spy, delay, true))\n    const clear = result.current[1]\n\n    expect(result.current[0]).to.be.false\n\n    act(clear)\n\n    expect(result.current[0]).to.be.true\n    expect(spy.called).to.be.false\n\n    act(clear)\n\n    expect(result.current[0]).to.be.true\n\n    expect(error).to.be.undefined\n  })\n\n  it('should check the received parameters to avoid errors', () => {\n    const { result } = renderHook(() => useConditionalTimeout(10, { foo: 'bar' }, true))\n    const clear = result.current[1]\n\n    expect(result.current[0]).to.be.false\n    expect(clear).to.be.a('function')\n\n    act(clear)\n\n    expect(result.current[0]).to.be.false\n  })\n})\n"
  },
  {
    "path": "test/useCookie.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHook, renderHook } from '@testing-library/react-hooks'\n\nimport useCookie from '../dist/useCookie'\nimport assertHook from './utils/assertHook'\nimport CookieStoreApiMock from './mocks/CookieStoreApi.mock'\n\nconst onErrorSpy = sinon.spy()\nconst consoleWarnSpy = sinon.spy()\nconst realConsoleWarning = console.warn\n\ndescribe('useCookie', () => {\n  before(() => {\n    console.warn = consoleWarnSpy\n    window.cookieStore = CookieStoreApiMock\n  })\n\n  after(() => {\n    delete window.cookieStore\n    console.warn = realConsoleWarning\n  })\n\n  beforeEach(() => {\n    cleanupHook()\n    cleanupReact()\n    sinon.reset()\n  })\n\n  assertHook(useCookie)\n\n  it('should return mocked object when browser does not support cookieStore API', () => {\n    delete window.cookieStore\n\n    const { result } = renderHook(() => useCookie())\n\n    expect(consoleWarnSpy.called).to.be.true\n    expect(result.current).to.be.an('object').that.has.all.deep.keys('onError', 'cookieValue', 'updateCookie', 'deleteCookie')\n\n    window.cookieStore = CookieStoreApiMock\n  })\n\n  it('should save default value when no cookie is set', async () => {\n    const { result, waitFor } = renderHook(() => useCookie('test', { defaultValue: 'default' }))\n\n    await waitFor(() => result.current.cookieValue === 'default');\n\n    expect(result.current.cookieValue).to.equal('default')\n  })\n\n  it('should intial, update and then delete cookie', async () => {\n    const { result, waitForNextUpdate, waitFor } = renderHook(() => useCookie('test', { defaultValue: 'default' }))\n\n    await waitFor(() => result.current.cookieValue === 'default');\n\n    expect(result.current.cookieValue).to.equal('default')\n    result.current.updateCookie('newValue')\n\n    await waitForNextUpdate()\n    expect(result.current.cookieValue).to.equal('newValue')\n\n    result.current.deleteCookie()\n\n    await waitForNextUpdate()\n    expect(result.current.cookieValue).to.be.undefined\n  })\n\n  it('should call onError callback when an arror occurs', async () => {\n    Object.defineProperty(window, \"cookieStore\", {\n      value: {\n        ...window.cookieStore,\n        get: () => {\n          throw new Error('error')\n        }\n      }\n    })\n\n    const TestComponent = () => {\n      const { onError } = useCookie('test', { defaultValue: 'default' })\n\n      onError(onErrorSpy)\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    expect(onErrorSpy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useDarkMode.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\n\nimport assertHook from './utils/assertHook'\nimport useDarkMode from '../dist/useDarkMode'\nimport matchMediaQueryListMock from './mocks/MatchMediaQueryList.mock'\n\nconst realMatchMedia = window.matchMedia\n\ndescribe('useDarkMode', () => {\n  before(() => {\n    window.matchMedia = () => matchMediaQueryListMock\n  })\n\n  after(() => {\n    window.matchMedia = realMatchMedia\n  })\n\n  beforeEach(() => {\n    cleanup()\n  })\n\n  afterEach(() => {\n    sinon.restore()\n  })\n\n  assertHook(useDarkMode)\n\n  it('should set the dark mode to true when the media query matches', () => {\n    const { result } = renderHook(() => useDarkMode())\n\n    expect(result.current.isDarkMode).to.be.true\n  });\n\n  it('should set the dark mode to false when the media query does not match', () => {\n    const updatedMatchMediaQueryListMock = {\n      ...matchMediaQueryListMock,\n      matches: false\n    }\n\n    window.matchMedia = () => updatedMatchMediaQueryListMock\n\n    const { result } = renderHook(() => useDarkMode())\n\n    expect(result.current.isDarkMode).to.be.true\n\n    window.matchMedia = () => matchMediaQueryListMock\n  });\n\n  it('should save dark mode to local storage', () => {\n    const { result } = renderHook(() => useDarkMode())\n    const localStorageKey = 'beautiful-react-hooks-is-dark-mode';\n\n    expect(window.localStorage.getItem(localStorageKey)).to.be.eq('true')\n\n    result.current.disable();\n    expect(window.localStorage.getItem(localStorageKey)).to.be.eq('false')\n\n    result.current.enable();\n    expect(window.localStorage.getItem(localStorageKey)).to.be.eq('true')\n\n    result.current.toggle();\n    expect(window.localStorage.getItem(localStorageKey)).to.be.eq('false')\n\n    result.current.disable();\n    expect(window.localStorage.getItem(localStorageKey)).to.be.eq('false')\n  });\n\n  it('should allow user to fully control dark mode state via props and returned functions', () => {\n    const { result } = renderHook(() => useDarkMode(true, 'test_key'))\n\n    expect(result.current.isDarkMode).to.be.true\n\n    result.current.disable();\n    expect(result.current.isDarkMode).to.be.false\n\n    result.current.enable();\n    expect(result.current.isDarkMode).to.be.true\n\n    result.current.toggle();\n    expect(result.current.isDarkMode).to.be.false\n\n    result.current.disable();\n    expect(result.current.isDarkMode).to.be.false\n  });\n})\n"
  },
  {
    "path": "test/useDebouncedCallback.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport useDebouncedCallback from '../dist/useDebouncedCallback'\nimport promiseDelay from './utils/promiseDelay'\nimport assertHook from './utils/assertHook'\n\ndescribe('useDebouncedCallback', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n  })\n\n  afterEach(sinon.restore)\n\n  assertHook(useDebouncedCallback)\n\n  it('should return a single function', () => {\n    const fn = () => 0\n    const { result } = renderHook(() => useDebouncedCallback(fn))\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('should return a debounced function', async () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const debouncedCallback = useDebouncedCallback(() => {\n        spy()\n      }, [], 250)\n\n      React.useEffect(() => {\n        debouncedCallback()\n        debouncedCallback()\n        debouncedCallback()\n        debouncedCallback()\n      }, [])\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    await promiseDelay(300)\n\n    expect(spy.called).to.be.true\n    expect(spy.callCount).to.equal(1)\n  })\n\n  it('should use the latest callback', async () => {\n    const firstSpy = sinon.spy();\n    const secondSpy = sinon.spy();\n\n    const TestComponent = () => {\n      const [callback, setCallback] = React.useState(() => firstSpy);\n      const debouncedCallback = useDebouncedCallback(callback, [callback], 250);\n\n      React.useEffect(() => {\n        debouncedCallback();\n        debouncedCallback();\n\n        setTimeout(() => {\n          setCallback(() => secondSpy);\n        }, 100);\n\n        setTimeout(() => {\n          debouncedCallback();\n          debouncedCallback();\n        }, 200);\n      }, [debouncedCallback]);\n\n      return <div />;\n    };\n\n    render(<TestComponent />);\n\n    await promiseDelay(600);\n\n    expect(firstSpy.callCount).to.equal(1); \n    expect(secondSpy.callCount).to.equal(1); \n  })\n})\n"
  },
  {
    "path": "test/useDefaultedState.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useDefaultedState from '../dist/useDefaultedState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useDefaultedState', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useDefaultedState)\n\n  it('should return an array', () => {\n    const { result } = renderHook(() => useDefaultedState(10))\n\n    expect(result.current).to.be.an('array')\n  })\n\n  it('should default the state when null or undefined', () => {\n    const defaultVal = 10\n    const { result } = renderHook(() => useDefaultedState(defaultVal))\n\n    expect(result.current[0]).to.equal(defaultVal)\n  })\n})\n"
  },
  {
    "path": "test/useDidMount.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useDidMount from '../dist/useDidMount'\nimport assertHook from './utils/assertHook'\n\ndescribe('useDidMount', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  afterEach(sinon.restore)\n\n  assertHook(useDidMount)\n\n  it('should return a single function', () => {\n    const { result } = renderHook(() => useDidMount())\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('the returned function should be a setter for a callback to be performed when component did mount', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onMount = useDidMount()\n\n      onMount(spy)\n\n      return null\n    }\n\n    render(<TestComponent />)\n\n    expect(spy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useDrag.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useDrag from '../dist/useDrag'\nimport assertHook from './utils/assertHook'\n\ndescribe('useDrag', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useDrag)\n\n  it('should return an object the state of the current dragging element', () => {\n    const targetRef = { current: document.createElement('div') }\n    const { result } = renderHook(() => useDrag(targetRef))\n\n    expect(result.current).to.be.an('boolean')\n  })\n})\n"
  },
  {
    "path": "test/useDragEvents.spec.js",
    "content": "import React, { useRef } from 'react'\nimport { cleanup as cleanupReact, fireEvent, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useDragEvents from '../dist/useDragEvents'\nimport assertHook from './utils/assertHook'\n\ndescribe('useDragEvents', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n    sinon.reset()\n  })\n\n  assertHook(useDragEvents)\n\n  it('should return an object of mouse-related callback setters', () => {\n    const targetRef = { current: document.createElement('div') }\n    const { result } = renderHook(() => useDragEvents(targetRef))\n\n    expect(result.current).to.be.an('object').that.has.all.keys('onDrag', 'onDrop', 'onDragEnter', 'onDragEnd', 'onDragExit', 'onDragLeave', 'onDragOver', 'onDragStart')\n  })\n\n  it('should set the draggable attribute to the given element ref', () => {\n    const TestComponent = () => {\n      const targetRef = useRef()\n      useDragEvents(targetRef)\n\n      return <div id=\"target\" ref={targetRef} />\n    }\n\n    const { container } = render(<TestComponent />)\n\n    expect(container.querySelector('#target').getAttribute('draggable')).to.equal('true')\n  })\n\n  it('should perform the set handlers when a drag event occurs to the target ref', () => {\n    const onDragSpy = sinon.spy()\n    const onDropSpy = sinon.spy()\n    const onDragEnterSpy = sinon.spy()\n    const onDragEndSpy = sinon.spy()\n    const onDragExitSpy = sinon.spy()\n    const onDragLeaveSpy = sinon.spy()\n    const onDragOverSpy = sinon.spy()\n    const onDragStartSpy = sinon.spy()\n\n    const TestComponent = () => {\n      const targetRef = useRef()\n      const {\n        onDrag, onDrop, onDragEnter, onDragEnd, onDragExit, onDragLeave, onDragOver, onDragStart\n      } = useDragEvents(targetRef)\n\n      onDrag(onDropSpy)\n      onDrop(onDragSpy)\n      onDragEnter(onDragEnterSpy)\n      onDragEnd(onDragEndSpy)\n      onDragExit(onDragExitSpy)\n      onDragLeave(onDragLeaveSpy)\n      onDragOver(onDragOverSpy)\n      onDragStart(onDragStartSpy)\n\n      return <div id=\"target\" ref={targetRef} />\n    }\n\n    const { container } = render(<TestComponent />)\n\n    fireEvent(container.querySelector('#target'), new MouseEvent('drag'))\n    fireEvent(container.querySelector('#target'), new MouseEvent('drop'))\n    fireEvent(container.querySelector('#target'), new MouseEvent('dragenter'))\n    fireEvent(container.querySelector('#target'), new MouseEvent('dragend'))\n    fireEvent(container.querySelector('#target'), new MouseEvent('dragexit'))\n    fireEvent(container.querySelector('#target'), new MouseEvent('dragleave'))\n    fireEvent(container.querySelector('#target'), new MouseEvent('dragover'))\n    fireEvent(container.querySelector('#target'), new MouseEvent('dragstart'))\n\n    expect(onDragSpy.called).to.be.true\n    expect(onDropSpy.called).to.be.true\n    expect(onDragEnterSpy.called).to.be.true\n    expect(onDragEndSpy.called).to.be.true\n    expect(onDragExitSpy.called).to.be.true\n    expect(onDragLeaveSpy.called).to.be.true\n    expect(onDragOverSpy.called).to.be.true\n    expect(onDragStartSpy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useDropZone.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useDropZone from '../dist/useDropZone'\nimport assertHook from './utils/assertHook'\n\ndescribe('useDropZone', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useDropZone)\n\n  it('should return an object the state of the current dragging element', () => {\n    const targetRef = { current: document.createElement('div') }\n    const { result } = renderHook(() => useDropZone(targetRef))\n\n    expect(result.current).to.be.an('object').that.has.all.deep.keys('isOver', 'onDrop')\n  })\n})\n"
  },
  {
    "path": "test/useEvent.spec.js",
    "content": "import React, { useRef } from 'react'\nimport { cleanup as cleanupReact, fireEvent, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useEvent from '../dist/useEvent'\nimport assertHook from './utils/assertHook'\n\ndescribe('useEvent', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n  })\n\n  assertHook(useEvent)\n\n  it('should return a single function', () => {\n    const target = { current: document.createElement('div') }\n    const { result } = renderHook(() => useEvent(target, 'click'))\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('the returned function should be a callback setter that fires when the event occurs', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const target = useRef()\n      const onElementClick = useEvent(target, 'click')\n\n      onElementClick(spy)\n\n      return <div ref={target} id=\"foo\" />\n    }\n\n    const { container } = render(<TestComponent />)\n\n    container.querySelector('#foo').click()\n\n    expect(spy.called).to.be.true\n    expect(spy.callCount).to.equal(1)\n\n    container.querySelector('#foo').click()\n    container.querySelector('#foo').click()\n    container.querySelector('#foo').click()\n\n    expect(spy.callCount).to.equal(4)\n  })\n\n  it('should change function when provided', () => {\n    const firstSpy = sinon.spy()\n    const secondSpy = sinon.spy()\n\n    const TestComponent = ({ callback }) => {\n      const ref = useRef()\n      const onRefClick = useEvent(ref, 'click')\n\n      onRefClick(callback)\n\n      return <div ref={ref} id=\"foo\" />\n    }\n\n    const { rerender, container } = render(<TestComponent callback={firstSpy} />)\n\n    container.querySelector('#foo').click()\n\n    expect(firstSpy.called).to.be.true\n    expect(firstSpy.callCount).to.equal(1)\n\n    rerender(<TestComponent callback={secondSpy} />)\n\n    container.querySelector('#foo').click()\n    container.querySelector('#foo').click()\n\n    expect(secondSpy.called).to.be.true\n    expect(firstSpy.callCount).to.equal(1)\n    expect(secondSpy.callCount).to.equal(2)\n  })\n\n  it('it should be \\'trickable\\' with global objects', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onWidowResize = useEvent({ current: window }, 'resize')\n\n      onWidowResize(spy)\n\n      return null\n    }\n\n    render(<TestComponent />)\n\n    const resizeEvent = window.document.createEvent('UIEvents')\n\n    resizeEvent.initUIEvent('resize', true, false, window, 0)\n\n    fireEvent(window, resizeEvent)\n\n    expect(spy.called).to.be.true\n    expect(spy.callCount).to.equal(1)\n  })\n})\n"
  },
  {
    "path": "test/useGeolocation.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useGeolocation from '../dist/useGeolocation'\nimport GeoLocationApiMock, { watchPositionSpy } from './mocks/GeoLocationApi.mock'\nimport assertHook from './utils/assertHook'\n\ndescribe('useGeolocation', () => {\n  before(() => {\n    window.navigator.geolocation = GeoLocationApiMock\n  })\n\n  beforeEach(() => cleanup())\n\n  after(() => {\n    delete window.navigator.geolocation\n  })\n\n  assertHook(useGeolocation)\n\n  it('should return an array where the first item is a geolocation state and the second an object of setters', () => {\n    const { result } = renderHook(() => useGeolocation())\n\n    expect(result.current).to.be.an('array')\n    expect(result.current.length).to.equal(2)\n    expect(result.current[0]).to.be.a('object').that.has.all.deep.keys('isSupported', 'isRetrieving', 'onError', 'position')\n    expect(result.current[1]).to.be.an('object').that.has.all.keys('isSupported', 'onChange', 'onError')\n  })\n\n  it('the provided options should be passed down to the other hooks', () => {\n    const optionsMock = { enableHighAccuracy: true }\n    renderHook(() => useGeolocation(optionsMock))\n\n    GeoLocationApiMock.listeners.s()\n    GeoLocationApiMock.listeners.e()\n\n    expect(watchPositionSpy.called).to.be.true\n    const lastOptions = watchPositionSpy.args[watchPositionSpy.callCount - 1][0]\n\n    expect(lastOptions).to.equal(optionsMock)\n  })\n})\n"
  },
  {
    "path": "test/useGeolocationEvents.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useGeolocationEvents from '../dist/useGeolocationEvents'\nimport GeoLocationApiMock, { watchPositionSpy } from './mocks/GeoLocationApi.mock'\nimport assertHook from './utils/assertHook'\n\ndescribe('useGeolocationEvents', () => {\n  before(() => {\n    window.navigator.geolocation = GeoLocationApiMock\n  })\n\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n    sinon.reset()\n  })\n\n  after(() => {\n    delete window.navigator.geolocation\n  })\n\n  assertHook(useGeolocationEvents)\n\n  it('should return an object of geolocation-related callback setters', () => {\n    const { result } = renderHook(() => useGeolocationEvents())\n\n    expect(result.current).to.be.an('object').that.has.all.deep.keys('isSupported', 'onChange', 'onError')\n    expect(result.current).to.be.frozen\n  })\n\n  it('should perform the onChange callback when geolocation changes', () => {\n    const onChangeSpy = sinon.spy()\n    const onErrorSpy = sinon.spy()\n\n    const TestComponent = () => {\n      const { onChange, onError } = useGeolocationEvents()\n\n      onChange(onChangeSpy)\n      onError(onErrorSpy)\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    GeoLocationApiMock.listeners.s()\n    GeoLocationApiMock.listeners.e()\n\n    expect(onChangeSpy.called).to.be.true\n  })\n\n  it('should accept an options object to be used as a parameter when calling watchPosition', () => {\n    const optionsMock = { foo: 'bar' }\n\n    const TestComponent = () => {\n      const { isSupported } = useGeolocationEvents(optionsMock)\n\n      return <div>{isSupported}</div>\n    }\n\n    render(<TestComponent />)\n\n    GeoLocationApiMock.listeners.s()\n    GeoLocationApiMock.listeners.e()\n\n    expect(watchPositionSpy.called).to.be.true\n    const lastOptions = watchPositionSpy.args[watchPositionSpy.callCount - 1][0]\n\n    expect(lastOptions).to.equal(optionsMock)\n  })\n})\n"
  },
  {
    "path": "test/useGeolocationState.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport GeoLocationApi, { positionMock, watchPositionSpy } from './mocks/GeoLocationApi.mock'\nimport useGeolocationState from '../dist/useGeolocationState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useGeolocationState', () => {\n  before(() => {\n    window.navigator.geolocation = GeoLocationApi\n  })\n\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n    sinon.reset()\n  })\n\n  after(() => {\n    delete window.navigator.geolocation\n  })\n\n  assertHook(useGeolocationState)\n\n  it('should return a frozen object containing information about the current position', () => {\n    const { result } = renderHook(() => useGeolocationState())\n\n    expect(result.current).to.be.frozen\n    expect(result.current).to.be.an('object').that.has.all.deep.keys('isSupported', 'isRetrieving', 'onError', 'position')\n    expect(result.current.position).to.deep.equal(positionMock)\n  })\n\n  it('should accept an options object to be used as a parameter when calling watchPosition', () => {\n    const optionsMock = { foo: 'bar' }\n\n    const TestComponent = () => {\n      const { isSupported } = useGeolocationState(optionsMock)\n\n      return <div>{isSupported}</div>\n    }\n\n    render(<TestComponent />)\n\n    expect(watchPositionSpy.called).to.be.true\n    const lastOptions = watchPositionSpy.args[watchPositionSpy.callCount - 1][0]\n\n    expect(lastOptions).to.equal(optionsMock)\n  })\n\n  describe('onError callback', () => {\n    const geolocationApiOnErrorTestWithoutMock = () => {\n      const onErrorSpy = sinon.spy()\n\n      const TestComponent = () => {\n        const { onError } = useGeolocationState()\n\n        onError(onErrorSpy);\n\n        return <div />\n      }\n\n      render(<TestComponent />)\n\n      expect(onErrorSpy.called).to.be.true\n\n      window.navigator.geolocation = GeoLocationApi;\n    }\n\n    it('should be called when the geolocation API`s getCurrentPosition function throws an error', () => {\n      Object.defineProperty(window.navigator, \"geolocation\", {\n        value: {\n          ...window.navigator.geolocation,\n          getCurrentPosition: (_, error) => {\n            error({\n              code: 1,\n              message: 'GeoLocation Error',\n            })\n          }\n        }\n      })\n\n      geolocationApiOnErrorTestWithoutMock();\n    });\n\n    it('should be called when the geolocation API`s watchPosition function throws an error', () => {\n      Object.defineProperty(window.navigator, \"geolocation\", {\n        value: {\n          ...window.navigator.geolocation,\n          watchPosition: (_, error) => {\n            error({\n              code: 1,\n              message: 'GeoLocation Error',\n            })\n          }\n        }\n      })\n\n      geolocationApiOnErrorTestWithoutMock();\n    });\n  });\n})\n"
  },
  {
    "path": "test/useGlobalEvent.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, fireEvent, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport { renderHook as renderServerHook } from '@testing-library/react-hooks/server'\nimport useGlobalEvent from '../dist/useGlobalEvent'\nimport assertHook from './utils/assertHook'\nimport noop from '../dist/shared/noop'\n\ndescribe('useGlobalEvent', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n  })\n\n  assertHook(useGlobalEvent)\n\n  it('should return a single function', () => {\n    const { result } = renderHook(() => useGlobalEvent('resize'))\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('the returned function should be a callback setter that fires when the event occurs', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onWindowResize = useGlobalEvent('resize')\n\n      onWindowResize(spy)\n\n      return null\n    }\n\n    render(<TestComponent />)\n\n    const resizeEvent = window.document.createEvent('UIEvents')\n    resizeEvent.initUIEvent('resize', true, false, window, 0)\n\n    fireEvent(window, resizeEvent)\n\n    expect(spy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useHandlerSetter.spec.js",
    "content": "import { act, cleanup, renderHook } from '@testing-library/react-hooks'\nimport createHandlerSetter from '../dist/factory/createHandlerSetter'\nimport assertFunction from './utils/assertFunction'\n\ndescribe('createHandlerSetter', () => {\n  beforeEach(() => cleanup())\n\n  assertFunction(createHandlerSetter)\n\n  it('should return an array of 2 elements', () => {\n    const { result } = renderHook(() => createHandlerSetter())\n\n    expect(result.current).to.be.an.instanceOf(Array)\n    expect(result.current.length).to.equal(2)\n  })\n\n  it('should return the reference to a handler', () => {\n    const { result } = renderHook(() => createHandlerSetter())\n    const [handlerRef] = result.current\n\n    expect(handlerRef.current).to.be.undefined\n    expect(handlerRef).to.be.an('object').that.has.all.keys('current')\n  })\n\n  it('should return a handler setter', () => {\n    const { result } = renderHook(() => createHandlerSetter())\n    const [handlerRef, setHandlerRef] = result.current\n\n    const fooCallback = () => undefined\n\n    expect(setHandlerRef).to.be.a('function')\n\n    act(() => {\n      setHandlerRef(fooCallback)\n    })\n\n    expect(handlerRef.current).to.equal(fooCallback)\n  })\n\n  it('the setter should throw when changing the handler to an invalid value', () => {\n    const { result } = renderHook(() => createHandlerSetter())\n    const [, setHandlerRef] = result.current\n\n    const shouldThrow = () => {\n      setHandlerRef({ foo: 'bar' })\n    }\n\n    expect(shouldThrow).to.throw()\n  })\n})\n"
  },
  {
    "path": "test/useInfiniteScroll.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useInfiniteScroll from '../dist/useInfiniteScroll'\nimport assertHook from './utils/assertHook'\n\ndescribe('useInfiniteScroll', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useInfiniteScroll)\n\n  it('should return an callback setter', () => {\n    const ref = { current: document.createElement('div') }\n    const { result } = renderHook(() => useInfiniteScroll(ref))\n\n    expect(result.current).to.be.a('function')\n  })\n})\n"
  },
  {
    "path": "test/useInterval.spec.js",
    "content": "import React from 'react'\nimport { act, cleanup, renderHook } from '@testing-library/react-hooks'\nimport useInterval from '../dist/useInterval'\nimport assertHook from './utils/assertHook'\n\ndescribe('useInterval', () => {\n  beforeEach(() => cleanup())\n  afterEach(sinon.restore)\n\n  assertHook(useInterval)\n\n  it('should return an array, the first item is the interval state whilst the second its clearing method', () => {\n    const { result } = renderHook(() => useInterval(() => null, 1000))\n\n    expect(result.current).to.be.an('array')\n    expect(result.current[0]).to.be.an('boolean')\n    expect(result.current[1]).to.be.a('function')\n  })\n\n  it('even if the provided options is null, it should keep working', () => {\n    const { result } = renderHook(() => useInterval(() => null, 1000, null))\n\n    expect(result.current).to.be.an('array')\n  })\n\n  it('should allow to clear the created interval', () => {\n    const spy = sinon.spy()\n    const ms = 100\n    const { result, error } = renderHook(() => useInterval(spy, ms))\n    const clear = result.current[1]\n\n    expect(result.current[0]).to.be.false\n\n    act(clear)\n\n    expect(result.current[0]).to.be.true\n    expect(spy.called).to.be.false\n\n    act(clear)\n\n    expect(result.current[0]).to.be.true\n\n    expect(error).to.be.undefined\n  })\n\n  it('should check the received parameters to avoid errors', () => {\n    const { result } = renderHook(() => useInterval(10, { foo: 'bar' }))\n    const clear = result.current[1]\n\n    expect(result.current[0]).to.be.false\n    expect(clear).to.be.a('function')\n\n    act(clear)\n\n    expect(result.current[0]).to.be.false\n  })\n})\n"
  },
  {
    "path": "test/useIsFirstRender.spec.js",
    "content": "import React from 'react'\nimport { cleanup, render } from '@testing-library/react'\n\nimport assertHook from './utils/assertHook'\nimport useIsFirstRender from '../dist/useIsFirstRender'\n\ndescribe('useIsFirstRender', () => {\n  beforeEach(() => {\n    cleanup()\n  })\n\n  assertHook(useIsFirstRender)\n\n  it('should return isFirstRender flag set to true before the first render and then always false', () => {\n    const TestComponent = ({ isAfterRerender }) => {\n      const isFirstRender = useIsFirstRender();\n\n      if (!isAfterRerender) {\n        expect(isFirstRender).to.be.eq(true)\n      } else {\n        expect(isFirstRender).to.be.eq(false)\n      }\n\n      return <div />\n    }\n\n    const { rerender } = render(<TestComponent isAfterRerender={false} />)\n\n    rerender(<TestComponent isAfterRerender />)\n    rerender(<TestComponent isAfterRerender />)\n  })\n})\n"
  },
  {
    "path": "test/useLifecycle.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useLifecycle from '../dist/useLifecycle'\nimport assertHook from './utils/assertHook'\n\ndescribe('useLifecycle', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useLifecycle)\n\n  it('the returned function should wrap other lifecycle hooks', () => {\n    const { result } = renderHook(() => useLifecycle())\n\n    expect(result.current).to.be.an('object').that.has.all.keys('onDidMount', 'onWillUnmount')\n  })\n})\n"
  },
  {
    "path": "test/useLocalStorage.spec.js",
    "content": "import { cleanup as cleanupReact } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport { act } from 'react-dom/test-utils'\nimport useLocalStorage from '../dist/useLocalStorage'\nimport assertHook from './utils/assertHook'\n\ndescribe('useLocalStorage', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  afterEach(() => {\n    sinon.restore()\n  })\n\n  assertHook(useLocalStorage)\n\n  it('should return null when no default value defined', () => {\n    const { result } = renderHook(() => useLocalStorage('storageKey_1'))\n    const [value] = result.current\n\n    expect(value).to.equal(null)\n  })\n\n  it('should return default value', () => {\n    const { result } = renderHook(() => useLocalStorage('storageKey_2', 100))\n    const [value] = result.current\n\n    expect(value).to.equal(100)\n    expect(JSON.parse(window.localStorage.getItem('storageKey_2'))).to.equal(100)\n  })\n\n  it('should store and return new values', () => {\n    const { result } = renderHook(() =>\n      useLocalStorage(\"storageKey_3\", 100)\n    )\n\n    expect(result.current[0]).to.equal(100)\n    expect(JSON.parse(window.localStorage.getItem('storageKey_3'))).to.equal(100)\n\n    act(() => {\n      result.current[1](200)\n    })\n\n    expect(result.current[0]).to.equal(200)\n    expect(JSON.parse(window.localStorage.getItem('storageKey_3'))).to.equal(200)\n  })\n\n  it('should accept a callback argument for setValue', () => {\n    const { result } = renderHook(() =>\n      useLocalStorage(\"storageKey_4\", 100)\n    )\n\n    expect(result.current[0]).to.equal(100)\n    expect(JSON.parse(window.localStorage.getItem('storageKey_4'))).to.equal(100)\n\n    act(() => {\n      result.current[1](prev => prev + 100)\n    })\n\n    expect(result.current[0]).to.equal(200)\n    expect(JSON.parse(window.localStorage.getItem('storageKey_4'))).to.equal(200)\n  });\n\n  it('should gracefully handle a getItem error and use the default value', () => {\n    Object.defineProperty(window, \"localStorage\", {\n      value: {\n        ...window.localStorage,\n        getItem: () => {\n          throw new Error()\n        },\n      },\n    })\n\n    const { result } = renderHook(() =>\n      useLocalStorage(\"storageKey_5\", 100)\n    )\n    const [value] = result.current\n\n    expect(value).to.equal(100)\n  })\n\n  it(\"should gracefully handle a setItem error and set the new value\", () => {\n    Object.defineProperty(window, \"localStorage\", {\n      value: {\n        ...window.localStorage,\n        setItem: () => {\n          throw new Error()\n        },\n      },\n    })\n\n    const { result } = renderHook(() =>\n      useLocalStorage(\"storageKey_6\", 100)\n    )\n\n    act(() => {\n      result.current[1](200)\n    })\n\n    expect(result.current[0]).to.equal(200)\n  })\n\n  it(\"should return the same setValue reference after setValue is called\", () => {\n    const { result } = renderHook(() =>\n      useLocalStorage(\"storageKey_7\", 100)\n    )\n\n    const startingSetValue = result.current[1]\n\n    act(() => {\n      result.current[1](prev => prev + 100)\n    })\n    \n    expect(result.current[1]).to.equal(startingSetValue)\n  })\n})\n"
  },
  {
    "path": "test/useLongPress.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useLongPress from '../dist/useLongPress'\nimport assertHook from './utils/assertHook'\n\ndescribe('useLongPress', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useLongPress)\n\n  it('should return a boolean value reporting whether the long-press event is happening as well as the handlers setters', () => {\n    const ref = { current: document.createElement('div') }\n    const { result } = renderHook(() => useLongPress(ref))\n\n    expect(result.current.isLongPressing).to.be.a('boolean')\n    expect(result.current.onLongPressStart).to.be.a('function')\n    expect(result.current.onLongPressEnd).to.be.a('function')\n  })\n})\n"
  },
  {
    "path": "test/useMediaQuery.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\n\nimport assertHook from './utils/assertHook'\nimport useMediaQuery from '../dist/useMediaQuery'\nimport mediaQueryListMock from './mocks/MatchMediaQueryList.mock'\n\ndescribe('useMediaQuery', () => {\n  beforeEach(() => {\n    cleanup()\n  })\n\n  afterEach(() => {\n    sinon.restore()\n  })\n\n  assertHook(useMediaQuery)\n\n  it('should return a boolean value', () => {\n    window.matchMedia = () => (mediaQueryListMock)\n    const { result } = renderHook(() => useMediaQuery('(min-width: 1024px)'))\n\n    expect(result.current).to.be.a('boolean')\n\n    delete window.matchMedia\n  })\n\n  it('should warn when the window.matchMedia API is not supported', () => {\n    delete window.matchMedia\n    const warnSpy = sinon.spy(console, 'warn')\n    const { result } = renderHook(() => useMediaQuery('(min-width: 1024px)'))\n\n    expect(result.current).to.be.false\n    expect(warnSpy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useMouse.spec.js",
    "content": "import { act, cleanup, renderHook } from '@testing-library/react-hooks'\nimport useMouse from '../dist/useMouse'\nimport assertHook from './utils/assertHook'\n\ndescribe('useMouse', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useMouse)\n\n  it('should return an array where the first item is a mouse state and the second a group of setters', () => {\n    const ref = { current: document.createElement('div') }\n    const { result } = renderHook(() => useMouse(ref))\n\n    expect(result.current).to.be.an('array')\n    expect(result.current.length).to.equal(2)\n    expect(result.current[0]).to.be.a('object').that.has.all.keys('clientX', 'clientY', 'screenY', 'screenY')\n    expect(result.current[1]).to.be.an('object').that.has.all.keys(\n      'onMouseDown', 'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp'\n    )\n  })\n\n  it('should work without a ref provided ', () => {\n    const positionMock = { clientX: 10, clientY: 10, screenX: 30, screenY: 30 }\n    const { result } = renderHook(() => useMouse())\n\n    act(() => {\n      const mouseEvent = new MouseEvent('mousemove', positionMock)\n      document.dispatchEvent(mouseEvent)\n    })\n\n    expect(result.current[0]).to.deep.equal(positionMock)\n  })\n})\n"
  },
  {
    "path": "test/useMouseEvents.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, fireEvent, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useMouseEvents from '../dist/useMouseEvents'\nimport assertHook from './utils/assertHook'\n\ndescribe('useMouseEvents', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n    sinon.reset()\n  })\n\n  assertHook(useMouseEvents)\n\n  it('should return an object of mouse-related callback setters', () => {\n    const { result } = renderHook(() => useMouseEvents())\n\n    expect(result.current).to.be.an('object').that.has.all.keys('onMouseDown', 'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp')\n  })\n\n  it('if no ref is provided, should perform the set callback when a mouse event occurs globally', () => {\n    const mouseMoveSpy = sinon.spy()\n    const mouseDownSpy = sinon.spy()\n    const mouseEnterSpy = sinon.spy()\n    const mouseLeaveSpy = sinon.spy()\n    const mouseOutSpy = sinon.spy()\n    const mouseUpSpy = sinon.spy()\n    const mouseOverSpy = sinon.spy()\n\n    const TestComponent = () => {\n      const {\n        onMouseDown, onMouseEnter, onMouseLeave, onMouseMove, onMouseOut, onMouseUp, onMouseOver\n      } = useMouseEvents()\n\n      onMouseDown(mouseDownSpy)\n      onMouseMove(mouseMoveSpy)\n      onMouseEnter(mouseEnterSpy)\n      onMouseLeave(mouseLeaveSpy)\n      onMouseOut(mouseOutSpy)\n      onMouseUp(mouseUpSpy)\n      onMouseOver(mouseOverSpy)\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    fireEvent(document, new MouseEvent('mousedown'))\n    fireEvent(document, new MouseEvent('mouseenter'))\n    fireEvent(document, new MouseEvent('mouseleave'))\n    fireEvent(document, new MouseEvent('mousemove'))\n    fireEvent(document, new MouseEvent('mouseout'))\n    fireEvent(document, new MouseEvent('mouseup'))\n    fireEvent(document, new MouseEvent('mouseover'))\n\n    expect(mouseMoveSpy.called).to.be.true\n    expect(mouseDownSpy.called).to.be.true\n    expect(mouseEnterSpy.called).to.be.true\n    expect(mouseLeaveSpy.called).to.be.true\n    expect(mouseOutSpy.called).to.be.true\n    expect(mouseUpSpy.called).to.be.true\n    expect(mouseOverSpy.called).to.be.true\n  })\n\n  it('if ref is provided, should perform the set callback when a mouse event occurs to the given ref', () => {\n    const refMock = { current: document.createElement('div') }\n    const mouseMoveSpy = sinon.spy()\n    const mouseDownSpy = sinon.spy()\n    const mouseEnterSpy = sinon.spy()\n    const mouseLeaveSpy = sinon.spy()\n    const mouseOutSpy = sinon.spy()\n    const mouseUpSpy = sinon.spy()\n    const mouseOverSpy = sinon.spy()\n\n    const TestComponent = () => {\n      const {\n        onMouseDown, onMouseEnter, onMouseLeave, onMouseMove, onMouseOut, onMouseUp, onMouseOver\n      } = useMouseEvents(refMock)\n\n      onMouseDown(mouseDownSpy)\n      onMouseMove(mouseMoveSpy)\n      onMouseEnter(mouseEnterSpy)\n      onMouseLeave(mouseLeaveSpy)\n      onMouseOut(mouseOutSpy)\n      onMouseUp(mouseUpSpy)\n      onMouseOver(mouseOverSpy)\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    fireEvent(refMock.current, new MouseEvent('mousedown'))\n    fireEvent(refMock.current, new MouseEvent('mouseenter'))\n    fireEvent(refMock.current, new MouseEvent('mouseleave'))\n    fireEvent(refMock.current, new MouseEvent('mousemove'))\n    fireEvent(refMock.current, new MouseEvent('mouseout'))\n    fireEvent(refMock.current, new MouseEvent('mouseup'))\n    fireEvent(refMock.current, new MouseEvent('mouseover'))\n\n    expect(mouseMoveSpy.called).to.be.true\n    expect(mouseDownSpy.called).to.be.true\n    expect(mouseEnterSpy.called).to.be.true\n    expect(mouseLeaveSpy.called).to.be.true\n    expect(mouseOutSpy.called).to.be.true\n    expect(mouseUpSpy.called).to.be.true\n    expect(mouseOverSpy.called).to.be.true\n  })\n\n  it('if the provided ref is not an instance of HTMLElement should not add any listener', () => {\n    const refMock = { current: { dispatchEvent: () => undefined } }\n    const mouseMoveSpy = sinon.spy()\n\n    const TestComponent = () => {\n      const { onMouseMove } = useMouseEvents(refMock)\n\n      onMouseMove(mouseMoveSpy)\n\n      return <div />\n    }\n\n    const { rerender } = render(<TestComponent />)\n\n    fireEvent(refMock.current, new MouseEvent('mousemove'))\n\n    expect(mouseMoveSpy.called).to.be.false\n\n    rerender(null)\n\n    fireEvent(refMock.current, new MouseEvent('mousemove'))\n\n    expect(mouseMoveSpy.called).to.be.false\n  })\n})\n"
  },
  {
    "path": "test/useMouseState.spec.js",
    "content": "import { act, cleanup, renderHook } from '@testing-library/react-hooks'\nimport useMouseState from '../dist/useMouseState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useMouseState', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useMouseState)\n\n  it('should return a mouse coordinates reporting object', () => {\n    const { result } = renderHook(() => useMouseState())\n\n    expect(result.current).to.be.a('object').that.has.all.keys('clientX', 'clientY', 'screenY', 'screenY')\n  })\n\n  it('should update the mouse position whilst it moves', () => {\n    const refMock = { current: document.createElement('div') }\n    const positionMock = { clientX: 10, clientY: 10, screenX: 30, screenY: 30 }\n    const { result } = renderHook(() => useMouseState(refMock))\n\n    act(() => {\n      const mouseEvent = new MouseEvent('mousemove', positionMock)\n      refMock.current.dispatchEvent(mouseEvent)\n    })\n\n    expect(result.current).to.deep.equal(positionMock)\n  })\n})\n"
  },
  {
    "path": "test/useMutableState.spec.js",
    "content": "import React, { useEffect } from 'react'\nimport { render } from '@testing-library/react'\nimport { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useMutableState from '../dist/useMutableState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useMutableState', () => {\n  beforeEach(cleanup)\n\n  assertHook(useMutableState)\n\n  it('should return an object', () => {\n    const { result } = renderHook(() => useMutableState({ value: 0 }))\n\n    expect(result.current).to.be.an('object').that.has.property('value')\n  })\n\n  it('should re-render when the value changes', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const state = useMutableState({ value: 0 })\n\n      spy()\n\n      useEffect(() => {\n        state.value = 1\n      }, [])\n\n      return <div>val: {state.value}</div>\n    }\n\n    render(<TestComponent />)\n\n    expect(spy.callCount).to.equal(2)\n  })\n})\n"
  },
  {
    "path": "test/useMutationObserver.spec.js",
    "content": "import React, { useRef, useState } from 'react'\nimport MutationObserverMock from 'mutation-observer'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\n\nimport assertHook from './utils/assertHook'\nimport promiseDelay from './utils/promiseDelay'\nimport useMutationObserver from '../dist/useMutationObserver'\n\ndescribe('useMutationObserver', () => {\n  const originalMutationObserver = global.MutationObserver\n\n  before(() => {\n    global.MutationObserver = window.MutationObserver = MutationObserverMock\n  })\n\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  after(() => {\n    global.MutationObserver = window.MutationObserver = originalMutationObserver\n  })\n\n  assertHook(useMutationObserver)\n\n  describe('when the MutationObserver API is not supported', () => {  \n    beforeEach(() => {\n      delete global.MutationObserver\n      delete window.MutationObserver\n    })\n  \n    afterEach(() => {\n      global.MutationObserver = window.MutationObserver = originalMutationObserver\n      sinon.restore()\n    })\n  \n    it('should not observe anything', async () => {\n      const refMock = { current: document.createElement('div') }\n      const warnSpy = sinon.spy(console, 'warn')\n  \n      const { result } = renderHook(() => useMutationObserver(refMock))\n  \n      expect(warnSpy.called).to.be.true\n      expect(result.current).to.be.undefined\n    })\n  })\n\n  it('should observe for element mutations when the MutationObserver API is supported', async () => {\n    const callbackSpy = sinon.spy()\n\n    const TestComponent = () => {\n      const ref = useRef(null)\n      const [count, setCount] = useState(0)\n\n      useState(() => {\n        const clear = setTimeout(() => {\n          setCount(prev => prev + 1)\n        }, 200);\n\n        return () => clearTimeout(clear)\n      }, [])\n\n      useMutationObserver(ref, callbackSpy)\n\n      return (\n        <div ref={ref}>\n          <div>Hello</div>\n          <div>World</div>\n          <div>Mutation counter: {count}</div>\n        </div>\n      );\n    }\n\n    render(<TestComponent />)\n\n    expect(callbackSpy.called).to.be.false\n\n    await promiseDelay(300)\n\n    expect(callbackSpy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useObjectState.spec.js",
    "content": "import { act, cleanup, renderHook } from \"@testing-library/react-hooks\";\n\nimport assertHook from \"./utils/assertHook\";\nimport useObjectState from \"../dist/useObjectState\";\n\ndescribe(\"useObjectState\", () => {\n  beforeEach(() => cleanup());\n\n  assertHook(useObjectState);\n\n  it(\"should return updated object state\", async () => {\n    const { result, waitFor } = renderHook(() =>\n      useObjectState({ test: \"test\", test1: \"test1\" })\n    );\n\n    const [state, setState] = result.current;\n\n    expect(state)\n      .to.be.an(\"object\")\n      .that.has.deep.equal({ test: \"test\", test1: \"test1\" });\n\n    act(() => {\n      setState({ test1: \"it works\" });\n    });\n\n    await waitFor(() => {\n      expect(result.current[0])\n        .to.be.an(\"object\")\n        .that.has.deep.equal({ test: \"test\", test1: \"it works\" });\n    });\n  });\n});\n"
  },
  {
    "path": "test/useObservable.spec.js",
    "content": "import React from 'react'\nimport { from } from 'rxjs'\nimport { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useObservable from '../dist/useObservable'\nimport assertHook from './utils/assertHook'\n\ndescribe('useObservable', () => {\n  beforeEach(() => cleanup())\n\n  afterEach(sinon.restore)\n\n  assertHook(useObservable)\n\n  it('should return a function', (done) => {\n    const observer = renderHook(() => useObservable(from([1]), () => done()))\n    expect(observer).to.be.a('function')\n  })\n\n  it('should subscribe correctly', (done) => {\n    const numbers$ = from([1, 2, 3, 4, 5])\n    const expected = []\n    renderHook(() => useObservable(numbers$, (result) => expected.push(result)))\n    expect(expected).to.have.lengthOf(5)\n    done()\n  })\n})\n"
  },
  {
    "path": "test/useOnlineState.spec.js",
    "content": "import { fireEvent } from '@testing-library/react'\nimport { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useOnlineState from '../dist/useOnlineState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useOnlineState', () => {\n  beforeEach(() => {\n    cleanup()\n    window.ononline = null\n  })\n\n  assertHook(useOnlineState)\n\n  it('should return a boolean value', () => {\n    const { result } = renderHook(() => useOnlineState('resize'))\n\n    expect(result.current).to.be.a('boolean')\n  })\n\n  it('should return true if the device not support online event', () => {\n    delete window.ononline\n\n    const spy = sinon.spy(window.console, 'warn')\n    const { result } = renderHook(() => useOnlineState())\n    expect(spy.calledOnce).to.be.true\n    expect(result.current).to.be.true\n  })\n\n  it('should change after an online/offline event', () => {\n    const { result } = renderHook(() => useOnlineState())\n    expect(result.current).to.be.true\n\n    const offlineEvent = window.document.createEvent('Event')\n    offlineEvent.initEvent('offline', false, false)\n    fireEvent(window, offlineEvent)\n    expect(result.current).to.be.false\n\n    const onlineEvent = window.document.createEvent('Event')\n    onlineEvent.initEvent('online', false, false)\n    fireEvent(window, onlineEvent)\n    expect(result.current).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/usePreviousValue.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport usePreviousValue from '../dist/usePreviousValue'\nimport assertHook from './utils/assertHook'\n\ndescribe('usePreviousValue', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  afterEach(sinon.restore)\n\n  assertHook(usePreviousValue)\n\n  it('should return undefined after the first render', () => {\n    const { result } = renderHook(() => usePreviousValue(10))\n\n    expect(result.current).to.be.undefined\n  })\n\n  it('should return the previous value of a given variable', () => {\n    const TestComponent = (props) => {\n      // eslint-disable-next-line react/prop-types\n      const { value } = props\n      const prev = usePreviousValue(value)\n\n      return <p>{prev}</p>\n    }\n\n    const { container, rerender } = render(<TestComponent value={1} />)\n    rerender(<TestComponent value={2} />)\n\n    expect(container.querySelector('p').innerHTML).to.equal('1')\n  })\n})\n"
  },
  {
    "path": "test/useQueryParam.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useQueryParam from '../dist/useQueryParam'\nimport assertHook from './utils/assertHook'\nimport ReactRouterWrapper from './utils/ReactRouterWrapper'\n\ndescribe('useQueryParam', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useQueryParam)\n\n  it('should work similar to useState', () => {\n    const initialValue = 'bar'\n    const { result } = renderHook(() => useQueryParam('foo', { initialValue }), { wrapper: ReactRouterWrapper })\n    const [val, setVal] = result.current\n\n    expect(val).to.be.a('string')\n    expect(val).to.equal(initialValue)\n    expect(setVal).to.be.a('function')\n  })\n})\n"
  },
  {
    "path": "test/useQueryParams.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useQueryParams from '../dist/useQueryParams'\nimport assertHook from './utils/assertHook'\nimport ReactRouterWrapper from './utils/ReactRouterWrapper'\n\ndescribe('useQueryParams', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useQueryParams)\n\n  it('should work similar to useState', () => {\n    const initialValue = ['1', '2', '3']\n    const { result } = renderHook(() => useQueryParams('foo[]', { initialValue }), { wrapper: ReactRouterWrapper })\n    const [val, setVal] = result.current\n\n    expect(val).to.be.an('array')\n    expect(val).to.deep.equal(initialValue)\n    expect(setVal).to.be.a('function')\n  })\n})\n"
  },
  {
    "path": "test/useRenderInfo.spec.js",
    "content": "import React from 'react'\nimport { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useRenderInfo from '../dist/useRenderInfo'\nimport assertHook from './utils/assertHook'\n\ndescribe('useRenderInfo', () => {\n  beforeEach(() => cleanup())\n\n  afterEach(sinon.restore)\n\n  assertHook(useRenderInfo)\n\n  it('should return an information object', () => {\n    const name = 'Foo'\n    const { result: { current: info } } = renderHook(() => useRenderInfo(name, false))\n\n    expect(info).to.be.an('object')\n    expect(info.module).to.equal(name)\n    expect(info.renders).to.be.a('number')\n    expect(info.sinceLast).to.be.a('string')\n    expect(info.timestamp).to.be.a('number')\n  })\n\n  it('should print consistent information', () => {\n    const { result: { current: info }, rerender } = renderHook(() => useRenderInfo('foo', false))\n\n    rerender()\n    rerender()\n\n    expect(info.renders).to.equal(3)\n  })\n\n  it('should print renders information in group', () => {\n    const groupSpy = sinon.spy(console, 'group')\n    const groupEndSpy = sinon.spy(console, 'groupEnd')\n    const logSpy = sinon.spy(console, 'log')\n\n    renderHook(() => useRenderInfo(name, true))\n\n    expect(logSpy.called).to.be.true\n    expect(groupSpy.called).to.be.true\n    expect(groupEndSpy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useRequestAnimationFrame.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useRequestAnimationFrame from '../dist/useRequestAnimationFrame'\nimport promiseDelay from './utils/promiseDelay'\nimport assertHook from './utils/assertHook'\n\ndescribe('useRequestAnimationFrame', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n    if (window.requestAnimationFrame) {\n      window.requestAnimationFrame = (fn) => fn()\n    }\n  })\n\n  afterEach(sinon.restore)\n\n  assertHook(useRequestAnimationFrame)\n\n  it('should immediately perform the given function', () => {\n    window.requestAnimationFrame = (fn) => fn()\n    const spy = sinon.spy()\n\n    renderHook(() => useRequestAnimationFrame(spy))\n\n    expect(spy.called).to.be.true\n    expect(spy.args[0][0]).to.be.a('number')\n    expect(spy.args[0][1]).to.be.a('function')\n\n    delete window.requestAnimationFrame\n  })\n\n  it('should return an onFinish callback to be performed when the animation finishes', async () => {\n    window.requestAnimationFrame = (fn) => setTimeout(fn, 1)\n\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onFinish = useRequestAnimationFrame((c, next) => next(), { increment: 5, finishAt: 50, startAt: 0 })\n\n      onFinish(spy)\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    await promiseDelay(500)\n\n    expect(spy.called).to.be.true\n    delete window.requestAnimationFrame\n  })\n})\n"
  },
  {
    "path": "test/useResizeObserver.spec.js",
    "content": "import { act, cleanup, renderHook } from '@testing-library/react-hooks'\nimport { expect } from 'chai'\nimport useResizeObserver from '../dist/useResizeObserver'\nimport ResizeObserverMock from './mocks/ResizeObserver.mock'\nimport promiseDelay from './utils/promiseDelay'\nimport assertHook from './utils/assertHook'\n\ndescribe('useResizeObserver', () => {\n  const originalRO = global.ResizeObserver\n\n  before(() => {\n    global.ResizeObserver = window.ResizeObserver = ResizeObserverMock\n  })\n\n  beforeEach(() => {\n    cleanup()\n  })\n\n  after(() => {\n    global.ResizeObserver = window.ResizeObserver = originalRO\n  })\n\n  assertHook(useResizeObserver)\n\n  it('should return undefined when first initialised', () => {\n    const refMock = { current: document.createElement('div') }\n    const { result } = renderHook(() => useResizeObserver(refMock, 100))\n    expect(result.current).to.be.undefined\n  })\n\n  it('should return a single function', async () => {\n    const refMock = { current: document.createElement('div') }\n    const { result, rerender } = renderHook(() => useResizeObserver(refMock, 0))\n\n    act(() => {\n      ResizeObserver.simulateResize(refMock.current)\n    })\n\n    rerender()\n\n    await promiseDelay(250) // wait 250ms to let the debounced fn to perform\n\n    return expect(result.current).to.be.an('object')\n  })\n})\n\ndescribe('useResizeObserver (when the API is not supported)', () => {\n  const originalRO = global.ResizeObserver\n\n  beforeEach(() => {\n    delete global.ResizeObserver\n    delete window.ResizeObserver\n  })\n\n  afterEach(() => {\n    global.ResizeObserver = window.ResizeObserver = originalRO\n    sinon.restore()\n  })\n\n  it('should not observe anything', async () => {\n    const refMock = { current: document.createElement('div') }\n    const warnSpy = sinon.spy(console, 'warn')\n\n    const { result } = renderHook(() => useResizeObserver(refMock))\n\n    expect(warnSpy.called).to.be.true\n    expect(result.current).to.be.undefined\n  })\n})\n"
  },
  {
    "path": "test/useSearchQuery.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useSearchQuery from '../dist/useSearchQuery'\nimport assertHook from './utils/assertHook'\nimport ReactRouterWrapper from './utils/ReactRouterWrapper'\n\ndescribe('useSearchQuery', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useSearchQuery)\n\n  it('should work similar to useState', () => {\n    const initialValue = 'foo'\n    const { result } = renderHook(() => useSearchQuery(initialValue), { wrapper: ReactRouterWrapper })\n    const [val, setVal] = result.current\n\n    expect(val).to.be.a('string')\n    expect(val).to.equal(initialValue)\n    expect(setVal).to.be.a('function')\n  })\n})\n"
  },
  {
    "path": "test/useSessionStorage.spec.js",
    "content": "import { cleanup as cleanupReact } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook, act } from '@testing-library/react-hooks'\nimport useSessionStorage from '../dist/useSessionStorage'\nimport assertHook from './utils/assertHook'\n\ndescribe('useSessionStorage', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  afterEach(() => {\n    sinon.restore()\n  })\n\n  assertHook(useSessionStorage)\n\n  it('should return null when no default value defined', () => {\n    const { result } = renderHook(() => useSessionStorage('storageKey_1'))\n    const [value] = result.current\n\n    expect(value).to.equal(null)\n  })\n\n  it('should return default value', () => {\n    const { result } = renderHook(() => useSessionStorage('storageKey_2', 100))\n    const [value] = result.current\n\n    expect(value).to.equal(100)\n    expect(JSON.parse(window.sessionStorage.getItem('storageKey_2'))).to.equal(100)\n  })\n\n  it('should store and return new values', () => {\n    const { result } = renderHook(() =>\n      useSessionStorage(\"storageKey_3\", 100)\n    )\n\n    expect(result.current[0]).to.equal(100)\n    expect(JSON.parse(window.sessionStorage.getItem('storageKey_3'))).to.equal(100)\n\n    act(() => {\n      result.current[1](200)\n    })\n\n    expect(result.current[0]).to.equal(200)\n    expect(JSON.parse(window.sessionStorage.getItem('storageKey_3'))).to.equal(200)\n  })\n\n  it('should accept a callback argument for setValue', () => {\n    const { result } = renderHook(() =>\n      useSessionStorage(\"storageKey_4\", 100)\n    )\n\n    expect(result.current[0]).to.equal(100)\n    expect(JSON.parse(window.sessionStorage.getItem('storageKey_4'))).to.equal(100)\n\n    act(() => {\n      result.current[1](prev => prev + 100)\n    })\n\n    expect(result.current[0]).to.equal(200)\n    expect(JSON.parse(window.sessionStorage.getItem('storageKey_4'))).to.equal(200)\n  })\n\n  it('should gracefully handle a getItem error and use the default value', () => {\n    Object.defineProperty(window, \"sessionStorage\", {\n      value: {\n        ...window.sessionStorage,\n        getItem: () => {\n          throw new Error()\n        },\n      },\n    })\n\n    const { result } = renderHook(() =>\n      useSessionStorage(\"storageKey_5\", 100)\n    )\n    const [value] = result.current\n    expect(value).to.equal(100)\n  })\n\n  it(\"should gracefully handle a setItem error and set the new value\", () => {\n    Object.defineProperty(window, \"sessionStorage\", {\n      value: {\n        ...window.sessionStorage,\n        setItem: () => {\n          throw new Error()\n        },\n      },\n    })\n\n    const { result } = renderHook(() =>\n      useSessionStorage(\"storageKey_6\", 100)\n    )\n\n    act(() => {\n      result.current[1](200)\n    })\n\n    expect(result.current[0]).to.equal(200)\n  })\n\n  it(\"should return the same setValue reference after setValue is called\", () => {\n    const { result } = renderHook(() =>\n      useSessionStorage(\"storageKey_7\", 100)\n    )\n\n    const startingSetValue = result.current[1]\n\n    act(() => {\n      result.current[1](prev => prev + 100)\n    })\n    \n    expect(result.current[1]).to.equal(startingSetValue)\n  })\n})\n"
  },
  {
    "path": "test/useSpeechRecognition.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useSpeechRecognition from '../dist/useSpeechRecognition'\nimport SpeechSynthesisUtteranceMock from './mocks/SpeechSynthesisUtterance.mock'\nimport SpeechSynthesisMock from './mocks/SpeechSynthesis.mock'\nimport assertHook from './utils/assertHook'\n\ndescribe('useSpeechRecognition', () => {\n  const originalSpeechSynth = global.speechSynthesis\n  const originalSpeechSynthesisUtterance = global.SpeechSynthesisUtterance\n\n  before(() => {\n    global.speechSynthesis = SpeechSynthesisMock\n    global.SpeechSynthesisUtterance = SpeechSynthesisUtteranceMock\n  })\n\n  beforeEach(() => cleanup())\n\n  after(() => {\n    global.SpeechSynthesisUtterance = originalSpeechSynthesisUtterance\n    global.speechSynthesis = originalSpeechSynth\n  })\n\n  assertHook(useSpeechRecognition)\n\n  it('should return an object containing the speak function and the utter', () => {\n    const { result } = renderHook(() => useSpeechRecognition())\n\n    expect(result.current).to.be.an('object')\n    expect(result.current.startRecording).to.be.a('function')\n    expect(result.current.stopRecording).to.be.a('function')\n    expect(result.current.transcript).to.be.a('string')\n    expect(result.current.isRecording).to.be.a('boolean')\n    expect(result.current.isSupported).to.be.a('boolean')\n  })\n})\n"
  },
  {
    "path": "test/useSpeechSynthesis.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useSpeechSynthesis from '../dist/useSpeechSynthesis'\nimport SpeechSynthesisUtteranceMock from './mocks/SpeechSynthesisUtterance.mock'\nimport SpeechSynthesisMock from './mocks/SpeechSynthesis.mock'\nimport assertHook from './utils/assertHook'\n\ndescribe('useSpeechSynthesis', () => {\n  const originalSpeechSynth = global.speechSynthesis\n  const originalSpeechSynthesisUtterance = global.SpeechSynthesisUtterance\n\n  before(() => {\n    global.speechSynthesis = SpeechSynthesisMock\n    global.SpeechSynthesisUtterance = SpeechSynthesisUtteranceMock\n  })\n\n  beforeEach(() => cleanup())\n\n  after(() => {\n    global.SpeechSynthesisUtterance = originalSpeechSynthesisUtterance\n    global.speechSynthesis = originalSpeechSynth\n  })\n\n  assertHook(useSpeechSynthesis)\n\n  it('should return an object containing the speak function and the utter', () => {\n    const { result } = renderHook(() => useSpeechSynthesis('text', { volume: 1, pitch: 1, rate: 1 }))\n\n    expect(result.current).to.be.an('object')\n    expect(result.current.speak).to.be.a('function')\n    expect(result.current.speechSynthUtterance).to.be.an('object')\n  })\n})\n"
  },
  {
    "path": "test/useStorage.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupHooks } from '@testing-library/react-hooks'\nimport createStorageHook from '../dist/factory/createStorageHook'\nimport assertFunction from './utils/assertFunction'\n\ndescribe('createStorageHook', () => {\n  beforeEach(cleanupHooks)\n\n  afterEach(sinon.restore)\n\n  assertFunction(createStorageHook)\n\n  it('should return a function', () => {\n    const useLocalStorage = createStorageHook('local')\n    expect(useLocalStorage).to.be.a('function')\n  })\n\n  it('should warn when an invalid storage name is provided', () => {\n    const warnSpy = sinon.spy(console, 'warn')\n\n    createStorageHook('foo')\n\n    expect(warnSpy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useSwipe.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useSwipe from '../dist/useSwipe'\nimport useHorizontalSwipe from '../dist/useHorizontalSwipe'\nimport useVerticalSwipe from '../dist/useVerticalSwipe'\nimport assertHook from './utils/assertHook'\n\ndescribe('useSwipe', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useSwipe)\n\n  it('should return the swipe state', () => {\n    const { result } = renderHook(() => useSwipe())\n\n    expect(result.current).to.be.an('object').that.has.all.keys('swiping', 'direction', 'alphaX', 'alphaY', 'count')\n  })\n})\n\ndescribe('useHorizontalSwipe', () => {\n  beforeEach(() => cleanup())\n\n  it('should be a function', () => {\n    expect(useHorizontalSwipe).to.be.a('function')\n  })\n\n  it('should return the swipe state', () => {\n    const { result } = renderHook(() => useHorizontalSwipe())\n\n    expect(result.current).to.be.an('object').that.has.all.keys('swiping', 'direction', 'alphaX', 'alphaY', 'count')\n  })\n})\n\ndescribe('useVerticalSwipe', () => {\n  beforeEach(() => cleanup())\n\n  it('should be a function', () => {\n    expect(useVerticalSwipe).to.be.a('function')\n  })\n\n  it('should return the swipe state', () => {\n    const { result } = renderHook(() => useVerticalSwipe())\n\n    expect(result.current).to.be.an('object').that.has.all.keys('swiping', 'direction', 'alphaX', 'alphaY', 'count')\n  })\n})\n"
  },
  {
    "path": "test/useSwipeEvents.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useSwipeEvents from '../dist/useSwipeEvents'\nimport assertHook from './utils/assertHook'\n\ndescribe('useSwipeEvents', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useSwipeEvents)\n\n  it('should return the swipe handler setters', () => {\n    const { result } = renderHook(() => useSwipeEvents())\n\n    expect(result.current).to.be.an('object').that.has.all.keys(\n      'onSwipeLeft', 'onSwipeRight', 'onSwipeStart', 'onSwipeMove', 'onSwipeEnd', 'onSwipeUp', 'onSwipeDown'\n    )\n  })\n})\n"
  },
  {
    "path": "test/useSystemVoices.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useSystemVoices from '../dist/useSystemVoices'\nimport SpeechSynthesisMock from './mocks/SpeechSynthesis.mock'\nimport assertHook from './utils/assertHook'\n\ndescribe('useSystemVoices', () => {\n  const originalSpeechSynth = window.speechSynthesis\n\n  before(() => {\n    window.speechSynthesis = SpeechSynthesisMock\n  })\n\n  beforeEach(() => cleanup())\n\n  after(() => {\n    window.speechSynthesis = originalSpeechSynth\n  })\n\n  assertHook(useSystemVoices)\n\n  it('should return the list of all available system voices', () => {\n    const { result } = renderHook(() => useSystemVoices())\n\n    expect(result.current).to.be.an('array')\n  })\n})\n"
  },
  {
    "path": "test/useThrottledCallback.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport useThrottledCallback from '../dist/useThrottledCallback'\nimport promiseDelay from './utils/promiseDelay'\nimport assertHook from './utils/assertHook'\n\ndescribe('useThrottledCallback', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n  })\n\n  afterEach(sinon.restore)\n\n  assertHook(useThrottledCallback)\n\n  it('should return a single function', () => {\n    const fn = () => 0\n    const { result } = renderHook(() => useThrottledCallback(fn))\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('should return a throttled function', async () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const throttledFn = useThrottledCallback(() => {\n        spy()\n      }, [], 250)\n\n      React.useEffect(() => {\n        throttledFn()\n        throttledFn()\n        throttledFn()\n        throttledFn()\n      }, [])\n\n      return <div />\n    }\n\n    render(<TestComponent />)\n\n    await promiseDelay(300)\n\n    expect(spy.called).to.be.true\n    expect(spy.callCount).to.equal(1)\n  })\n\n  it('should use the latest callback', async () => {\n    const firstSpy = sinon.spy();\n    const secondSpy = sinon.spy();\n\n    const TestComponent = () => {\n      const [callback, setCallback] = React.useState(() => firstSpy);\n      const throttledCallback = useThrottledCallback(callback, [callback], 250); \n\n      React.useEffect(() => {\n        throttledCallback();\n        throttledCallback();\n      }, [throttledCallback]);\n\n      React.useEffect(() => {\n        setTimeout(() => {\n          setCallback(() => secondSpy);\n        }, 100);\n      }, []);\n\n      return <div />;\n    };\n\n    render(<TestComponent />);\n\n    await promiseDelay(600);\n\n    expect(firstSpy.callCount).to.equal(1); \n    expect(secondSpy.callCount).to.equal(1); \n  })\n})\n"
  },
  {
    "path": "test/useTimeout.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { act, cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useTimeout from '../dist/useTimeout'\nimport promiseDelay from './utils/promiseDelay'\nimport assertHook from './utils/assertHook'\n\ndescribe('useTimeout', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  afterEach(sinon.restore)\n\n  assertHook(useTimeout)\n\n  it('should return an array, the first item is the timeout state whilst the second its clearing method', () => {\n    const { result } = renderHook(() => useTimeout(() => null, 1000))\n\n    expect(result.current).to.be.an('array')\n    expect(result.current[0]).to.be.an('boolean')\n    expect(result.current[1]).to.be.a('function')\n  })\n\n  it('should allow to define whether the timeout should be cleared on unmount', async () => {\n    const delay = 50\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      useTimeout(spy, delay, { cancelOnUnmount: false })\n\n      return <div />\n    }\n\n    const { rerender } = render(<TestComponent />)\n    rerender(null)\n\n    await promiseDelay(10 + delay)\n\n    expect(spy.called).to.be.false\n  })\n\n  it('even if the provided options is null, it should keep working', () => {\n    const { result } = renderHook(() => useTimeout(() => null, 1000, null))\n\n    expect(result.current).to.be.an('array')\n  })\n\n  it('should allow to clear the created timeout', () => {\n    const spy = sinon.spy()\n    const delay = 100\n    const { result, error } = renderHook(() => useTimeout(spy, delay))\n    const clear = result.current[1]\n\n    expect(result.current[0]).to.be.false\n\n    act(clear)\n\n    expect(result.current[0]).to.be.true\n    expect(spy.called).to.be.false\n\n    act(clear)\n\n    expect(result.current[0]).to.be.true\n\n    expect(error).to.be.undefined\n  })\n\n  it('should check the received parameters to avoid errors', () => {\n    const { result } = renderHook(() => useTimeout(10, { foo: 'bar' }))\n    const clear = result.current[1]\n\n    expect(result.current[0]).to.be.false\n    expect(clear).to.be.a('function')\n\n    act(clear)\n\n    expect(result.current[0]).to.be.false\n  })\n})\n"
  },
  {
    "path": "test/useToggle.spec.js",
    "content": "import React from 'react'\nimport { renderHook } from '@testing-library/react-hooks'\nimport { fireEvent, render } from '@testing-library/react'\nimport useToggle from '../dist/useToggle'\nimport assertHook from './utils/assertHook'\n\ndescribe('useToggle', () => {\n\n  assertHook(useToggle)\n\n  it('first item should be a boolean', () => {\n    const { result } = renderHook(() => useToggle())\n\n    expect(result.current).to.be.an('array')\n    expect(result.current[0]).to.be.a('boolean')\n  })\n\n  it('second item should be a React setState function', () => {\n    const { result } = renderHook(() => useToggle())\n\n    expect(result.current).to.be.an('array')\n    expect(result.current[1]).to.be.a('function')\n  })\n\n  it('should toggle boolean values ', () => {\n    const TestComponent = () => {\n      const [toggle, changeToggle] = useToggle(true)\n\n      return <button onClick={changeToggle}>{toggle ? 'on' : 'off'}</button>\n    }\n\n    const { container } = render(<TestComponent />)\n    const button = container.querySelector('button')\n\n    expect(button.innerHTML).to.equal('on')\n\n    fireEvent.click(button)\n\n    expect(button.innerHTML).to.equal('off')\n  })\n})\n"
  },
  {
    "path": "test/useTouchEvents.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useTouchEvents from '../dist/useTouchEvents'\nimport assertHook from './utils/assertHook'\n\ndescribe('useTouchEvents', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useTouchEvents)\n\n  it('should return an object of mouse-related callback setters', () => {\n    const { result } = renderHook(() => useTouchEvents())\n\n    expect(result.current).to.be.an('object').that.has.all.keys('onTouchStart', 'onTouchEnd', 'onTouchMove', 'onTouchCancel')\n  })\n})\n"
  },
  {
    "path": "test/useTouchState.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useTouchState from '../dist/useTouchState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useTouchState', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useTouchState)\n\n  it('should return a TouchList object', () => {\n    const { result } = renderHook(() => useTouchState())\n\n    expect(result.current).to.have.property('length')\n  })\n})\n"
  },
  {
    "path": "test/useURLSearchParams.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useURLSearchParams from '../dist/useURLSearchParams'\nimport assertHook from './utils/assertHook'\nimport ReactRouterWrapper from './utils/ReactRouterWrapper'\n\ndescribe('useURLSearchParams', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useURLSearchParams)\n\n  it('should return an instance of URLSearchParams', () => {\n    const { result } = renderHook(() => useURLSearchParams(), { wrapper: ReactRouterWrapper })\n    expect(result.current).to.be.an.instanceOf(URLSearchParams)\n  })\n})\n"
  },
  {
    "path": "test/useUnmount.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useUnmount from '../dist/useUnmount'\nimport assertHook from './utils/assertHook'\n\ndescribe('useUnmount', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  assertHook(useUnmount)\n\n  it('should return a single function', () => {\n    const { result } = renderHook(() => useUnmount())\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('the returned function should be a setter for a callback to be performed when component did unmount', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onUnmount = useUnmount()\n\n      onUnmount(spy)\n\n      return null\n    }\n\n    const { rerender } = render(<TestComponent />)\n\n    rerender(null)\n\n    expect(spy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useUpdateEffect.spec.js",
    "content": "import { useEffect } from 'react'\nimport { cleanup, renderHook } from '@testing-library/react-hooks'\n\nimport assertHook from './utils/assertHook'\nimport useUpdateEffect from '../dist/useUpdateEffect'\n\ndescribe('useUpdateEffect', () => {\n  beforeEach(() => {\n    cleanup()\n  })\n\n  assertHook(useUpdateEffect)\n\n  it('should represent directly the difference between useEffect and useUpdateEffect', () => {\n    const useEffectCallbackSpy = sinon.spy()\n    const useUpdateEffectCallbackSpy = sinon.spy()\n\n    const { rerender: rerenderUseEffect } = renderHook(() => useEffect(useEffectCallbackSpy))\n    const { rerender: rerenderUseUpdateEffect } = renderHook(() => useUpdateEffect(useUpdateEffectCallbackSpy))\n\n    expect(useEffectCallbackSpy.called).to.be.true\n    expect(useUpdateEffectCallbackSpy.called).to.be.false\n\n    rerenderUseEffect();\n    rerenderUseUpdateEffect()\n\n    expect(useEffectCallbackSpy.called).to.be.true\n    expect(useUpdateEffectCallbackSpy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useValidatedState.spec.js",
    "content": "import { act, cleanup, renderHook } from '@testing-library/react-hooks'\nimport useValidatedState from '../dist/useValidatedState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useValidatedState', () => {\n  const makeValidator = (value = true) => () => value\n\n  beforeEach(() => cleanup())\n\n  assertHook(useValidatedState)\n\n  it('should return an array of state, setState and validation', () => {\n    const initialState = 10\n    const { result } = renderHook(() => useValidatedState(makeValidator(), initialState))\n\n    expect(result.current).to.be.an('array')\n    expect(result.current[0]).to.be.equal(initialState)\n    expect(result.current[1]).to.a('function')\n    expect(result.current[2]).to.an('object')\n  })\n\n  it('should return the validated state', () => {\n    const initialState = 10\n    const { result } = renderHook(() => useValidatedState(makeValidator(true), initialState))\n    const [, setState] = result.current\n\n    act(() => {\n      setState(20)\n    })\n\n    expect(result.current[0]).to.equal(20)\n    expect(result.current[2]).to.deep.equal({ changed: true, valid: true })\n  })\n})\n"
  },
  {
    "path": "test/useValueHistory.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useValueHistory from '../dist/useValueHistory'\nimport assertHook from './utils/assertHook'\n\ndescribe('useValueHistory', () => {\n  beforeEach(() => cleanup())\n\n  assertHook(useValueHistory)\n\n  it('should return an array', () => {\n    const { result } = renderHook(() => useValueHistory(10))\n\n    expect(result.current).to.be.an('array')\n  })\n\n  it('should return the history of the given value', () => {\n    const { result, rerender } = renderHook((value) => useValueHistory(value), { initialProps: 1 })\n\n    rerender(2)\n    rerender(3)\n\n    expect(result.current).to.deep.equal([1, 2, 3])\n  })\n\n  it('should return the history of the unique given value', async () => {\n    const { result, rerender } = renderHook((value) => useValueHistory(value, true), { initialProps: 1 })\n\n    rerender(2)\n    rerender(1)\n    rerender(1)\n\n    expect(result.current).to.deep.equal([1, 2])\n  })\n})\n"
  },
  {
    "path": "test/useViewportSpy.spec.js",
    "content": "import { act, cleanup, renderHook } from '@testing-library/react-hooks'\nimport useViewportSpy from '../dist/useViewportSpy'\nimport IntersectionObserverMock from './mocks/IntersectionObserver.mock'\nimport assertHook from './utils/assertHook'\n\ndescribe('useViewportSpy', () => {\n  before(() => {\n    window.IntersectionObserver = IntersectionObserverMock\n  })\n\n  beforeEach(() => cleanup())\n\n  after(() => {\n    delete window.IntersectionObserver\n  })\n\n  assertHook(useViewportSpy)\n\n  it('should return a single boolean value', () => {\n    const refMock = { current: document.createElement('div') }\n    const { result } = renderHook(() => useViewportSpy(refMock))\n\n    expect(result.current).to.be.a('boolean')\n  })\n\n  it('should spy on the viewport', () => {\n    const refMock = { current: document.createElement('div') }\n    const { result } = renderHook(() => useViewportSpy(refMock, { threshold: 0.2 }))\n\n    act(() => {\n      IntersectionObserverMock.simulateObservation()\n    })\n\n    expect(result.current).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useViewportState.spec.js",
    "content": "import { cleanup, renderHook } from '@testing-library/react-hooks'\nimport useViewportState from '../dist/useViewportState'\nimport assertHook from './utils/assertHook'\n\ndescribe('useViewportState', () => {\n\n  beforeEach(() => cleanup())\n\n  assertHook(useViewportState)\n\n  it('should return an object containing information on the current window state', () => {\n    const { result } = renderHook(() => useViewportState())\n\n    expect(result.current).to.be.an('object').that.has.all.keys('width', 'height', 'scrollY', 'scrollX')\n  })\n})\n"
  },
  {
    "path": "test/useWillUnmount.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useWillUnmount from '../dist/useWillUnmount'\nimport assertHook from './utils/assertHook'\n\ndescribe('useWillUnmount', () => {\n  beforeEach(() => {\n    cleanupHooks()\n    cleanupReact()\n  })\n\n  assertHook(useWillUnmount)\n\n  it('should return a single function', () => {\n    const { result } = renderHook(() => useWillUnmount())\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('the returned function should be a setter for a callback to be performed when component will unmount', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onUnmount = useWillUnmount()\n\n      onUnmount(spy)\n\n      return null\n    }\n\n    const { rerender } = render(<TestComponent />)\n\n    rerender(null)\n\n    expect(spy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useWindowResize.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, fireEvent, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useWindowResize from '../dist/useWindowResize'\nimport assertHook from './utils/assertHook'\n\ndescribe('useWindowResize', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n  })\n\n  assertHook(useWindowResize)\n\n  it('should return a single function', () => {\n    const { result } = renderHook(() => useWindowResize())\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('the returned function should be a setter for a callback to be performed when window resizes', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onWindowResize = useWindowResize()\n\n      onWindowResize(spy)\n\n      return null\n    }\n\n    render(<TestComponent />)\n\n    const resizeEvent = window.document.createEvent('UIEvents')\n    resizeEvent.initUIEvent('resize', true, false, window, 0)\n\n    fireEvent(window, resizeEvent)\n\n    expect(spy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/useWindowScroll.spec.js",
    "content": "import React from 'react'\nimport { cleanup as cleanupReact, fireEvent, render } from '@testing-library/react'\nimport { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks'\nimport useWindowScroll from '../dist/useWindowScroll'\nimport assertHook from './utils/assertHook'\n\ndescribe('useWindowScroll', () => {\n  beforeEach(() => {\n    cleanupReact()\n    cleanupHooks()\n  })\n\n  assertHook(useWindowScroll)\n\n  it('should return a single function', () => {\n    const { result } = renderHook(() => useWindowScroll())\n\n    expect(result.current).to.be.a('function')\n  })\n\n  it('the returned function should be a setter for a callback to be performed when window scrolls', () => {\n    const spy = sinon.spy()\n\n    const TestComponent = () => {\n      const onWindowScroll = useWindowScroll()\n\n      onWindowScroll(spy)\n\n      return null\n    }\n\n    render(<TestComponent />)\n\n    const resizeEvent = window.document.createEvent('UIEvents')\n    resizeEvent.initUIEvent('scroll', true, false, window, 0)\n\n    fireEvent(window, resizeEvent)\n\n    expect(spy.called).to.be.true\n  })\n})\n"
  },
  {
    "path": "test/utils/ReactRouterWrapper.js",
    "content": "import React from 'react'\nimport { MemoryRouter } from 'react-router-dom'\n\nconst ReactRouterWrapper = ({ children }) => (\n  <MemoryRouter>\n    {children}\n  </MemoryRouter>)\n\nexport default ReactRouterWrapper\n"
  },
  {
    "path": "test/utils/assertFunction.js",
    "content": "const assertFunction = (fn) => {\n  it(`${fn.name || 'it'} should be a function`, () => {\n    expect(fn).to.be.a('function')\n  })\n}\n\nexport default assertFunction\n"
  },
  {
    "path": "test/utils/assertHook.js",
    "content": "import assertFunction from './assertFunction'\n\nconst assertHook = (hook) => {\n  assertFunction(hook)\n\n  it('name should start with \\'use\\'', () => {\n    expect(hook.name.substring(0, 3)).to.equal('use')\n  })\n}\n\nexport default assertHook\n"
  },
  {
    "path": "test/utils/promiseDelay.js",
    "content": "const promiseDelay = (delay = 1000) => new Promise((resolve) => {\n  setTimeout(() => {\n    resolve()\n  }, delay)\n})\n\nexport default promiseDelay\n"
  },
  {
    "path": "test/warnOnce.spec.js",
    "content": "import { createSandbox } from 'sinon'\nimport assertFunction from './utils/assertFunction'\nimport warnOnce from '../dist/shared/warnOnce'\n\ndescribe('warnOnce', () => {\n  assertFunction(warnOnce)\n\n  const sandbox = createSandbox()\n\n  beforeEach(() => {\n    sandbox.spy(console, 'warn')\n  })\n\n  afterEach(() => {\n    sandbox.restore()\n  })\n\n  it('should not warn the same message twice', () => {\n    const message = 'foo'\n    const repeats = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n    repeats.forEach(() => warnOnce(message))\n\n    expect(console.warn.calledOnce).to.be.true\n  })\n})\n"
  },
  {
    "path": "tsconfig.cjs.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./dist/\"\n  }\n}\n"
  },
  {
    "path": "tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"declaration\": false,\n    \"target\": \"es6\",\n    \"outDir\": \"./dist/esm\"\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"include\": [\n    \"./src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"types\": [\"node\"],\n    \"allowSyntheticDefaultImports\": true,\n    \"noImplicitAny\": true,\n    \"target\": \"es5\",\n    \"jsx\": \"react\",\n    \"allowJs\": false,\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": true,\n    \"rootDir\": \"./src\",\n    \"outDir\": \"./dist\",\n    \"rewriteRelativeImportExtensions\": true\n  }\n}\n"
  },
  {
    "path": "tsconfig.types.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"emitDeclarationOnly\": true,\n    \"declaration\": true,\n    \"target\": \"es2020\"\n  }\n}\n"
  }
]